Using the ECM-RI for CCM components
The ECM-RI provides a standard CCM container implementation and its associated OMG IDL3 / CIDL
compilers for the Java programming language. It does not provide any packaging, assembling, or
distributed deployment tool. However, it provides command line scripts which can be used to
manually write a deployment sequence.
To illustrate the design, implementation, packaging, and deployment of CCM components with the
ECM-RI, we'll use the session demonstration located in the demos/runtime/session
directory. Please remind that the packaging and deployment is done manually ONLY because the ECM-RI
is a container implementation and not a full CCM implementation. In particular, we'll present some
internal stuff which is hidden from the end-user perspective in a full CCM implementation.
Quick links:
-
Overview
-
Component design
-
Component implementation
-
Component packaging
-
Component deployment
Overview of the demonstration
The session demonstration consists of a client accessing a server to purchase some products.
Purchased products are not saved in the client, but in the server (in a caddie), which means that the server
is statefull and that an instance can't be shared between many clients. This is typically the case
where session components apply in the CCM.
It's expected that the client has a GUI with the following operations:
- enter button: create a server instance (i.e. a caddie) which will be later used by the client
- leave button: destroy the created instance, i.e. empty the caddie
- purchase button: purchase the selected products in the panel above the button, i.e.
add the selected products in the caddie
- remove button: remove the selected products in the panel above the button, i.e. remove
the selected products from the caddie

Demonstrated Features
The session demonstration illustrates the following features:
- Component design:
- component with facet / receptacle
- component using a home interface
- basic home
- Ant tasks for OpenCCM
ir3_start , ir3_feed , ir3_idl2 ,
ir3_stop generation scripts
- Ant tasks for compiling an OMG IDL file, compiling Java sources and building a Jar
file
- Component implementation:
- Ant tasks for ECM-RI
cidl_idl and cidl_jimpl generation scripts
- Implementation rules for a home
- Implementation rules for a component
- Using the context to manage receptacles
- Using the
Components::SessionComponent callback interface to manage private
members
- Component packaging:
- Writing the XML CSD, mandatory elements
- Writing the XML CCD, mandatory elements
- Building the ZIP archive
- Component assembling: nothing
- Component deployment:
- Using the
ns_* , extci_* , corba_runtime_* , and
ccm_runtime_* command line scripts
- Writing manually the deployment sequence
Pre-requisites
Before going further in this tutorial, you should compile and install the demonstrations.
To compile, call the build script:
- On Linux system, just do:
$ ./make.sh --demos
Select ORB: 1) OpenORB 1.3.1 2) OpenORB 1.4.0 2) ORBacus 4.1.0
...
- On Windows system, just do:
> make.bat /demos
Select ORB: 1) OpenORB 1.3.1 2) OpenORB 1.4.0 2) ORBacus 4.1.0
...
This will compile ALL the demonstration for the selected ORB product. Then, you have to install
the demonstrations:
- On Linux system, just do:
$ ./make.sh --install
Select ORB: 1) OpenORB 1.3.1 2) OpenORB 1.4.0 2) ORBacus 4.1.0
...
- On Windows system, just do:
> make.bat /install
Select ORB: 1) OpenORB 1.3.1 2) OpenORB 1.4.0 2) ORBacus 4.1.0
...
This will install ALL the demonstrations for the selected ORB product.
Component design
The idl/session.idl3 file contains the OMG IDL3 definitions for the session
demonstration. It defines two components: the Client component and the
Server component.
The Server component
The definition for the Server component is the following:
interface IServer {
ProductSeq list_products();
void purchase_products(in ProductIdSeq pids);
void remove_products(in ProductIdSeq pids);
ProductSeq view_caddie();
};
component Server {
provides IServer i_server;
};
home ServerHome manages Server {};
The i_server facet provides the IServer OMG IDL interface for clients.
This interface allows to obtain the full list of products sold by the server, to purchase some products, to
remove some from the caddie, and to view the current content of the caddie. The ServerHome
home allows to create and destroy Server components.
The Client component
The definition for the Client component is the following:
component Client {
uses ServerHome server_home;
uses IServer i_server;
};
home ClientHome manages Client {};
The server_home receptacle allows the component to use the Server
component home interface to create and destroy Server component instances. This will allow us
to implement the enter and leave buttons. The i_server receptacle
allow the component to use the IServer OMG IDL interface. This will allow us to
fill the panel above the purchase button (operation list_products ), to implement
the purchase button (operation purchased_products ), to implement the
remove button (operation remove_products ). Note that the view_caddie
operation will be called each time the purchase or remove button is fired to fill
the panel above the remove button. The ClientHome home allows to create and destroy
Client components.
Using the Ant tasks
The ECM-RI provides a set of Ant tasks which allows to generate the OMG IDL2 equivalent to the OMG IDL3
(so-called client-side mapping), to compile OMG IDL files, to compile Java sources, and to build Jar files.
To use these tasks, you must:
- Add the
externals/Ant-1.6.0/lib/ecm_ant_tasks.jar Jar file to your classpath
- Import the task definition from the
org/objectweb/ecm/taskdefs/taskdefs.properties
file in the Jar file. You can do that by including in your Ant file the following line:
<taskdef resource="org/objectweb/ecm/taskdefs/taskdefs.properties"/>
Generating the OMG IDL2
To generate the OMG IDL2 for a OMG IDL3 file, you have can use the OpenCCM Ant tasks provided by the ECM-RI.
You have to follow these steps (the examples are taken from the ant/session.xml Ant file):
- Create a temporary directory: use the
tempdir task, for example:
<tempdir dir="session.tmp.dir"/>
The dir attribute will contain the value of the created temporary directory
- Start the OpenCCM IR3: use the
ir3start task, for example:
<ir3start cfgdir="${session.tmp.dir}"/>
The cfgdir attribute must contain an existing directory which is used as the configuration
directory for the OpenCCM IR3
- Feed the OpenCCM IR3 with your OMG IDL3 file: use the
ir3feed task, for example:
<ir3feed idl3file="../idl/session.idl3"
cfgdir="${session.tmp.dir}"/>
The idl3file attribute must contain the path to the OMG IDL3 file;
the cfgdir attribute must correspond to the value used in the ir3start task
- Generate the OMG IDL2 from the OpenCCM IR3 for a target declaration (generally the top-level
declaration of your OMG IDL3 file): use the
ir3idl2 task, for example:
<ir3idl2 scope="::org::objectweb::ccm::sessiondemo"
generateto="${ECM.build.ORB.idl.dir}"
cfgdir="${session.tmp.dir}"/>
The scope attribute must contain the target declaration fully scoped name;
the generateto attribute must contain the directory where the OMG IDL files are
generated;
the cfgdir attribute must correspond to the value used in the ir3start task
- Stop the OpenCCM IR3: use the
ir3stop task, for example:
<ir3stop cfgdir="${session.tmp.dir}"/>
The cfgdir attribute must correspond to the value used in the ir3start task
Compiling an OMG IDL file
To compile an OMG IDL file with the idl2java task, you have first to import the ORB support
Ant file:
<import file="components/runtime/orb_support/ant/orb_support.xml"/>
NOTE: This requires the name of the target ORB to be set in the ORB.name
property. Legal values are: ORBacus-4.1.0 , OpenORB-1.3.1 , and
OpenORB-1.4.0 .
You can also directly import the target ORB Ant file:
<import file="components/runtime/orb_support/ORBacus-4.1.0/ant/orb.xml"/>
Importing the ORB support Ant file provides you the idl2java task but also with the
orb.class.path path which is used for Java compilation. Other paths may be available
depending on the ORB. To compile one of the previously generated OMG IDL file, you have to do:
<idl2java idlfile = "${ECM.build.ORB.idl.dir}/org_objectweb_ccm_sessiondemo.idl"
genfile = "org/objectweb/ccm/sessiondemo/Client.java"
generateto = "${ECM.build.ORB.gen.dir}">
<includedir file="${ECM.build.ORB.idl.dir}"/>
<includedir file="${OpenCCM.install.idl.dir}"/>
</idl2java>
The idl2java task supports the following attributes:
-
idlfile : the OMG IDL file which is compiled
-
genfile : a generated file, this attribute is used to perform uptodate checks
in order to avoid generating for an uptodate OMG IDL file
-
generateto : the directory where Java files are generated
In addition, the idl2java task supports the includedir nested element which
allows to specify directories to be included for the pragma include file resolution.
Compiling Java sources and building a Jar file
To compile Java sources and build Jar files, you can use the buildjar task. This task can work
in three modes:
- Compile-only mode: used to compile Java sources
- Build-only mode: used to build a Jar file from already compiled Java classes
- Twin mode: compile Java sources and build a Jar file from the result
The only difference between the three modes is the attributes which are set. For the compile-only mode,
the srcdir , packagedir , and compileto attributes must be set.
For the build-only mode, the archivename , and buildto attributes must be set.
For the twin mode, the five previous attributes must be set.
To compile the previously generated Java files, you have to do:
<buildjar srcdir = "${ECM.build.ORB.gen.dir}/org/objectweb/ccm/sessiondemo"
packagedir = "org/objectweb/ccm/sessiondemo"
compileto = "${ECM.build.ORB.class.dir}">
<bootclasspath refid="orb.class.path"/>
<bootclasspath refid="jdk.class.path"/>
<bootclasspath>
<fileset dir="${ECM.build.ORB.lib.dir}" includes="*.jar"/>
</bootclasspath>
</buildjar>
To build a Jar file from the previously compiled Java files, you have to do (this example is not
in the ant/session.xml file:
<buildjar archivename = "sessiondemo_idl.jar"
buildto = "${ECM.build.ORB.lib.dir}">
<classes dir="${ECM.build.ORB.class.dir}">
<include name="**/sessiondemo/**/*.class"/>
</classes>
</buildjar>
The buildjar task supports the following attributes (co means compile-only mode,
bo means build-only mode, and twin means twin mode):
-
srcdir : source directory, subdirectories are included also (co, twin)
-
packagedir : path corresponding to the sources package name (co, twin)
-
compileto : directory where compiled classes are put (co, twin)
-
archivename : name of the Jar file (bo, twin)
-
buildto : directory where the Jar file is put (bo, twin)
In addition, the buildjar task supports the following nested elements:
-
bootclasspath : a bootclasspath to consider for the compilation (co, twin), note
that such paths are considered in the order they appear. This element is similar to
a Ant path element
-
classes : classes to be added to the Jar file (bo, twin). This element is
similar to a Ant fileset element
-
library : Jar file to be merged in the built Jar file (bo, twin)
Component implementation
The java directory contains the Java sources for the session demonstration. The
client subdirectory contains the implementation for the Client component.
The server subdirectory contains the implementation for the Server component.
The SessionDemo class is described as part of the
application deployment.
Implementing the homes
The following rules apply for the homes implementation.
Rule 1: For an OMG IDL3 home definition:
home <home_name> manages <component_name> {};
the corresponding home implementation must inherit from the generated <home_name>_Base
base Java class, so the OMG IDL3 ClientHome definition:
home ClientHome manages Client {};
will result in:
public class ClientHomeImpl
extends ClientHome_Base
Rule 2: The following operations must be provided by the home implementation:
- no-arg constructor, for example:
public ClientHomeImpl() {}
- static
create_home operation: shall return a new instance of the home implementation,
for example:
static public org.omg.CORBA.Object
create_home() {
return new ClientHomeImpl();
}
-
create_component_segment operation: defined by the Components::HomeExecutor
OMG IDL interface, as segmentation is not supported, it shall return a new instance of the component main
segment, for example:
final public org.omg.Components.ExecutorSegmentBase
create_component_segment(short sid)
return new ClientImpl(); // monolithic => one segment
}
NOTE: the factory keyword is not supported.
NOTE: the definitions for the Components OMG IDL module can be found in the
omg-ccm-components.idl file in the components/runtime/ccm_runtime/idl
directory.
General rules for components implementation
The following rules apply for the components implementation.
Rule 1: For an OMG IDL3 component definition:
component <component_name> {};
the corresponding component implementation must inherit from the generated
<component_name>_MainSegBase base Java class, so the OMG IDL3
Client definition:
component Client {};
will result in:
public class ClientImpl
extends Client_MainSegBase
Rule 2: Any component implementation must implement the
java.io.Serializable Java interface. This is required by the passivation
feature.
Rule 3: The following operations MUST be provided by the component
implementation:
- no-arg constructor, for example:
public ClientImpl() {}
Rule 4: The following operations MAY be provided by the component
implementation:
-
configuration_complete operation: called at the end of the deployment process, see
the Client component section for an example
-
ccm_activate , ccm_passivate , and ccm_remove : defined by the
Components::SessionComponent interface, and used to notify the component implementation
of state changes in its lifecycle, see the Server component section for an example
Rule 5: The following operations are provided to the component implementation:
-
Components::CCM2Context getCCM2Context(); operation: allow the component implementation
to obtain its context as a CCM2Context instance
-
Components::Session2Context getSession2Context(); operation: allow the component implementation
to obtain its context as a Session2Context instance
Rule 6: Operations defined in the facets of the component MUST be provided by the
implementation.
Rule 7: For each event sink of the component, operations defined in the equivalent
interface MUST be provided by the implementation (not illustrated in the session demonstration).
Rule 8: When you want to use a connected interface, you MUST ALWAYS obtain it from
the context. In other words, NO reference to one or many connected interfaces CAN BE STORED in the
implementation internal state. Cookies can be stored instead.
NOTE: the definitions for the Components OMG IDL module can be found in the
omg-ccm-components.idl file in the components/runtime/ccm_runtime/idl
directory.
Implementing the Client component
According to our expectations, the Client component holds a GUI with four actions: enter,
leave, purchase, and remove. We're going to use the configuration_complete operation to
implement the GUI creation. That way, the client's GUI will appear once the component is fully deployed
and configured. Let's see how to use the ECM-RI to implement each action. Note that the code examples are
slightly modified versions of what you find in the demonstration files.
Enter action: basically, when the client pushes the enter button, the following actions
must be realized:
- create instance: create a new
Server component instance and configure it
- connect components: connect the
i_server facet of this instance to the i_server
receptacle of the Client component
- obtain the list of products and display them
To create a new Server component instance, we first have to obtain its home. Normally, a
ServerHome home instance should be connected to the server_home receptacle
of the component. To obtain the connected instance, we have to use the get_connections operation
of the Components::LocalReceptacles OMG IDL interface. This interface is obtained using the
get_receptacles operation of the Components::CCM2Context OMG IDL interface. So we
have to do:
// Obtain the LocalReceptacles OMG IDL interface (remind rule 5 for getting the right context)
org.omg.Components.LocalReceptacles lrecs = getCCM2Context().get_receptacles();
// Obtain the current connections
omg.Components.LocalConnection[] cnxs = lrecs.get_connections("server_home");
// Only one connection
org.omg.CORBA.Object href = cnxs[0].ref();
// Narrow to the exact type
ServerHome shome = ServerHomeHelper.narrow(obj);
Now, we create a new Server component instance using the create operation of the
home instance (note: this operation comes from the client-side mapping of the ServerHome home),
and configure it:
// Create instance
Server server = shome.create();
// No configuration
// Complete configuration
server.configuration_complete();
Now, we connect the components using the connect operation of the
Components::LocalReceptacles OMG IDL interface and the provide_i_server operation
(note: this operation comes from the client-side mapping of the Server component):
// Connect components
// NOTE: we keep the cookie for later disconnection
org.omg.Components.Cookie ck = null;
ck = lrecs.connect("i_server", server.provide_i_server());
Now, we retrieve the previously connected IServer interface to obtain the list of
products.
// Only one connection
org.omg.CORBA.Object obj = lrecs.get_connections("i_server")[0].ref();
// Narrow to exact type
IServer iserver = IServerHelper.narrow(obj);
// Get list of products
Product[] products = iserver.list_products();
// And update GUI (not shown)
Purchase action: basically, when the client pushes the purchase button, the following actions
must be realized:
- get selected items and purchase them
- obtain the current caddie and display it
To purchase the selected items, we use the purchase_products operation of the connected
IServer OMG IDL interface:
// Obtain the connected IServer interface
org.omg.CORBA.Object obj = lrecs.get_connections("i_server")[0].ref();
// Narrow to exact type
IServer iserver = IServerHelper.narrow(obj);
// Purchase selected products
iserver.purchase_products(ids);
Then, we obtain the current caddie to display it:
// Get current caddie content
Product[] products = iserver.view_caddie();
// Update GUI
Remove action: basically, when the client pushes the remove button, the following actions
must be realized:
- get selected items and remove them
- obtain the current caddie and display it
To remove the selected items, we use the remove_products operation of the connected
IServer OMG IDL interface:
// Obtain the connected IServer interface
org.omg.CORBA.Object obj = lrecs.get_connections("i_server")[0].ref();
// Narrow to exact type
IServer iserver = IServerHelper.narrow(obj);
// Remove selected products
iserver.remove_products(ids);
Then, we obtain the current caddie to display it:
// Get current caddie content
Product[] products = iserver.view_caddie();
// Update GUI
Leave action: basically, when the client pushes the leave button, the following actions
must be realized:
- clear caddie
- disconnect components: disconnect the current connected
IServer interface from the receptacle
- destroy component: destroy the connected
Server component instance
- clear GUIs
To clear the caddie, we use the remove_products operation of the connected
IServer OMG IDL interface:
// Obtain the connected IServer interface
org.omg.CORBA.Object obj = lrecs.get_connections("i_server")[0].ref();
// Narrow to exact type
IServer iserver = IServerHelper.narrow(obj);
// Remove all products
iserver.remove_products(ids);
Now, we reuse the stored cookie to disconnect the components. We use the disconnect operation
of the Components::LocalReceptacles OMG IDL interface:
// ck is the previously created cookie
lrecs.disconnect(ck);
Finally, we use the remove_component operation of the home instance (note: this operation comes
from the client-side mapping of the ServerHome home):
// Obtain the connected home
org.omg.CORBA.Object href = lrecs.get_connections("server_home")[0].ref();
// Narrow to the exact type
ServerHome shome = ServerHomeHelper.narrow(obj);
// Use the remove_component operation
shome.remove_component(server);
NOTE: You MUSN'T use the remove operation of the component equivalent interface
(i.e. from the client-side mapping) directly. You MUST always destroy the component through the
remove_component operation. Otherwise, the component is not cleanly removed.
NOTE: the definitions for the Components OMG IDL module can be found in the
omg-ccm-components.idl file in the components/runtime/ccm_runtime/idl
directory.
Implementing the Server component
According to our expectations, the Server component holds the current caddie of a
Client component instance. In the CORBA Component Model, a component may be passivated
in order to save memory when its host get overloaded. As such a component may hold an internal state,
the CCM defines the Components::SessionComponent callback interface so that the component
implementation can be notified of lifecycle boundaries. We're going to use this interface to manage the
caddie internal state. Note that the code examples are slightly modified versions of what you
find in the demonstration files. But let's start with the implementation of the operational operations
first.
Implementing the facets: according to the rule 6, operations defined in the facets of
the component must be provided by the component implementation. Therefore, the list_products ,
purchase_products , remove_products , and view_caddie are provided
by the ServerImpl Java class. We will not detail their implementation. Let's note that the
caddie is stored using a java.util.ArrayList .
Managing the internal state: when the component is passivated, we don't want to save
the java.util.ArrayList , but only the ProductId s in a packed data structure.
Actually, the _purchased internal attribute which holds the caddie is marked transient
which implies that it will not be saved when the component is serialized (i.e. passivated). Instead, we
keep the ProductId s information is the _spurchased string (each ProductId
being separated by a comma). So, we have to implement the callback interface operations.
To be notified of passivation (to be able to act before the component gets passivated), we have to implement
the ccm_passivate operation:
final public void
ccm_passivate()
throws org.omg.Components.CCMException {
// Store purchased items ids in a string
StringBuffer buffer = new StringBuffer();
String[] purchased = (String[])_purchased.toArray(new String[0]);
for (int i=0;i<purchased.length;i++) {
// Add each ProductId to the string with a comma as separator
buffer.append(purchased[i]+",");
}
_spurchased = buffer.toString();
}
After the call to ccm_passivate , the component is serialized and the value of the
_purchased array list is lost (but the value of the _spurchased string
is preserved). Then, to be notified of activation (to be able to restore the array list), we have
to implement the ccm_activate operation:
final public void
ccm_activate()
throws org.omg.Components.CCMException {
// First activation, create array list
// ....
// Restore the array list using the _spurchased value
String purchased = _spurchased;
int idx = purchased.indexOf(',');
String pid = null;
// Break the string
while (idx!=-1) {
pid = purchased.substring(0, idx);
purchased = purchased.substring(idx+1);
idx = purchased.indexOf(',');
// Add to array list
_purchased.add(pid);
}
_purchased.add(purchased);
_spurchased = null;
}
After, the call to ccm_passivate , the component should be ready to process requests.
Finally, we can also act before the component is removed by providing the ccm_remove
operation:
final public void
ccm_remove()
throws org.omg.Components.CCMException {
// Reset internal attributes
_purchased.clear();
_purchased = null;
_spurchased = null;
}
NOTE: passivating or removing the component does not mean that it will be garbaged,
it can also be returned to a pool.
Code generation
The ECM-RI provides two code generators which are used during the component implementation:
-
cidl_idl generator: generates the segment definitions as OMG IDL interfaces
from a OMG IDL3 definition. The result of this generation is used by the component and
home base implementations
-
cidl_jimpl generator: generates the component and home base implementation
from a OMG IDL3 definition. The result of this generation correspond to the classes inherited
by your home and component implementations
These generators can be used as command line scripts, but some Ant tasks are also provided by
the ECM-RI. These tasks work in a way similar to the OpenCCM's ir3idl2 task. So, to
generate the segment definitions and the base implementations, you have to follow these steps
(the examples are taken from the ant/session.xml Ant file):
- Create a temporary directory (already illustrated in the component design section)
- Start the OpenCCM IR3 (already illustrated in the component design section)
- Feed the OpenCCM IR3 with your OMG IDL3 file (already illustrated in the component design section)
- Generate the OMG IDL2 segment definitions from the OpenCCM IR3 for a target declaration (generally the top-level
declaration of your OMG IDL3 file): use the
cidl2idl task, for example:
<cidl2idl scope="::org::objectweb::ccm::sessiondemo"
generateto="${ECM.build.ORB.idl.dir}"
cfgdir="${session.tmp.dir}"/>
The scope attribute must contain the target declaration fully scoped name;
the generateto attribute must contain the directory where the OMG IDL files are
generated;
the cfgdir attribute must correspond to the value used in the ir3start task
- Generate the Java base implementations from the OpenCCM IR3 for a target declaration (generally the top-level
declaration of your OMG IDL3 file): use the
cidl2jimpl task, for example:
<cidl2jimpl scope="::org::objectweb::ccm::sessiondemo"
generateto="${ECM.build.ORB.gen.dir}"
cfgdir="${session.tmp.dir}"/>
The scope attribute must contain the target declaration fully scoped name;
the generateto attribute must contain the directory where the Java files are
generated;
the cfgdir attribute must correspond to the value used in the ir3start task
- Stop the OpenCCM IR3 (already illustrated in the component design section)
NOTE: You have to compile the generated IDL (using for example the previous idl2java Ant task)
file and the generated Java files (using for example the previous buildjar task).
Component packaging
The xml directory contains the XML descriptors for the session demonstration. The
client subdirectory contains the descriptors for the Client component.
The server subdirectory contains the descriptors for the Server component.
The Component Software Descriptor (CSD)
The XML CSD describes the various implementations contained in the component archive. Amongst the many elements
specified by the CCM, some are not supported (or not used) by the ECM-RI and others are required.
The following elements are required:
-
softpkg root element: obviously, this element must be defined. The name and
version attributes are not used, for example:
<softpkg name="Server" version="2,0">
-
implementation element: the CSD must define at least one implementation element,
for example (note that the id attribute is normally a DCE UUID):
<implementation id="DCE:ServerImpl">
-
descriptor element: each implementation element must define exactly one
descriptor element. The type attribute is not used.
The element must define a fileinarchive child element to point the XML CCD for that
implementation, for example:
<descriptor type="CORBA Component">
<fileinarchive name="server.ccd"/>
</descriptor>
-
code element: each implementation element must define exactly one code
element. The type attribute is not used.
The element must define a fileinarchive child element to point the Jar file containing the
compiled code of the implementation.
The element must define a entrypoint child element to define the entrypoint of the home
implementation (i.e. the static create_home operation described before), for example:
<code type="Java class">
<fileinarchive name="server.jar"/>
<entrypoint>org.objectweb.ccm.sessiondemo.ServerHomeImpl.create_home</entrypoint>
</code>
NOTE: the XML CSD file MUST define the following document type:
<!DOCTYPE softpkg SYSTEM "softpkg.dtd">
NOTE: even if the others XML CSD are not required or used by the ECM-RI, we strongly recommend you
to set them.
The CORBA Component Descriptor (CCD)
The XML CCD describes the component features and the service dependencies of a particular component implementation.
Amongst the many elements specified by the CCM, some are not supported (or not used) by the ECM-RI and others are required.
-
corbacomponent root element: obviously, this element must be defined, for example:
<corbacomponent>
-
componentrepid element: this element must be defined with the repid attribute set
to the right CORBA::RepositoryId value, for example:
<componentrepid repid="IDL:org/objectweb/ccm/sessiondemo/Server:1.0"/>
-
homerepid element: this element must be defined with the repid attribute set
to the right CORBA::RepositoryId value, for example:
<homerepid repid="IDL:org/objectweb/ccm/sessiondemo/ServerHome:1.0"/>
NOTE: the XML CSD file MUST define the following document type:
<!DOCTYPE softpkg SYSTEM "ccd.dtd">
NOTE: even if the others XML CCD are not required or used by the ECM-RI, we strongly recommend you
to set them.
Building the ZIP archive
Unlike other ECM-RI features, no Ant task is specifically provided for the building of ZIP archives. This comes
from the fact that normally, ZIP archives are built using a packaging tool (such as the one provided by
OpenCCM). So, you'll have to build the ZIP archives manually. In the session
demonstration, we use the zip Ant task. You only have to remind that you must build the ZIP archive which
correspond to the information defined in the CSD file, in particular with respect to the fileinarchive
elements. This means that the XML CCD and the Jar files must have their ZIP entry matching the value of the name
attribute.
Component deployment
In CCM, the deployment is based on the assembly archive. As the ECM-RI does not provide this feature, we have to
manually write the deployment sequence of our application. The ECM-RI provides for that purpose a set of command
line scripts. The windows and unix directories contain the scripts to start and stop the
session demonstration.
Using the ECM-RI runtime scripts
The deployment sequence for our application is the following (single node):
- Start a CORBA
CosNaming service for the registration of home instances
- Start a CCM
ComponentInstallation service for the installation of component
archives and install the Client and Server components archives
- Start a
ClientHome home instance and register it to the CosNaming service
- Start a
ServerHome home instance and register it to the CosNaming service
- Execute the deployment plan, i.e. create one or more
Client component instances and connect
it/them with the ServerHome home instance
It's noteworthy that the ECM-RI provides a dedicated command line script for each step of the sequence.
Assuming the the install_dir variable holds your ECM-RI installation directory, you have to do:
- Start the
CosNaming service:
call %install_dir%\bin\ns_start.bat
This starts the service on the node
- Start the
ComponentInstallation service:
call %install_dir%\bin\extci_start.bat /autoload "%client_zip%,%server_zip%"
This starts the service on the node. Note that the autoload option allows to define
a list of component archives which are immediately installed. The format of the parameter is a list
of UUID=location patterns separated by commas (where UUID must match one
of the implementation id defined in the XML CSD of the component archive, and location
is the URL where the archive can be downloaded). For example, we have:
set client_zip=DCE:ClientImpl=file:%install_dir%\zips\sessiondemo_client.zip
set server_zip=DCE:ServerImpl=file:%install_dir%\zips\sessiondemo_server.zip
- Start a
ClientHome home instance and register it:
call %install_dir%\bin\ccm_runtime_start.bat /uuid DCE:ClientImpl ClientHome
This starts the home instance. Note that the uuid option must point an implementation id
already installed on the ComponentInstallation service. The ClientHome
parameter is used for the automatic registration of the home instance to the CosNaming
service (this registration is performed by the runtime)
- Start a
ServerHome home instance and register it:
call %install_dir%\bin\ccm_runtime_start.bat /uuid DCE:ServerImpl ServerHome
- Execute the deployment plan:
set entrypt=org.objectweb.ccm.sessiondemo.SessionDemo.main
set location=%install_dir%\lib\sessiondemo_main.jar
call %install_dir%\bin\corba_runtime_start.bat /entrypoint %entrypt% /location %location% SessionDemoMain
This starts the main of the demonstration. Note that the entrypoint option must point
a static Java operation and the location option must point the location of the implementation.
Please refer to the next section to know how to write this main.
Writing the main
To implement to main of the deployment, we use the CORBA runtime framework of the ECM-RI. The CORBA runtime is an
internal framework which mainly provides a set of configurable objects which a mind of simplifying the development
of pure CORBA applications. These objects are wrappers of CORBA features, such as the ORB and the POA. Indeed, with the
CORBA runtime, ORBs or POAs are never created directly. Instead, they're created by a factory according to a configuration.
Most of the interfaces used by the main are OMG IDL interfaces defined in the ecm-corba-sc.idl file in the
components/runtime/corba_runtime/idl directory
The implementation of a main on top of the CORBA runtime must follow these rules:
- The signature of the main operation must be:
static public java.lang.Runnable
<op_name>(ORBService orbs) {
// ...
}
The <op_name> operation must return an object which implements the
java.lang.Runnable Java interface. The ORBService type is an OMG IDL interface
defined in the ecm-corba-sc.idl file. Basically, this interface is a wrapper of the CORBA ORB.
It is used to register valuetype factories, and to resolve initial references.
In the SessionDemo class, we decided to give to possibility to create Client component
instances through a simple GUI. Therefore, the implementation of the run operation only lookups the
home instances in the CosNaming service. For that we use the RegistrationService service
(provided by the CORBA runtime) to obtain an INSRegistrationScheme scheme:
RegistrationService regs = org.objectweb.corba.runtime.Runtime.getRegistrationService();
INSRegistrationScheme scheme = (INSRegistrationScheme)regs.get_scheme(INSRegistrationScheme.SCHEME_ID);
Next, we use the lookup operation of the INSRegistrationScheme scheme to lookup the
home instances:
// The first parameter is the name previously passed to the ccm_runtime_start script
// The second parameter is the ORBService instance given to the main operation
org.omg.CORBA.Object obj = scheme.lookup("ClientHome", orbs);
// Narrow to exact type
ClientHome chome = ClientHomeHelper.narrow(obj);
// Create the GUI (not shown)
In addition, as we use receptacles, we have to register a factory instance for the Components::Cookie
valuetype. For that, we use the register_valuefactory operation of the ORBService :
// Create the ValueFactory instance
// The first parameter is the CORBA::RepositoryId of the valuetype
// The second parameter is the factory instance
ValueFactory vfact = new ValueFactoryImpl(org.omg.Components.CookieHelper.id(), new CookieFactoryImpl());
// Register to the ORBService
orbs.register_valuefactory(vfact);
Finally, when a client pushes the new client button of the GUI, we create a Client
component instance using the home, connect this instance to the ServerHome home instance, and configure
it:
// Use the create operation coming from the client-side mapping of the home
Client client = chome.create();
// Connect the server_home receptacle with the ServerHome home instance
// The connect_server_home operations comes from the client-side mapping of the receptacle
client.connect_server_home(shome);
// No configuration
// Complete configuration
client.configuration_complete();
We hope that you have found in this tutorial enough material to understand the basic CCM features provided by
the ECM-RI. Remarks, typos, or suggestions are welcomed.
Go to the next section: Using the ECM-RI to define, implement, package,
and deploy ECM-aware components
|