Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Advanced CORBA Programming wit C++ - M. Henning, S. Vinoski.pdf
Скачиваний:
65
Добавлен:
24.05.2014
Размер:
5 Mб
Скачать

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