Information
We are currently investigating an issue with the editor of some pages. Please save your work and avoid to create new pages until this banner is gone.
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <xmlentity.idl> #include <acscomponent.idl> #pragma prefix "alma" module demo { typedef xmlentity::XmlEntityStruct ObsProposal; typedef xmlentity::XmlEntityStruct SchedBlock; typedef sequence <SchedBlock> SchedBlockSeq; exception XmlComponentException {}; struct ObsProjectTree { ObsProposal prop; SchedBlockSeq schedBlocks; }; interface XmlComponent : ACS::ACSComponent { long dumbMethod(in string somevalue); ObsProposal createObsProposal(); SchedBlockSeq getAllSchedBlocks(); void xmlInOutMethod(in ObsProposal opsPropIn, out SchedBlock schedBlockOut); ObsProjectTree getEntireTreeInAStruct(); void exceptionMethod() raises (XmlComponentException); }; }; |
A1 | xmlentity.idl comes from define/idl and declares the CORBA struct XmlEntityStruct which is used to transport serialized XML together with some meta data. It must be included whenever xml entity objects are used (see I-K). The developer does usually not have to know the details of that struct. | ||||
B3 | The prefix pragma must come after the include statements; this restriction might be lifted in the future, but for now the TAO IFR would have a problem otherwise. | ||||
C5 | We use the same module as for the HelloDemo component | ||||
D7 | Typedefs for xml entity classes. The interface methods that use entity classes as parameters or return types (see H-K) must use these named typedefs like 'ObsProposal' instead of 'XmlEntityStruct'. This not only makes the interface more readable, but is also required for the automatic use of Java binding classes. | ||||
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="cfccb5d4-5e6c-4cef-9301-f6acc082b3e5"><ac:plain-text-body><![CDATA[ | E11 | Declaration of an exception. (How to use the ACS Error System [6] instead of plain CORBA exceptions may be demonstrated in a future version of this document.) | ]]></ac:plain-text-body></ac:structured-macro> | ||
F13 | A struct that contains XML entities. | ||||
G19 | Interface declaration for the XmlComponent | ||||
H21 | Just to have something dumb in here | ||||
I22 | Method that returns an xml entity object (as a struct that contains the xml data as a string if the component is accessed as a plain CORBA object, see below.) | ||||
J23 | Demonstrates the use of a sequence (~array) of xml entity objects | ||||
K24 | Demonstrates the use of xml entity objects as an OUT parameter | ||||
L26 | Uses the ObsProjectTree struct, with entities inside | ||||
27 | Uses an exception (again, later the | <ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="685d4215-19d0-490c-9384-82793378ebad"><ac:plain-text-body><![CDATA[ | M | Uses an exception (again, later the mechanism described in [6] will be used.) | ]]></ac:plain-text-body></ac:structured-macro> |
...
We have to add the new IDL file to jcontexmpl/src/Makefile:
IDL_FILES = HelloDemo XmlComponent
In addition to running this file through the standard CORBA IDL compiler, it is also fed into the "ACS IDL compiler". This tool gets started by the build process, so you never have to see it; the interested reader can find it in the CVS module directory ACS/…/XmlIdl. The ACS IDL compiler creates additional Java classes which the CORBA IDL compiler would not create. They are used for working with Java XML binding classes instead of plain XML strings, see 5.1.1.
In the Makefile, the line
XML_IDL = "ObsProposal=alma.xmljbind.test.obsproposal.ObsProposal; \
SchedBlock=alma.xmljbind.test.schedblock.SchedBlock"
provides the mapping from IDL typedefs (see lines 6-8) to Java binding classes (conceptually: to the schema that defines the entities).
The Java files that are produced from XmlComponent.idl are
...
The classes shown in normal print are mandated by CORBA standards and generated by the CORBA IDL compiler, while the italicized classes are required by the ACS framework and are generated by the ACS IDL compiler.
...
In section 5.2, we saw the IDL file with the typedefs for the entity classes, and their use in the methods of the XmlComponent interface.
The following two functional interfaces have been generated for XmlComponent. The component implementation must implement one of them:
Anchor | ||||
---|---|---|---|---|
|
Anchor | ||||
---|---|---|---|---|
|
Anchor | ||||
---|---|---|---|---|
|
For each component class, a corresponding helper Naming convention: For the component of an interface "xxx", the helper file is named as "xxxComponentHelper". This should not be so easily confused with the IDL-generated "xxxHelper". class is needed. In most cases this helper class will be used only by the framework, which means that the component developer will not have to look at it much.
The framework uses the helper class to
We will choose the convenience and type-safety offered when implementing XmlComponentJ. The interface generated by the ACS IDL compiler is listed below (Javadoc lines omitted).
Code Block | ||
---|---|---|
| ||
package alma.demo;
/**
* XML binding class aware ACS component interface XmlComponentJ */
public interface XmlComponentJ extends alma.ACS.ACSComponentOperations
{
public int dumbMethod(String somevalue);
public alma.xmljbind.test.obsproposal.ObsProposal createObsProposal();
public | ||
Wiki Markup | ||
\\ We will choose the convenience and type-safety offered when implementing XmlComponentJ. The interface generated by the ACS IDL compiler is listed below (Javadoc lines omitted). \\ <span style="color: #808080">01</span> <span style="color: #7f0055"><strong>package </strong></span>alma.demo; <span style="color: #808080">02</span> <span style="color: #808080">03</span> <span style="color: #3f5fbf">/**</span> <span style="color: #808080">04</span> <span style="color: #ffffff"> </span><span style="color: #3f5fbf"><strong> XML binding class aware ACS component interface XmlComponentJ </strong>/</span> <span style="color: #808080">05</span> <span style="color: #7f0055"><strong>public interface </strong></span>XmlComponentJ <span style="color: #7f0055"><strong>extends </strong></span>alma.ACS.ACSComponentOperations <span style="color: #808080">06</span> \{ <span style="color: #808080">10</span> <span style="color: #ffffff"> </span><span style="color: #7f0055"><strong>public int </strong></span>dumbMethod(String somevalue); <span style="color: #808080">11</span> <span style="color: #808080">15</span> <span style="color: #ffffff"> </span><span style="color: #7f0055"><strong>public </strong></span>alma.xmljbind.test.obsproposal.ObsProposal createObsProposal(); <span style="color: #808080">16</span> <span style="color: #808080">25</span> <span style="color: #ffffff"> </span><span style="color: #7f0055"><strong>public </strong></span>alma.xmljbind.test.schedblock.SchedBlock\[\] getAllSchedBlocks(); <span style="color: #808080">26</span> <span style="color: #808080">30</span> <span style="color: #ffffff"> </span><span style="color: #7f0055"><strong>public void </strong></span>addNewSchedBlocks( alma.xmljbind.test.schedblock.SchedBlock\[\] newSchedBlocks); <span style="color: #808080">31</span> <span style="color: #808080">35</span> <span style="color: #ffffff"> </span><span style="color: #7f0055"><strong>public void </strong></span>xmlInOutMethod( alma.xmljbind.test.obsproposal.ObsProposal opsPropIn, alma.demo.SchedBlockHolder schedBlockOut); <span style="color: #808080">36</span> <span style="color: #808080">40</span> <span style="color: #ffffff"> </span><span style="color: #7f0055"><strong>public </strong></span>alma.demo.ObsProjectTreeJ getEntireTreeInAStruct(); <span style="color: #808080">41</span> <span style="color: #808080">50</span> <span style="color: #ffffff"> </span><span style="color: #7f0055"><strong>public void </strong></span>exceptionMethod() <span style="color: #808080">51</span> <span style="color: #ffffff"> </span><span style="color: #7f0055"><strong>throws </strong></span>alma.demo.XmlComponentException; <span style="color: #808080">53</span> \} \\ Comparing this with the IDL definition, we see that binding classes like alma.xmljbind.test.schedblock.SchedBlock are used whenever the IDL contained a typedef'd entity struct. In addition to this direct substitution, the ACS IDL compiler created the class ObsProjectTreeJ which contains binding classes, thus substituting the IDL struct ObsProjectTree as the return type of the method getEntireTreeInAStruct(); \\ Let's look at the implementation of the method createObsProposal(). \\ <span style="color: #808080">121</span> <span style="color: #ffffff"> </span><span style="color: #7f0055"><strong>public </strong></span>ObsProposal createObsProposal() <span style="color: #808080">122</span> <span style="color: #ffffff"> </span>\{ <span style="color: #808080">123</span> <span style="color: #ffffff"> </span>ObsProposal obsProp = <span style="color: #7f0055"><strong>new </strong></span>ObsProposal(); <span style="color: #808080">124</span> <span style="color: #ffffff"> </span> <span style="color: #808080">125</span> <span style="color: #ffffff"> </span><span style="color: #7f0055"><strong>try</strong></span> <span style="color: #808080">126</span> <span style="color: #ffffff"> </span>\{ <span style="color: #808080">127</span> <span style="color: #ffffff"> </span>ObsProposalEntityT entity = <span style="color: #7f0055"><strong>new </strong></span>ObsProposalEntityT(); <span style="color: #808080">128</span> <span style="color: #ffffff"> </span>m_containerServices.assignUniqueEntityId(entity); <span style="color: #808080">129</span> <span style="color: #ffffff"> </span>obsProp.setObsProposalEntity(entity); <span style="color: #808080">130</span> <span style="color: #ffffff"> </span> <span style="color: #808080">131</span> <span style="color: #ffffff"> </span>obsProp.setPerformanceGoals( <span style="color: #2a00ff">"peak performance enduring a 24-7-365 schedule."</span>); <span style="color: #808080">132</span> <span style="color: #ffffff"> </span>\} <span style="color: #808080">133</span> <span style="color: #ffffff"> </span><span style="color: #7f0055"><strong>catch </strong></span>(ContainerException e) <span style="color: #808080">134</span> <span style="color: #ffffff"> </span>\{ <span style="color: #808080">135</span> <span style="color: #ffffff"> </span>m_logger.log(Level.SEVERE, <span style="color: #2a00ff">"failed to create ObsProposal. "</span>, e); <span style="color: #808080">136</span> <span style="color: #ffffff"> </span>\} <span style="color: #808080">137</span> <span style="color: #ffffff"> </span> <span style="color: #808080">138</span> <span style="color: #ffffff"> </span><span style="color: #7f0055"><strong>return </strong></span>obsProp; <span style="color: #808080">139</span> <span style="color: #ffffff"> </span>\} \\ We see that the Java class ObsProposal has type-safe methods like "setPerformanceGoals" or "setObsProposalEntity". The latter takes an object of type ObsProposalEntityT, also generated by the binding framework. It is used to store administrational information about the ObsProposal object, most important the object ID. \\ For a new entity object, a valid and unique object ID can be obtained conveniently through a call to ContainerServices#assignUniqueEntityId, for which the container collaborates with the archive. If the archive is not present, it defaults to using random numbers which should be almost always unique (2^64). \\ Our method implementation simply returns the top-level Java object for the ObsProposal. The container framework will then automatically serialize it to XML, embed the string in the XmlEntity CORBA struct, and send it to the client using CORBA. If the client is another Java component, its container will automatically create an ObsProposal class and fill it with the data from the serialized XML. \\ To keep the size of this tutorial small, the implementations of the other methods are not listed here. They are meant to serve as more detailed examples, for which the source code of the module jcontexmpl should be retrieved anyway. Alternatively, the code listing can be found online at the ACS documentation site: [[] getAllSchedBlocks(); public void addNewSchedBlocks( alma.xmljbind.test.schedblock.SchedBlock[] newSchedBlocks); public void xmlInOutMethod( alma.xmljbind.test.obsproposal.ObsProposal opsPropIn, alma.demo.SchedBlockHolder schedBlockOut); public alma.demo.ObsProjectTreeJ getEntireTreeInAStruct(); public void exceptionMethod() throws alma.demo.XmlComponentException; } |
Comparing this with the IDL definition, we see that binding classes like alma.xmljbind.test.schedblock.SchedBlock
are used whenever the IDL contained a typedef’d entity struct. In addition to this direct substitution, the ACS IDL compiler created the class ObsProjectTreeJ
which contains binding classes, thus substituting the IDL struct ObsProjectTree
as the return type of the method getEntireTreeInAStruct();
Let’s look at the implementation of the method createObsProposal().
Code Block | ||
---|---|---|
| ||
public ObsProposal createObsProposal()
{
ObsProposal obsProp = new ObsProposal();
try
{
ObsProposalEntityT entity = new ObsProposalEntityT();
m_containerServices.assignUniqueEntityId(entity);
obsProp.setObsProposalEntity(entity);
obsProp.setPerformanceGoals(
"peak performance enduring a 24-7-365 schedule.");
}
catch (ContainerException e)
{
m_logger.log(Level.SEVERE, "failed to create ObsProposal. ", e);
}
return obsProp;
}
|
We see that the Java class ObsProposal has type-safe methods like “setPerformanceGoals” or “setObsProposalEntity”.
The latter takes an object of type ObsProposalEntityT, also generated by the binding framework. It is used to store administrational information about the ObsProposal object, most important the object ID.
For a new entity object, a valid and unique object ID can be obtained conveniently through a call to ContainerServices#assignUniqueEntityId, for which the container collaborates with the archive. If the archive is not present, it defaults to using random numbers which should be almost always unique (2^64).
Our method implementation simply returns the top-level Java object for the ObsProposal. The container framework will then automatically serialize it to XML, embed the string in the XmlEntity CORBA struct, and send it to the client using CORBA. If the client is another Java component, its container will automatically create an ObsProposal class and fill it with the data from the serialized XML.
To keep the size of this tutorial small, the implementations of the other methods are not listed here. They are meant to serve as more detailed examples, for which the source code of the module jcontexmpl should be retrieved anyway.
Alternatively, the code listing can be found online at the ACS documentation site:
...
To see how the code would look like if the component would implement XmlComponentOperations, take a look at the inner class XmlComponentHelper::IFTranslator.
...
For each component class, a corresponding helper Naming convention: For [1]class is needed. In most cases this helper class will be used only by the framework, which means that the component developer will not have to look at it much.
...
[1]Naming convention: For the component of an interface "xxx", the helper file is named as "xxxComponentHelper". This should not be so easily confused with the IDL-generated "xxxHelper". class is needed. In most cases this helper class will be used only by the framework, which means that the component developer will not have to look at it muchshould not be so easily confused with the IDL-generated "xxxHelper".
The framework uses the helper class toto
A template for the helper class gets generated automatically by the build system if the Makefile contains the line
COMPONENT_HELPERS=on
The template has a file ending .java.tpl to ensure that no edited .java helper class gets overwritten. It is meant as a convenience for the component developer who will normally just have to remove the .tpl ending and then treat that Java file like his/her own, which requires checking it into CVSGIT.
For our HelloDemo component, the helper class does not need to be changed (some Javadoc lines stripped from the listing):
23 package
Code Block | ||
---|---|---|
| ||
package alma.demo.HelloDemoImpl; |
...
import java.util.logging.Logger; |
...
import alma.acs.component.ComponentLifecycle; |
...
import alma.acs.container.ComponentHelper; |
...
import alma.demo.HelloDemoOperations; |
...
import alma.demo.HelloDemoPOATie; |
...
import alma.demo.HelloDemoImpl.HelloDemoImpl; |
...
/** * To create an entry for your component in the Configuration Database, * copy the line below into a new entry in the file $ACS_CDB/MACI/Components/Components. |
...
xml * and modify the instance name of the component and the container: * Name="HELLODEMO1" |
...
Code="alma.demo.HelloDemoImpl.HelloDemoComponentHelper" |
...
Type="IDL:alma/demo/HelloDemo:1.0" |
...
Container="frodoContainer" |
...
*/ public class HelloDemoComponentHelper extends ComponentHelper { public HelloDemoComponentHelper(Logger containerLogger) { super(containerLogger); |
...
} protected ComponentLifecycle _createComponentImpl() |
...
{ return new HelloDemoImpl(); |
...
} protected Class _getPOATieClass() |
...
{ return HelloDemoPOATie.class; |
...
} protected Class _getOperationsInterface() |
...
{ return HelloDemoOperations.class; |
...
} } |
Only in special situations, when a Java component chooses to sometimes use Java binding classes, but other times send or receive serialized XML instead, then the helper class must be modified. This goes beyond the scope of this tutorial and will be described in a more specialized document.
An example for this can be found in alma.demo.XmlComponentImpl.XmlComponentComponentHelper from jcontexmpl/src/.
...
The ACS configuration database contains information about which components are deployed on the different machines. It assists the ACS Manager to locate components at runtime. All the runtime action is hidden from the programmer by the container.
There are two different types of components:
Wiki Markup |
---|
dynamic components whose type (and optionally container location) is fixed at deployment time, whereas the number and names of instances is determined only at runtime. For more details on this, refer to \[3\], topic "FAQGeneralCompDynamic". |
Let’s Let's make HelloDemo a static component. We create a new line in the file CDB/MACI/Components/ Components.xml with
Note that the generated component helper class contains these values in a comment (code listing above, line 42). This facilitates adding the CDB entry using copy and paste.
The CDB file Components.xml then looks similar to
Code Block | ||
---|---|---|
| ||
<?xml version="1.0" encoding="utf-8"?> |
...
<Components xmlns="urn:schemas-cosylab-com:Components:1.0" |
...
xmlns:cdb="urn:schemas-cosylab-com:CDB:1.0" |
...
xmlns:baci="urn:schemas-cosylab-com:BACI:1.0" |
...
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
...
<_ Name="TEST_PS_1" Code="acsexmplPowerSupplyImpl" |
...
Type="IDL:alma/PS/PowerSupply:1.0" Container="bilboContainer"/> |
...
<_ Name="HELLODEMO1" Code="alma.demo.HelloDemoImpl.HelloDemoHelper" |
...
Type="IDL:alma/demo/HelloDemo:1.0" Container="frodoContainer" /> |
...
<_ Name="XMLCOMP1" Code="alma.demo.XmlComponentImpl.XmlComponentHelper" |
...
Type="IDL:alma/demo/XmlComponent:1.0" Container="frodoContainer" /> |
...
<_ Name="LAMP1" Code="acsexmplLamp" Type="IDL:ALMA/PS/Lamp:1.0" Container="bilboContainer"/> |
...
<_ Name="OPERATIONAL_ARCHIVE" Code="alma.archive.components.OperationalHelper" |
...
Type="IDL:alma/xmlstore/Operational:1.0" Container="frodoContainer" /> |
...
</Components> |
ACS ships with a default CDB that contains the entries for the demo components.
You'll You’ll have to add entries for your own components, or create a new CDB structure and reset the ACS_CDB environment variable.
...
...
A component can have different kinds of clients which we'll discuss separately:
...
We can use the ACS tool ObjectExplorer as a generic client for all components. Run it with
objexp
and you should find your Java components (e.g. XmlComponent) and their instances (e.g. XMLCOMP1) listed on the dialog, together with C++ components (e.g. Lamp).
At first, you see only a visualization of the information in the CDB, as opposed to actually loaded components. When you click on a component instance, the Manager will tell the Container to activate the component with the given instance name.
The screenshot shows the output after XMLCOMP1 has been loaded and the method getBestSchedBlock has been called (with View → Expand result data checked in ObjectExplorer.)
...
We've We’ve seen the example of a Java component accessing a C++ Component in 4in 4.2, and a Java component accessing another Java component without transparent XML binding support referenced in 5in 5.1.
To use support for xml binding classes on the client side of a call, we first obtain the other component (here: XMLCOMP1)
XmlComponent xmlComp
Code Block | ||
---|---|---|
| ||
XmlComponentxmlComp=alma.demo.XmlComponentHelper.narrow( |
...
getComponent("XMLCOMP1")); |
and then ask the container to wrap it with the more convenient interface that uses XML binding classes, provided in the ContainerServices interface
Code Block | ||
---|---|---|
| ||
XmlComponentJ xmlCompJ= |
...
(XmlComponentJ)m_containerServices |
...
.createXmlBindingWrapper( XmlComponentJ.class, xmlComp, XmlComponentOperations.class); |
Now we can keep working with xmlCompJ, and the framework will delegate all calls to xmlComp, translating between XML binding classes and serialized XML presentation in between.
...
To facilitate the writing of JUnit test clients, ACS (module jcont) offers the class alma
alma.acs.component.client.ComponentClientTestCase
which is a subclass of JUnit's JUnit’s TestCase that does the talking with ACS Manager. It provides most of the functionality that ContainerServices provides for components.
A JUnit test that gets a reference to the XmlComponent component and runs some tests on it is is
jcontexmpl/src/alma.demo.client.XmlComponentClient 020 package
Code Block | ||
---|---|---|
| ||
package alma.demo.client; |
...
import alma.acs.component.client.ComponentClientTestCase; |
...
import alma.demo.SchedBlockHolder; |
...
import alma.demo.XmlComponent; |
...
import alma.demo.XmlComponentException; |
...
import alma.demo.XmlComponentJ; |
...
import alma.demo.XmlComponentOperations; |
...
import alma.entities.commonentity.EntityT; |
...
import alma.xmljbind.test.obsproposal.ObsProposal; |
...
import alma.xmljbind.test.schedblock.SchedBlock; |
...
public class XmlComponentClient extends ComponentClientTestCase { private XmlComponentJ m_xmlCompJ; public XmlComponentClient() throws Exception { super("XmlComponentClient"); |
...
} protected void setUp() throws Exception { super.setUp(); |
...
org.omg.CORBA |
...
.Object compObj = getContainerServices().getComponent( |
...
"XMLCOMP1"); |
...
assertNotNull(compObj); |
...
XmlComponent xmlComp = alma.demo.XmlComponentHelper.narrow(compObj); |
...
m_ |
...
xmlCompJ = |
...
(XmlComponentJ) |
...
getContainerServices() |
...
.getTransparentXmlComponent(XmlComponentJ.class, |
...
xmlComp, XmlComponentOperations.class); |
...
assertNotNull(m_xmlCompJ); |
...
} public void testSayHelloUsingHelloDemoComponent() |
...
{ String reply = m_xmlCompJ.sayHello(); |
...
assertNotNull(reply); |
...
System.out.println(" |
...
received reply " + reply); assertEquals("reply must be 'hello'", |
...
"hello", |
...
reply); |
...
} public void testCreateObsProposal() |
...
{ ObsProposal obsProp = m_xmlCompJ.createObsProposal() |
...
; assertNotNull(obsProp); |
...
EntityT ent = obsProp.getObsProposalEntity(); |
...
assertNotNull(ent); |
...
String id = ent.getEntityId(); |
...
assertNotNull(id); |
...
System.out.println(" |
...
received ObsProposal with id " + id); } public void testXmlInOutMethod() { ObsProposal obsProp = m_xmlCompJ.createObsProposal(); |
...
assertNotNull(obsProp); |
...
SchedBlockHolder sbh = new SchedBlockHolder(); |
...
m_xmlCompJ.xmlInOutMethod(obsProp, |
...
sbh); SchedBlock schedBlock = sbh.value; assertNotNull(schedBlock); |
...
EntityT ent = schedBlock.getSchedBlockEntity(); |
...
assertNotNull(ent); |
...
String id = ent.getEntityId(); |
...
assertNotNull(id); |
...
System.out.println(" |
...
received out-param SchedBlock with id " + id); } public void testException() throws Exception { boolean gotException = false; try { m_xmlCompJ.exceptionMethod(); |
...
} catch (XmlComponentException e) { gotException = true; System.out.println(" |
...
received XmlComponentException as intended."); |
...
} assertTrue(" |
...
must receive XmlComponentException", |
...
gotException); |
...
} } |
The constructor must call the constructor of the base class
...
with a name to be used for this client (here:
...
“XmlComponentClient”). If you override the setup() method,
...
it’s necessary there to call super.setUp() first
...
.
JUnit will call all methods that start with
...
“test” in their name, such as testException().
In the Eclipse Java Perspective, you can run such a class with JUnit. Open the class in the editor, then choose
Menu Run → Run As → JUnit Test. It will display the results.