Table of Contents
This document provides important information about the OpenORB Trading Object Service. More precisely, this document explains how to build, install, configure and use this service.
A Trading Service facilitates the offering and the discovery of instances of services of particular types. A trader is a CORBA object that supports the trading object service in a distributed environment. It can be viewed as an object through which other objects can advertise their capabilities and match their needs against advertised capabilities.
Advertising a capability or offering a service is called export. Matching against needs or discovering services is called import. Export and import facilitate dynamic discovery of, and late binding to, services.
To export an offer, a service describes a Service Type that contains a set of properties ( typed values ). A client application matches its needs by applying a constraint on the properties ( through a constraint language defined by OMG ). Dynamic properties are allowed ( it means that such a property is evaluated by an external property evaluator that gives the ability to measure some specific features like for example memory ).
The OpenORB Trading Service provides a fully compliant implementation of this service. It provides:
The OpenORB Trading Object Service requires : OpenORB, and the Persistent State Service
Thus, before building and installing OpenORB, be sure that the previous requirements are correctly installed and configuring on your host.
The Trading Service is built thanks to an Ant script. In addition, the Trading Service provides two scripts files : build.bat for Windows and build.sh for Unix. To build the Trading service, run the script: build or sh build.sh
To run the ant script, the Ant tool must be previously installed. Ant is provided with the OpenORB distribution. When you add the OpenORB openorb_tools-{version}.jar file into your classpath, it is not necessary to add something else into your classpath in order to use Ant ( except if you are using JDK 1.1.x )
This script builds the Trading Service, the examples and the documentation. In addition, you can also build the trading service plugin : build plugin
Now, extend your classpath to add the openorb_trader-{version}.jar ( this file is created into the dist directory ).
The trading service used a set of properties to manage its behavior. These properties are define in a module named trader which is described in the trader.xml file. This file is by default embedded in the Trading Service Jar file.
At least a property must be customized in the trader module. The next chapter explains how to do that.
After this step, the OpenORB trading service is now installed. Please check the next section to discover how to configure it.
The module trader.xml available in src/config for the source code distribution and config for the Pre-Built version, must be edited to customized at least one property.
Each Trading Server must have a name. To specify it, the module contains a property named name. Customize its value to supply the trader name to use. All the others properties have a default value that can be used, so, if you don't want to study during your first read the next properties, you can directly go to the next sub title How to complete the configuration ?
If you start two trading servers on the same host, they will have both the same trader name !. To avoid this problem, you can specify the trader name for the second trading service from the command line ( see next section about how to run the trading object server.
When a service offer is exported, the trading server will apply additional checks if you set the property name ir to true . This property specifies if the Interface Repository must be used to apply additional checks.
If set to true, the Interface Repository must be previously started before running the trading object service. All interface descriptions should have been previously loaded into the interface repository.
If you want to use the service type repository as a stand alone server, you have to supply the following properties :
By default, the trader is started under a transient mode. However, it's possible to modify this default behaviour through the persistence property. If you want to always start the trader under a persistent mode, set its value to true.
The trading service behaviour is influenced by a set of properties:
In addition to the previous properties a set of attributes are defined through properties.
To complete the configuration, we are going to replace the embedded configuration by the new one. The way to do that depends on the distribution that you are currently using : source code or pre built distribution. The following paragraphs describes how to proceed for each distribution kind.
In the case of the source code distribution, a Ant target is provided to replace the embedded configuration file. From the command line: build config
The new configuration file must be available in the src/config directory. Moreover, the Jar file where the configuration will be output must be available in the dist directory.
In the case of the pre built distribution, the config directory contains a script named setConfig ( setConfig.bat for Windows and setConfig.sh for Unix ). We have just to start this script to replace the embedded configuration file.
The new configuration file must be available in the config directory. Moreover, the Jar file where the configuration will be output must be available in the lib directory.
Table of Contents
The Trading Object Server is composed of 2 parts: the trader, and the service type repository
To start the trader, execute the Java class org.openorb.trader.Server. You can apply several options when you start the trader:
The service type repository can be used as embedded into the trader or in a stand alone mode. ( In this case, you have to start the trader and specifying the CORBA URL for the stand alone service type repsitory ).
To start the service type repository, execute the following Java class org.openorb.trader.repository.Server. Several options are available :
The Easy Trader System is an exclusive mechanism provided by the OpenORB Trading Object Service. The OMG Trading Service is a very interesting service that provides powerful features. However, it is often very difficult to use it, because it requires a lot of code to develop a simple application.
This is the reason why the OpenORB Trading Object Service provides a Service Type compiler that generates some Java classes ( fully portables ) to facilitate the Trading Service usage.
To describe a Service Type, you have to use the following grammar :
service <ServiceTypeName> [ : <BaseServiceTypeName> [ , <BaseServiceTypeName> ]* ] { interface <InterfaceTypeName>; [ [ mandatory ] [ readonly ] property <IDLType> <PropertyName> ; ]* };
Each service type description must be defined in a file that uses the ".st" extension. This file could include IDL descriptions ( via #include ), and could use comments ( /* .. */ ).
This description must be compiled with the OpenORB Service Type compiler ( see next chapter to get more information about this compiler ).
When a ServiceType description is compiled, a file is generate <ServiceTypeName>Helper.java. This class provides the following operations :
Plus, if you use the -export flag with the service type compiler, another class is generated with the following name : <ServiceTypeName>.java
This class contains several operations :
The OpenORB Trading Object Service provides a service type compiler to generate Java classes that provide an easy way to use the trader.
The compiler class is: java org.openorb.trader.compiler.StdlCompiler
In addition to the standard IDL compiler flags, the STDL compiler provides :
OpenORB provides an Ant task that eases the use of OpenORB STDL compiler. The Ant task can be easily included in your projects by using the taskdef tag. The task does additionnal uptodate checks and only compiles idl files which are more recent than the target Java files. This is done using a cache (in a file called stdl2java.cache by default) which is updated every time the compiler is run.
<project name="myproject"> <taskdef resource="stdl2java.properties"> ...
You only need to reference the openorb_tools-<version>.jar and openorb_trader-<version>.jar in the classpath of your build. The source files are set using a nested FileSet task which means that it possible to specify a whole tree of files to be compiled. It is possible to refine the set of files that are being compiled. This can be done with the includes, includesfile, excludes, and excludesfile attributes. With the includes or includesfile attribute, you specify the files you want to have included. The exclude or excludesfile attribute is used to specify the files you want to have excluded. In both cases, the list of files can be specified by either the filename, relative to the directory(s) specified in the srcdir attribute or nested <src> element(s), or by using wildcard patterns. See the section on Ant Manual,directory-based tasks, for information on how the inclusion/exclusion of files works, and how to write wildcard patterns.
Attribute | Description | Required |
---|---|---|
srcdir | Location of the idlfiles files. | Yes, unless nested <src> elements are present. |
destdir | Location to store the generated java files.generated will be used if nothingspeficied. | No |
includes | Comma- or space-separated list of files (may bespecified using wildcard patterns) that must be included; all .idl files are included whenomitted. | No |
includesfile | The name of a file that contains a list of files toinclude (may be specified using wildcard patterns). | No |
excludes | Comma- or space-separated list of files (may bespecified using wildcard patterns) that must beexcluded; no files (except default excludes) areexcluded when omitted. | No |
excludesfile | The name of a file that contains a list of files toexclude (may be specified using wildcard patterns). | No |
includepath | The path where other included IDL files can be found.This is a path structure and should contain comma- orspace-separated list of directories. An additionnal resource protocol for loading from JAR files can be used (prepend to directory name, e.g. resource:/org/openorb/idl/) if includeorbidl is set to true (by default). | No |
quiet | suppress any output | No |
export | Generate a Java class for each Service Type that exports an offer; defaults toyes. | No |
verbose | Shows debug output; defaults to no. | No |
jdk14code | Generates classes that use JDK1.4 features. The generated classes will not compile on previous versions;defaults to no | No |
generateall | Generate mapping for included files; defaults tono. Be careful when using this option with the uptodatechecks as the cache is not notified of the included idl files. | No |
uptodatechecks | Indicates if the compiler is doing uptodate checks on idl files and target java files; defaults to yes. | No |
cachefile | Indicates where to place the compiler cache file; defaults to stdl2java.cache. | No |
Example:
<stdl2java destdir="${gensrc.dir}/examples" includepath="${examples.dir}/org/openorb/trader/examples/bank" srcdir="${examples.dir}/org/openorb/trader/examples/bank" includes="Bank.st" />
This tutorial explains how to use the OpenORB Trading Service and in a more generic way how to use a trader. The source code used by this tutorial is available into the "examples" directory of the OpenORB Trading Service distribution.
The source code for the steps 1 to 4 is available inside the "example/bank" directory.
To access the trader server, the TradingService key word must be resolved. A Lookup interface reference is returned :
org.omg.CosTrading.Lookup lookup = null; try { org.omg.CORBA.Object obj = orb.resolve_initial_references("TradingService"); lookup = org.omg.CosTrading.LookupHelper.narrow( obj ); } catch ( org.omg.CORBA.ORBPackage.InvalidName ex ) { System.out.println("Unknown service :" + ex.toString() ); System.exit(1); }
The Lookup interface provides all attributes and operations to use and manage the Trading Service.
There are two solutions to describe a service type :
Here, we are going to explain the two methods, but we will begin by the second solution, which is really easier !
We would like to describe a service type that corresponds to a bank. This service type provides a bank name and a property that indicates if this bank object supports the transactions. Thus, we create a file named "Bank.st" where we describe the following service :
#include "bank.idl" service BankService { interface Bank; mandatory property string bank_name; mandatory property boolean transactional; };
Now, we have to compile this description : java org.openorb.trader.compiler.StdlCompiler bank.st -export
Two files are generated :
In the Bank server, to create the BankService description creation into the trader, we have to write:
BankServiceHelper.create_service( lookup );
And that's all !
The second solution to create a service type description is a little bit more complicated. First, we have to describe each properties, then the interface type, then the inheritance ( if any ) as shown in the following source code we have :
First, we create the list of properties ( here 2 : bank name + transactional ) :
org.omg.CosTradingRepos.ServiceTypeRepositoryPackage.PropStruct [] properties = new org.omg.CosTradingRepos. ServiceTypeRepositoryPackage.PropStruct[2];
Then, we describe the two properties ( name / mode / type ) :
// Property bank_name properties[0] = new org.omg.CosTradingRepos.ServiceTypeRepositoryPackage.PropStruct(); properties[0].name = "bank_name"; properties[0].value_type = orb.get_primitive_tc( org.omg.CORBA.TCKind.tk_string ); properties[0].mode =org.omg.CosTradingRepos.ServiceTypeRepositoryPackage.PropertyMode.PROP_MANDATORY_READONLY; // Property transactionnal properties[1] = new org.omg.CosTradingRepos.ServiceTypeRepositoryPackage.PropStruct(); properties[1].name = "transactional"; properties[1].value_type = orb.get_primitive_tc( org.omg.CORBA.TCKind.tk_boolean ); properties[1].mode = org.omg.CosTradingRepos.ServiceTypeRepositoryPackage.PropertyMode.PROP_MANDATORY;
Now, we describe the inheritance ( here no inheritance ) :
String [] inherited = new String[0];
Then, to finish we create the new description ( first, we have to get access to the repository ) :
try { org.omg.CosTradingRepos.ServiceTypeRepository repository = org.omg.CosTradingRepos.ServiceTypeRepositoryHelper.narrow( lookup.type_repos() ); org.omg.CosTradingRepos.ServiceTypeRepositoryPackage.IncarnationNumber incarnation = null; incarnation = repository.add_type( "BankService", "::Bank", properties, inherited ); } catch ( java.lang.Exception ex ) { System.out.println("Unable to create the service type description !"); System.exit(1); }
Now, this is finished ! We suggest you always use the Service Type compiler, because it generates portable source code that could be reused by another trading service !
To export an offer, two approaches are also available !
The first one is as usual the most simple, it uses the generated files from the service type description. If you use the -export flag with the compiler, it also generates a class which has the same name than the service type. The following piece of code explains how to use this class :
BankService bank_service = new BankService( orb, lookup );
The previous line uses the constructor to create a new instance of the BankService. This class contains an accessor to set the value for each property :
bank_service.bank_name( "Barclays" ); bank_service.transactional( false );
When the values are set, the last thing to do is to export the offer :
if ( bank_service.export( bank._this( orb ) ) == null ) { System.out.println("Unable to export offer..."); }
The second approach ( the standard approach ) is more complicated as shown above :
org.omg.CosTrading.Property [] properties = new org.omg.CosTrading.Property[2]; properties[0] = new org.omg.CosTrading.Property(); properties[0].name = "bank_name"; properties[0].value = orb.create_any(); properties[0].value.insert_string( "barclays" ); properties[1] = new org.omg.CosTrading.Property(); properties[1].name = "transactional"; properties[1].value = orb.create_any(); properties[1].value.insert_boolean( false ); try { return register.export( bank._this( orb ), "BankService", properties ); } catch ( java.lang.Exception ex ) { }
To find a service, again, two solutions :
org.omg.CosTrading.Offer [] offers = BankServiceHelper.resolve_service( orb, lookup, "transactional == FALSE", "" );
In the previous line, we ask for a BankService offer, by providing the ORB instance, the Lookup reference, the constraint and the preference.
// -- Check for errors -- if ( offers == null ) { System.out.println("An error occured during query..."); System.exit(0); } // -- Check if there are some compliant offers -- if ( offers.length == 0 ) { System.out.println("No compliant Bank found..."); System.exit(0); } // -- Access to a compliant offer -- Bank bank = BankHelper.narrow( offers[ 0 ].reference );
The second possibility ( standard way ) :
org.omg.CosTrading.OfferSeqHolder offers = new org.omg.CosTrading.OfferSeqHolder(); org.omg.CosTrading.OfferIteratorHolder iterator = new org.omg.CosTrading.OfferIteratorHolder(); org.omg.CosTrading.PolicyNameSeqHolder limits = new org.omg.CosTrading.PolicyNameSeqHolder(); try { org.omg.CosTrading.Policy [] policies = new org.omg.CosTrading.Policy[3]; policies[0] = new org.omg.CosTrading.Policy(); policies[0].name = "exact_type_match"; policies[0].value = orb.create_any(); policies[0].value.insert_boolean( true ); policies[1] = new org.omg.CosTrading.Policy(); policies[1].name = "use_dynamic_properties"; policies[1].value = orb.create_any(); policies[1].value.insert_boolean( true ); policies[2] = new org.omg.CosTrading.Policy(); policies[2].name = "use_proxy_offers"; policies[2].value = orb.create_any(); policies[2].value.insert_boolean( true ); org.omg.CosTrading.LookupPackage.SpecifiedProps desired_properties = new org.omg.CosTrading.LookupPackage.SpecifiedProps(); desired_properties.all_dummy((short)0); lookup.query( "BankService", "transactional == FALSE", "", policies, desired_properties, 10, offers, iterator, limits ); return offers.value; } catch ( java.lang.Exception ex ) { System.out.println("An error occured during query..."); System.exit(0); } // -- Check if there are some compliant offers -- if ( offers.value.length == 0 ) { System.out.println("No compliant Bank found..."); System.exit(0); } // -- Access to a compliant offer -- Bank bank = BankHelper.narrow( offers.value[ 0 ].reference );
A property can be dynamic. It means that you don't have to provide a value for the property, but you have to register an external evaluator that is invoked when you want to get the dynamic property value.
The source code of this example is available in example/task. In this section we only explain the most simple way which uses the OpenORB TOS extension ( the service type compiler and its generated files ).
The example Task shows this kind of properties. In this example, we are looking for a task executor which provides in its offer the quantity of memory available to run the task. The memory quantity is evaluted via a dynamic property :
service TaskService { interface Task; mandatory property string host_name; mandatory property long long memory; };
As you see in the previous description, the memory property is not marked as dynamic. Indeed, any property can be dynamic ! The compiler generates two kind of accessors for each property :
Example :
public class TaskService { // ... public void memory( long value ) { // ... } public void memory( org.omg.CosTradingDynamic.DynamicPropEval eval ) { // ... } }
An evaluator is simple to develop :
public class MemoryEval extends org.omg.CosTradingDynamic.DynamicPropEvalPOA { private org.omg.CORBA.ORB orb; public MemoryEval( org.omg.CORBA.ORB orb ) { this.orb = orb; } public org.omg.CORBA.Any evalDP( java.lang.String name, org.omg.CORBA.TypeCode returned_type, org.omg.CORBA.Any extra_info ) throws org.omg.CosTradingDynamic.DPEvalFailure { if ( ! name.equals("memory") ) throw new org.omg.CosTradingDynamic.DPEvalFailure( name, returned_type, extra_info ); long free = java.lang.Runtime.getRuntime().freeMemory(); org.omg.CORBA.Any any = orb.create_any(); any.insert_longlong( free ); return any; } }
Now to export the offer :
TaskService task_service = new TaskService( orb, lookup ); String name = java.net.InetAddress.getLocalHost().getHostName(); task_service.host_name( name ); task_service.memory( eval._this( orb ) ); // -- And to finish, export the offer -- if ( task_service.export( task._this( orb ) ) == null ) { System.out.println("Unable to export offer..."); }