The Community OpenORB - TradingObjectService

Jerome Daniel

J.Scott Evans


Table of Contents

Introduction
1. Overview
2. Compilation
3. Installation
4. Configuration
5. Deployment
How to run the Trading Object Server ?
The Easy Trader System
The STDL compiler
The STDL Compiler Ant Task
A quick tutorial
6. Frequently Asked Questions
A. Appendix

Introduction

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.

Chapter 1. Overview

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:

  • traders federation
  • embedded or standalone service type repository
  • proxy offers
  • dynamic properties
  • persistent or transient modes
  • a graphical console to browse service offers, to query and so on...

Chapter 2. Compilation

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

Chapter 3. Installation

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.

Chapter 4. Configuration

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 :

  • embedded_repository : this property is set to true if the service type repository is embedded
  • repository_url : if the service type repository is not embedded, this property specifies the CORBA URL that denotes the stand alone service type repository

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:

  • supports.modifiable_properties : if set to true, this property means that modifiable properties are supported.
  • supports.dynamic_properties : if set to true, this property means that dynamic properties are allowed.
  • supports.proxy_offers : if set to true, this property means that proxy offers are allowed.

In addition to the previous properties a set of attributes are defined through properties.

  • imports.def_search_card : default upper bound of offers to be searched for a query operation
  • imports.max_search_card : maximum upper bound of offers to be searched for a query operation
  • imports.def_match_card : default upper bound of matched offers to be ordered in applying a preference criteria
  • imports.max_search_card : maximum upper bound of matched offers to be ordered in applying a preference criteria
  • imports.def_return_card : default upper bound of ordered offers to be returned to an importer
  • imports.max_return_card : maximum upper bound of ordered offers to be returned to an importer
  • imports.def_hop_count : default upper bound of depth of links to be traversed
  • imports.max_hop_count : maximum upper bound of depth of links to be traversed
  • imports.max_list : the upper bound on the size of any list returned by the trader, namely the returned offers parameter in query, and the next_n operations in OfferIterator and OfferIdIteraor
  • imports.def_follow_policy : default link follow behaviour for a particular trader
  • imports.max_follow_policy : limiting link follow policy for all links of the trader
  • imports.link_follow_policy : most permissive follow policy allowed when creating new links

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.

Chapter 5. Deployment

How to run the Trading Object Server ?

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:

  • -ir : Use this flag if you want to use Interface Repository for type checking.
  • -ior : This flag implies the generation of the Lookup interface IOR into a file named lookup.ior. If the service type repository is embedded, another file is generated strep.ior for it.
  • -naming : This flag specifies to the trader, to bind the Lookup interface to the naming service with the following name : COS\TradingService\Lookup. If the service type repository is embedded, it is bound with the following name : COS\TradingService\ServiceTypeRepository
  • -tradername : This flag allows the trader name specification from the command line : -tradername foo
  • -url : This flag specifies the service type repository URL : -url corbaname://1.2@foo:3080/bar
  • -persistence : this flag starts the trader under a persistent mode.
  • -namingpath : This flag supplies a name for the naming service to bind the lookup interface : -namingpath COS\MyPath implies the Lookup interface to be bound with the COS\MyPath\Lookup

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 :

  • -ir : Use this flag if you want to use Interface Repository for type checking.
  • -ior : This flag implies the generation of the service type repository IOR into a file named strep.ior
  • -naming : This flag binds the service type repository with the following name : COS\TradingService\ServiceTypeRepository
  • -persistence : this flag starts the service type repository under a persistent mode.

The Easy Trader System

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 :

  • create_service : this operation creates the service type description into the trader server. If the description is already registered, no exception is raised.
  • remove_service : removes a service type description from the trader server.
  • resolve_service : returns a list of offers compliant with the provided constraints.

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 :

  • two accessors for each property described into the service type. An accessor to set a value for the property and an accessor to set the evaluator for this property ( to use a dynamic property ).
  • export : export an offer to the trader server. To export an offer, the user has to previously use the accessors to set the values for all properties.
  • modify : modify an offer.
  • remove : remove an offer.

The STDL compiler

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 :

  • -release : displays the release number of the OpenORB Trading Object Service
  • -export : generates a java class to export offers.

The STDL Compiler Ant Task

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.

AttributeDescriptionRequired
srcdirLocation of the idlfiles files.Yes, unless nested <src> elements are present.
destdirLocation to store the generated java files.generated will be used if nothingspeficied.No
includesComma- or space-separated list of files (may bespecified using wildcard patterns) that must be included; all .idl files are included whenomitted.No
includesfileThe name of a file that contains a list of files toinclude (may be specified using wildcard patterns).No
excludesComma- or space-separated list of files (may bespecified using wildcard patterns) that must beexcluded; no files (except default excludes) areexcluded when omitted.No
excludesfileThe name of a file that contains a list of files toexclude (may be specified using wildcard patterns).No
includepathThe 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
quietsuppress any outputNo
exportGenerate a Java class for each Service Type that exports an offer; defaults toyes.No
verboseShows debug output; defaults to no.No
jdk14codeGenerates classes that use JDK1.4 features. The generated classes will not compile on previous versions;defaults to noNo
generateallGenerate 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
uptodatechecksIndicates if the compiler is doing uptodate checks on idl files and target java files; defaults to yes.No
cachefileIndicates 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" />

A quick tutorial

How to access to the Trading Object Service ?

How to access to the Trading Object Service ?

How to access to the Trading Object Service ?

How to access to the Trading Object Service ?

How to access to the Trading Object Service ?

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 :

  • to develop all the description that use Trading Object Service API
  • to describe the service offer and to use the OpenORB TOS ServiceType compiler.

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 :

  • BankServiceHelper.java
  • BankServive.java

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 :

  • a simple accessor to export a value
  • a complex accessor to export an evaluator reference for a dynamic 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...");
                }
                

Chapter 6. Frequently Asked Questions

Set

6.1. ?
6.1.

?

!

Appendix A. Appendix