Object-Oriented Programming Using SOM and DSOM/Working with the Interface Repository
The Interface Repository (IR) is a database that stores interface definitions. The SOMobjects Developer Toolkit includes an Interface Repository emitter. It can be invoked through the SOM compiler to create or update the Interface Repository. In addition, a set of classes are defined to provide access to the objects defined in the IR. This set of classes is known as the Interface Repository Framework. You can write programs to find information stored in the IDLs through the programming interfaces in the Interface Repository Framework.
Who Uses the Interface Repository
The Interface Repository is used by the Distributed, Persistence, and Replication Frameworks. All of them use the Interface Repository to find the class definitions and the method signatures. DSOM uses the information in the IR when creating local proxies and interpreting request messages. PSOM uses the IR to determine whether a class or its attributes are persistent. RSOM uses the IR to determine if a class is replicable.
The Interface Repository also assists in the dynamic loading of classes. The default implementation for methods like somFindClass and somLocateClass-File consult the IR for the value of the dllname modifier of the class.
Managing the Interface Repository
The Interface Repository is composed of a list of files that are located by the environment variable. When you install SOM, the install program adds the following statement to your "config.sys" file, assuming that SOM is installed on your C drive:
set SOMIR=C:\SOM\etc\som ir;som.ir
The %SOMBASE%\etc\som.jr file contains objects that describe all the types, classes, and methods provided by the various Frameworks of the SOMobjects Developer Toolkit. Since all new classes will be derived from these predefined SOM classes, this file should always be included in your SOMIR path. The second file, som.ir, refers to the IR file in your current directory.
The Interface Repository emitter uses the environment variable SOMIR to locate the designated IR file. The SOMIR environment variable can consist of a list of files. The IR emitter will only update the last file that is on the list. If the file does not exist, the IR emitter creates it. If the SOMIR variable is not set, the IR emitter creates a file called "som.ir" in your current directory.
When running SOM programs that access the Interface Repository; the files that are listed by the SOMIR environment variable are processed from left to right. The SOM programs are not aware of the division of information across the separate files. The objects in the files appear as if they reside in a single interface repository file.
Therefore, by changing the environment variable SOMIR, you can control the interfaces that are visible to your programs. In a development environment, you might want to have separate IR files so you can separate the stable interfaces from those that are under development. For example, assuming the stable interfaces are in the file "c:\project\common.ir", developers John and Mary are working on separate classes. The SOMIR for John might be:
set SOMIR=%SOMBASE%\etc\som .ir;c:\project\common.ir;john.ir
And the SOMIR for Mary might be:
set SOMIR=%SOMBASE%\etc\som.ir;c:\project\common.ir;mary.ir
Since the Interface Repository emitter only updates the last file on the list, the changes made by John, when updating the JR, will not be reflected in Mary's IR. When either feels that the interfaces they are working on are stable enough, they can move the interfaces to the "common.ir" file so they can be included in other people's IRs.
In a production environment, it is also important to control your SOMIR settings. The path length and the size of each IR file have an impact on the performance for each IR access. The longer the path, or the bigger the file size, the slower the access. This is because the search for each class definition starts from the beginning of the path. The Interface Repository Framework does perform some internal caching to minimize the search. However, if you set the SOMIR variable to the minimum set of files that only contain the class definitions for Your application, the performance of your application will be improved. In particular, if your application requires only a few of the base interfaces supplied with the SOM Toolkit in %SOMBASE%\etc\somir then you can set SOMIR to a local som.jr and add in those extra base interfaces. This can have a big impact on performance.
Building the Interface Repository
The Interface Repository is built by compiling IDL files with the Interface Repository emitter (ir) and the update (-u) option. For example, the following command compiles car.idl into the Interface Repository file that is designated by the SOMIR environment variable.
sc -u -sir cad.idl
If the IR file does not exist, the Interface Repository emitter creates it. Otherwise, the Interface Repository emitter checks all the type information in the IDL source file being compiled for internal consistency and updates the contents of the IR file if necessary.
Note that it is also possible to invoke the Interface Repository emitter by simply using the -u option. In this case, the Interface Repository emitter, plus any other emitters that are indicated by the run. By default, SMEMIT environment variable, will be SMEMIT is set to run the emitters that emit C binding files and .ih). For example, the following command compiles the file (.h Interface Repository and generates the files car.idl into the car.h and car.ih.
sc -u car.idl
If the IDL source file contains private information that is defined using the __PRIVATE__ preprocessor macro, the SOM compiler will not compile the private information into the Interface Repository unless the -p option is also used. For example the following command will place both the public and the private car.idl into the Interface Repository.
sc -up -sir car.idl
Accessing the Interface Repository
The Interface Repository Framework allows you to retrieve information from the Interface Repository. The information in the Interface Repository is maintained as a set of objects. The class names for these objects are listed below:
- Repository: there is only one instance of this class for the entire Interface Repository. It contains modules, interfaces, constants, typedefs, and exceptions.
- ModuleDef: an instance of this class exists for each module defined in an IDL file. It contains constants, typedefs, exceptions, interface definitions and other modules.
- InterfaceDef: an instance of this class exists for each interface defined in an IDL file. It contains constants, types, exceptions, operations, and attributes.
- AttributeDef: an instance of this class exists for each attribute defined in an IDL file.
- OperationDef: an instance of this class exists for each method defined in an IDL file. It contains lists of parameters and exceptions raised by this method.
- ParameterDef: an instance of this class exists for each parameter of each method defined in an IDL file.
- TypeDef: an instance of this class exists for each typedef, struct, enum, or union defined in an IDL file.
- ConstantDef: an instance of this class exists for each constant defined in an IDL file.
- ExceptionDef: an instance of this class exists for each exception defined in an IDL file.
These objects are accessible from a program. They can be useful when an application needs to find information about an object it encounters at run-time. A common set of operations are defined for locating objects within the Interface Repository. These operations are defined using two generic interfaces, Container and Contained.
The Container Class
The Container class provides three methods for navigating through a container to locate other objects.
Understanding Container and Contained
The Container interface provides methods for locating objects that a particular container contains. Repository, ModuleDef, InterfaceDef, and OperationDef are all containers. They are derived from the Container interface and they can contain, or hold, other objects. For example, an OperationDef can contain ParameterDefs.
The Contained interface provides methods for accessing information in the specified contained object. AttributeDef, ConstantDef, TypeDef, ParameterDef, and ExceptionDef are all contained objects and are derived from the Contained interface. Each of them provides access to the corresponding definition in the Interface Repository. For example, an AttributeDef object returns information on an attribute definition in an IDL.
ModuleDef, InterfaceDef, and OperationDef are also contained objects. That is, they are derived from both the Container and Contained classes. This is because they are all contained by the Repository class.
1. contents - this method returns a list of objects contained by the specified Container object. It can be used to navigate the hierarchy of objects within the Interface Repository. For example, you can invoke this method on the Repository Container object. Then, for each object that is returned, if it is a Container object, invoke the contents method on it. This process can be repeated until you have iterated through each object in each container. The C syntax for contents follows:
sequence<Contained> _contents(container, // pointer to Container object env, // pointer to Environment structure limitType, // what type of objects excludeInherited); //flag to include/exclude inherited obj
The parameter container is a pointer to a Container object whose contained objects are to be returned. The parameter limit'I'ype specifies what type of objects this method should return. It can be set to one of the following values: "AttributeDef", "ConstantDef", "ExceptionDef", "InterfaceDef", "ModuleDef", "ParameterDef", "OperationDef", "TypeDef" or "all". If it is set to "all"' then objects of all interface types will be returned. Otherwise, only objects of the requested types are returned.
The parameter excludeInherited is a boolean. If it is set to TRUE, then any inherited objects will not be returned.
2. describe_contents - this method combines the operations of the contents method and the describe method described below.
3. lookup_name - this method locates an object by name within a specified Container object.
Objects that are containers inherit these navigation methods from the Container class. We will use the contents method to navigate through the Repository and the InterfaceDef objects in our Browser example in Section 8.6 on page 222.
The Contained Class
The Contained class provides the generic interface for all objects in the Interface Repository, since all objects in the Interface Repository, except the root Repository object, can be contained by some other objects. It provides the following methods:
- within - this method returns a sequence of Container objects within the Interface Repository that contain the specified Contained object.
- describe - this method returns a structure containing IDL information of the specified Contained object. The C syntax for describe follows:
Description _describe( contained, // pointer to Container object env); // pointer to Environment structure
The structure of Description follows:
struct Description { Identifier name; any }; value;
The information that is returned in the Description structure depends on the type of the contained object. For example, if the contained object is an AttributeDef, the name field of the returned Description will contain the identifier "AttributeDescription" and the value._value field will contain a pointer to an AttributeDescription structure.
Every contained object has its own Description structure. For example, ConstantDef has a ConstantDescription structure, InterfaceDef has an InterfaceDescription structure. The structure of a ConstantDescription follows:
struct ConstantDescription { Identifier name; // non-unique name that identifies object within its containment Repository Id id; // unique Id that identifies object in IA Repository Id defined_in; // unique Id that identifies container for this ConstantDef object TypeCode type; // the type of this constant any value; // the value of this constant };
The Repository Class
The Repository class provides global access to the Interface Repository. You can obtain an instance of the Repository class by using the Repository New() macro in C, or by using the new operator in C++. Once you have a pointer to the Repository object, you can use methods like contents or lookup_name that it inherits from the Container class to look up any objects in the Interface Repository. The Repository class also introduces its own lookup_id and lookup_modifier methods for returning an object with a specified Repository ID.
All objects in the Interface Repository have both a name and a Repository ID. A name is not necessarily unique within an Interface Repository. However, it is unique within the context of the object that contains it. A Repository ID is guaranteed to be unique within an Interface Repository.
TypeCode
Much of the information contained in the Interface Repository is represented in the form of TypeCodes. A TypeCode is an architected way of describing everything known about a particular data type in the IDL, regardless of whether it is a built-in type, or a user-defined type.
Every TypeCode contains a kind field, which describes what it is, and a parameter list, which carries descriptive information for that particular kind of TypeCode. For example, the IDL type long has TypeCode tk_long and no parameters. The IDL type sequence<char,10> has TypeCode tk_sequence and two parameters, 10 and char. Table 8.1 lists the combinations of kind and parameter list as well as the type of the parameters and their functions.
As you can see, TypeCodes can be nested, so they can describe any kind of data. In the cases of struct, union and enum, they can have repeated members as indicated by the number "N" in the Parameters column.
A number of functions are provided to obtain information about a TypeCode. Some of them are listed below.
- TypeCode_kind-this function returns the kind of the specified TypeCode.
- TypeCode_param_count-this function returns the number of parameters in a given TypeCode.
- TypeCode_parameter-this function returns a specified parameter from a given TypeCode.
A Simple IR Browser
The BROWSER program source code is presented in this section. Browser traverses the Interface Repository and prints out information on every interface definition. The main line creates an instance of the Repository class and invokes the contents method with the "all" option to retrieve all the objects in the Interface Repository. If an object is an InterfaceDef, then the displaylnterfaceDef function is called to display the information on the interface definition. Note that another way is to invoke the contents method with the "InterfaceDef" option, but we want to show you how you can find out the type of the returned object by invoking the describe method.
Recall that anlnterfaceDef can contain ConstantDefs, TypeDefs, ExceptionDefs, AttributeDefs, and OperationDefs. The displaylnterfaceDef function prints out information on the constants, types, attributes, and methods contained in an interface definition. Although exceptions are not included, they can be added easily as an exercise.
The browse.cpp file is listed in Figure 8.1.
#include <repostry.xh> #include <containd.xh> #include <stdio.h> #include <intfacdf.xh> // InterfaceDef include #include <attribdf.xh> // AttributeDef include #include <constdef.xh> // ConstantDef include #include <typedef.xh> // TypeDef include #include <string.h> Environment *ev; //**************************************** // Prototypes //**************************************** displayInterfaceDef(InterfaceDef *); displayTypeDef(TypeDef *); displayConstantDef(ConstantDef *); displayTypeCode(TypeCode); printType(TypeCode); //****************************************************** // Simple Interface Repository Browser //****************************************************** main(int argc, char *argv[], char *envp[]) { Repository *repo; _IDL_SEQUENCE_Contained allObj; short i ; ev = SOM_CreateLocalEnvironment(); repo = new Repository(); allObj = repo->contents(ev, "all", TRUE); for (i=0; i < sequenceLength(allObj); i++ ) { Contained *contained; Description desc; contained = sequenceElement(allObj,i); desc = contained->describe(ev); if (strcmp(desc.name, "InterfaceDescription") == 0) { displayInterfaceDef( (InterfaceDef *) contained); } } } displayInterfaceDef(InterfaceDef *intdef) { short i, j; FullInterfaceDescription fid; TypeCode tc; Description desc; InterfaceDescription *id; _IDL_SEQUENCE_Contained allObj; desc = intdef->describe(ev); id = (InterfaceDescription *) desc.value._value; printf("Interface Name: %s\n", id->name); //****************************************************** // An Interface Defn can contain ConstantDef, TypeDef, // ExceptionDef, AttributeDef and OperationDef. // In the following, we displayed TypeDef and ConstantDef //****************************************************** allObj = intdef->contents(ev, "all", TRUE); for (i=0; i < sequenceLength(allObj); i++ ) { Contained *contained; Description desc; contained = sequenceElement(allObj,i); desc = contained->describe(ev); if (strcmp(desc.name, "ConstantDescription") == 0) { displayConstantDef( (ConstantDef *) contained); } if (strcmp(desc.name, "TypeDescription") == 0) { displayTypeDef( (TypeDef *) contained); } } // Get a description of all the methods and attributes in the IR fid = intdef->describe_interface(ev); //*********************************************************** // Display all the attributes in this Interface Defn //*********************************************************** _IDL_SEQUENCE_AttributeDescription attrd; attrd = fid.attributes; printf("List of attributes\n"); for (i=0; i< sequenceLength(attrd); i++) { printf("<Attribute Name:> %s", sequenceElement(attrd,i).name); printf(" <Type:> "); printType(sequenceElement(attrd,i).type); if (sequenceElement(attrd,i).mode == AttributeDef_READONLY) { printf(" (readonly)"); } printf("\n"); } //************************************************************* // Display all the methods in this Interface Defn //************************************************************* _IDL_SEQUENCE_OperationDescription opd; opd = fid.operation; printf("\nList of methods\n"); for (i=0; i < sequenceLength(opd); i++) { printf("<Method Name:> %s <Return Type:> ", sequenceElement(opd,i).name); printType(sequenceElement(opd,i).result); printf("\n"); //************************************************** // Display all parameters //************************************************** _IDL_SEQUENCE_ParameterDescription parmd; parmd = sequenceElement(opd,i).parameter; for (j=0; j < sequenceLength(parmd); j++ ) { switch (sequenceElement(parmd,j).mode) { case ParameterDef_IN: printf(" in "); break; case ParameterDef_OUT: printf(" out "); break; default: printf(" inout "); } printf("%s ", sequenceElement(parmd,j).name); printType(sequenceElement(parmd,j).type); printf("\n"); } } printf("\n*************************************************\n"); } displayTypeDef(TypeDef *typdef) { Description desc; TypeDescription *td; desc = typdef->describe(ev); td = (TypeDescription *) desc.value._value; printf("Typedef %s defined in %s\n", td->name, td->defined_in); displayTypeCode(td->type); printf("\n"); } displayConstantDef(ConstantDef *condef) { Description desc; ConstantDescription *cd; desc = condef->describe(ev); cd = (ConstantDescription *) desc.value._value; printf("Constant %s defined in %s\n", cd->name, cd->defined_in); printf("<Type:> "); switch (TypeCode_kind(cd->value._type, ev)) { case tk_string: printf("string <Value:> %s\n", *((string *) cd->value._value)); break; case tk_long: printf("long <Value:> %ld\n", *((long *) cd->value._value)); break; case tk_float: printf("float <Value:> %f\n", *((float *) cd->value._value)); break; case tk_ushort: printf("unsigned short <Value:> %d\n", *((unsigned short *) cd->value._value)); break; case tk_ulong: printf("unsigned long <Value:> %d\n", *((unsigned long *) cd->value._value)); break; } printf("\n"); } printType(TypeCode tc) { switch (TypeCode_kind(tc, ev)) { case tk_null: printf("null "); break; case tk_void: printf("void "); break; case tk_short: printf("short "); break; case tk_long: printf("long "); break; case tk_ushort: printf("unsigned short "); break; case tk_ulong: printf("unsigned long "); break; case tk_float: printf("float "); break; case tk_double: printf("double "); break; case tk_boolean: printf("boolean "); break; case tk_char: printf("char "); break; case tk_octet: printf("octet "); break; case tk_any: printf("any "); break; case tk_TypeCode: printf("TypeCode "); break; case tk_Principal: printf("Principal "); break; case tk_objref: printf("Object Reference "); break; case tk_struct: printf("struct "); break; case tk_union: printf("union "); break; case tk_enum: printf("enum "); break; case tk_string: printf("string "); break; case tk_sequence: printf("sequence "); break; case tk_array: printf("array "); break; case tk_pointer: printf("pointer "); break; case tk_self: printf("Self "); break; case tk_foreign: printf("foreign "); break; default: printf("not valid data type\n"); break; } } //********************************************************* // Navigate TypeCode to display complex data types //********************************************************* displayTypeCode(TypeCode tc) { TypeCode membertc, seqtc; short i; any parm; long len; string memname; switch (TypeCode_kind(tc, ev)) { case tk_short: printf("short\n"); break; case tk_long: printf("long\n"); break; case tk_ushort: printf("unsigned short\n"); break; case tk_ulong: printf("unsigned long\n"); break; case tk_float: printf("float\n"); break; case tk_double: printf("double\n"); break; case tk_boolean: printf("boolean\n"); break; case tk_char: printf("char\n"); break; case tk_octet: printf("octet\n"); break; case tk_any: printf("any\n"); break; case tk_objref: parm = TypeCode_parameter(tc, ev, 0); printf("%s\n", *((string *)parm._value)); break; case tk_struct: parm = TypeCode_parameter(tc, ev, 0); printf("<Structure:> %s\n", *((string *)parm._value)); //************************************************** // Get the name and type for each struct member //************************************************** for (i=1; i < TypeCode_param_count(tc,ev); i+=2 ) { parm = TypeCode_parameter(tc,ev,i); printf(" <Member Name:> %s", *((string *)parm._value)); parm = TypeCode_parameter(tc,ev,i+1); printf(" <Member Type:> "); //*********************************************** // Recursively call displayType to display the // type of each member //*********************************************** displayTypeCode( *( (TypeCode *)parm._value ) ); } printf("\n"); break; case tk_union: parm = TypeCode_parameter(tc, ev, 0); printf("<Union:> %s\n", *((string *)parm._value)); //************************************************ // Get the union switch type //************************************************ parm = TypeCode_parameter(tc, ev, 1); printf("<Discriminator Type:> "); printType( *((TypeCode *)parm._value) ); for (i=2; i < TypeCode_param_count(tc,ev); i+=3) { // Get label value parm = TypeCode_parameter(tc,ev,i); printf("\n <Label:> %ld ", *((long *)parm._value) ); // Get member name parm = TypeCode_parameter(tc,ev,i+1); memname = *((string *)parm._value); // Get member type parm = TypeCode_parameter(tc,ev,i+2); printf("<Member Type:> "); printType( *((TypeCode *)parm._value) ); printf(" <Member Name:> %s", memname); } printf("\n\n"); break; case tk_enum: parm = TypeCode_parameter(tc, ev, 0); printf("<Enum:> %s\n", *((string *)parm._value)); //************************************************** // Get the name for all enumerators //************************************************** for (i=1; i < TypeCode_param_count(tc,ev); i++ ) { parm = TypeCode_parameter(tc,ev,i); printf(" <enumerator:> %s\n", *((string *)parm._value)); } printf("\n"); break; case tk_string: parm = TypeCode_parameter(tc, ev, 0); len = *((long *)parm._value); if (len != 0) { printf("string, maximum length: %ld\n", len); } else { printf("string\n"); } break; case tk_sequence: printf("sequence\n"); //************************************************* // First parm contains the sequence type //************************************************* parm = TypeCode_parameter(tc, ev, 0); printf("<Sequence Type:> "); printType( *((TypeCode *)parm._value) ); //************************************************* // Second parm contains the sequence maximum len //************************************************* parm = TypeCode_parameter(tc,ev,1); len = *((long *)parm._value); if (len != 0) { printf(" <Maximum Length:> %ld\n", len); } printf("\n"); break; case tk_array: printf("array\n"); //*********************************************** // First parm contains the array type //*********************************************** parm = TypeCode_parameter(tc, ev, 0); printf("<Array Type:> "); printType( *((TypeCode *)parm._value) ); //*********************************************** // Second parm contains array size //*********************************************** parm = TypeCode_parameter(tc, ev, 1); printf("<Size:> %ld\n", *((long *)parm._value)); break; default: printf("not supported ..."); break; } }
Figure 8.1 The BROWSER program
Table 8.1 TypeCode functions and parameters
TypeCode kind | Parameters | Type | Function |
---|---|---|---|
tk_null | 0 | - | - |
tk_void | 0 | - | - |
tk_short | 0 | - | - |
tk_long | 0 | - | - |
tk_ushort | 0 | - | - |
tk_ulong | 0 | - | - |
tk_float | 0 | - | - |
tk_double | 0 | - | - |
tk_boolean | 0 | - | - |
tk_char | 0 | - | - |
tk_octet | 0 | - | - |
tk_any | 0 | - | - |
tk_TypeCode | 0 | - | - |
tk_Principal | 0 | - | - |
tk_objref | 1 | string | The ID of the corresponding lnterfaceDef in the Interface Repository |
tk_struct | 2N + 1 | string string TypeCode |
The name of the struct - repeat for each member The name of the struct member The type of the struct member |
tk_union | 3N + 2 | string TypeCode long string TypeCode |
The name of union The type of the discriminator -- repeat for each member The name of the label The name of the member The type of the member |
tk_enum | N + 1 | string string |
The name of the enum - repeat for each enumerator The name of the enumerator |
tk_string | 1 | long | The maximum string length or 0. |
tk_sequence | 2 | TypeCode long |
Element type in sequence The maximum number of elements or 0. |
tk_array | 2 | TypeCode long |
Element type in array The maximum number of elements |
tk_pointer | 1 | TypeCode | The type of the referenced datum |
tk_self | 1 | string | The name of the referenced enclosing struct or union |
tk_foreign | 3 | string string long |
The name of the foreign type The implementation context The size of an instance |
Constant Definition
The displayConstantDef function in the BROWSER program prints out the name, type, and value of a constant, as well as where it is defined. The following code excerpt illustrates how the type and the value of a constant is extracted from the value field in the ConstantDescription structure.
switch (TypeCode_kind(cd->value._type, ev)) { case tk_string : printf("string <Value> %s\n'', *((string*) cd->value._value)); break; case tk_long: printf( "long <Value:> %1d\n", *((long*) cd->value._value)); break; ... }
The value field is of type any. Recall that the type any is made up of two fields, a _type field and a_ value field. The _type field is a TypeCode that describes the data in the _value field. Therefore, we use the TypeCode_kind function to determine what the data type is, and extract the corresponding value by using the appropriate cast.
We did not code all of the possible valid types for a constant definition. We leave this as an easy exercise for the reader.
Type Definition
The displayTypeDef function in the BROWSER program prints out the name of the type and where it is defined and then calls displayTypeCode with the type field from the TypeDescription structure. The type field is a TypeCode that represents the type of the typedef.
The function displayTypeCode demonstrates how you can navigate a TypeCode to find out arbitrary complex type information. The following code is used to handle the type struct:
case tk_struct: parm = TypeCode_parameter(tc, ev, O); printf(''<Structure> %s\n", *((string *)parm._value)); //*************************************************************** // Get the name and type for each struct member //*************************************************************** for (i=1; i < TypeCode_param_count(tc,ev); i+=2) { parm = TypeCode_parameter(tc,ev,i); printf(" <Member Name> %s", *((string *)parm._value)); parm = TypeCode_parameter(tc,ev,i+ 1 ); printf{" <Member Type> "); //******************************************************************************* // Recursively call displayType to display the type of each member //******************************************************************************* displayTypeCode( *( (TypeCode *)parm._value) ); printf(''\n"); break;
Recall that a tk_struct has 2N + 1 parameters, where the first parameter is the name of the struct, and the next two parameters are repeated for the name and the type of a struct member. We use the function TypeCode_param_count to obtain the number of parameters, and TypeCode_parameter to obtain the parameters from the TypeCode. Since the type of the struct member is also a TypeCode, we call displayTypeCode recursively so that we can display the type of the struct member.
Attribute and Method Definition
The lnterfaceDef class introduces a new method, describe_interface, that returns a description of all the methods and attributes of an interface definition. The displaylnterfaceDeffunction in the BROWSER program invokes it.
fid = intdef->describe_interface(ev) ;
The returned structure is a FulllnterfaceDescription.
struct FulllnterfaceDescription { Identifier name; Repositoryld id; Repositoryld defined_in; sequence<Operation Def: :Operation Description> operation; sequence<AttributeDef: :AttributeDescription> attributes; } ;
The displaylnterfaceDeffunction iterates through the attribute sequence to print out the name and type of each attribute. If an attribute is readonly, it will be indicated.
Similarly, the operation sequence is looped through to print out the name, return type, and parameters for each method.
Running the Program
Make sure the environment variable SOMIR is set. The BROWSE program will return all the interface definitions that are in the interface repository list. You might want to set SOMIR to a smaller subset of IRs if you do not want to see the information from the pre-defined SOM classes.
You can use the test.idl file shown in Figure 8.2 as a test case. It contains various type, attribute, and method definitions.
#include <somobj.idl> interface Test: SOMObject { enum Fruit { apple, orange, strawberry }; struct Dummy { short x, y; SOMObject obj; string name; Fruit afruit; sequence<Fruit, 50> flist; long counts[10]; }; union Foo switch (long) { case 1: long x; case 2: float y; default: char z; }; const unsigned long MAXSIZE = 50; attribute Foo myfoo; attribute double mydouble; readonly attribute any anyvalue; attribute sequence<long,MAXSIZE> longList; void add(in string name); string query(in short index, inout octet aByte); long print(out boolean status); #ifdef __SOMIDL__ implementation { releaseorder : _get_myfoo, _set_myfoo, _get_mydouble, _set_mydouble, _get_anyvalue, _set_anyvalue, _get_longList, _set_longList, add, query, print; }; #endif };
Figure 8.2 An IDL to illustrate the BROWSER program
Figure 8.3 shows the output list for the Test interface. Observe the output for the struct Dummy. The types that are within Dummy are printed out because of the recursion.
Interface Name: Test Typedef Fruit defined in ::Test <Enum:> Fruit <enumerator:> apple <enumerator:> orange <enumerator:> strawberry Typedef Dummy defined in ::Test <Structure:> Dummy <Member Name:> x <Member Type:> short <Member Name:> y <Member Type:> short <Member Name:> obj <Member Type:> ::SOMObject <Member Name:> name <Member Type:> string <Member Name:> afruit <Member Type:> <Enum:> Fruit <enumerator:> apple <enumerator:> orange <enumerator:> strawberry <Member Name:> flist <Member Type:> sequence <Sequence Type:> enum <Maximum Length:> 50 <Member Name:> counts <Member Type:> array <Array Type:> long <Size:> 10 Typedef Foo defined in ::Test <Union:> Foo <Discriminator Type:> long <Label:> 1 <Member Type:> long <Member Name:> x <Label:> 2 <Member Type:> float <Member Name:> y <Label:> 0 <Member Type:> char <Member Name:> z Constant MAXSIZE defined in ::Test <Type:> string <Value:> 50 List of attributes <Attribute Name:> myfoo <Type:> union <Attribute Name:> mydouble <Type:> double <Attribute Name:> anyvalue <Type:> any (readonly) <Attribute Name:> longList <Type:> sequence List of methods <Method Name:> add <Return Type:> void in name string <Method Name:> query <Return Type:> string in index short inout aByte octet <Method Name:> print <Return Type:> long out status boolean
Figure 8.3 Output from the BROWSER program