Novell is now a part of Micro Focus

Novell Trader Helper Class: TraderService

Articles and Tips: article

PAUL R. ROPER
Software Engineer Novell Trader
Java Technologies Group

01 Nov 1997


A great majority of all common user CORBA Trader interaction can now be handled by the new TraderService classes in a straightforward and easy-to-understand manner. This article discusses such topics as registering a service type, exporting an offer, and querying.

Introduction

Hey, let's face it! Distributed object development is difficult to master. There are so many setup method calls to make with ugly parameters compounded by confusing long names. Well, it's TraderService to the rescue! Ninety-nine percent of all common user CORBA Trader interaction can now be handled by the new TraderService classes in a straightforward and easy-to-understand manner. Registering trader service types and the exporting of distributed object services are easily handled with only a few method calls. Subsequent query calls to the trader by a client to discover distributed object services are also made simpler by using TraderService methods.

The goal of the TraderService classes is to put as much CORBA as possible under the covers, thereby reducing the number of method calls as well as the number of parameters required in each call. Method pre-conditions are handled internally whenever possible, and overloading of TraderService methods is used extensively to make the interface to Novell Trader services as straightforward as possible.

TraderService Classes

Their are five TraderService Java classes:

  • TraderService

  • TraderType

  • TraderOffer

  • TraderQuery

  • TraderServiceException

TraderService is the main trader interface class and handles the binding and interaction with the Novell Trader services of offer registration and lookup query. All TraderService operations with the Trader are described in TraderService definition objects. TraderType, TraderOffer, and TraderQuery are definition objects. They are passed to the TraderService class and contain set up parameters for service type, service offer, and Lookup query operations, respectively. Finally, the TraderServiceException class is a "catch-all" exception class for all TraderService error processing.

Getting Started

So, let's get started. Remember in the last issue of Novell Developer Notes ("Using the Novell Trader," October 1997), we described the "normal" process of building a simple distributed object system from scratch and making it known on the network via the Novell Trader. A very simplistic calculator distributed object was built for the Trader and ORB.

We will further refine that example in this article and illustrate how much simpler it is to use the TraderService classes rather than the traditional OMG trader methods to construct this model. The IDL process and service code remain the same, but the exporting of the service offer and subsequent querying for that service by a client are greatly simplified when using the TraderService classes.

TraderService services are made available to a Java program by first instantiating the TraderService class. There are various constructor methods available to allow binding to specific traders and setting process tracking, but of these, the most common would be:

TraderService trader = new TraderService(  );       // Get reference to TraderService

The constructor for the above instantiation binds through the ORB to the Novell Trader referenced by the system variable "System.getProperty( "TRADER" )." If a specific Trader is needed, that Trader name would be included as an argument.

There would normally be only one Service Type Repository but many Traders available. To guarantee that the correct service type repository is used with any given trader, the TraderService class queries the bound Trader for its service type repository link.

Registering a Service Type

Normally, before a service object can be exported to the Trader and made available to querying clients, there must be an associated service type and interface name (the IDL contract) already registered with the Trader Service Type Repository. Here is an example of registering a "calculator" service type and one associated property, namely "cost" with the Service Type Repository:

TraderType calcObj = new TraderType ( );    // Instantiate TraderService Type object

calcObj.setServiceType( "Calculator"  );        // Set service type

calcObj.setInterface( "IDL:Calc:1.0"  );            // Set interface name

calcObj.addProperty(  "cost", calcObj.INT, calcObj.NORMAL  );// Add normal int property

trader.addServiceType(calcObj);             // Register new Calculator Service Type

or even more simply:

//  Instantiate Type object w/type and interface

TraderType calcObj = new TraderType( "Calculator", "IDL:Calc:1.0" );

calcObj.addProperty( "cost", calcObj.INT );       // Add normal int property

trader.addServiceType(calcObj);     // Register new Calculator Service Type

Notice that overloading is used to simplify the process and that other "not-so-common" parameters, such as super types and property mode, are not required and default to the correct state. Another advantage when using the TraderService classes is that the service object type does not have to first be registered with the Service Type Repository if no special property constraints are needed, such as "mandatory" or "read-only."

The service type and property types of the first exported offer will automatically be registered with the Service Type Repository when no corresponding service type is found in the Service Type Repository. The type of the property will be the property type in the offer and the mode will be "normal." This guarantees that all subsequent exported offers will have the same type for properties of the same name.

Exporting an Offer

Once a service type has been registered in the Trader Service Type Repository (or you use the service type and property types of the first exported offer), distributed service objects can then be exported against that service type with the Trader.

Here is an example of how to export an object named "calc1" with one property "cost" of value 50 to the Offer Repository:

myCalc cObj = new myCalc ( "calc1" );       // Instantiate a calculator named calc1

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

                            // Instantiate calculator offer

calcOffer.addProperty ( "cost", 50 );           // Add property cost with value 50

trader.exportOffer ( calcOffer );           // Export to Type and Offer Repository

That's it! The distributed object "calc1" is now available throughout the network via the ORB. What remains is for a client to locate the object via a TraderService query and bind with it; then it can call its methods as normally done in any Java program.

Querying

The Novell Trader is a "Yellow Pages" for locating distributed network objects that have been registered with the ORB. The TraderService query methods facilitate finding the "best fit" service object. The service type name, interface name, and a "qualifying" language string called a "constraint" are used to determine which offers in the Trader Offer Repository match the clients needs. The constraint language is string and resolves to an expression or boolean value. The constraint consists of property names of conformant offers and literals language along with:

  • comparative functions: ==, !=, >, >=, <, <=, ~, and in

  • boolean connectives: and, or, not

  • property existence: exist

  • numeric and string constants

  • mathematical operators: +, =, *, /

  • grouping operators: ( and )

Once a list of matching offers is found, the specified sort order instructs the Trader to return these offers in order of the very best matches. The sort order is set in the TraderQuery object by the setSortOrder method and its argument consists of one of the following:

min<expression< max<expression< with<expression< random, or first

The TraderService query method returns as a CORBA Object the best offer found. (Other matching offers are made available using the getHowManyLeftand getNextOffermethods.)

In addition, before the object methods of the queried serve object can be used, the query object reference must be "narrowed" to complete the binding operation. The following illustrates the TraderService query process:

TraderQuery calcQuery = new TraderQuery( );         // Instantiate TraderService Query

calcQuery.setServiceType( "calculator" );               // Set service type to calculator

calcQuery.setConstraint( "cost<100" );                  // Set constraint

calcQuery.setSortOrder( "min cost" );                   // Set sort order

calcQuery.addReturnProperty( "cost" );                  // Return cost property

CORBA.Object calcObj = trader.query( calcQuery );       // Make Trader Query

Calc calcObj = CalcHelper.narrow( calcObj )             // Narrow reference

or simply,

TraderQuery calcQuery = new TraderQuery( ); // Instantiate calculator query object

TraderQuery calcQuery = new TraderQuery( "calculator", "cost<100", "min cost" );

calcQuery.addReturnProperty( "cost" );

// Make query and narrow reference

Calc calcObj = CalcHelper.narrow( trader.query ( calcQuery ) );

The methods of the distributed service "calc1" are now available for the client to use and can be called directly. Again notice the use of method overloading as well as the defaulting of various query parameters such as query policies, iterators, pass-on results, and even how many offers to return. These are all handled within the TraderService class and are easily overridden by other method calls.

Comparing Calculator Example

Examine the Java listings for old and new calculator distributed service object. The service itself is the same in both examples, but the implementation of service setup, registration, and exporting is greatly reduced by using the TraderServices.

Calculator Service

// myCalcServer.java - implementation of calc server 

import java.util.*; 

import org.omg.CosTradingRepos.ServiceTypeRepositoryPackage.*; 



class myCalc extends _CalcImplBase 

{   public myCalc( String name) {super(name); }     

    public myCalc() { super(); }    

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

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

}  



public class MyCalcServer

{   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 calc1

            myCalc cObj = new myCalc( "calc1" );

            boa.obj_is_ready(cObj); 



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

            org.omg.CosTradingRepos.ServiceTypeRepository typeObj; 

            typeObj = org.omg.CosTradingRepos.ServiceTypeRepositoryHelper.bind(orb); 

            try 

            { typeObj.add_type("calculator", "calc_if",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);}  



            // bind to trader's register interface 

            org.omg.CosTrading.Register regObj;

            regObj = org.omg.CosTrading.RegisterHelper.bind(orb);  



            // build property sequence with just one property entry "cost = 50" 

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

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

            costAny.insert_long(50); 

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

            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);}    

    } 

}

Calculator Service Using TraderServices

// myNewCalcServer.java - implementation of calc server 

import com.novell.trader.*;



class myCalc extends _CalcImplBase 

{   public myCalc( String name) { super(name); } 

    public myCalc( ) { super( ); } 

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

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

}



public class MyNewCalcServer 

{   public static void main( String[] args )

    {   try     

        {       // Instantiate Trader Services

                TraderService trader = new TraderService( );



                // Instantiate a calculator named calc1

                myCalc cObj = new myCalc( "calc1" );





            // Instantiate calculator offer 

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

            calcOffer.addProperty( "cost", 50 );            



            // Export offer to Type and Offer Repository

            trader.exportOffer( calcOffer );



            // Process calculator requests

            trader.waitForRequests( );

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

    }

}

Calculator Client

// CalcClient.java  



public class CalcClient

{   public static void main(String args[])

    {   try 

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

            org.omg.CosTrading.Lookup lookup=org.omg.CosTrading.LookupHelper.bind(orb);



            // Setup query arguments 

            org.omg.CosTrading.Policy[] policies = new org.omg.CosTrading.Policy[0]; 

            org.omg.CosTrading.LookupPackage.SpecifiedProps desired_props = 

                new org.omg.CosTrading.LookupPackage.SpecifiedProps(); 

            String[] props = new String[1]; 

            props[0] = "cost"; 

            desired_props.prop_names(props);



            // Setup query return parameters 

            org.omg.CosTrading.OfferSeqHolder offer = 

                new org.omg.CosTrading.OfferSeqHolder();    

            org.omg.CosTrading.OfferIteratorHolder offer_itr =              

                new org.omg.CosTrading.OfferIteratorHolder();           

            org.omg.CosTrading.PolicyNameSeqHolder limits_applied =                 

                new org.omg.CosTrading.PolicyNameSeqHolder();  



            try 

            {   lookup.query("calculator", "cost < 100", "min cost", policies, 

                    desired_props, 10, offer, offer_itr, limits_applied); 

            }   catch (org.omg.CORBA.UserException e) {}    



            String objName = offer.value[0].reference._object_name(); 

            Calc calcObj = CalcHelper.bind(orb, objName); 

            System.out.println(objName+" thinks 3+3 = "+calcObj.add(3,3));  



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

    } 

}

Calculator Client Using TraderServices

// NewCalcClient.java 

import com.novell.trader.*; 

public class NewCalcClient 

{   public static void main(String args[]) 

    {   try 

        {   // Instantiate Trader Services

            TraderService trader = new TraderService( );



            // Instantiate calculator query object 

            TraderQuery calcQuery = new TraderQuery( "calculator", "cost<100", "min

            cost" ); 

            calcQuery.addReturnProperty( "cost" );                      





            // Query Trader for offer matching query object and narrow reference            

            Calc calcObj = CalcHelper.narrow( trader.query( calcQuery ) );      





            // Object methods are now available 

            System.out.println( calcQuery.getOfferName( ) + " thinks 3+3 = "

                                    + calcObj.add(3,3) );

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

    } 

}

By using TraderService methods, distributed object development is easier to master. There are fewer methods to call and no confusing long names to remember. Almost all CORBA Trader interaction can now be handled in a straight-forward and easy-to-understand manner.

TraderService Summary


TraderService Methods
Description

TraderService constructors

public TraderService( ) public TraderService( boolean oFlag ) public TraderService( String traderName ) public TraderService( String traderName, boolean oFlag )

Trader Service constructors

Service Type Repository methods

public void addServiceType( TraderType typeObject ) public void removeServiceType( TraderType typeObject ) public void removeServiceType( String serviceTypeName )

Adds and removes service type fromService Type repository

Offer Repository methods

public String exportOffer( TraderOffer offerObject ) public String exportOfferDirect( TraderOffer offerObject ) public void withDrawOffer( String offerObjectId ) public void withDrawOffers( String serviceTypeName, String constraint)

Exports and withdraws offers from the Offer Repository

Lookup Query methods

public org.omg.CORBA.Object query( TraderQuery queryObject ) public int getHowManyLeft( ) public org.omg.CORBA.Object getNextOffer( ) public String getOfferName( org.omg.CORBA.object.objRef )

Queries the Trader Lookup interface for matching offers.

Miscellaneous methods

public void waitForRequests( ) public static String[] listTraders( ) public String[] listServiceTypes( ) public org.omg.CosTrading.Lookup lookup_if( ) public org.omg.CosTrading.Register register_if( ) public org.omg.CosTradingRepos.ServiceTypeRepository typeRepository_if( )

Miscellaneous methods to wait forclient requests, return federated trader information, and various object references


TraderType Methods
Description

TraderType constructors

public TraderType( ) public TraderType( boolean oFlag) public TraderType( String serviceTypeName ) public TraderType( String serviceTypeName, boolean oFlag ) public TraderType( String serviceTypeName, String interfaceName ) public TraderType( String serviceTypeName, String interfaceName, boolean oFlag ) public void setServiceType( String serviceTypeName ) public void setInterface( String interfaceName ) public void addSuperType( String superType ) public void addProperty( String propertyName, int type ) public void addProperty( String propertyName, int type, int mode )

TraderType constructors

Sets type, interface, supertype, and properties for Service Type Repository

type = INT, STRING, BOOLEAN, or FLOAT mode = NORMAL, READONLY, MANDATORY, orMANDATORY_READONLY


TraderOffer Methods
Description

TraderOffer constructors

public TraderOffer( ) public TraderOffer( boolean oFlag ) public TraderOffer( String serviceTypeName ) public TraderOffer( String serviceTypeName, boolean oFlag ) public TraderOffer( String serviceTypeName, org.omg.CORBA.Object offerObj ) public TraderOffer( String serviceTypeName, org.omg.CORBA.Object offerObj, boolean oFlag ) public void setServiceType( String serviceTypeName ) public void setOfferObject ( org.omg.CORBA.Object offerObject ) public void addProperty( String propertyName, int propertyValue ) public void addProperty( String propertyName, String propertyValue ) public void addProperty( String propertyName, float propertyValue ) public void addProperty( String propertyName, boolean propertyValue ) public void addProperty( String propertyName, org.omg.CosTradingDynamic.DynamicPropEvalOperations object ) public void removeProperty( String propertyName )

TraderOffer constructorsSets offer type and object referenceOverloaded add property and valueRemove property from type


TraderQuery Methods
Description

TraderQuery constructors

public TraderQuery( ) public TraderQuery( boolean oFlag ) public TraderQuery( String serviceTypeName ) public TraderQuery( String serviceTypeName, boolean oFlag ) public TraderQuery( String serviceTypeName, String constraint ) public TraderQuery( String serviceTypeName, String constraint, boolean oFlag ) public TraderQuery( String serviceTypeName, String constraint, String sortOrder ) public TraderQuery( String serviceTypeName, String constraint, String sortOrder, boolean oFlag ) public void setServiceType( String serviceTypeName ) public void setSortOrder( String sortOrder ) public void setConstraint( String constraint ) public void setHowMany( int howMany ) public String getOfferName( ) public void addPolicy( String policyName, float policyValue ) public void addPolicy( String policyName, int policyValue ) public void addPolicy( String policyName, String policyValue ) public void addPolicy( String policyName, boolean policyValue ) public void setReturnProperties( int mode ) public void addReturnProperty( String name )

TraderQuery constructorsSets query type, sort order, constraintSets how many offers to sortReturns queried offer nameAdds policy name and value to querySets return property mode (no, some, all) Adds return property name

* 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