Novell is now a part of Micro Focus

Novell Trader: An Advanced Tutorial on Registration and Server Object Creation

Articles and Tips: article

ROBERT WHITEHEAD
Novell Trader Architect
Java Technologies Group

01 Dec 1997


Takes you step-by-step through the process of registering a distributed object service with the trader. Covers both the fundamentals and in-depth information on distributed object server instantiation and its registration with a trader.

Introduction

Distributed object systems are becoming a reality. Developing an object then supplying a remote access to that object is what distributed object technology is all about. This development process is made easier with the aid of Object Broker Technology. This process is further strengthened when a trader is used. The deployment of a client/server software system using object development languages like C++ and Java is known as building a distributed object system. Separating the server logic from the client logic leads to powerful system architectures.

When these systems are developed using Object Request Brokers (ORBs), the communication infrastructure is provided for the programmer. Built into the ORBs are the capabilities for marshaling object method calls across machine and process boundaries. Marshaling is a very important, fundamental building block of a distributed object system. Additional object management mechanisms built within the ORB are useful, such as: naming, interface discovery, trading for objects, and communication connection management.

As the number of distributed objects on a network grows the need for a powerful distributed object management system occurs. This management is where a trader becomes essential.

Novell has built a Common Object Trader Service which is 100% compliant with the Object Management Group (OMG) specification. This article takes you step-by-step through the process of registering a distributed object service with the trader. Covered in this article are both the fundamentals and the detail depth information of distributed object server instantiation and it's registration with a trader.

Previous articles published in Novell Developer Notes are useful as background information. These articles are: "Novell Trader Service Architectural Overview" ( August 1997), "Using the Novell Trader" (October 1997), and "Novell Trader Helper Class: Trader Service" (November 1997).

The trader has five interface categories:

  • register

  • lookup

  • link

  • proxy

  • admin

The Register Interface

We are going to concentrate on the register interface. Specifically, we will explore the export method call within the register interface.

The register interface has six method calls:

  • export

  • withdraw

  • describe

  • modify

  • withdraw_using_constraint

  • resolve

The export method is used for registering a server object with the trader. Withdraw removes an offer previously registered. Details of any registered offer are obtained by invoking the describe method and the properties of any offer may be changed by the modify method. Each of these three functions (withdraw, describe, and modify) use an OfferId as the only input.

The OfferId was originally returned when the export method was invoked. A list of OfferIds are also available from the Trader Admin Interface by calling the list_offers method.

Removing a group of offers is easily done with the withdraw_using_ constraint method call. A constraint is a criteria string used for offer matching. All offers that match the constraint are removed. OfferIds are not used for the withdraw_using_constraint mechanism. If the constraint is not wisely specified, offers beyond what the user intends are removed.

Resolve, as the sixth and final method in the register interface group, is provided to return an object reference for an external federated trader. A federated trader is a trader which has registered with it a list of other traders in the system. This list builds a relationship of linked traders known as a trader graph. Each trader maintains a separate list. The deployment of multiple traders results in a federated trader environment. In short, traders trade for traders. The resolve method call is used to return an object reference which then functions as a connection to another trader within the system.

As mentioned earlier, the six methods of export: withdraw, modify, describe, resolve, and withdraw_using_constraint are contained with an abstract grouping known as the register interface. The register interface is not an actual method call itself, but a name to describe the encapsulated grouping of these six method operations.

To simplify the work for a programmer, a TraderService class has been developed by the Novell trader project team to aid in using the register and lookup interfaces. The TraderService class encapsulates the register interface methods. All trader and CORBA specific references and arguments are not exposed in APIs of the TraderService. It is recommended that the TraderService class be used for normal access to the trader. However, in some cases, the programmer may wish to code directly to the trader method calls. This article shows both approaches.

Export Method

Before we describe how to use the preferred way of connecting to the trader via the TraderService class we will discuss the actual export method call. This is for the programmer who wishes to bypass the TraderService class and code directly to the trader. Understanding of this material is helpful when using the higher abstraction provided by the TraderService class.

The Java language method signature for export is:

java.lang.String OfferId = 

   export (org.omg.CORBA.Object    reference,

          java.lang.String     type,

          org.omg.CosTrading.PropertySeq    properties);

Seven exceptions can be thrown by this method which we will cover after first describing the method arguments.

As can be seen in the method signature above, the export method has three parameters. The first of these parameters is a reference to a CORBA object. A server object must first be built and then the reference to that object is used as the argument.

The simple form of the type argument contains a string such as: "MyServiceType." However, a type can be related in a hierarchy that reflects interface type inheritance. This hierarchy provides the basis for deciding if one type may be substituted for another super type. In general only the simple form is needed. The format for an inherited type uses double colons as separators.

Fully qualified types such as "MyServiceTypeMyCalcMyBase" can be used. MyCalc and MyBase are super types (parent types) to MyServiceType. Upon searching for all objects that supply the MyBase type then all exported objects of subtypes MyCalc and MyServiceType are also returned as qualifying matches. This advanced feature will be supported in later releases of trader. The simple form and fully qualified forms are currently supported.

Properties, the last argument, is an array of name-value pairs. Each element of the array contains an individual name-value pair. The value must be of the same data type (integer, string, etc.) as specified when the type was previously registered with the service type repository. Shown in Example 1 is a code sample for building property elements.

Example 1: Static Property Registration

org.omg.CosTrading.Property[] properties= new org.omg.CosTrading.Property[2];

org.omg.CORBA.Any value1 = org.omg.CORBA.ORB.init().create_any();

value1.insert_long(500);

org.omg.CORBA.Any value2 = org.omg.CORBA.ORB.init().create_any();

value54.insert_string("blue");

properties[0] = new org.omg.CosTrading.Property("cost",value1);

properties[1] = new org.omg.CosTrading.Property("color",value2);

A property array of size two is used above. There is no limit to the number of property elements which can be specified. The CORBA "any" type is used for the value part of the name-value pair. "Any" types include, but are not limited to, support for booleans, longs, strings, and floats. An interested property type is a dynamic property. A dynamic property functions much like a call-back. Rather than the trader registering a static name-value pair, an exported offer using a dynamic property will cause the trader to ask the original object for the value at runtime.

The code shown in Example 2 uses a dynamic property element. Notice that dynamic and static properties can be mixed.

Example 2: Dynamic Property Definition

org.omg.CosTradingDynamic.DynamicProp dp = new

org.omg.CosTradingDynamic.DynamicProp();

dp.eval_if = dp1;

dp.returned_type = orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_long);

dp.extra_info = orb.create_any();



org.omg.CORBA.Any value1 = org.omg.CORBA.ORB.init().create_any();

org.omg.CosTradingDynamic.DynamicPropHelper.insert(value1,dp);



org.omg.CORBA.Any value2 = org.omg.CORBA.ORB.init().create_any();

value2.insert_long(51);



org.omg.CosTrading.Property[] properties= new org.omg.CosTrading.Property[2];

properties[0] = new org.omg.CosTrading.Property("cost",value1);

properties[1] = new org.omg.CosTrading.Property("speed",value2);

The following code in Example 3 shows the object support for dynamic properties. The evalDP method is added to the class. For simplicity in this example, the value of five is always returned. Supplying a value that changes would be more meaningful.

Example 3: Method Implementation of a Dynamic Property

public org.omg.CORBA.Any evalDP(

       java.lang.String name,

       org.omg.CORBA.TypeCode return_type,

       org.omg.CORBA.Any extra_info

      ) throws

    org.omg.CosTradingDynamic.DPEvalFailure,

    org.omg.CORBA.SystemException 

{

       org.omg.CORBA.Any value = org.omg.CORBA.ORB.init().create_any();

       value.insert_long(5);

       return value;

}

Now it's time to try and put the whole export picture together. First, we begin by taking the Interface Definition Language for an object. In this case we use calc.idl.

Example 4: IDL for Calc

interface Calc {

                long add (in long n1, in long n2);

                long sub (in long n1, in long n2);

};

Calc.idl is parsed by the IDL compiler as follows:

promt> idl2java Calc.idl

Produced as output from the IDL compiler are the following files:


File

Description

_CalcImplBase.java

A server distributed object inherits from this class. This is not used whenever dynamic properties are specified. In the case of dynamic properties the tie class and operations classes are used instead.

_CalcOperations.java

This is the Java Interface class that specifies the method signatures. In the case of dynamic properties, a server object implements this class along with the dynamic properties operations class.

_tie_Calc.java

The class is used to combine operations classes together.

CalcHelper.java

Static methods are implemented in this class to support binding and in the case of export to insert a dynamic property into an "any" type.

In the code shown in Example 5, CalcOperations and org.omg.CosTradingDynamic.DyanmicPropEvalOperations are specified as interface classes. The server code must implement all method calls defined in these two classes. Hopefully, this puts the whole export registration picture together. It may look complicated at first, but it really isn't. After working with the examples for a while it becomes easy to see how it all fits together.

Unfortunately, the use of dynamic properties does take away some simplicity. However, in return, the use of dynamic properties adds a very powerful feature to name-value property pairs.

Example 5: Server Object Code with Dynamic Properties Using the Trader Directly

// CalcServer.java - implementation of calc server with dynamic properties

import java.util.*;

import org.omg.CosTradingRepos.ServiceTypeRepositoryPackage.*;

import org.omg.CosTradingRepos.*;

import org.omg.CORBA.*;



class myCalcDynamic implements CalcOperations,

org.omg.CosTradingDynamic.DynamicPropEvalOperations {

   public myCalcDynamic () { }

   public int add( int n1, int n2 ) { return n1+n2; }

   public int sub( int n1, int n2 ) { return n1-n2; }



   public Any evalDP (String name, TypeCode return_type, Any extra_info)

   throws org.omg.CosTradingDynamic.DPEvalFailure

  {

   Any value = ORB.init().create_any();

   value.insert_long(5);

   return value;

  }

}

        

public class CalcServerDynamic {

  public static void main( String[] args )

 { try

    {  // initialize the orb & boa

        org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init();

        org.omg.CORBA.BOA boa = orb.BOA_init();



        // Instantiate a calculator named Simple Calculator 



        myCalcDynamic calcObject = new myCalcDynamic();



        // Obtain a calculator object reference

        Calc cObj = new _tie_Calc(calcObject,"Simple Calculator");



        // Obtain a dynamic property object reference   

        org.omg.CosTradingDynamic.DynamicPropEval dynamic_property = 

                new org.omg.CosTradingDynamic._tie_DynamicPropEval(calcObject);



        boa.obj_is_ready(cObj);



       // bind to trader's register interface

       org.omg.CosTrading.Register regObj;

       regObj =     org.omg.CosTrading.RegisterHelper.bind(orb,

                                 System.getProperty("TRADER"));



       // Add a calculator type if one doesn't exist

      org.omg.CosTradingRepos.ServiceTypeRepository typeObj;

      typeObj = ServiceTypeRepositoryHelper.narrow( regObj.type_repos() );



      try {

          typeObj.add_type("calculator", "IDL:Calc:1.0", new PropStruct[0], new

String[0]);

      } catch (ServiceTypeExists e) {System.out.println("Calculator already

exists");}

   catch (org.omg.CORBA.UserException e) {System.out.println(e);}



      // build a dynamic property

      org.omg.CosTradingDynamic.DynamicProp dp = 

            new org.omg.CosTradingDynamic.DynamicProp();

      dp.eval_if = dynamic_property;

      dp.returned_type = orb.get_primitive_tc(TCKind.tk_long);

      dp.extra_info = orb.create_any();



      org.omg.CORBA.Any dynamic_reference = orb.create_any();

      org.omg.CosTradingDynamic.DynamicPropHelper.insert(dynamic_reference,dp);



      // build property sequence with just one dynamic property entry "cost"

      org.omg.CosTrading.Property[] props = new org.omg.CosTrading.Property[1];

      props[0] = new org.omg.CosTrading.Property("cost", dynamic_reference);



      try  {    String offerID = regObj.export(cObj, "calculator", props);

      }  catch (org.omg.CORBA.UserException e) {System.out.println(e);}



      // Wait for incoming requests

      boa.impl_is_ready();

      }  catch (org.omg.CORBA.SystemException e) {System.err.println(e);}

  }

}

Exception Handling

As promised earlier, we will now cover exception handling. Seven exceptions can be returned from the export method call.


Exception

Description

InvalidObjectRef

This exception is thrown when the reference parameter of the export method is not a valid distributed object reference containing an IOR structure.

IllegalServiceType

Thrown when the type is not specified in the proper format such as, MyServiceMyBaseMyCalc. This occurs whenever a delimiter set besidesdouble colons are used as separators.

UnknownServiceType

The export method verifies that the service type has been registered with the type repository prior to it's usage. If not previously registered, then this exception is used.

PropertyTypeMismatch

This exception is thrown whenever the value in the properties name-value pair are of a different type (interger, float, etc.) than the type specified in the service type repository. If the service type repository does not have an entry for the property name then no type matching is done on that property.

IllegalPropertyName

This exception is thrown whenever the property name contains illegal characters. The set of legal characters are specified in the BNF documented in the OMG Trader Specification.

InterfaceTypeMismatch

This exception is used whenever the object registered does not support the interface name. The interface name is generated by the idl compiler. This name is used when adding the service type to the service type repository.

ReadOnlyDynamicProperty

This exception is thrown when the service type repository has specified the property as read only, but a dynamic property is used in the export.

MissingMandatoryProperty

When a property marked as mandatory in the service type repository has not been defined in the exported properties then this exception will thrown.

DuplicatePropertyName

Duplicate property names are not allowed to be registered.

So far, the arguments along with the possible exceptions to the export method call in the trader register interface have been explored in this article. Further information may be obtained by reading the OMG Trader Object Service Specification available on the OMG web site (http://www.omg.org -- in the technical documents area).

In last month's article, a TraderService Java class was introduced as a slick way to register objects. It is recommended that this class library be used instead of coding to the lower level API's as shown in the examples so far in this article.

Example 6 contains the functionality of Example 5 rewritten to use the TraderService classes. For the power programmer who wishes to not use the TraderService wrapper class the information in this article should be valuable. Notice how compact Example 6 is when comparing it with Example 5. This is why we recommend using the TraderService classes.

Example 6: Dynamic Properties Using the TraderService

// newCalcServerDynamic.java - implementation of calc server with dynamic properties

import java.util.*;

import org.omg.CosTradingRepos.ServiceTypeRepositoryPackage.*;

import org.omg.CosTradingRepos.*;

import org.omg.CORBA.*;

import com.novell.trader.*;



class myCalcDynamic implements CalcOperations,

org.omg.CosTradingDynamic.DynamicPropEvalOperations {

   public myCalcDynamic () { }

   public int add( int n1, int n2 ) { return n1+n2; }

   public int sub( int n1, int n2 ) { return n1-n2; }



  public Any evalDP (String name, TypeCode return_type, Any extra_info)

      throws org.omg.CosTradingDynamic.DPEvalFailure

 {

    Any value = ORB.init().create_any();

    value.insert_long(5);

    return value;

  }

}



public class newCalcServerDynamic  {

  public static void main( String[] args )  {

    try {   // Instantiate Trader Service

      TraderService trader = new TraderService( );



      // Instantiate a calculator named Simple Calculator   



      myCalcDynamic calcObject = new myCalcDynamic();

      // Obtain a calculator object reference

      Calc cObj = new _tie_Calc(calcObject,"Simple Calculator");



      // Instantiate calculator offer and export to Offer Repository

      TraderOffer calcOffer = new TraderOffer( "calculator", cObj, true );

      calcOffer.addProperty("cost",calcObject);



      trader.exportOffer( calcOffer );



      // Process calculator requests

      trader.waitForRequests();

    } catch ( TraderServiceException err ) { System.err.println(err); }

  }

}

The trader supports static properties and dynamic properties. A property is defined as either mandatory or normal. The property characteristics of mandatory and normal applies to both static and dynamic properties. Dynamic properties function as real-time object attribute values whereas the values for static properties are set upon object export. The static property values, however, may be modified using the register's interface modify method. The modify method performs a property delete and property add.

A property may be defined as read-only. Read-only applies to both mandatory and normal property types. The read-only modifier is specified when the service type is added to the service type repository. A read-only dynamic property is not allowed. In this case, a ReadonlyDynamicProperty exception is thrown from the export method call.

The dynamic property functionality of the trader provides a powerful solution beyond just using static properties. The purpose of this article was to give a tutorial on building a distributed object server with support for dynamic properties. Don't be afraid to use them.

* Originally published in Novell AppNotes


Disclaimer

The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.

© Copyright Micro Focus or one of its affiliates