- •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++
Import policies are specified for each individual import operation and affect only that operation. For example, the importer can limit the number of matching offers that will be returned.
Link policies
Link policies apply to each individual federation link and are set when a link is created. For example, there is a link policy to control whether or not a particular link will be followed by default during import operations.
19.4 IDL Overview
The IDL for the OMG Trading Service is large and offers a wide range of functionality and features. The specification defines three IDL modules.
CosTradingRepos
The CosTradingRepos module contains the functionality required to define, examine, and delete service types.
CosTrading
The CosTrading module contains most of the IDL for the trader. It consists of 11 interfaces that provide the functionality to create service offers, perform imports, maintain trader federations, set policies, and so on.
CosTradingDynamic
The CosTradingDynamic module contains a single interface called DynamicPropEval. Dynamic properties contain an object reference to this interface; the trader invokes an operation on the interface to get the current value of a dynamic property.
The sections that follow discuss these three modules in detail.
19.5 The Service Type Repository
The service type repository defined by the CosTradingRepos module is a database of service type definitions. The trader uses the repository when it requires type information about service offers (such as when it evaluates a search or when an exporter creates a new service offer). The relationship between the service type repository and the trader is shown in Figure 19.1.
Figure 19.1 Relationship between trader and type repository.
Each trader uses exactly one type repository (you cannot configure a trader to use more than one type repository at the same time). Several traders can share a single type
719
IT-SC book: Advanced CORBA® Programming with C++
repository. Typically, a shared type repository is used by traders if they are federated. (Strictly speaking, the specification does not require a single, shared repository; however, if traders in a federation use separate repositories, they must somehow ensure that the type information in the individual repositories is identical for those service offers that are accessible to federated queries.)
Note that the association between a trader and its repository is navigable only from the trader to the repository. Given a reference to a repository, you cannot find out which traders are using it. The fact that there is no way to get from a type repository to its traders has important consequences, which we discuss on page 847.
Each service type in a repository has a name that is unique within that repository, such as Controller. The service type name must start with a letter and must otherwise consist of letters, digits, underscore, period, and colon. Each service type stores the following information:
The repository ID of the IDL interface type
A list of property definitions
A (possibly empty) list of its parent service types
The IDL interface type stored in each service type is the repository ID of the object providing the service. For example, if we were to advertise controllers, we might have a repository ID such as IDL:acme.com/CCS/Controller:1.0. The service type name and the IDL interface name need not be the same or even similar, although, in practice, you will likely choose a service type name that is the same as the IDL interface name. We strongly recommend that you either use the fully scoped IDL interface name as the service type name or otherwise ensure that the service type name is unique. If you use simple, unqualified names for your service types, you may get a name clash with service types created by other applications.
For each property, the list of property definitions details the name and type of the property, whether it is mandatory or optional, and whether it is read-only or writable (see
Section 19.5.1).
The list of parent types contains the service type names of the immediate parent types if the service type is derived. Note that the repository supports multiple inheritance because a list of parent types is stored in each service type. We discuss the semantics of inheritance in Section 19.5.2.
19.5.1 Properties
A service type can have any number of properties, including zero. Each property is defined by
A property name
720
IT-SC book: Advanced CORBA® Programming with C++
A type code that determines the type of the property's value
The property mode
The name of a property must be a simple identifier (following IDL identifier rules), such as Price. No two properties within the same service type can have the same name. However, because a service type acts as a scope for property names, different service types can use the same property name.
The property's type is described by a type code (recall from Chapter 16 that type codes can be sent across the wire). Because property types are described by type codes, you can have properties of any type, such as string-valued properties, floating-point properties, and so on. You can also create properties of complex user-defined type, such as structures or sequences.
Normally, you have an IDL definition for each property type, but this is not mandatory. Instead of defining property types using IDL, you can use the TypeCode interface to create a type code for a property and use the DynAny interface to create a value for a property at run time. In practice, to keep applications simple, properties almost always have a static type provided by an IDL definition.
You cannot use user-defined types, such as structures, as property values and in queries because the query language supports only simple IDL types. However, user-defined complex property types can still be useful because an importer can request that the value of properties be returned as part of the result. (This shifts the burden of evaluating userdefined properties for matches from the trader to the importer.)
If an exporter supplies a value for a property, the value must match the property's type; otherwise, the trader will reject the export.[1]
[1] See Section 19.7.3 for an exception to this rule.
In addition to having a name and a type, properties have a mode. The mode of a property is one of the following.
Normal
The property is both optional and modifiable. An exporter that creates a new service offer need not include a value for this property. The property can be modified in place while the service offer is stored in the trader.
Read-only
The property is optional and read-only. An exporter that creates a new service offer need not include a value for this property. After the service offer has been created by an exporter, the trader will reject attempts to modify the value of the property; the value of the property is "frozen" at export time.
Mandatory
721
IT-SC book: Advanced CORBA® Programming with C++
When an exporter creates a service offer, the exporter must provide a value for the property. The property can be modified in place while the service offer is stored in the trader.
Mandatory and read-only
The property must be present in every service offer, and the trader will reject attempts to modify the value of the property while it stores the offer.
Armed with this information, we can define a service type for controllers. To define a service type, we decide on a name for the service type, as well as a name, type, and mode for each property and an IDL interface type for the object that acts as the controller. (We ignore type inheritance for the time being.)
Table 19.1. Property definitions for a controller service type.
Property Name |
Property Type |
Property Mode |
Model |
CORBA::_tc_string |
Mandatory, read-only |
Manufacturer |
Manufacturing::_tc_AddressType |
Normal |
Phone |
CORBA::_tc_string |
Mandatory |
Supports |
Airconditioning::_tc_ModelType |
Read-only |
MaxDevices |
CORBA::_tc_ulong |
Normal |
Assume that we have decided to call the service type CCS::Controllers and that the controller interface is provided by objects having the repository ID
IDL:acme.com/CCS/Controller:1.0. Table 19.1 shows the property definitions we might use.
There are many other properties we could have included, depending on exactly how we want to advertise controllers. For your applications, you can probably define whatever properties are most appropriate for the problem at hand. However, as trading technology becomes more widespread, we expect that different industry consortia and standards bodies will define industry-standard service types for commodities advertised in traders.
Note that we use the type code constants generated by the IDL compiler to indicate the property types. Of course, a type repository really stores not only the name of the constant but also the full type code referred to by that name.
The Address property has the type code Manufacturing::_tc_AddressType. Clearly, this is a user-defined type. Here is a possible definition:
module Manufacturing { // ...
struct AddressType { string name; string street_1; string street_2; string city; string state; string postcode; string country;
};
722
IT-SC book: Advanced CORBA® Programming with C++
// ...
};
There are many possible options for defining this structure. The important point is that even though the type is a user-defined complex type, we can still use it as a property type. However, we cannot search for service offers by specifying a city or post code because the query language does not allow us to query service offers by looking "inside" the fields of a complex type.
The Supports property also has a user-defined type—namely, a sequence of strings. A possible IDL definition is
module Airconditioning { |
DeviceModels; |
typedef string |
|
typedef sequence<DeviceModels> |
ModelType; |
// ... |
|
}; |
|
Although the Supports property has a user-defined type, we can use the property in queries. The query language has a special operator to test whether a particular value occurs in a sequence of simple values (see Section 19.10.6).
19.5.2 Service Type Inheritance
The CCS::Controllers service type defined in Section 19.5.1 does not inherit from any other service type. Suppose we want to create service offers for other kinds of controllers—for example, multiprotocol and wireless controllers. We assume that these controllers have the same description as ordinary controllers but also provide additional information about their functionality. We can use inheritance to express this. We make
the multiprotocol and wireless controllers derived services types, as shown in Figure 19.2.
Figure 19.2 Specialization of service types.
The semantics of inheritance are that derived service types guarantee to have all the properties of the base type. A derived service type can also modify the mode of an inherited property. Here are the rules.
723
IT-SC book: Advanced CORBA® Programming with C++
The IDL interface type of the derived service type must be the same as, or be derived from, the IDL interface type of the base service type.
The derived service type inherits all property definitions from its base type. The derived service type cannot change the type of an inherited property.
The derived service type can change the mode of an inherited property. If it does, the mode of the property in the derived service type must be stronger than the mode of the same property in the base service type (see Figure 19.3).
Figure 19.3 Strength of property modes.
The derived type can define properties with names not used by its base service type. These rules make sense. Obviously, a derived service type must support all the properties of its base type, and the inherited properties must have the same type as they have in the base type. Otherwise, importers would get nasty surprises because their queries could become meaningless. Similarly, the IDL interface type (the type of the object reference) in the derived service type must be compatible with that in the base service type. This restriction ensures that if the importer asks for controllers and the trader returns a multiprotocol controller, the importer can safely deal with the multiprotocol controller as if it were an ordinary controller. In addition, the derived service type can change the mode of an inherited property to a stronger mode. Figure 19.3 shows how modes increase in strength.
The strengthening rule ensures that a property in a derived service type cannot change a guarantee established in the base service type. In other words, if a property is mandatory in the base service type, the derived service type cannot make that property optional but can make it read-only.
Table 19.2 shows the properties we could define for a multiprotocol controller. The service type for multiprotocol controllers adds one new property: the list of supported protocols. In addition, it modifies the inherited Supports property by strengthening its mode from read-only to mandatory and read-only. Multiprotocol controllers also inherit all the properties of ordinary controllers, so a multiprotocol controller also has the
Model, Manufacturer, and Phone properties.
Table 19.2. Property definitions for a multiprotocol controller service type.
Property Name |
Property Type |
Property Mode |
724
IT-SC book: Advanced CORBA® Programming with C++
Protocols |
|
RemoteSensing::_tc_Protocols |
Mandatory |
||
Supports |
|
Airconditioning::_tc_ModelType |
Mandatory, read-only |
||
|
|
|
|
||
|
Table 19.3. Property definitions for a wireless controller service type. |
||||
Property Name |
Property Type |
|
Property Mode |
||
Range |
|
|
CORBA::_tc_ulong |
|
Mandatory |
For the wireless controller, we could define an additional property to specify the range of the controller, as shown in Table 19.3. Multiple inheritance of service types is supported. If a service type has more than one base service type, the derived service type combines all the properties of its base types. For example, with the preceding definitions, we could define a wireless multiprotocol controller type as shown in Figure 19.4.
Figure 19.4 Multiple inheritance of service types.
With this definition, a wireless multiprotocol controller has all the properties of its ancestor types: Model, Manufacturer, Phone, Supports, Protocols, and
Range. As with IDL, multiple inheritance must be unambiguous. If two base types define the same property, that property must have the same value type and mode on both base types for multiple inheritance to be legal.
19.5.3 IDL for the Service Type Repository
The IDL for the service type repository is large, so we present it here in several sections.
CosTradingRepos contains a single interface called ServiceTypeRepository. All the definitions for the type repository are part of this interface, so the overall structure of the IDL is as follows.
//File: CosTypeRepos.idl #include <CosTrading.idl> #include <orb.idl> #pragma prefix "omg.org"
725
IT-SC book: Advanced CORBA® Programming with C++
module CosTradingRepos {
interface ServiceTypeRepository {
// Definitions for the type repository here...
};
};
For the remainder of this section, we show the contents of the ServiceTypeRepository interface without explicitly showing the interface itself or its enclosing module.
IDL Types and Exceptions
The ServiceTypeRepository interface defines a number of types and exceptions that are used throughout the remainder of the specification:
typedef CosTrading::Istring Identifier;
enum PropertyMode { PROP_NORMAL, PROP_READONLY,
PROP_MANDATORY, PROP_MANDATORY_READONLY
}; |
|
struct PropStruct { |
name; |
CosTrading::PropertyName |
|
CORBA::TypeCode |
value_type; |
PropertyMode |
mode; |
}; |
|
typedef sequence<PropStruct> PropStructSeq; |
|
exception ServiceTypeExists { CosTrading::ServiceTypeName name;
};
exception InterfaceTypeMismatch {
CosTrading::ServiceTypeName |
base_service; |
Identifier |
base_if; |
CosTrading::ServiceTypeName |
derived_service; |
Identifier |
derived_if; |
}; |
|
exception HasSubTypes { |
|
CosTrading::ServiceTypeName the_type; CosTrading::ServiceTypeName sub_type;
};
exception AlreadyMasked { CosTrading::ServiceTypeName name;
};
exception NotMasked { CosTrading::ServiceTypeName name;
};
exception ValueTypeRedefinition {
CosTrading::ServiceTypeName |
type_1; |
PropStruct |
definition_1; |
CosTrading::ServiceTypeName |
type_2; |
PropStruct |
definition_2; |
};
exception DuplicateServiceTypeName {
726
IT-SC book: Advanced CORBA® Programming with C++
CosTrading::ServiceTypeName name;
};
We explain the use and meaning of these exceptions as we discuss the relevant operations.
Creating a New Service Type
The add_type operation creates a new service type:
struct IncarnationNumber { unsigned long high; unsigned long low;
};
typedef sequence<CosTrading::ServiceTypeName> ServiceTypeNameSeq;
IncarnationNumber add_type( |
name, |
in CosTrading::ServiceTypeName |
|
in Identifier |
if_name, |
in PropStructSeq |
props, |
in ServiceTypeNameSeq |
super_types |
) raises(
CosTrading::IllegalServiceType, ServiceTypeExists, InterfaceTypeMismatch, CosTrading::IllegalPropertyName, CosTrading::DuplicatePropertyName, ValueTypeRedefinition, CosTrading::UnknownServiceType, DuplicateServiceTypeName
);
The name parameter is the name of the new service type. The type name must follow IDL scoped identifier rules. To avoid clashes with names used by other applications, we recommend that you use a scoped name such as CCS::Controllers.
The if_name parameter provides the repository ID of the IDL interface type. It must be a string conforming to the syntax for repository IDs (see Section 4.19), such as "IDL:acme.com/CCS/Controller:1.0".
The props parameter is a sequence of property definitions. Each sequence element is a structure of type PropStruct, which specifies the name, type, and mode of a property. The type of the property is passed as an object reference of type CORBA::TypeCode. Typically, you use the IDL-generated type code constants (see Section 16.6) to specify the type of a property, but you could also create your own type code at run time.
The super_types parameter is a list of service type names of the immediate ancestor types for the new service type. If the new service type does not have base types, this sequence must be empty.
The add_type operation can raise a number of exceptions.
CosTrading::IllegalServiceType
727
IT-SC book: Advanced CORBA® Programming with C++
This exception indicates that the name parameter is malformed and does not conform to the syntax for scoped IDL identifiers.
ServiceTypeExists
This exception indicates that the name for the new type is already in use.
InterfaceTypeMismatch
This exception can be raised only if the new type is a derived type. The exception indicates that the IDL interface type of the new type is incompatible with the IDL interface type of one of its base types.
Many traders do not check this error condition when you create a type. This is because the only way for the type repository to enforce matching interface types is to consult the ORB's IFR at run time. However, not all ORBs have an IFR, or if they do, the IFR may not be populated with the relevant types, so the check may be impossible. Some traders permit you to use a configuration attribute to control whether the check is carried out; consult your vendor's documentation for details.
If your trader cannot enforce this restriction, you must make sure that the IDL interface type of a derived service type is compatible with the IDL interface types of its base service types. If you neglect to do this, importers will get unpleasant surprises because the object references returned by the trader may have the wrong type for the service it purports to offer.
CosTrading::IllegalPropertyName
A property name is malformed and does not conform to the syntax for simple (unqualified) IDL identifiers.
CosTrading::DuplicatePropertyName
The props parameter contains two or more property definitions having the same name.
ValueTypeRedefinition
This exception indicates that the new type defines a property having the same name as that of a property in one of its base types, but the property in the derived type either has a different value type or has a weaker mode than the one in the base type. This exception is also raised if the new type has more than one base type and if the base types define properties having the same name but a conflicting value type or mode.
CosTrading::UnknownServiceType
This exception indicates that at least one of the base types in the super_types parameter does not exist.
DuplicateServiceTypeName
The super_types parameter contains two or more elements having the same name. Note that the add_type operation returns a value of type IncarnationNumber (a structure containing two long values). Like a serial number, an incarnation number acts
728
IT-SC book: Advanced CORBA® Programming with C++
as a marker that assigns a unique identifier to the new type. Another operation, list_types, allows you to supply the incarnation number of a previously created type. If an incarnation number is provided, list_types returns only those types that were created or modified since the creation of that incarnation number. The ServiceTypeRepository interface contains the last-used incarnation number in an attribute:
readonly attribute IncarnationNumber incarnation;
Unfortunately, the incarnation number is not particularly useful. It was intended for use by the trader to permit caching of parts of a type repository. However, the incarnation number does not work for caching. Using the incarnation number, a trader can find out whether new service types have been created or modified, but it cannot detect whether service types have been deleted. As far as application code is concerned, the incarnation number serves no useful purpose, so we recommend that you ignore it. Fortunately, the incarnation number is a fixed-length type, so you can safely ignore the return value without leaking memory.
Removing a Service Type
The remove_type operation removes a service type from the type repository:
void remove_type(
in CosTrading::ServiceTypeName name ) raises(
CosTrading::IllegalServiceType,
CosTrading::UnknownServiceType, HasSubTypes
);
The name parameter indicates the name of the type to be removed. If the name parameter is syntactically malformed, remove_type raises the IllegalServiceType exception. Attempts to remove a non-existent type raise UnknownServiceType.
You can remove a type only if it does not have derived types. If you call remove_type on a type that still acts as a base type for other types, the operation raises the
HasSubTypes exception.
Never remove a type from the type repository unless you are certain that there are no more service offers in the trader that use this type. Recall from Figure 19.1 that each trader knows about its type repository but that the type repository has no idea which traders are using it. If you delete a service type while there are still service offers in the trader that depend on that type, you will destroy the trader's type system.
This type deletion problem is typical of systems that share type definitions among a number of independent parties. It is difficult to safely delete a type unless you can be sure
729
IT-SC book: Advanced CORBA® Programming with C++
that the type is no longer in use. The type repository offers a mask_type operation (see page 849) that allows you to deprecate a type without actually deleting it. Masking of types mitigates the problem somewhat but does not solve it.
The specification could have addressed this issue by requiring the trader to inform the type repository which types are in use so that the type repository could refuse deletion of types that have existing service offers. However, that approach would have created a mutual dependency between the type repository and the trader and would have coupled the two very tightly. Such coupling was seen as undesirable in light of the work on type systems that is currently under way in the OMG. In particular, the OMG Meta-Object Facility (MOF) [25] may in the future provide all the CORBA core and the CORBA services with a unified type system, and a mutual dependency of the type repository and the trader would have blocked use of the MOF for trading. As it is, we must live with this wrinkle in the specification until a future revision.
Listing Types
The list_types operation returns a sequence of type names:
enum ListOption { all, since };
union SpecifiedServiceTypes switch (ListOption) { case since:
IncarnationNumber incarnation;
};
ServiceTypeNameSeq list_types(
in SpecifiedServiceTypes which_types
);
The operation returns a sequence of service type names. The which_types union parameter allows you to supply the incarnation number of a previously created type. If it is supplied, list_types returns only types created or modified since that incarnation number. As pointed out on page 846, the incarnation number is not particularly useful, so we recommend that you always set the discriminator of the which_types parameter to all.
Note that list_types does not have provision to return an iterator object. This means that the operation will fail when the number of type names gets larger than what can be returned in a single return value by your ORB implementation. Again, this is a wrinkle of the specification we must live with. Fortunately, most applications work with quite a small number of service types, so this problem rarely occurs in practice.
Obtaining the Details of a Type
The describe_type operation returns the details of a service type:
struct TypeStruct {
730
IT-SC book: Advanced CORBA® Programming with C++
Identifier if_name; PropStructSeq props; ServiceTypeNameSeq super_types; boolean masked; IncarnationNumber incarnation;
};
TypeStruct describe_type(
in CosTrading::ServiceTypeName name ) raises(
CosTrading::IllegalServiceType,
CosTrading::UnknownServiceType
);
The name parameter indicates the name of the type whose details are to be returned. The return value is a structure of type TypeStruct, which contains the details of the type: its IDL interface type, its property definitions, its list of base types, its incarnation number, and whether or not the type is masked.
If you call describe_type on a derived type, the returned structure does not contain the properties of the base types. Instead, it contains only those properties that were specified when the derived type was created.
To get the full description of a type, including the properties of all the base types, you call fully_describe_type:
TypeStruct fully_describe_type(
in CosTrading::ServiceTypeName name ) raises(
CosTrading::IllegalServiceType,
CosTrading::UnknownServiceType
);
The fully_describe_type operation works like describe_type but returns all the properties for a type, including those inherited from base types. If the derived type has made changes to the modes of inherited properties, fully_describe_type returns the modes as they apply to the derived type. If the type specified by the name parameter does not have base types, fully_describe_type returns the same result as describe_type.
Masking and Unmasking Types
The mask_type operation permits deprecation of a particular type as well as the creation of abstract base types:
void mask_type(
in CosTrading::ServiceTypeName name ) raises(
CosTrading::IllegalServiceType,
731
IT-SC book: Advanced CORBA® Programming with C++
CosTrading::UnknownServiceType, AlreadyMasked
);
The operation expects the name parameter to contain the name of the type to be masked. Masking a type that is already masked raises the AlreadyMasked exception.
After a type is masked, it is no longer possible to create service offers of that type. However, service offers of a type derived from a masked type can still be created. These semantics allow you to create an abstract base type by masking it immediately after creation.
You can also use mask_type to deal with the type deletion problem mentioned on page 847. Instead of deleting a type, you can mask it to make it impossible for exporters to create new service offers of that type. The hope is that eventually, all service offers using that type will be withdrawn, at which time the type can be safely deleted (but there is no easy way of knowing when that time has arrived). In addition, masking a type solves the type deletion problem only partially, because we cannot safely delete a type unless all service offers using derived types are also withdrawn. We could also mask all derived types to get around this problem, but we cannot do this without examining the whole inheritance graph. The type repository interfaces allow you to navigate the inheritance structure only toward the root of the inheritance tree and not toward the leaves.[2]
[2] This is another defect that we hope will be addressed in a future version of the specification.
The inverse of mask_type is provided by the unmask_type operation:
void unmask_type(
in CosTrading::ServiceTypeName name ) raises(
CosTrading::IllegalServiceType,
CosTrading::UnknownServiceType, NotMasked
);
Unmasking a type that is not masked raises the NotMasked exception.
19.5.4 Using the Service Type Repository with C++
Using the type repository from C++ is a simple matter of calling operations on the ServiceTypeRepository interface. However, before you can do this, you need a reference to the service type repository.
Obtaining a Service Type Repository Reference
Calling resolve_initial_references with a service name of "TradingService" returns an IOR to the service type repository. The returned
732
IT-SC book: Advanced CORBA® Programming with C++
reference is of type CosTrading::Lookup (we examine the Lookup interface in detail in Section 19.11). The Lookup interface supports a read-only attribute called type_repos that contains the object reference to the actual type repository. This reference is of type Object and can be narrowed to CosTradingRepos:: ServiceTypeRepository.
Following is a code example that illustrates these steps. Note that instead of calling resolve_initial_references directly, we use the resolve_init helper function we defined on page 819.
//Get reference to Lookup interface. CosTrading::Lookup_var lookup;
lookup = resolve_init<CosTrading::Lookup>(orb, "TradingService");
//Read type_repos attribute to get IOR to type repository. CORBA::Object_var obj = lookup->type_repos();
//Narrow.
CosTradingRepos::ServiceTypeRepository_var repos;
repos = CosTradingRepos::ServiceTypeRepository::_narrow(obj); if (CORBA::is_nil(repos)) {
cerr < "Not a type repository reference" < endl; throw 0;
}
The reason for returning the type repository as type Object is to permit a later version of the specification to change to a type repository generated by the OMG MOF.
Creating Service Types with C++
The following code example creates the four service types for controllers you saw in Sections 19.5.1 and 19.5.2. This is simply a matter of creating the service types in the right order, starting with the base type. Note that we use a using directive to keep identifiers short. If you are in a non-standard C++ environment, you must use fully qualified identifiers instead.
using namespace CosTradingRepos;
// Fill in property definitions for controllers. ServiceTypeRepository::PropStructSeq props; props.length(5);
props[0].name = CORBA::string_dup("Model"); props[0].value_type = CORBA::TypeCode::_duplicate(
CORBA::_tc_string );
props[0].mode = ServiceTypeRepository::PROP_MANDATORY_READONLY;
props[1].name = CORBA::string_dup("Manufacturer"); props[1].value_type = CORBA::TypeCode::_duplicate(
Manufacturing::_tc_AddressType );
733
IT-SC book: Advanced CORBA® Programming with C++
props[1].mode = ServiceTypeRepository::PROP_NORMAL;
props[2].name = CORBA::string_dup("Phone"); props[2].value_type = CORBA::TypeCode::_duplicate(
CORBA::_tc_string );
props[2].mode = ServiceTypeRepository::PROP_MANDATORY;
props[3].name = CORBA::string_dup("Supports"); props[3].value_type = CORBA::TypeCode::_duplicate(
Airconditioning::_tc_ModelType );
props[3].mode = ServiceTypeRepository::PROP_NORMAL;
props[4].name = CORBA::string_dup("MaxDevices"); props[4].value_type = CORBA::TypeCode::_duplicate(
CORBA::_tc_ulong );
props[4].mode = ServiceTypeRepository::PROP_MANDATORY;
//Create Controllers service type. ServiceTypeRepository::ServiceTypeNameSeq base_types; repos->add_type(
"CCS::Controllers",
"IDL:CCS/Controller:1.0",
props, base_types
);
//Fill in property definitions for multiprotocol controllers. props.length(2);
props[0].name = CORBA::string_dup("Protocols"); props[0].value_type = CORBA::TypeCode::_duplicate(
RemoteSensing::_tc_Protocols );
props[0].mode = ServiceTypeRepository::PROP_MANDATORY; props[1].name = CORBA::string_dup("Supports"); props[1].value_type = CORBA::TypeCode::_duplicate(
Airconditioning::_tc_ModelType );
props[1].mode = ServiceTypeRepository::PROP_MANDATORY_READONLY;
//Initialize base type list base_types.length(1);
base_types[0] = CORBA::string_dup("CCS::Controllers");
//Create multiprotocol controller service type. repos->add_type(
"CCS::MPControllers",
"IDL:acme.com/CCS/MPController:1.0",
props, base_types
);
//Fill in property definitions for wireless controllers. props.length(1);
props[0].name = CORBA::string_dup("Range");
734
