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 :
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..."); }
The plugin requires the ManagementBoard distribution. For more information concerning that module, refer to the documentation which is delivered with the ManagementBoard packaging.
You can download the ManagementBoard module on the http://openorb.sf.net web site. You need to put the openorb_board-{version}.jar file in your CLASSPATH environment variable.
Once you have dowloaded that module, you can build the Trader Plugin application with the ant tool. Enter the following command to build the Plugin : ( under the TradingService directory ) build plugin
You will then find a traderplugin-{version}.jar file in the dist directory. Add it to your CLASSPATH environment variable.
You also have to update your OpenORB.xml file to specify that you want to start the Board with the Trader Plugin. When editing your OpenORB.xml file, add the following information in the board module.
<property name="traderPluginClass" value="org.openorb.trader.plugin.Plugin"> <property name="traderPluginPath" value="<PATH>/traderplugin.jar"> <property name="traderPluginHelp" value="">
Add the trader plugin to the plugins list in the board module.
For more information about such a configuration, refer to the ManagementBoard documentation.
Now, before beginning this overview, be sure that the Trading Object Service is running.
When starting the Management Board, a new tab is available for the Trader Plugin. Select this tab and click on the connect button.
The following dialog window appears. If the Trading Service is previously configured on your host, you can resolve it through the initial references, so click on the connect button.
Now, the Trader Plugin is connected to the trading server. The plugin interface is divided into two parts :
For example, click ( on the left side ) on the service types topic. All service types descriptions managed by the trading service are displayed as children of this topic. If you click on one of these children, you will get its description on the right panel, as shown on the next screenshot :
Thanks to the Trader plugin, you can manage all parts of your trading server :
To see the offers, click on the offers topic ( on the left side ). All available offers are displayed as children of the offer topic. If you select one of the available offers, its properties values are displayed on the right side.
To view or modify the Trading Server configuration, select on the left side the config topic. The right panel displays all configuration parameters and their values.
To modify a parameter, select it in the right panel then click on the edit button.
At last, to query some offers, click on the query topic on the left side. All existing queries are displayed as children of the query topic. To create a new query, click on the add button. Fill all the required fields and validate.
Then, to execute a query, select the query name ( on the left side ), then click on the execute button. All compliant offers are displayed on the right panel.