- •Advanced CORBA® Programming with C++
- •Review
- •Dedication
- •Preface
- •Prerequisites
- •Scope of this Book
- •Acknowledgments
- •Chapter 1. Introduction
- •1.1 Introduction
- •1.2 Organization of the Book
- •1.3 CORBA Version
- •1.4 Typographical Conventions
- •1.5 Source Code Examples
- •1.6 Vendor Dependencies
- •1.7 Contacting the Authors
- •Part I: Introduction to CORBA
- •Chapter 2. An Overview of CORBA
- •2.1 Introduction
- •2.2 The Object Management Group
- •2.3 Concepts and Terminology
- •2.4 CORBA Features
- •2.5 Request Invocation
- •2.6 General CORBA Application Development
- •2.7 Summary
- •Chapter 3. A Minimal CORBA Application
- •3.1 Chapter Overview
- •3.2 Writing and Compiling an IDL Definition
- •3.3 Writing and Compiling a Server
- •3.4 Writing and Compiling a Client
- •3.5 Running Client and Server
- •3.6 Summary
- •Part II: Core CORBA
- •Chapter 4. The OMG Interface Definition Language
- •4.1 Chapter Overview
- •4.2 Introduction
- •4.3 Compilation
- •4.4 Source Files
- •4.5 Lexical Rules
- •4.6 Basic IDL Types
- •4.7 User-Defined Types
- •4.8 Interfaces and Operations
- •4.9 User Exceptions
- •4.10 System Exceptions
- •4.11 System Exceptions or User Exceptions?
- •4.12 Oneway Operations
- •4.13 Contexts
- •4.14 Attributes
- •4.15 Modules
- •4.16 Forward Declarations
- •4.17 Inheritance
- •4.18 Names and Scoping
- •4.19 Repository Identifiers and pragma Directives
- •4.20 Standard Include Files
- •4.21 Recent IDL Extensions
- •4.22 Summary
- •Chapter 5. IDL for a Climate Control System
- •5.1 Chapter Overview
- •5.2 The Climate Control System
- •5.3 IDL for the Climate Control System
- •5.4 The Complete Specification
- •Chapter 6. Basic IDL-to-C++ Mapping
- •6.1 Chapter Overview
- •6.2 Introduction
- •6.3 Mapping for Identifiers
- •6.4 Mapping for Modules
- •6.5 The CORBA Module
- •6.6 Mapping for Basic Types
- •6.7 Mapping for Constants
- •6.8 Mapping for Enumerated Types
- •6.9 Variable-Length Types and _var Types
- •6.10 The String_var Wrapper Class
- •6.11 Mapping for Wide Strings
- •6.12 Mapping for Fixed-Point Types
- •6.13 Mapping for Structures
- •6.14 Mapping for Sequences
- •6.15 Mapping for Arrays
- •6.16 Mapping for Unions
- •6.17 Mapping for Recursive Structures and Unions
- •6.18 Mapping for Type Definitions
- •6.19 User-Defined Types and _var Classes
- •6.20 Summary
- •Chapter 7. Client-Side C++ Mapping
- •7.1 Chapter Overview
- •7.2 Introduction
- •7.3 Mapping for Interfaces
- •7.4 Object Reference Types
- •7.5 Life Cycle of Object References
- •7.6 Semantics of _ptr References
- •7.7 Pseudo-Objects
- •7.8 ORB Initialization
- •7.9 Initial References
- •7.10 Stringified References
- •7.11 The Object Pseudo-Interface
- •7.12 _var References
- •7.13 Mapping for Operations and Attributes
- •7.14 Parameter Passing Rules
- •7.15 Mapping for Exceptions
- •7.16 Mapping for Contexts
- •7.17 Summary
- •Chapter 8. Developing a Client for the Climate Control System
- •8.1 Chapter Overview
- •8.2 Introduction
- •8.3 Overall Client Structure
- •8.4 Included Files
- •8.5 Helper Functions
- •8.6 The main Program
- •8.7 The Complete Client Code
- •8.8 Summary
- •Chapter 9. Server-Side C++ Mapping
- •9.1 Chapter Overview
- •9.2 Introduction
- •9.3 Mapping for Interfaces
- •9.4 Servant Classes
- •9.5 Object Incarnation
- •9.6 Server main
- •9.7 Parameter Passing Rules
- •9.8 Raising Exceptions
- •9.9 Tie Classes
- •9.10 Summary
- •Chapter 10. Developing a Server for the Climate Control System
- •10.1 Chapter Overview
- •10.2 Introduction
- •10.3 The Instrument Control Protocol API
- •10.4 Designing the Thermometer Servant Class
- •10.5 Implementing the Thermometer Servant Class
- •10.6 Designing the Thermostat Servant Class
- •10.7 Implementing the Thermostat Servant Class
- •10.8 Designing the Controller Servant Class
- •10.9 Implementing the Controller Servant Class
- •10.10 Implementing the Server main Function
- •10.11 The Complete Server Code
- •10.12 Summary
- •Chapter 11. The Portable Object Adapter
- •11.1 Chapter Overview
- •11.2 Introduction
- •11.3 POA Fundamentals
- •11.4 POA Policies
- •11.5 POA Creation
- •11.6 Servant IDL Type
- •11.7 Object Creation and Activation
- •11.8 Reference, ObjectId, and Servant
- •11.9 Object Deactivation
- •11.10 Request Flow Control
- •11.11 ORB Event Handling
- •11.12 POA Activation
- •11.13 POA Destruction
- •11.14 Applying POA Policies
- •11.15 Summary
- •Chapter 12. Object Life Cycle
- •12.1 Chapter Overview
- •12.2 Introduction
- •12.3 Object Factories
- •12.4 Destroying, Copying, and Moving Objects
- •12.5 A Critique of the Life Cycle Service
- •12.6 The Evictor Pattern
- •12.7 Garbage Collection of Servants
- •12.8 Garbage Collection of CORBA Objects
- •12.9 Summary
- •Part III: CORBA Mechanisms
- •Chapter 13. GIOP, IIOP, and IORs
- •13.1 Chapter Overview
- •13.2 An Overview of GIOP
- •13.3 Common Data Representation
- •13.4 GIOP Message Formats
- •13.5 GIOP Connection Management
- •13.6 Detecting Disorderly Shutdown
- •13.7 An Overview of IIOP
- •13.8 Structure of an IOR
- •13.9 Bidirectional IIOP
- •13.10 Summary
- •14.1 Chapter Overview
- •14.2 Binding Modes
- •14.3 Direct Binding
- •14.4 Indirect Binding via an Implementation Repository
- •14.5 Migration, Reliability, Performance, and Scalability
- •14.6 Activation Modes
- •14.7 Race Conditions
- •14.8 Security Considerations
- •14.9 Summary
- •Part VI: Dynamic CORBA
- •Chapter 15 C++ Mapping for Type any
- •15.1 Chapter Overview
- •15.2 Introduction
- •15.3 Type any C++ Mapping
- •15.4 Pitfalls in Type Definitions
- •15.5 Summary
- •Chapter 16. Type Codes
- •16.1 Chapter Overview
- •16.2 Introduction
- •16.3 The TypeCode Pseudo-Object
- •16.4 C++ Mapping for the TypeCode Pseudo-Object
- •16.5 Type Code Comparisons
- •16.6 Type Code Constants
- •16.7 Type Code Comparison for Type any
- •16.8 Creating Type Codes Dynamically
- •16.9 Summary
- •Chapter 17. Type DynAny
- •17.1 Chapter Overview
- •17.2 Introduction
- •17.3 The DynAny Interface
- •17.4 C++ Mapping for DynAny
- •17.5 Using DynAny for Generic Display
- •17.6 Obtaining Type Information
- •17.7 Summary
- •Part V: CORBAservices
- •Chapter 18. The OMG Naming Service
- •18.1 Chapter Overview
- •18.2 Introduction
- •18.3 Basic Concepts
- •18.4 Structure of the Naming Service IDL
- •18.5 Semantics of Names
- •18.6 Naming Context IDL
- •18.7 Iterators
- •18.8 Pitfalls in the Naming Service
- •18.9 The Names Library
- •18.10 Naming Service Tools
- •18.11 What to Advertise
- •18.12 When to Advertise
- •18.13 Federated Naming
- •18.14 Adding Naming to the Climate Control System
- •18.15 Summary
- •Chapter 19. The OMG Trading Service
- •19.1 Chapter Overview
- •19.2 Introduction
- •19.3 Trading Concepts and Terminology
- •19.4 IDL Overview
- •19.5 The Service Type Repository
- •19.6 The Trader Interfaces
- •19.7 Exporting Service Offers
- •19.8 Withdrawing Service Offers
- •19.9 Modifying Service Offers
- •19.10 The Trader Constraint Language
- •19.11 Importing Service Offers
- •19.12 Bulk Withdrawal
- •19.13 The Admin Interface
- •19.14 Inspecting Service Offers
- •19.15 Exporting Dynamic Properties
- •19.16 Trader Federation
- •19.17 Trader Tools
- •19.18 Architectural Considerations
- •19.19 What to Advertise
- •19.20 Avoiding Duplicate Service Offers
- •19.21 Adding Trading to the Climate Control System
- •19.22 Summary
- •Chapter 20. The OMG Event Service
- •20.1 Chapter Overview
- •20.2 Introduction
- •20.3 Distributed Callbacks
- •20.4 Event Service Basics
- •20.5 Event Service Interfaces
- •20.6 Implementing Consumers and Suppliers
- •20.7 Choosing an Event Model
- •20.8 Event Service Limitations
- •20.9 Summary
- •Part VI: Power CORBA
- •Chapter 21. Multithreaded Applications
- •21.1 Chapter Overview
- •21.2 Introduction
- •21.3 Motivation for Multithreaded Programs
- •21.4 Fundamentals of Multithreaded Servers
- •21.5 Multithreading Strategies
- •21.6 Implementing a Multithreaded Server
- •21.7 Servant Activators and the Evictor Pattern
- •21.8 Summary
- •22.1 Chapter Overview
- •22.2 Introduction
- •22.3 Reducing Messaging Overhead
- •22.4 Optimizing Server Implementations
- •22.5 Federating Services
- •22.6 Improving Physical Design
- •22.7 Summary
- •Appendix A. Source Code for the ICP Simulator
- •Appendix B. CORBA Resources
- •Bibliography
IT-SC book: Advanced CORBA® Programming with C++
UnknownOfferId, ProxyOfferId
);
// ...
};
The describe operation returns the complete details for the service offer specified by the id parameter. The operation is useful for dumping the complete contents of a trader. Because not all service types may have a common root base type, you cannot use the query operation to get the complete set of service offers. (The query operation can return only service offers of a particular type and its derived types.)
Another use for describe is to locate the offer ID of a lost service offer. You can use list_offers to iterate over the complete set of offer IDs and invoke describe on each returned offer ID to match the service offer details against the lost service offer. Clearly, this technique is cumbersome and inefficient because potentially you must examine all service offers in a trader to recover the lost one. Unfortunately, apart from withdraw_using_constraint and this technique, there is no standard way to recover lost offers (but your vendor may offer proprietary tools this purpose).
19.15 Exporting Dynamic Properties
Support for dynamic properties is provided in a separate module called
CosTradingDynamic:
//File:CosTradingDynamic.idl #include <CosTrading.idl> #include <orb.idl>
#pragma prefix "omg.org"
module CosTradingDynamic { |
|
exception DPEvalFailure { |
name; |
CosTrading::PropertyName |
|
CORBA::TypeCode |
returned_type; |
any |
extra_info; |
}; |
|
interface DynamicPropEval { any evalDP(
in CosTrading::PropertyName |
name, |
in CORBA::TypeCode |
returned_type, |
in any |
extra_info |
) raises(DPEvalFailure); |
|
}; |
|
struct DynamicProp {
DynamicPropEval |
eval_if; |
CORBA::TypeCode |
returned_type; |
any |
extra_info; |
}; |
|
}; |
|
770
IT-SC book: Advanced CORBA® Programming with C++
Dynamic property evaluation uses the callback pattern. To export a service offer containing a dynamic property, you specify the service offer type as you would for any other service offer. For example, the service type for controllers we established earlier does not need to change at all in order for property values to be dynamic. However, at export time, the exporter does not supply a value of the offer; instead, the exporter sets the any value for the dynamic property to contain a structure of type DynamicProp.
The DynamicProp structure must contain an object reference to an object supporting the DynamicPropEval interface in the eval_if member. The trader invokes the evalDP operation on that object when it requires the value of the dynamic property. You must set the returned_type member to indicate the type of value that evalDP must return when it is called. The extra_info member is an any value that you can use to pass additional information to evalDP. The trader does not interpret this member in any way but simply passes it to evalDP when it evaluates the dynamic property.
Table 19.4. Property definitions for a share service type.
Property Name |
Property Type |
Property Mode |
Name |
CORBA::_tc_string |
Mandatory, read-only |
Price |
CORBA::_tc_ulong |
Mandatory |
After you have exported a dynamic property, the trader invokes the evalDP operation on the reference for the dynamic property whenever it needs to evaluate that property. The trader passes the name of the property, the expected type of the value evalDP should return, and the extra_info member that was stored at export time to the operation. The return value from evalDP is an any that delivers the property value back to the trader. The value returned must match the expected return type indicated by the returned_type parameter.
If for some reason evalDP cannot evaluate the property, it raises the DPEvalFailure exception. (You can fill the exception data members with the values indicated in the IDL. However, there is little point, because that exception is never propagated back to the importer. This means that you might as well leave the exception members in the defaultconstructed state.)
The following code fragment illustrates export of a Price property as a dynamic property. We assume that a service type StockMarket::Shares already exists and that it has the property definitions shown in Table 19.4.
using namespace CosTrading;
using namespace CosTradingDynamic;
//Get reference to Register interface...
Register_var regis = ...;
//Assume we have a reference to a DynamicPropEval interface...
771
IT-SC book: Advanced CORBA® Programming with C++
DynamicPropEval_var dpe = ...;
//Create dynamic property structure for Price property. DynamicProp dp;
dp.eval_if = dpe;
dp.returned_type = CORBA::TypeCode::_duplicate(CORBA::_tc_ulong); dp.extra_info <= "234.234.234.234:5678";
//Fill in property definition for the share offer.
PropertySeq props; props.length(2);
props[0].name = CORBA::string_dup("Name"); props[0].value <= "Acme Corporation";
props[1].name = CORBA::string_dup("Price");
props[1].value <= dp; // Dynamic property
//Get reference to the share interface we want to advertise...
StockMarket::Shares_var shares = ...;
//Export the offer.
OfferId_var offer_id = regis->_cxx_export(
shares, "StockMarket::Shares", props
);
cout < "Created new offer with id " < offer_id < endl;
The only difference between this code and an ordinary export operation is that the any value for the price property contains a DynamicProp structure. In this example, we use the extra_info member of the structure to contain an IP address and port number. The assumption is that the implementation of evalDP will use that addressing information to retrieve the current stock price, for example, from a commercial stock ticker. This is only one of many options. Because the extra_info member is of type any, you can use it to pass arbitrarily complex information to the evalDP operation.
The implementation of evalDP is responsible for delivering the current property value to the trader. Here is an outline of one possible implementation:
CORBA::Any * |
|
DynamicPropEval_impl:: |
|
evalDP( |
name, |
const char * |
|
CORBA::TypeCode_ptr |
returned_type, |
const CORBA::Any & |
extra_info |
) throw(CORBA::SystemException, CosTradingDynamic::DP EvalFailure)
{
//Get the address details for the ticker from the extra
//info parameter and read current price from ticker. const char * addr;
extra_info >>= addr;
CORBA::ULong price = read_price(addr, name);
if (price |
== 0) |
// Error |
throw |
CosTradingDynamic::DPEvalFailure(); |
|
772
IT-SC book: Advanced CORBA® Programming with C++
// Return the current price.
CORBA::Any *ap = new CORBA::Any; (*ap) <= price;
return ap;
}
In this example, the evalDP operation uses the address details passed in the extra_info parameter and the name of the property to access a remote service that delivers the current price for the stock. If the attempt to read the price fails, the code throws a DPEvalFailure exception to indicate to the trader that the property value is not available. Otherwise, the code returns the current price in the any returned from the operation.
19.16 Trader Federation
Traders can be linked into a federation graph, which can have any structure (even loops are permitted). If trader A is federated with trader B, trader A has a link to trader B, and import operations on trader A return service offers found in both A and B. Links are unidirectional, so if A is linked to B, imports on trader B return only service offers found in trader B.
All traders in a federation typically are configured to use the same type repository. If several type repositories are used in a federation, they must all agree on at least those service types that are used by service offers in more than one trader.
Federation applies only to imports and not to exports. If an importer runs a query on a federated trader, the returned service offers may have come from any trader in the federation. However, exporters must choose a particular trader to which to export a service offer; that is, an export operation always stores the service offer in the trader on which the operation was invoked, regardless of federation.
The links in a federation have names; this is similar to the way bindings in a Naming Service are labeled with names. Figure 19.6 shows a possible federation graph. The link names effectively assign names to each linked trader. For example, from trader A's perspective, trader B is known by the name sub. Because a trader can be pointed to by more than one link, the name of a trader can vary depending on the sequence of links via which it is accessed. For example, from trader A's perspective, trader D is known by the names sub/shares and acme/CC. (Trader names are sequences of strings, so the slashes in the names act as separators and are not part of the names themselves.)
Figure 19.6 Four traders in a federation.
773
IT-SC book: Advanced CORBA® Programming with C++
19.16.1 Link and Federation Policies
Each link in a federation has a default link policy and a limiting link policy. The link policies determine under what circumstances a query will be passed to a federated trader via its link. The default link policy applies if an importer does not explicitly specify a link policy, and the limiting link policy provides an upper "hard" limit as to how permissive that link can be. Link policies have one of the three values shown on page 886.
The local_only policy value means that queries will not be passed via that link.
The if_no_local policy value means that a query will be passed via that link only if no matching offers can be found locally.
The always policy value means that queries will always be passed via that link.
In addition to link policies, there are federation policies. These policies exist both as trader policies and as import policies.
Hop count
The hop count determines how many times a query will be forwarded. Each query has an initial hop count. Before forwarding a query to a linked trader, the forwarding trader decrements the hop count. Queries are forwarded only while the hop count is non-zero. For example, for the federation graph on page 1, a query submitted to trader A will reach traders B and C only if the hop count is 1. With a hop count greater than 1, the same query will also reach trader D.
Follow behavior
The follow behavior has the value local_only, if_no_local, or always.
774
IT-SC book: Advanced CORBA® Programming with C++
Link policies override import policies, and trader policies override link policies. The most restrictive set of policies arrived at after evaluation of this policy hierarchy applies to each import operation.
Hop Counts
The hop count mechanism gives an importer some degree of control over how widely a query will propagate throughout a federation. This control can be important in commercial trading, where each query incurs a charge. By limiting the extent of query propagation, the importer gets some control over the cost. Keep in mind, though, that this mechanism is crude and does not limit the absolute number of traders that can be searched, because the absolute number depends on the fan-out of the federation graph.
Three policies determine the initial hop count for an import. def_hop_count (trader policy)
This is the default hop count that applies if an importer does not use the hop_count policy. You can control the default value via the Admin interface.
max_hop_count (trader policy)
This is the maximum hop count permitted by the trader. If an importer specifies a hop_count policy with a value greater than max_hop_count, the hop count for the query is silently adjusted to max_hop_count. You can control the max_hop_count value for the trader via the Admin interface.
hop_count (import policy)
You can set this policy as part of the policies parameter for an import operation. The trader uses the specified value for the import provided that it does not exceed max_hop_count, in which case max_hop_count applies.
Follow Behavior
Follow behavior applies to links. A query is passed via a particular link only if the follow behavior permits it. Both follow behavior and hop count determine whether a link is followed. If the follow behavior disallows traversal of a particular link, the link is not followed even if the hop count would permit it; if the follow behavior permits traversal of a link, the link is followed only if the hop count is still non-zero.
The follow behavior for a particular link is affected by the following policies.
def_follow_policy (trader policy)
This policy determines the default follow behavior for a trader and applies if the importer does not specify a value for the link_follow_rule policy. Most traders set this policy to if_no_local to avoid the cost of federating a query if matching offers can be found locally.
max_follow_policy (trader policy)
775
IT-SC book: Advanced CORBA® Programming with C++
This policy sets the limit for the trader and overrides any more permissive values specified by an importer or a link.
max_link_follow_policy (trader policy)
This value limits the most permissive behavior for a link's limiting_follow_policy at the time of the link's creation or modification. Links cannot be created or modified to have a more permissive behavior than this value. def_pass_on_follow_rule (link policy)
This policy applies if an importer does not request a specific behavior by setting the link_follow_rule policy. The def_pass_on_follow_rule policy is modified by the trader's max_follow_policy.
limiting_follow_rule (link policy)
This is the most permissive behavior that a particular link will tolerate. The value is further limited by the trader's max_follow_policy.
link_follow_rule (import policy)
The importer can specify the desired follow behavior for a particular query by setting this policy in the policies parameter of the query. The value is limited by the max_follow_policy of the trader as well as the limiting_follow_policy of each link.
You can control the values of def_follow_policy, max_follow_policy, and max_link_follow_policy via operations on the Admin interface.
19.16.2 Request Identifiers
A trader federation graph permits a trader to be reached via multiple paths. (The graph even permits loops.) This arrangement introduces a problem: multiple copies of a query can end up being forwarded to a given trader via multiple paths. Unless traders specifically deal with this problem, a single query could end up searching the offer space of a trader multiple times (something that is wasteful), or worse, a query could end up being indefinitely forwarded from trader to trader in a loop so that the query would never terminate.
To prevent redundant searches and infinite loops, the first trader that accepts a query from an importer generates a unique ID value and prepends that trader's request ID stem (see Section 19.13.1) to that unique ID. The resulting value is passed in the request_id policy whenever a query is forwarded to a federated trader. The net effect is that every query carries a unique ID value that is generated by the trader that accepts the initial import; thereafter, the ID never changes and is simply passed from trader to trader as the query propagates through a federation.
Each trader maintains a cache of recently processed request IDs. If a query arrives at a trader and the request ID for the query is not in the cache, the trader adds the request ID to the cache and evaluates the query. Otherwise, if the request ID for a query is already in the cache, the trader recognizes that it has processed the same query earlier and returns an empty result set.
776
IT-SC book: Advanced CORBA® Programming with C++
This caching mechanism is very effective. It reliably prevents multiple redundant searches of the same trader even if the cache is small and contains only a few dozen entries. The cache is maintained in least-recently-used order. In the rare case when a request ID is dropped from the cache while a query is still propagating, the worst outcome is that the trader will process the same query a second time. This has no harmful effects on the results returned to the importer (unless a search cardinality limits further query propagation and causes offers to be missed elsewhere, and that is unlikely).
As an importer, you should never set the request_id policy. Its value is generated automatically if a trader receives a query without a value for this policy.
19.16.3 Nominating a Starting Trader
You can direct a query to begin execution in a specific starting trader by setting the starting_trader policy. Note that this policy was added to the specification mainly to permit migration from earlier (non-OMG-compliant) traders that used different concepts for federation. You should not have a reason to set this policy value, so the discussion here is included mainly for completeness. You can get equivalent functionality by using the Register::resolve operation (see Section 19.16.5).
The starting_trader policy is an import policy. Its value must be of type
TraderName:
typedef Istring |
LinkName; |
typedef sequence<LinkName> |
LinkNameSeq; |
typedef LinkNameSeq |
TraderName; |
By setting this policy to the sequence of link names that lead to a starting trader, you can direct a query to begin executing in that trader. For example, for the federation graph in Figure 19.6, a query directed at trader A with a sequence containing the names sub and shares for the starting_trader policy directs the query to begin execution in trader D. Trader A forwards the query untouched to trader B, which in turn forwards it to trader D, where it begins execution.
The starting_trader policy is always obeyed for a query and overrides all other policies, such as link_follow_rule and max_follow_policy. On its way to the starting trader, the other policies for a query are passed from trader to trader without change, so they begin to take effect only after the query has reached the starting trader.
19.16.4 The Link Interface
The Link interface permits you to add, remove, and modify links. In addition, you can list the links for a trader and examine their configuration.
typedef Istring |
LinkName; |
typedef sequence<LinkName> |
LinkNameSeq; |
typedef LinkNameSeq |
TraderName; |
777
IT-SC book: Advanced CORBA® Programming with C++
enum FollowOption { local_only, if_no_local, always };
interface Link :
TraderComponents, SupportAttributes, LinkAttributes {
struct LinkInfo { |
target; |
Lookup |
|
Register |
target_reg; |
FollowOption |
default_follow_rule; |
FollowOption |
limiting_follow_rule; |
}; |
|
exception InvalidLookupRef { Lookup target;
};
exception IllegalLinkName { LinkName name;
};
exception UnknownLinkName { LinkName name;
};
exception DuplicateLinkName { LinkName name;
};
exception DefaultFollowTooPermissive { FollowOption default_follow_rule; FollowOption limiting_follow_rule;
};
exception LimitingFollowTooPermissive { FollowOption limiting_follow_rule; FollowOption max_link_follow_policy;
}; |
|
|
void |
add_link( |
name, |
|
in LinkName |
|
|
in Lookup |
target, |
|
in FollowOption |
default_follow_rule, |
|
in FollowOption limiting_follow_rule |
|
|
) raises( |
|
|
IllegalLinkName, DuplicateLinkName, |
|
|
InvalidLookupRef, DefaultFollowTooPermissive, |
|
|
LimitingFollowTooPermissive |
|
|
); |
|
void |
remove_link(in LinkName name) |
|
|
raises(IllegalLinkName, UnknownLinkName); |
|
void |
modify_link( |
name, |
|
in LinkName |
|
|
in FollowOption |
default_follow_rule, |
|
in FollowOption |
limiting_follow_rule |
778
IT-SC book: Advanced CORBA® Programming with C++
|
) raises( |
|
IllegalLinkName, UnknownLinkName, |
|
DefaultFollowTooPermissive, |
); |
LimitingFollowTooPermissive |
|
|
LinkInfo |
describe_link(in LinkName name) |
raises(IllegalLinkName, UnknownLinkName);
LinkNameSeq list_links();
};
Note that the Link interface exists mainly as an administrative interface. Ordinary applications do not normally use it because they typically must integrate with whatever federation structure is in place at a particular installation. (This does not cause problems because federation is transparent to clients of the trader.)
Creating a Link
The add_link operation creates a new link:
typedef Istring |
LinkName; |
typedef sequence<LinkName> |
LinkNameSeq; |
typedef LinkNameSeq |
TraderName; |
enum FollowOption { local_only, if_no_local, always };
interface Link :
TraderComponents, SupportAttributes, LinkAttributes { // ...
void |
add_link( |
name, |
|
in LinkName |
|
|
in Lookup |
target, |
in FollowOption default_follow_rule, in FollowOption limiting_follow_rule
) raises(
IllegalLinkName, DuplicateLinkName, InvalidLookupRef, DefaultFollowTooPermissive, LimitingFollowTooPermissive
);
// ...
};
The add_link operation creates a new link between two traders. The link points from the trader on which add_link is invoked to the trader whose Lookup interface is specified by the target parameter. The name parameter names the new link. The default_follow_rule and limiting_follow_rule parameters determine the default and limiting follow behavior for the link (see Section 19.16.1).
The operation can raise one of the following exceptions.
IllegalLinkName
779
IT-SC book: Advanced CORBA® Programming with C++
The name for the link is syntactically invalid. Unfortunately, the specification does not define a syntax for link names, so it is probably best to use simple identifiers.
DuplicateLinkName
Another link for this trader already has the supplied name.
InvalidLookupRef
The object reference to the Lookup interface of the target trader is nil or denotes a nonexistent object.
DefaultFollowTooPermissive
The default_follow_rule parameter specifies a behavior that is more permissive than the one specified by the limiting_follow_rule parameter.
LimitingFollowTooPermissive
The limiting_follow_rule parameter specifies a behavior that is more permissive than that specified by the trader's max_link_follow_policy. This test is made only at creation time. If you change a trader's max_link_follow_policy later, it is possible that a link has a more permissive policy than the trader's limiting policy. However, the trader's limit still takes precedence during query evaluation.
Removing a Link
The remove_link operation removes a link:
interface Link :
TraderComponents, SupportAttributes, LinkAttributes { // ...
void remove_link(in LinkName name) raises(IllegalLinkName, UnknownLinkName);
// ...
};
The name parameter identifies the link to be removed. If the link name has illegal syntax, the operation raises IllegalLinkName. If the specified link does not exist, the operation raises UnknownLinkName.
Modifying a Link
The modify_link operation changes a link's follow policies:
interface Link :
TraderComponents, SupportAttributes, LinkAttributes {
// ... |
modify_link( |
|
void |
name, |
|
|
in LinkName |
in FollowOption default_follow_rule, in FollowOption limiting_follow_rule
) raises(
IllegalLinkName, UnknownLinkName, DefaultFollowTooPermissive, LimitingFollowTooPermissive
);
780
IT-SC book: Advanced CORBA® Programming with C++
// ...
};
You can use the operation to change a link's policy values without having to remove and re-create a link.
Listing Links
The list_links operation returns the names of all links for a trader:
interface Link :
TraderComponents, SupportAttributes, LinkAttributes { // ...
LinkNameSeq list_links(); // ...
};
Note that no iterator is provided for this operation. Omitting the iterator is reasonable because a trader will never have more than a handful of federation links.
Obtaining Link Details
The describe_link operation returns the details of a link:
interface Link :
TraderComponents, SupportAttributes, LinkAttributes {
struct LinkInfo {
Lookup |
|
target; |
Register |
|
target_reg; |
FollowOption |
default_follow_rule; |
|
FollowOption |
limiting_follow_rule; |
|
}; |
|
|
// ... |
|
|
LinkInfo |
describe_link(in LinkName name) |
|
}; |
|
raises(IllegalLinkName, UnknownLinkName); |
|
|
|
The return value of type LinkInfo contains the details of the link. Note that the return value contains not only the Lookup reference for the link but also the target trader's Register reference. If the target trader does not support the Register interface, the target_reg member contains a nil reference.
19.16.5 Locating a Trader's Register Interface
The resolve operation allows you to explicitly locate a federated trader's Register interface:
781
IT-SC book: Advanced CORBA® Programming with C++
interface Register : TraderComponents, SupportAttributes {
// ...
exception IllegalTraderName { TraderName name;
};
exception UnknownTraderName { TraderName name;
};
exception RegisterNotSupported { TraderName name;
}; |
|
// ... |
|
Register |
resolve(in TraderName name) raises( |
|
IllegalTraderName, |
|
UnknownTraderName, |
|
RegisterNotSupported |
|
); |
};
The resolve operation is useful if you want to export a service offer into a trader in a federation other than the local trader. The name parameter specifies the sequence of link names for the target trader whose Register interface is to be returned. If the specified trader does not support a Register interface, the operation raises
RegisterNotSupported.
Unfortunately, resolve is part of the Register interface instead of the Link interface. As a result, a trader that does not support the Register interface but does support federation cannot offer the resolve operation. In addition, resolve cannot return a reference to a trader that does not support the Register interface. Therefore, if you require reliable resolution, it is probably better to use list_links and describe_link to navigate to the target trader and then obtain that trader's Register reference.
19.16.6 Federation and Import Policies
Unfortunately, the OMG Trading Service specification does not define how to treat the search_card, match_card, and return_card policies for federated queries. In particular, the search_card policy presents problems.
Assume that we set the search_card policy to 10,000 for a query submitted to trader A as shown in Figure 19.6. Also assume that the hop count and link policies permit the query to reach traders B, C, and D. The question is, what should trader A do when it passes the query to traders B and C?
782
IT-SC book: Advanced CORBA® Programming with C++
Trader A could simply leave the search cardinality at 10,000 when it forwards the query to each trader. However, that would result in an effective search cardinality of at least 20,000, because both trader B and trader C will search as many as 10,000 offers (assuming that they honor the policy at all). If trader B or C forwards the query in turn to trader D, this results in a further 10,000 offers being searched. The net effect is that the total number of searched offers can be 40,000 instead of the specified 10,000.
Another strategy would be for trader A to look at the size of its own offer space first. Assume that A holds 6,000 offers. In that case, trader A could decide to pass a search cardinality of 2,000 to each of its federated traders B and C. Depending on the size of their own offer spaces—say, 1,500 offers each—traders B and C may in turn decide to pass the query to trader D with a search cardinality of 500. The problem with this approach is that it may result in missed matches. For example, trader D may hold many matching offers, whereas traders A, B, and C may have no matching offers. However, because the query reaches trader D with a search cardinality of 500, trader D may never examine enough of its offer space to locate any matching offers. Similarly, if trader A had decided to pass a value of 3,000 to trader B and 1,000 to trader C, additional offers might have been discovered in trader B.
In yet another scenario, trader A has 100,000 offers in its database, and the search cardinality is 10,000. This means that the trader should never forward the query to any federated trader, because it can satisfy the requirement to search no more than 10,000 offers locally. However, the link policy on the federation links to trader B and C may be set to always. Which policy should take precedence now—the link policy or the search cardinality? Unfortunately, the specification is silent on this point.
Because the required behavior is unspecified, different traders use different strategies when they pass queries around a federation. In addition, because different traders in the federation may be sourced from different vendors, different strategies might apply at different points throughout the federation, making it even harder to decide what the effects will be. Your vendor may provide documentation on how the search cardinality is treated for federated queries, but that does not help you if traders from different vendors are federated.
In defense of the trading specification, the contributors were aware of the limitations and problems of how federation interacts with cardinality limits. Yet at the same time, it was felt that there had to be a way for importers to prevent a query from searching traders halfway around the planet. It is unlikely that you would be interested in a tire shop in Europe if you are living in the United States, especially if you must pay for the search.
In general, it is difficult to limit query propagation across arbitrary graphs of distributed databases. At the very least, it requires global knowledge of the federation graph and the number of offers at each node of the graph, but that conflicts with the requirements to keep the system stateless and scalable.
783
