Novell Trader Helper Class: TraderService
Articles and Tips: article
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
- TraderService Classes
- Getting Started
- Registering a Service Type
- Exporting an Offer
- Querying
- Comparing Calculator Example
- TraderService Summary
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.