Novell is now a part of Micro Focus

Finding Services with the Novell Trader

Articles and Tips: article

MIKHAIL ZLOCHEVSKIY
Software Engineer, Novell Trader
Java Technologies Group

01 Dec 1997


Focuses on the basic query method for the lookup of distributed objects with the Novell trader. Explains the query parameters and how to successfully locate objects registered with the Trader.

Introduction

Managing, advertising, and locating network objects is becoming a critical technology as distributed object systems become a reality. This technology is provided by the Novell Trader. Novell Trader organizes information about distributed objects into a common repository and provides interfaces for registration, lookup, and administration of objects in this repository.

This article will focus on the basic query method for the lookup of distributed objects with Novell Trader. The Novell Trader is a distributed object trading service and 100% CORBA compliant with the OMG specification. This article will explain the query parameters and will discuss several query parameter combinations to successfully locate objects (offers) registered with the trader.

This article continues the series of Novell Trader publications in Novell Developer Notes. These publications are: "Novell's Trader Architecture Overview" (August, 1997), "Using the Novell Trader" (September, 1997), and "Novell Trader Helper Class" (October, 1997). Novell Trader may be downloaded from http://developer.novell.com/orb/documentation/trader; the OMG specification can be found at http://www.omg.org/library/public-doclist.html, document formal/97-05-01: CORBAservices - Trader Service, CORBAservices specification.

The main advantage of a Trading Service verses a Naming Service is the convenient search mechanism of the Trader based on categories of service. A client does not need to know in advance an address, e.g., URL, of a service provider or exporter. To find a service, it is enough to know a service type (category) and some significant (for the client) attributes or properties of the desired service.

Actually, the goal of search with a Trader is to get back service offers matching query terms consisting of service type, properties, policies, and so forth. More formally, an importer (client) looks for references to the interfaces of the service objects which represent services provided by exporter.

The Lookup Interface's Query() method, described in the OMG specification, is quite complex for common use. Novell developed special Novell Trader Helper Classes (TraderService) which hide some of the complexity and simplify the use of Query() method. However, we will discuss several hidden details you should be aware of to make the search process with Novell Trader more understandable for an end-user.

Simple Client Code for Novell Trader

One of the most important and useful descriptions of a service offer is a set of offer properties. Properties are name-value pairs which reflect the offer's features like speed of processing, cost of the service, vendor's brand name, etc. An offer's properties may be one of the following types: non-modifiable, modifiable, or dynamic. Non-modifiable type means that the property's name-value cannot be changed once it is advertized, i.e. the exporter guarantees support for this offer's feature continuously while the offer exists.

Modifiable type indicates that a name-value pair may be occasionally modified by the exporter or trader administrator. Dynamic type is a special type of property with a constant name while the value is dynamically updated by exporter, e.g., a stock price at the time of the query. In the following sections we will explain how a client is able to search for offers of desirable type and properties.

Let's look at a sample code of the CalculatorClient class operating with the Query() method and based on the Novell TraderService classes.

Example 1: CalculatorClient Class Operating with the Query() method

import com.novell.trader.*;
Public class CalculatorClient {
   public static void main(String args[]) {
       try {
             // instantiate Tarder Service
      TraderService trader = new TraderService("MyTrader");
            // instantiate CalculatorClient's Query object
	TraderQuery calcQuery = new TraderQuery();

            // specify Query's parameters
         calcQuery.setServiceType( "calculator" );	// service type name
         calcQuery.setConstraint( "cost<100" );	// constraint expression
         calcQuery.setReturnProperty( calcQuery. some );           // desired properties 
                                                                   mode (all/none/some ):
         calcQuery.addReturnProperty( "cost" );	// desired property name
         calcQuery.addReturnProperty( "speed" );	// desired property name
         calcQuery.setSortOrder( "min cost" );	// preferences
         calcQuery.addPolicy( "search_card", 1000 );	// policy
         calcQuery.addPolicy( "match_card", 500 );		// policy
         calcQuery.addPolicy( "return_card", 100 );		// policy
         calcQuery.addPolicy( "hop_count", 1);		// policy
         calcQuery.addPolicy( "use_modifiable_properties", true ); 	// policy
         calcQuery.addPolicy( "exact_type_match", true );	// policy
         calcQuery.setHowMany( 100 );    // how many

            // Query Trader for offer matching query object
     Calc calcObj = (Calc)trader.query( calcQuery );

            // Object methods are now available
     System.out.println( trader.getOfferName() + " thinks 3+3 = " +
calcObj.add(3,3) );

            // look at all offers returned from the query
     int j = trader.getHowManyOffers();
            // list of the offer names
     for( int i=0; i < j; i++ ) {
        calcObj = (Calc)trader.getNextOffer();
        System.out.println( trader.calcQuery.getOfferName() + " thinks 3+3 = " + 
                                calcObj.add(3,3) );
                           }
           // list of properties per offer
    for( int p=0; p < j; p++) { 
     calcObj = (Calc)trader.getNextOffer();    // retreive next offer from the 
offer list:
        int k = trader.query_properties.length;  // length of the property list 
for the retrieved offer:
           for( int l=0; l<k; l++ {<
           System.out.println(l+": property name= " + 
(trader.query_properties[l]).name);
          }
                             }
             // list of policies applied to the query and limited the search 
      int n = trader.limits_applied.length;
      for( int m=0; m<k; m++ {<
          System.out.println(m+": applied policy (name)= " + 
trader.limits_applied[m]);
                             }
                  } catch ( TraderServiceException err )
              { System.err.println( err ); }
              }
}

The body of the main routine begins by entering a try-catch block that catches TraderServiceException which, in turn, captures CORBA exceptions generated during the communication process. At the first step in the try-catch block, the client class instantiates the TraderService object which, in turn, initiates CORBA Object Request Broker and binds to the MyTrader's Lookup Interface. Then the Query object (calcQuerry) is instantiated.

The calcQuery represents the Query() method and provides access to the method's parameters. There are two groups of parameters in the Query() method: "search" parameters and return parameters. The TraderQuery class contents setServiceType, setConstraint, setReturnProperty, addReturnProperty, setSortOrder, addPolicy, setHowMany and getHowManyOffers, getOfferName, getNextOffer methods for these two groups of parameters respectively. Next several statements of the sample code will demonstrate the use of the TraderQuery class methods.

TraderQuery Class Methods Parameters

The rest of the article will concentrate on the meanings and types of parameters of the TraderQuery class methods.

Note: All strings used in the parameters are 16-bit Unicode-based and almost all of the value types are Java primitive types; other specific types of parameters will be discussed where necessary.

Service Type Name Parameter

The Service Type Name (STN) parameter is used by getServiceType method. The parameter stands for a name of category of service and is represented by a string. With this parameter, The Client Object implies a desired interface type. According to the Trading Object Service specification, the syntax of the STN displays a "list of service types from which this service type is derived, which, in turn, defines where service of this service type can substitute for other service." If the STN string syntax does not obey mentioned rule then TraderServiceException [IllegalServiceType] exception is raised.

Unfortunately, a client has to be lucky enough to specify an STN which can be recognized within trader scope as known name, otherwise a TraderServiceException [UnknownServiceType] exception is raised. This happens if the STN has not been previously registered with the Service Type Repository.

Constraint Parameter

The Constraint parameter (expression) is used by setConstraint method. Currently, NovellTrader uses the OMG 1.0 constraint language. The constraint expression describes criterium which the client would like the service offers to match.

The constraint expression deals with an offer's properties which define "a computational behavior of the desired service, non-functional aspects, and non-computational aspects (such as the organization owning the objects that provide the service)." As offers may be dynamically changed, the client is only guaranteed that returned offers match the constraint at the time of import.

The match mechanism works as follows: every property name mentioned in the constraint expression is checked against the set of offer's properties if the offer matches the specified STN. After the specified property name is found among the offer's property names, the property's value is extracted and compared to the corresponding value in the constraint. The result of the comparison is then used to determine whether the offer matches the constraint expression.

In the real world, a client always takes a risk: the property name mentioned in the constraint may not match an offer's property set because of misspelling or absence "in stock." That is why Novell Trader uses three-state logic instead boolean logic to determine a query match. For example, if property A is found in the offer's property list and property B is not, the result of logical operation (A and B) is not "FALSE" but "unknown", and the final result takes into account all other components of the constraint expression.

The syntax rules of the Constraint parameter are described in the Appendix of this article. If the constraint expression does not obey these rules then a TraderServiceException [IllegalConstraint] exception is raised.

The constraint expression may be an empty string or may include one or more property names and several computational and/or boolean logical operations. Here are some examples of constraint expression where "time", "owner", "cost", "color", and "speed" are property names:

A:  <<OMG 1.0>>
B:  <<OMG 1.0>> cost == 100
C:  cost < 200 and speed >= 51
D:  ( exists color ) and (( "gray"~ color) or ( "Gray" ~
    color )) and cost > 150
E:  (( "Novell, Inc."== owner ) or ( "Novell" ~ owner ))
    and ( time * speed >= 387.581)
F:  (( not exists speed) or ( speed > 100 )) and ( cost <
    1000*( time-30)/10e-2 )

For examples A and B, the <<OMG 1.0<< prefix indicates to the trader that the OMG Constraint Language 1.0 defines the constraint. The prefix syntax is << Identifier major.minor <<. If prefix is missing, the <<OMG 1.0<< is accepted as the default value. Examples B,C,D, and F use boolean operands like "==", ">", ">", ">=", ">=", as well as "and", "or", and "not". For example C, the "cost" property value has to be less than 200 and the "speed" property value has to be greater than or equal to 51.

Operators "~" and "==" mean that the values of "color" and "owner" have to include the text in the quotes as a sub-string (examples D and E), or have to be equal to the text in the quotes. The math operators (+,--,*, / ) may be applied to the numeric values as well as to the property values ( example F ).

Preference Parameter

The client can query offers to be returned by Novell Trader in the order of client's greatest interest. To do this, you should specify a Preference parameter (expression) for the setSortOrder method. It is a string which has to be written according to the same syntax rules as the Constraint parameter.

The Preference parameter contents a sort key and a sort calculation criterion. The sort key values are: max, min, with, first, and random. Let's look at some examples:

A:	max  cost * speed
B:	min  cost + (100- time )/ speed
C:	with "Novell" ~ owner

Example A means that found offers will be returned in the descending order according to the result of multiplication of the "cost" and the "speed" properties' values. Example B shows expression for the ascending order according to the calculated result of the expression. If only offers in which the owner's name includes "Novell" are desired, the client may use example C. The sort key means that the return order is the same as the order of the offer acquisition, and the sort key "random" means a random order of the returned offers.

Obviously, all property names specified in the Preference parameter have to match the offers' property sets. If the match fails, the default order ("first") is applied.

Policies Parameter

The Policy parameter is the most complex of the Query() method parameters. It is in charge of how the search should be performed. The Policy parameter includes a sequence of name-value pairs (policies) and deals with Novell Trader's Admin, Link, and Proxy interfaces. These interfaces are the subjects of special articles in our series. To set up the name-value pairs, the addPolicy method is used.

If a policy name does not obey the syntactic rules for legal policies' name, then a TraderServiceException [IllegalPolicyName] exception is raised. Some name-values can impact integration with other parameters or can impact linking or federation of traders. That is why if the type of the value associated with certain policy name differs from that specified in the OMG Trading Object Service specification, then a TraderServiceException [PolicyTypeMismatch] exception is raised.

If the Policies parameter contains the same policy name-value pair several times, then a TraderServiceException [DuplicatePolicyName] exception is raised. And finally, any processing errors of policies's values cause a TraderServiceException [InvalidPolicyValue] exception.

Policies parameter's name-value components may be split into four groups as shown in the following table.


Group Name

Policy Names

Importer Group

search_card, match_card, return_card, hop_count

Support Group

use_modifiable_properties, use_dynamic_properties, use_proxy_offers

Trader Group

starting_trader, exact_type_match

Link Group

link_follow_rule

Looking on the sample code section you can note that not all of the policy names listed above were specified in the code. The Novell Trader takes care of the non-specified policies using default values.

The client has to be quite accurate working with Policy parameter because this dramatically impacts the performance of a trading service. Now, we will discuss each of the policies.

Importer Group. The "serch_card" policy specifies the maximum number of offers the Novell Trader should consider when searching for service type conformance and constraint expression match. The Trader's Admin Interface sets the "max_search_card" value which can override client's value; the minimum of these two values is used in the searching process.

The "match_card" policy specifies the maximum number of matching offers which have to sorted according the Preference parameter's value. The Trader's Admin Interface sets the "max_match_card" value which can override client's value; the minimum of these two values is used in the searching process.

The "return_card" policy specifies for the trader the maximum number of matching offers to be returned as a result of query. The Trader's Admin Interface sets the "max_return_card" value which can override client's value; the minimum of these two values is used in the searching process.

The "hop_count" policy specifies the maximum number of hops across trader federation links that might be involved in the resolution of the query. The Trader's Admin Interface sets the "max_hop_count" value which can override client's value; the minimum of these two values is used in the searching process. If the "hop_count" value is set to zero that means no federated queries are permitted.

Support Group. The "use_modifiable_properties" policy, being set to false, notifies the Novell Trader to not consider and to return offers which have modifiable properties. If this policy is not specified, the default value of true is used, i.e. such offers will be included into the return list.

The "use_dynamic_properties" policy, being set to false, notifies the Novell Trader to not consider and to return offers which have dynamic properties. If this policy is not specified, the default value of true is used, i.e. such offers will be included into the return list.

The "use_proxy_offers" indicates whether or not the Novell Trader should consider such offers when constructing the return offer list. The default value is true.

Trader Group. The "starting_trader" policy value forces the Novell Trader to explicitly navigate the link graph to the remote trader of the specified trader's name. If the client decides to employ this policy, it has to be used as the first name-value pair in the Policies parameter. If no actual link name matches the policy value, a TraderServiceException [InvalidPolicyValue] exception is raised.

The "exact_type_match" policy, being set to true, indicates to the Novell Trader that all returning offers must exactly match the STN, specified by the setServiceType method. In other words, the client does not expect any offers of possible sub-service that type might be discovered by the query.

Link Group. The "link_follow_rule" policy* specifies how the client prefers links to be followed. This policy has three possible values: local_only, if_no_local, and always. The value of local_only indicates that the link is followed by explicit navigation, i.e. value of "starting_trader" policy. The value of if_no_local sets the rule that the link is followed only if there are no local offers that can resolve the query. And the value of always means that the link has to always be followed.

You can already note that the setup for policy values has to be balanced. For example, if the "search_card" value is set to 1000 and the "return_card" value is set to 1, that means the client will be able to receive back only one offer matching query's terms in spite of several offers among 1000 that might meet query's terms. Another example, if the "search_card" value is set to 1000 and the "match_card" value is set to 1, then the client will receive back the first offer which met the query's terms and it may not be the best possible offer for the client.

* At the moment when the article was written, this policy implementation was under development.

Desired Properties Parameters

Let us assume, that the client is interested (at this moment) in only one property of the service offers and this property is "cost"; this simplifies the analysis of the offers for the client. There are two TraderQuery methods which provide the client with mentioned feature: setReturnProperty and addReturnProperty. The client can specify the set of properties of the most interest by the Desired Properties parameters, i.e. only these properties will be represented to the client with returned offers.

The setReturnProperty method specifies the mode of desired properties and has three choices: "none" of the properties are desired (TraderQuery.none constant), "all" of the properties are desired but without having to name all of them(TraderQuery.all constant), and only "some" of the properties are desired(TraderQuery.some constant). If the latter one is used, the desired property names have to be explicitly added by the addReturnProperty method.

If added property names does not obey the Constraint parameter's syntax rules (see Appendix), then a TraderServiceException [IllegalPropertyName] exception is raised. If a property name is added more then once, then a TraderServiceException [DuplicatePropertyName] exception is raised.

How_many Parameter

The How_many parameter, which is set up by the setHowMany method, is the last query parameter specified by the client. With this parameter the client sets the number of offers to be returned among the offers matching the query terms.

Returned Offers Methods

The client can retrieve the returned offers using the following three methods: getHowManyOffers, getOfferName, and getNextOffer. These methods are provided by TraderService class.

The getHowManyOffersmethod. This method returns the number of the offers which are returned by query. This value may be implicated by the Policies parameters set and the How_many parameter (it is always less than or equal to the number of discovered matching offers). If it is necessary to look through the list of returned offers, this value can be used as a high board of the loop. If the number cannot be determined, a TraderServiceException [UnknownMaxLeft] exception is raised.

The getNextOffermethod. This method returns the reference to the Offer object which is the next in the returned offers list. The Offer object is the CORBA object. To retrieve a reference to the interface that provides the service, you can use the (trader).query_reference variable. To get access to the name-value property array of the offer, use the (trader).query_properties variable.

The getOfferNamemethod. This method retrieves a name of the Offer object and returns it in the form of a string. If during trader federation or proxy any limits were applied to the query, the (trader).limits_applied array contains the names of policies which limited the query. That is, if the client received back the query returns which differed from what were expected, the (trader).limits_applied may be helpful for understanding the query results.

Some Tips for Importing from the Novell Trader

  • For the Constraint parameter, let us put your attention to the expression "((not exists speed)or(speed > 100))" in example F. Assume that the client looks for high speed processing service but is not sure, in advance, whether desirable service has a property "speed" in its offer. Mentioned constraint will be successful in any case whether the "speed" exists or not, i.e. the client's concern will never affect the match process for other properties in the expression.

  • Usually, a client can get back service offers of the specified STN and service offers of derived sub-types which the client may not requested. To avoid extra returns, make sure the Policies parameter "exact_type_match" is set to true (for the first use of NovellTrader it is a default setup).

  • For the Desired Properties parameter, to avoid situation when the query can miss the offer with desired property, the client has to specify the property's name in the expression "exists property_name" in the Constraint parameter of the query.

  • If the client prefers to make visual analysis of the returned service offers, it makes sense to set up:

    • the "match_card" policy value equal to or less than the "how_many" policy value;

    • the "return_card" policy value equal to or less than the "how_many" policy value;

    • the number of returned service offers ("return_card" policy value) equal to the readable amount.

Appendix

OMG Constraint Language BNF

This appendix provides the BNF specification of the CORBA standard constraint language; it is used for specifying both the constraint and preference expression parameters to various operations in the trader interfaces.

A statement in this language is an Istring. Other constraint languages may be supported by a particular trader implementation; the constraint language used by a client of the trader is indicated by embedding "<<Identifier major.minor>>" at the beginning of the string. If such an escape is not used, it is equivalent to embedding "<<OMG 1.0>>" at the beginning of the string.

1. Language Basics

1.1. Basic Elements

Both the constraint and preference expressions in a query can be constructed from property names of conformant offers and literals. The constraint language in which these expressions are written consists of the following items (examples of these expressions are shown in square brackets below each bulleted item):

  • comparative functions: == (equality), != (inequality), >, >=, <, <=, ~ (substring match), in (element in sequence); the result of applying a comparative function is a boolean value ["Cost < 5" implies only consider offers with a Cost property value less than 5; " Visa in CreditCards" implies only consider offers in which the CreditCards property, consisting of a set of strings, contains the string Visa ]

  • boolean connectives: and, or, not ["Cost >= 2 and Cost >= 5" implies only consider offers where the value of the Cost property is in the range 2 <= Cost <= 5]

  • property existence: exist

  • property names

  • numeric and string constants

  • mathematical operators: +, -, *, / ["10 < 12.3 * MemSize + 4.6 * FileSize" implies only consider offers for which the arithmetic function in terms of the value of the MemSize and FileSize properties exceeds 10]

  • grouping operators: (, )

Note that the keywords in the language are case sensitive.

1.2. Precedence Relations

The following precedence relations hold in the absence of parentheses, in the order of highest to lowest:

() exist unary-minus not * / + -~ in == != < <= > >= and or

1.3. Legal Property Value Types

While one can define properties of service types with arbitrarily complex OMG IDL value types, only the following property value types can be manipulated using the constraint language:

  • boolean, short, unsigned short, long, unsigned long, float, double, char, Ichar, string, Istring

  • sequences of the above types

The "exist" operator can be applied to any property name, regardless of the property's value type.

1.4. Operator Restrictions


exist

can be applied to any property

~

can only be applied if left operand and right operand areboth strings or both Istrings in can only be applied if the leftoperand is one of the simple types described above andthe right operand is a sequence of the same simple type

==

can only be applied if the left and right operands are of thesame simple type

!=

can only be applied if the left and right operands are of thesame simple type

<

can only be applied if the left and right operands are of thesame simple type

<=

can only be applied if the left and right operands are of thesame simple type

can only be applied if the left and right operands are of thesame simple type

>=

can only be applied if the left and right operands are of thesame simple type

can only be applied to simple numeric operands

-

can only be applied to simple numeric operands

can only be applied to simple numeric operands

/

can only be applied to simple numeric operands

<, <=, >, >= comparisons imply use of the appropriate collating sequence for characters and strings; TRUE is greater than FALSE for booleans.

1.5. Representation of Literals


boolean

TRUE or FALSE

integers

sequences of digits, with a possible leading + or -

floats

digits with decimal point, with optional exponential notation

characters

char and Ichar are of the form '<char<', string andIstring are of the form '<char<<char<+'; to embedan apostrophe in a string, place a backslash (\) infront of it; to embed a backslash in a string, use \\.

2 The Constraint Language BNF

2.1. The Constraint Language Proper in Terms of Lexical Tokens

<constraint>:=/* empty */
| | <bool>
<preference>:=/* <empty> */
  | min <bool>
  | max <bool>
  | with <bool>
  | random
  | first
<bool>:=<bool_or>
<bool_or>:=<bool_or> or <bool_and>
  | <bool_and>
<bool_and>:=<bool_and> and <bool_compare>
  | <bool_compare>
<bool_compare>:=<expr_in> == <expr_in>
  | <expr_in> != <expr_in>
  | <expr_in> < <expr_in>
  | <expr_in> <= <expr_in>
  | <expr_in> > <expr_in>
  | <expr_in> >= <expr_in>
  | <expr_in>
<expr_in>:=<expr_twiddle> in <Ident>
  | <expr_twiddle>
<expr_twiddle>:=<expr> ~ <expr>
  | <expr>
<expr>:=<expr> + <term>
  | <expr> - <term>
  | <term>
<term>:=<term> * <factor_not>
  | <term> / <factor_not>
  | <factor_not>
<factor_not>:=not <factor>
  | <factor>
<factor>:=( <bool_or> )
  | exist <Ident>
  | <Ident>
  | <Number>
  | - <Number>
  | <String>
  | TRUE
  | FALSE
2.2. "BNF" for Lexical Tokens up to Character Set Issues
<Ident>:=<Leader> <FollowSeq>
<FollowSeq>:=/* <empty> */
  | <FollowSeq> <Follow>
<Number>:=<Mantissa>
  | <Mantissa> <Exponent>
<Mantissa>:=<Digits>
  | <Digits> .
  | . <Digits>
  | <Digits> . <Digits>
<Exponent>:=<Exp> <Sign> <Digits>
<Sign>:=+
  | -
Exp>:= E
  | e
<Digits>:=<Digits> <Digit>
  | <Digit>
<String>:=' <TextChars> '
<TextChars>:=/* <empty> */
  | <TextChars> <TextChar>
<TextChar>:=<Alpha>
  | <Digit>
  | <Other>
  | <Special>
<Special>:=\\
  | \'

2.3. Character Set Issues

The previous BNF has been complete up to the non-terminals <Leader>, <Follow>, <Alpha>, <Digit>, and <Other>. For a particular character set, one must define the characters which make up these character classes.

Each character set which the trading service is to support must define these character classes. This appendix defines these character classes for the ASCII character set.

<Leader>:=<Alpha>
<Follow>:=<Alpha>
  | | <Digit>
  | | _

<Alpha> is the set of alphabetic characters [A-Z, a-z]
<Digit> is the set of digits [0-9]
<Other> is the set of ASCII characters that are not <Alpha>, <Digit>, or <Special>

* 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