In this chapter, the integration of SDL applications with CORBA is described. Initially, a general overview of the solution is provided, and is followed by a more elaborate description of the different aspects involved. A set of rules is given for how IDL is mapped to SDL, both to increase the understanding of how the integration is supposed to work, and to facilitate the manual operations that are sometimes necessary.
This chapter also outlines how an application should be created that is accessible from clients through CORBA, and which can also address other CORBA servers.
In the end of this chapter, a few technical issues are discussed, such as how the Master Library (see The Master Library) is affected. The CORBA Tutorial, further describes in some detail how a CORBA application can be created.
This chapter is about how CORBA (The Common Object Request Broker: Architecture and Specification) is integrated with applications generated by SDT.
To begin with, some different approaches to perform such an integration are described in Integrating CORBA with SDL.
After that, the mapping rules that should be used when transforming IDL (Interface Definition Language) to SDL are described in Mapping IDL to SDL. IDL is an abstract language that is used to describe the interfaces of objects; these objects are then represented in SDL, which is where the behavior of the objects is implemented. In particular, this section also describes a special package, containing SDL versions of CORBA types, that must be used by all SDL systems that are turned into CORBA applications.
In the following section, Creating an Object Implementation, it is described how an SDL application is actually created, and this is immediately followed by a section on how other servers can be addressed through CORBA from the SDL application (in Using Other CORBA Objects).
After that, some technical sections follow, such as The IDL Compiler, where it is shown how an IDL compiler can be used to automatically create a stub utilizing the IDL to SDL mapping rules. Only types can be generated, which means that the behavior of the types must be implemented before it is possible to generate an application.
In The Environment it is then showed how the SDL application is encapsulated by wrappers on both the client side and the server side, and how the environment functions are used to mediate messages between the SDL system and the wrappers.
The Master Library describes the additions that have been made to the Master Library. This includes an account of the new libraries that are created and that must used when creating a CORBA application, but also of the functions and types that have been added to facilitate communication with the C++ wrapper.
The platform and tool requirements for the CORBA integration is as follows:
Platform | ORB |
---|---|
Sun Solaris 2.5 |
Orbix 2.1mt, with SPARCompiler C++ 4.x |
When integrating CORBA with SDL there are basically two ways to go about this:
These approaches might appear very similar at first, but the methodologies used are different as will be seen in the subsequent sections. In SDT, only the first approach is currently supported.
The CORBA-oriented approach is primarily used when SDL is viewed as a design (implementation) language, and a given IDL description should be designed using SDL, as is depicted in Figure 505.
Figure 505 : The CORBA-oriented approach
|
The basic activities when building a system using the CORBA-oriented approach are:
A system created using the CORBA-oriented approach is intended as a part of a larger distributed system, the components of which might be defined using other languages than SDL, as is exemplified in Figure 506. Each of the different SDL applications contains one or more SDL processes.
Figure 506 : An example of a distributed system using CORBA
|
The concepts introduced here are further elaborated in section Creating an Object Implementation.
Note: The SDL-oriented approach is not supported in SDT; a brief overview is included here mainly to give an understanding of what is supported and what is not. |
The SDL-oriented approach is primarily used when SDL is viewed as a specification language. Once the specification of the entire distributed application has been performed in SDL, it should be partitioned into arbitrarily small subsystems that are then (optionally) implemented on different machines and which communicate with each other using CORBA as underlying messaging mechanism. The smallest unit of partitioning is an SDL process.
Figure 507 : The CORBA-oriented approach
|
The process of creating a system using the SDL-oriented approach is seemingly simple:
In the SDL-oriented approach, the SDL system contains the entire distributed system, where SDL processes communicate with each other through CORBA. Compare this approach with the targeting of SDL applications on a real-time OS, as is described in a separate manual.
Figure 508 : An SDL system targeted on CORBA
|
An important part of the CORBA-oriented approach is to transform an IDL description into an SDL stub. In order to do this the same way every time it is necessary to have mapping rules describing how this transformation should be performed.
IDL is a language used for describing interfaces abstractly, and its definition can be found in The Common Object Request Broker: Architecture and Specification (CORBA) standard that is issued by OMG.
The IDL description cannot be used by itself, but is always mapped to a target language. CORBA specifies mapping rules from IDL to several target languages, such as C++ and Smalltalk. When using SDT, this target language is SDL, and the mapping rules are presented in this section.
Note: The mapping rules given here are not standardized, and may be subject to change in future releases. |
The textual Phrase Representation of SDL (SDL/PR) is used to describe SDL concepts throughout this section.
The package concept of SDL is utilized to describe the mapping from IDL to SDL, and the end result depends on whether the IDL description is used to define an SDL implementation or to access other servers in the CORBA environment. In the first case, the SDL system implements the IDL description, while in the second case it makes use of an IDL description that is implemented elsewhere using some arbitrary target language.
The two packages that are used in SDL are an interface package and a definition package.
An IDL description consists of one or more text files using the extension.idl
, and one of these is always considered the main file from which the other files are included in the same manner as C++ header files are included. In this chapter, when an IDL file is mentioned, it is always as the main file of an IDL description.
The interface package contains interface specifications in the form of for example data types, signals, remote procedures, synonyms, and signal lists. This package is always generated from an IDL description, and represents information that is externally visible. The interface package is named after the IDL file that was used, and the suffix _interface
is always appended to the name. This resembles the way a C++ header file is used in the IDL C++ mapping.
The definition package contains structure information that is inherent in the IDL description in the form of modules and interfaces, and it also contains a system type which can be instantiated when behavior has been added. The definition package is only generated from an IDL description if a new server should be created in SDL. The definition package is also named after the IDL file that was used, and the suffix _definition
is always appended to the name. The system that is defined in this package is also named after the IDL file, but with the suffix _system
appended instead. The definition package always uses the interface package. This resembles the way a C++ source file is used in the IDL C++ mapping.
Finally, the system type is instantiated using the name of the IDL file.
Consider the example IDL file name.idl
. When implementing a server based on this description, the corresponding (transformed) SDL system would look like:
Note that the definition package must make use of the interface package to be valid. Furthermore, the predefined package idltypes
must always be used. This package contains SDL types that represent the basic IDL types.
If the IDL description represents a server that has already been implemented somewhere else, and will only be used to access that server from the SDL system being implemented, the same IDL file (name.idl
) is mapped like:
IDL | SDL |
---|---|
name.idl |
use idltypes; package name_interface; /* interface definition */ endpackage; |
Note that only the interface package is generated in this case.
In the mapping rules given below it will be indicated whether a definition should be part of the interface or the behavior package.
When an identifier is mapped from IDL to SDL, there is a problem with names being able to clash with other names.
For example, consider an interface in which a new type is defined. This type cannot be defined inside the corresponding SDL entity because then it would not be visible at the system level where signals and remote procedures might want to use it for its parameters. For this reason, the type must be defined at (i.e., moved to) the system level. Since all definitions must be made at the system level, there is a possibility that multiple definitions using the same name are made (e.g., if two interfaces contain different type definitions using the same name).
In order to avoid this problem, global names are enforced in all mappings from IDL to SDL, i.e., each occurrence of "::" in the global name is replaced with an `_' (underscore), and then the leading underscore is removed. This is the general way of handling global names that is specified in CORBA.
A module is mapped to a block type, where nested modules become nested block types.
IDL | SDL |
---|---|
module M { }; module N1 { module N2 { }; }; |
/* definition package */ block type M; endblock type; block type N1; block type N1_N2; endblock type; endblock type; |
An interface is mapped to a process type. If the interface is defined within a module, the process type is defined within the corresponding block type.
IDL | SDL |
---|---|
interface I { }; module M { interface I { }; }; |
/* definition package */ process type I; endprocess type; block type M; process type M_I; endprocess type; endblock type; |
An object reference, i.e., a reference to an object implementing an interface, is mapped to the type PId.
Note: |
An operation is mapped differently to SDL depending on whether it is asynchronous or synchronous, i.e., whether it is defined using the IDL keyword oneway
or not.
In order to prevent problems with name clashing, operation names starting with "get_" or "set_" should generally be avoided (see Attributes for more information on this subject). |
Each asynchronous operation (which in IDL is defined using the keyword oneway
) is mapped to a pair of one signal and one procedure, while a synchronous operation is mapped to a remote procedure.
// IDL
interface I {
oneway void async();
void sync();
};
/* SDL interface package */ signal I_async; remote procedure I_sync; /* SDL definition package */ process type I; virtual procedure I_async; endprocedure; virtual exported procedure I_sync; endprocedure; endprocess type;
A remote procedure can be called from the environment, or the SDL system can call a remote procedure defined in the environment (this is standardized in SDL-96).
It is required that the paths leading to or from the environment (signalroutes and channels) contain the remote procedures that can be called (possibly with the keyword procedure to distinguish them from signals).
An IDL operation can carry three kinds of parameters: in-, inout-, and out-parameters, whereas only two kinds are available in SDL: in- and in/out-parameters. The mappings between these parameter kinds are straightforward:
IDL | SDL |
---|---|
in inout out |
in in/out in/out |
An operation return type is mapped to a corresponding remote procedure return.
// IDL
interface I {
oneway void async (in long p1, in octet p2);
string sync (in short p1, inout char p2, out
unsigned long p3);
};
/* SDL interface package */
signal I_async(CORBA_long, CORBA_octet);
remote procedure I_sync;
fpar
in CORBA_short,
in/out CORBA_char,
in/out CORBA_unsigned_long;
returns CORBA_string;
/* SDL definition package */
process type I;
virtual procedure type I_async;
fpar
in p1 CORBA_long,
in p2 CORBA_octet;
endprocedure;
virtual exported procedure I_sync;
fpar
in p1 CORBA_short,
in/out p2 CORBA_char,
in/out p3 CORBA_unsigned_long;
returns CORBA_string;
endprocedure;
endprocess type;
The mapping rules of the types that appear in the above example can be found in Types.
Note: Raises expressions are not supported. |
Note: Context expressions are not supported. |
An attribute is mapped to a variable declaration and a pair of remote procedures to set and get the value of the variable. The accessor functions are named by appending the attribute with a prefix: get_
or set_
.
If the attribute is defined as readonly, the remote procedure to set the variable is omitted.
The behavior of the remote procedures is well defined for attributes, and can therefore be included in the mapping rules. For set-operations, the attribute value should be assigned a new value, while for get-operations, the attribute value should only be returned.
// IDL
interface I {
attribute double a1;
readonly attribute string a2;
};
/* SDL interface package */ remote procedure I_get_a1; returns CORBA_double; remote procedure I_set_a1; fpar in CORBA_double; remote procedure I_get_a2; returns CORBA_string; /* SDL definition package */ process type I; dcl double a1; exported procedure I_get_a1; returns CORBA_double; start; return a1; endprocedure; exported procedure I_set_a1; fpar in a1_new CORBA_double; start; task a1 := a1_new; return; endprocedure; dcl a2 CORBA_string; exported procedure I_get_a2; returns CORBA_string; start; return a2; endprocedure; endprocess type;
IDL inheritance cannot be mapped to SDL inheritance; instead, inheritance must be represented using a flat structure, where all procedures corresponding to operations and attributes defined in a base process type must be duplicated in a derived process type.
By using the above approach, it is also possible to support multiple inheritance.
// IDL
interface A {
typedef boolean status;
void sync1 (in status p1);
};
interface B:A {
typedef long status;
void sync2 (in status p1);
};
/* SDL interface package */ syntype A_status = CORBA_boolean endsyntype; syntype B_status = CORBA_long endsyntype; remote procedure A_sync1; fpar in A_status; remote procedure B_sync1; fpar in A_status; remote procedure B_sync2; fpar in B_status; /* SDL definition package */ process type A; virtual exported procedure A_sync1; fpar in p1 A_status; endprocedure; endprocess type; process type B; virtual exported procedure B_sync1; fpar in p1 A_status; endprocedure; virtual exported procedure B_sync2; fpar in p1 B_status; endprocedure; endprocess type;
A constant is mapped to a synonym.
// IDL
const string name = "testing";
interface A {
const float pi = 3.14159;
};
/* SDL interface package */ synonym name CORBA_string = `testing'; synonym A_pi CORBA_float = 3.14159; /* SDL definition package */ process type A; endprocess type;
Each IDL type has a corresponding SDL type. In some cases, the SDL type is predefined, and in other cases it has to be generated based on the IDL specification.
SDL types based on the basic IDL types are available in a predefined package (idltypes
) in the same manner as ordinary SDL types are available from a predefined package.
The package containing the predefined CORBA types should be used by all packages and systems that are part of an CORBA application.
Basic IDL types are typical examples of types that are predefined in SDL. All CORBA types are defined as syntypes of existing SDL types, according to the following table:
IDL | SDL | syntype of |
---|---|---|
long |
CORBA_long |
Integer |
short |
CORBA_short |
Integer |
unsigned long |
CORBA_unsigned_long |
Integer |
unsigned short |
CORBA_unsigned_short |
Integer |
double |
CORBA_double |
Real |
float |
CORBA_float |
Real |
char |
CORBA_char |
Character |
boolean |
CORBA_boolean |
Boolean |
octet |
CORBA_octet |
Octet1 |
Note: |
A typedef is mapped to a syntype.
// IDL
typedef double xt;
interface I {
typedef char xt, yt;
};
/* SDL interface package */ syntype xt = CORBA_double endsyntype; syntype A_xt = CORBA_char endsyntype; syntype A_yt = CORBA_char endsyntype; /* SDL definition package */ process type I; endprocess type;
An enum is mapped to a literal type.
// IDL
enum e {
red,
green,
blue
};
/* SDL interface package */ newtype e literals e_red, e_green, e_blue endnewtype;
A struct is mapped to a struct type.
// IDL
struct s1 {
struct s2 {
long p;
} x;
enum e {
yes,
no
} y;
};
/* SDL interface package */ newtype s1_s2 struct p CORBA_long; endnewtype; newtype s1_e literals s1_e_yes, s1_e_no endnewtype; newtype s1 struct x s1_s2; y s1_e; endnewtype;
Note: The type union is not supported in SDL. |
A sequence is mapped to a string, regardless of whether it is bounded or unbounded.
// IDL
typedef sequence<long> x;
struct s {
sequence<sequence<short, 5> > x;
};
/* SDL interface package */ newtype CORBA_sequence_long string(CORBA_long, Empty); endnewtype; syntype x = CORBA_sequence_long endsyntype; newtype CORBA_sequence_short string(CORBA_short, Empty); endnewtype; newtype CORBA_sequence_sequence_short string(CORBA_sequence_short, Empty); endnewtype; newtype s struct x CORBA_sequence_sequence_short; endnewtype;
A string is mapped to SDL as is shown in the following table, regardless of whether the string is bounded or unbounded:
IDL | SDL | syntype of |
---|---|---|
string |
CORBA_string |
Charstring |
The SDL type CORBA_string
is present in the package idltypes
.
// IDL
typedef string address_type;
struct s {
string<20> name;
address_type address;
};
/* SDL interface package */ syntype address_type = CORBA_string endsyntype; newtype s struct CORBA_string name; address_type address; endnewtype;
An array is mapped to an array.
For each array, however, it is necessary to define a specific range type, whose index goes from 0 to <size> - 1, where <size> is the number of elements specified for the IDL array.
Multi-dimensional arrays require multiple range specifications.
// IDL
typedef long arr[4];
struct s {
long x[6][4];
arr y;
};
/* SDL interface package */ syntype COBRA_long_4_range constants 0:3 endsyntype; newtype CORBA_long_4 array(CORBA_long_4_range, CORBA_long); endnewtype; syntype arr = CORBA_long_4 endsyntype; syntype CORBA_long_4_6_range constants 0:5 endsyntype; newtype CORBA_long_4_6 array(CORBA_long_4_6_range, CORBA_long_4); endnewtype; newtype s struct x CORBA_long_4_6; y arr; endnewtype;
The process of creating an object implementation is described in this section. When using the CORBA-oriented approach, development is assumed to start with an IDL description, and then to proceed using the following steps:
These steps are further elaborated below.
The first step in creating an SDL application capable of being used in a CORBA environment is to produce the IDL description that is supposed to be implemented. The three most obvious ways to obtain an IDL description are:
If the IDL description already exists, it should be entered in the Organizer, which is done by using the menu command Add Existing. When this is done a file dialog pops up, where the appropriate IDL file should be selected. By pressing OK, the chosen file will appear in the Organizer as an IDL file in the Organizer.
To create a new IDL description, the menu command Add New should be used; in the popup dialog a document of type Text IDL should then be chosen. It is customary to use the suffix .idl
when naming an IDL file.
When pressing OK, the IDL file appears in the Organizer, and a text editor where the file can be created is also displayed on the screen.
The previous approach of creating an IDL description can be combined with the copy/paste as concept that is defined in the SOMT method.
In that case, it is possible to copy classes from the Object Model Editor, and then to paste them as IDL modules or interfaces in the file that has been opened in the text editor.
The mapping rules that are used are very simple; if a class is mapped to an IDL module, the module will be empty (regardless of whether the class contained attributed or operations). If, on the other hand, a class is mapped to an IDL interface, the attributes and operations of the class will become attributes and operations of the interface.
However, it is not possible to deduce all properties of the IDL description from the Object Model, which means that some properties must be manually added to the IDL description once the transformation from the Object Model has been performed.
For more information about this subject, please refer to the volume SOMT Methodology Guidelines.
There are then several ways to convert the IDL description into an SDL stub:
sdtidl
(see The IDL Compiler).Once the IDL description has been converted, the SDL system should be entered into the Organizer.
When the menu command Convert IDL to SDL is used from the Organizer, a dialog pops up. In this dialog, the main file name of the IDL description should be used as source file. Furthermore, since it is an implementation that is being created, code should be generated for a server, and all names should be global. If it is needed, the target directory where the resulting files will be placed can also be specified. All of these options are further described in The IDL Compiler.
Figure 509 : The Convert IDL to SDL dialog
|
Once the appropriate IDL file has been selected, and the options have been set, the actual conversion is started by pressing Convert.
This conversion will result in a set of files (see The File Structure for a description of these files), some of which describe the SDL system. These files are known as Graphical Representation (GR) files.
The generated SDL system is a stub (or skeleton) which contains no behavior at all.
If the IDL compiler is invoked from the command line, the approach is slightly different. In this case, the IDL compiler should be invoked as:
sdtidl name.idl
Both the server and global aspects are used by default. However, the compiler will only produce one file in textual Phrase Representation (PR), i.e., the SDL specification is represented as one textual file. Compare this with the Organizer approach, where a set of GR files were created. In the Organizer, it is then necessary to convert this PR file to a set of GR files, which is done by issuing the menu command Convert to GR, using the generated PR file as source file.
In order to view the resulting SDL system in the Organizer, the menu command Import SDL is used.
There are two things to keep in mind when importing the generated SDL system, and these are:
.ssy
instead. If the IDL file was named name.idl
, the file that should be imported is name.ssy
. The transformed IDL description will appear in the Organizer when Import is performed.
Since the converted SDL system is only a skeleton it is necessary to add behavior to it. This is not different from creating an ordinary SDL system, except that some of the work has already been automatically performed.
Do not alter the automatically generated names of the SDL system as this may cause the executable to behave incorrectly. |
If changes are made to parameters and such in the SDL system, the corresponding parameters of the initial IDL description should also be altered accordingly.
When the behavior of the system has been provided it is possible to simulate and validate the application. Note that it is not possible to simulate the entire distributed system of which this SDL system might be only a part (compare with Figure 506).
Note: An SDL system skeleton should be generated only once. If behavior is added, and new functionality is entered in the IDL description, the SDL system should be manually updated according to the mapping rules given in Mapping IDL to SDL. If a new generation is performed, any behavioral aspects that had been added to the system are lost. |
Once the behavior of the SDL system has been satisfactorily provided it is time to create the final executable, which is the CORBA application that is eventually registered to the ORB. On order to create such an application, the menu command Make should be performed.
In the Make dialog, it is important to see to it that the appropriate options are set.
Figure 510 : Appropriate options in the Make dialog
|
In the section Analyze & generate code, the following options should be set:
Note: In order to make use of the CORBA support, it is necessary to have a license for Cadvanced. |
Furthermore, Generate environment header file should also be turned on.
In the Makefile section, the Generate makefile and use template option should be chosen, where the template file to use is named after the IDL description (see The File Structure), but with the suffix .tpm
. If the IDL file was called name.idl
, the make template file to use is called name.tpm
.
Finally, in the Compile & link section, the kernel to be used is found in the directory $sdtdir/SCTCORBA
. More information about kernels can be found in The Master Library.
When all of these options have been checked, the application is created by pressing Make.
If all goes well, an executable is created. Again, if the IDL file that was initially used was called name.idl
, the executable would be named name_acx.sct
.
This application usually has to be registered with an ORB to function as a part of a larger distributed system. In Orbix, the way to register an application is by using the shell command putit
, e.g.,
putit -hmachine name name_acx.sct
It is recommended that the name of the server is the same as the name of the generated SDL system (in the case of name.idl
, the server name should thus simply be name
). If another server name is wanted, it is necessary to modify the function call xxSetServerName
in the generated C++ wrapper file (this file is name_i.cc
, as is shown in The File Structure). This function is used during the server initialization to set up the correct server name for when the ORB function impl_is_ready
is called.
When the application has been registered, it is possible for clients to access the server, making use of the offered services. The application can be launched manually from a command shell, or automatically by Orbix in response to an incoming operation invocation.
When the CORBA application was created, the kernel SCTCORBA
was used. It is possible to use the kernel SCTCORBASIM
instead, which behaves approximately as the ApplicationDebug
kernel that is described in The Master Library.
When using a debug application it is possible to trace all events in the SDL system using the simulator.
The creation process when creating a debug application is basically as is outline above. The only difference is that the server must be started as a persistent server, i.e., it must be manually launched before it can be accessed by the ORB. This can be done either from the Simulator UI, or from the command line by running the executable. It cannot, however, be started by a client through the ORB.
When the application has been opened in the simulator, the command start-env
must be executed before the ORB is able to communicate with the ORB.
During the course of providing behavior to an SDL system, it might be found that there exists a CORBA server which provides some functionality that is needed. In such cases, it is useful to be able to request those services directly from the SDL system, i.e., to let the SDL system act as a client of that server.
The very few steps that are required to be able to achieve this include:
There are then a couple of ways to convert the IDL description into an SDL interface package:
sdtidl
(see The IDL Compiler).Once the IDL description has been converted, the SDL system should be entered into the Organizer.
When the menu command Convert IDL to SDL is used from the Organizer, a dialog pops up. In this dialog, the main file name of the IDL description should be used as source file. Furthermore, since the IDL description describes services that are to be used by a client, code should be generated for a client, and all names should be global. If it is needed, the target directory where the resulting files will be placed can also be specified. All of these options are further described in The IDL Compiler.
Once the appropriate IDL file has been selected, and the options have been set, the actual conversion is started by pressing Convert.
This conversion will result in a set of files (see The File Structure for a description of these files), where one GR file describes the SDL interface package that corresponds to the IDL description.
If an SDL system exists in the Organizer by the time of the conversion, the name of the system will be used in the generated header file of the C++ wrapper. If no SDL system exists, the generated header file will contain an entry of the form #include Untitled.ifc
, which will have to be manually corrected by replacing "Untitled" with the actual system name.
If the IDL compiler is invoked from the command line, the approach is slightly different. In this case, the IDL compiler should be invoked as:
sdtidl -Sclient name.idl
However, the compiler will only produce one file in textual Phrase Representation (PR), i.e., the SDL interface package is represented as one textual file. Compare this with the Organizer approach, where a GR file was directly created. In the Organizer, it is then necessary to convert this PR file to a GR file, which is done by issuing the menu command Convert to GR, using the generated PR file as source file.
In order to view the resulting SDL interface package in the Organizer, the menu command Import SDL is used.
There are two things to keep in mind when importing the generated SDL system, and these are:
_interface.sun
instead. If the IDL file was named name.idl
, the file that should be imported is name_interface.sun
. The transformed IDL description will appear in the Organizer when Import is performed.
The system that wishes to utilize the services offered by an IDL description should use the corresponding SDL interface package.
The operations that are available on the server are found in the interface package in the form of signals or remote procedures, and if an object reference (or PId value) of the server is known, a request can be sent in the form of a signal or a remote procedure to that PId value.
If, however, the object reference is not known, and the signal is sent without specifying a receiver, the signal will be sent to one server which implements that service. This server is located by the ORB, and when using Orbix, the _bind
function is used to find it.
When the application is generated, a make template file is used. The contents of this make template file is shown in The File Structure.
When implementing the server side of an application, this template file is automatically created. However, when using the client side of an application it is necessary to add a few entries in order to make the application correctly.
Basically, for each additional server that is used by the system, two new entries (object files) should be made, as is shown in the following table where the added entries are highlighted:
CORBA server(s) | Contents of make template file |
---|---|
server.idl |
serverOBJECTS = serverC.o server_c.o |
server1.idl server2.idl |
serverOBJECTS = server1C.o server1_c.o \ server2C.o server2_c.o |
The first object file is generated by the ORB, while the second object file is generated by SDT. These must be present in the make template file for the compiled and linked application to be able to communicate through with other servers through the ORB.
The mapping rules that are described in Mapping IDL to SDL must sometimes be used manually, for example when a change is made to the IDL specification once the corresponding SDL system has already been implemented.
When first creating the SDL system, however, it is advantageous to make use of the IDL compiler that accompanies SDT, sdtidl
, to automatically generate code from an IDL specification.
The primary use of the IDL compiler is to generate an SDL stub from an IDL specification according to the mapping rules, but it is also used to generate the C++ wrappers that are needed for the CORBA application. In the Organizer, there is a dialog that can be used to invoke the IDL compiler (see Converting an IDL Description to an SDL System Skeleton). A summary of the most important flags to use when generating code is shown below (note that some of these flags can only be used when invoking the IDL compiler from the command line):
The sdtidl
compiler can be found in the directory $sdtbin
.
The IDL compiler sdtidl
is used to generate an SDL stub (skeleton), but also to generate SDT specific wrappers to the used ORB.
This ORB generally also has an IDL compiler of its own, which is used to generate stubs and skeletons needed by the ORB. However, the invocation of this external IDL compiler is implicit, and is made when the final application is being compiled (how the invocation is performed can be deduced from the makeoptions
file (see The makeoptions File).
There are several switches that can be used to control the behavior of the IDL compiler, and these are described below.
The version number of the IDL compiler can be found by using the switch -V:
sdtidl -V
When this switch is set, no other actions are performed.
All switches that are possible to use with the IDL compiler are shown if the switch -u is used:
sdtidl -u
No other actions are performed when this switch is used.
The IDL compiler is intended to produce an SDL stub according to the mapping rules in Mapping IDL to SDL. However, it is also used to produce the C++ wrapper (see The SDL System) and the make template file (see The Make Template File) for the SDL application.
As default, the following files are generated from an IDL specification (it is assumed that the IDL specification file is named name.idl
):
name.pr
name_i.hh
and name_i.cc
name.tpm
In some cases, however, it is advantageous to produce only a subset of these files, and to achieve that the -L
switch is used. This switch takes an argument that can be either c++
or sdl
.
Only the C++ wrapper is produced (along with the make template file) when the -Lc++
option is used; this is particularly useful if there already exists an SDL system that should not be changed:
sdtidl -Lc++ name.idl
On the other hand, only the SDL stub is generated when the -Lsdl
option is used; this is particularly useful when the SDL system should only be simulated, and not be made into an application:
sdtidl -Lsdl name.idl
If, at a later stage, the simulated SDL system should be turned into a CORBA application, it is only necessary to create the C++ wrapper using the -Lc++
switch.
When generating SDL from IDL, it is possible to choose between two different modes: by default SDL names must be made global (see Scoped Names) in order to avoid discrepancies. It is not recommended to use local names due to this fact.
The switch -N
is used to control the namescope, and it should be used together with an argument that is either global
or local
.
Note: The usage of |
When using the IDL compiler, it is possible to denote whether the produced code should be used on the client or the server side of the application. By default, code is generated for the server side.
By using the switch -S
it is possible to choose side by using either of the arguments server
and client
.
Thus, in order to produce code for only the client side of the system, the following command should be given:
sdtidl -Sclient name.idl
When generating code for the client side, i.e. when using -Sclient
, you can specify in which SDL system the IDL specification will be used. In this way, the generated header file of the C++ wrapper will include the correctly named .ifc
file for the system. This is done by using the switch -Wb
directly followed by the SDL system name:
sdtidl -Sclient -WbSystemName name.idl
If no name is specified, the generated header file of the C++ wrapper will contain an entry of the form #include Untitled.ifc
, which will have to be manually corrected by replacing "Untitled" with the actual system name.
The code that is produced by the IDL compiler is by default placed in the directory in which the compiler was invoked. However, it is possible to control where the output is to be placed by using the switch -T
, which takes a target directory as argument:
sdtidl -T/path/directory name.idl
There are some limitations regarding the capability of the IDL compiler. These limitations can be divided into two separate areas: unsupported IDL features and simplifications.
The following is a list of IDL features that are not supported in SDL:
The following is a list of simplifications that are made when generating SDL from an IDL specification.
// IDL
typedef long symbolic_type;
const
symbolic_typeN = 17;
/* SDL interface package */ syntype symbolic_name = CORBA_long endsyntype; synonym NCORBA_long
= 17;
// IDL
const double value =
4.3 + 2.7;
/* SDL interface package */ synonym value CORBA_double = 7.0;
The following error codes may be produced by the IDL compiler:
An illegal options is passed to the IDL compiler (see Flags for a list of available options).
ERROR 4201 IDL feature not supported in SDL
An IDL concept that is not supported by SDT is used (a list of unsupported features is found in Unsupported IDL Features).
ERROR 4203 Could not open file
The IDL compiler attempts to create files to place its output, but for some reason it could not create a file. This is most likely due to an incorrect directory path, but may also be caused by memory limitations.
ERROR 4204 Could not start the IDL compiler
The IDL compiler failed to generate code, probably due to memory limitations.
ERROR 4205 SDL identifier is not unique
This error message will only appear when a local namescope is used.
ERROR 4206 IDL identifier is an SDL keyword
An IDL identifier is used that is also an SDL keyword, which may cause the SDL specification to be illegal.
Apart from providing the mapping rules from IDL to SDL, the major part of the integration between SDL applications and CORBA is performed within the environment of the system.
The integration is basically divided into three layers, as is shown in Figure 511, with the SDL system being the topmost one. However, the SDL system itself is always encapsulated by a C++ wrapper (there are different wrappers depending on whether it is the server side or the client side of the application that is viewed). The final layer is the ORB itself, which connects the application with other CORBA applications.
Figure 511 : Architecture of an CORBA application in SDL
|
Additionally, a set of environment functions are used between the SDL system and the C++ wrappers to handle signal sending to and from the SDL system.
How all of these layers are connected will be thoroughly explained in the following sections.
There are several files that make up a single application, as is hinted at in Figure 512.
Figure 512 : Creating the files of a CORBA application
|
In each layer, a set of files are either predefined or generated, and all of these files are then compiled and linked together to form the final executable.
In all of the following sections a specific IDL file is assumed, say name.idl
.
The ORB creates several files from the IDL file using its own IDL compiler (the files mentioned here are all produced by Orbix; other ORBs have similar files):
name.hh
: A header file containing the information needed by the source files below, for example the IDL C++ classes.nameC.cc
: A source file needed on the client side of an application to be able to make outgoing requests.nameS.cc
: A source file needed on the server side of an application to able to receive incoming requests.Each C++ wrapper is created by the IDL compiler provided by SDT, sdtidl
. On the server side of an application the following files would be generated (only when an IDL description is being implemented as an SDL system):
name_i.hh
: A header file containing the declaration of the C++ implementation classes that are used to implement the IDL C++ classes.name_i.cc
: A source file containing the implementation of the C++ implementation classes that were declared in name_i.hh
. name.tpm
: A make template file which is used when creating the SDL CORBA application. It specifies which server object files that should be used when making the final application, but also which client object files that should be used.On the client side of an application the following files would be generated (only when an IDL description is used by an SDL system).
name_c.hh
: A header file containing the declaration of the functions needed to make outgoing requests from the SDL system. name_c.cc
: A source file containing the implementation of the functions that were declared in name_c.hh
. The SDL system makes use of a runtime library which is defined by the Master Library. When creating a CORBA application, however, it is necessary to add some additional files containing CORBA specific parts (these files are all predefined in the Master Library, and can be found in the directory $sdtdir/INCLUDE/CORBA
):
orb.hh
: A header file containing macros for ORB functionality, ORB threading, and signal sending, but also declarations of variables and functions used by the wrapper files.orbutil.hh
: A header file containing macros for thread support, and also for class declarations for lists and queues.orbutil.cc
: A source files implementing the classes declared in orbutil.hh
. orbenv.cc
: A source file which implements the environment functions, and also the functions that are needed by the wrapper files.In addition to the files mentioned above, there are several C files generated by the SDL system. This part is further described in The Cadvanced/Cbasic Code Generator.
The first layer of the application is the SDL system itself. The entire application works as a single process in the operative system, and the SDL system part is a single thread of that application. This thread has a scheduler which divides the work between the processes in the system, as is shown in Figure 513.
Figure 513 : The SDL system part of an application
|
All requests to and from the SDL system are passed through the environment functions. A call from a client would be inserted through the use of the function xInEnv
, while a call to an external server would be passed through the function xOutEnv
. This will be further elaborated in Environment Functions.
Also, each process in the SDL system has a corresponding C++ object in the C++ wrapper encapsulating the system. The purpose of the C++ wrappers is described in The Server Wrapper and The Client Wrapper.
The server wrapper is a C++ wrapper that encapsulates an SDL system which implements an IDL description. It also acts as an interface to the ORB, so that all clients wishing to interact with the SDL system must always go through this wrapper. In fact, as seen from the ORB, the C++ object implementation is the SDL system, but the behavior of the objects is actually implemented by the SDL system.
Each process in the SDL system has a corresponding object in the wrapper, and whenever the ORB receives a new request it is routed to a certain object. This object, in turn, converts the request to an appropriate signal or remote procedure call (according to the mapping rules in Operations), which is sent into the SDL system to the corresponding SDL process.
The server wrapper's most important feature is the C++ implementation classes (the jargon used in Orbix's Programming Guide is used here as well; other terminologies might be used by other ORBs). Based on the IDL description, a set of IDL C++ classes is generated by the ORB. To these IDL C++ classes it is then necessary to add behavior, which is done by providing C++ implementation classes which are then bound to the appropriate IDL C++ classes using what is known as the TIE approach. This is depicted in Figure 514.
|
For the C++ classes used here, the IDL to C++ mapping rules that are specified by CORBA are used.
The IDL C++ classes contain the information needed to read and write information from the network, while the C++ implementation classes are supposed to contain the behavior (implementation) of each class.
The objects of these combined TIE classes are the ones that are actually accessed by clients in the distributed CORBA system.
The same IDL description is used both to create the SDL system skeleton and the C++ server wrapper. This also means that for each process type in the SDL system (that is generated from an IDL description) there exists a corresponding class in the C++ server wrapper.
Whenever a new SDL process instance is created, the function xCreateInstance
is called. The purpose of this function is to create a corresponding object of the process instance in the server wrapper, and to set up a communication path between these.
Whenever an object receives a request, this request is forwarded immediately to its corresponding SDL process instance.
Note that process instances that are not derived from an IDL interface have no corresponding C++ object, and cannot be called from external clients.
When a process instance is terminated, it depends on the kind of application what happens to the object. If the kernel SCTCORBA
was used, the corresponding object is removed, while it is not removed if the kernel SCTCORBASIM
is used.
The reason for keeping the object in the latter case is to make it possible to trace client requests in the server even though the actual process instance that was addressed no longer exists. In an application, the signal is simply lost, but an exception is raised to the client that an invalid object reference has been used. This does not show in the server, though.
Note: Exceptions that are raised are currently not visible in the SDL system, but could be detected by the C++ wrapper. |
In a normal CORBA application implemented using C++, the user would have to implement the C++ implementation classes. In this case, however, the C++ implementation classes merely form a kind of gateway to the SDL system, and are generated completely automatically from the IDL description; the user has to provide an implementation of the SDL system instead.
Figure 515 : Handling a request from a client
|
An object that receives a request from a client creates the corresponding signal or remote procedure call, and assigns its parameters before it sends it into the SDL system. If the request is not asynchronous a reply is also expected from the SDL system.
In order to be able to handle new requests while one is being treated by the SDL system, each new request is executed in a thread of its own, which means that while one thread is waiting for a reply it is possible for the SDL system to receive requests from other clients as well. Without this threading mechanism, the SDL system would be blocked while handling a request.
The behavior of a general operation can be summarized as follows:
A more elaborate account of these events are given for different kinds of operations in the next few sections. Note that a new request thread is created for each kind of operation.
The simplest operation is a oneway
operation, which is mapped to a signal in SDL. Once such a request has been sent into the SDL system, the request thread is no longer needed since no reply is expected. The actions that have to be performed in the C++ implementation class are as follows (remember, all of this is automatically generated):
sdtidl
as part of the server wrapper.For an ordinary operation a reply is always expected (these operations might be thought of as synchronous). Such operations are more difficult to handle than asynchronous operations, especially considering that if only asynchronous requests were made it would not be necessary to spawn a new thread for each request. All ordinary operations are mapped to remote procedures in SDL.
When such an operations is received, the following actions are performed by the C++ implementation class:
sdtidl
as part of the server wrapper.sdtidl
as part of the server wrapper.An attribute is mapped to two operations, and each of these is handled exactly as an ordinary operation.
The server wrapper is generated automatically from the IDL description at the same time an SDL system skeleton is created (as was described in Converting an IDL Description to an SDL System Skeleton).
It is also possible to generate a server wrapper by addressing the IDL compiler sdtidl
directly:
sdtidl -Lc++ -Sserver name.idl
The client wrapper has the same purpose as the server wrapper; it encapsulates the SDL system, and provides an interface to the ORB. A different client wrapper is produced from the IDL description of each server that the SDL system wants to communicate with.
Each operation in the IDL description is associated with a function that is called when the corresponding SDL signal or remote procedure call is made to the environment (i.e., to some object residing outside the SDL system itself). This function executes in a thread of its own, which makes it possible for the rest of the SDL system to continue executing while the request is being handled by a server.
In Figure 516 it is shown how a request is associated with a function that describes how a request should be performed. For each operation or attribute in the IDL description there is such a function.
Figure 516 : Handling a request from an SDL system
|
The general method for handling a request from a client is as follows:
A more elaborate description of these events are given in the next few sections.
During the initialization of the SDL system, all functions that are associated with IDL descriptions (for external servers) are tied to the corresponding signal definitions in the form of function pointers.
This means that when a signal is received in the function xOutEnv
, and it contains such a function pointer, then that function should be invoked as a new thread, which only executes as long as it takes to handle the request. Once the request has been handled, the thread is terminated.
As was the case in the server wrapper, asynchronous operations are easier to handle than synchronous operations. Such operations are signals that are sent from the SDL system, and they do not require a reply. The function that is called upon the reception of such a request signal from the SDL system has the following behavior:
sdtidl
as part of the client wrapper.When dealing with synchronous operations, which are represented using remote procedures, the reply signal must also be taken into account. In order to be able to continue executing other processes in the SDL system while a request is being handled, each request must execute as a thread of its own. When issuing a synchronous request from the SDL system, the following actions are taken by the request function:
sdtidl
as part of the client wrapper.sdtidl
as part of the client wrapper.Attributes are mapped to two operations, and each of these is handled exactly as an ordinary operation.
It has been stated several times that if no receiver for a request is specified, one must be located. This is based on the fact that when a request is made in SDL this can be done in one of two ways: with or without a recipient specified using to
(as is exemplified in Figure 517).
Figure 517 : Issuing a request in SDL
|
If the request is made to a known receiver (as in case B), this PId value in SDL is converted to an object reference in the C++ client wrapper to which a request can be issued.
If no receiver is specified (as in case A), it is absolutely necessary to locate a receiver before a request can actually be made. This is done by making use of the _bind
functionality in Orbix (this might be called something else in other ORBs), where a possible recipient object is searched for in other servers.
The client wrapper is generated automatically from the IDL description at the same time an SDL interface package is created (as was described in Converting an IDL Description to an SDL Interface Package).
It is also possible to generate a client wrapper by addressing the IDL compiler sdtidl
directly:
sdtidl -Lc++ -Sclient name.idl
The environment functions make up the glue that binds the SDL system to the C++ wrapper. They are responsible for:
The environment functions also contain much of the actual behavior of the C++ wrappers in the form of functions. This way it is easy to change the underlying implementation without changing the code generated by the IDL compiler.
The files that make up the environment functions are: orb.hh
, orbenv.cc
, orbutil.hh
, and orbutil.cc
, and can be found in the directory $sdtdir/INCLUDE/CORBA
.
Note: Often, the environment functions are placed in a file called |
These files themselves will be examined more closely in The Master Library, whereas their different responsibilities will be covered in this section.
During the initialization of the SDL system the function xInitEnv
is called by the scheduler to allow the environment of the SDL system to be initialized as well.
The main task of xInitEnv
is to establish the communication with the ORB. The SDL system cannot be allowed to run before such a connection has been made.
In order to establish the communication, the ORB function impl_is_ready
is called using a macro defined in orb.hh
:
CORBA_IMPL_IS_READY(server_name, 0)
The server_name
is assigned by the server wrapper, and should be the same as is used by the client to _bind
to the server (consequently, if the SDL system works only as a client and there is no server wrapper, it is not necessary to establish this connection with the ORB). This name is set by the function xxSetServerName
, and if another name is wanted this function call must be altered.
It should also be noted that the second parameter is 0, which means that any pending requests from clients should not be treated during the setup.
As has already been stated, the SDL system executes in a thread of its own. There is also another thread that is always running, and this is the event manager thread, the purpose of which is to listen to the ORB for incoming requests, and to spawn a new request thread whenever a new request is detected.
The event manager thread is created as part of the initialization performed in xInitEnv
.
The key functionality in the event manager is the following macro call:
CORBA_PROCESS_EVENTS(CORBA_INFINITE_TIMEOUT)
This is a call to the ORB function processEvents
, which is responsible for detecting events from external clients. Also note that this call sets an infinite timeout, which means that the thread will never terminate (until the application is closed).
The function xInEnv
is repeatedly called by the scheduler to check whether there are incoming requests from the ORB that have to be taken care of.
The first thing that is done by this function is to allow all threads that have been started since the last time the function was called to execute, and to place a signal in the InputBuffer
. Once this has been done, all the signals in the InputBuffer
are sent into the SDL system.
It should be noted that replies from external servers are also placed in the InputBuffer
before they are returned to the calling SDL process
When a remote procedure call from the environment is answered by the SDL system, the appropriate remote procedure reply is sent to the environment using the function xOutEnv
.
This function is also called if the SDL system issues a (new) request to an external server.
What is done in this function is first to determine if the call was a new request; this is determined by examining if the function pointer Request_Function
is set or not. If it is set, that function is called as a new thread, where the actual request to the server is performed.
If the signal was not a new request, it is checked whether it is a remote procedure reply to a previously received remote procedure call. If it is, the reply is entered into the ReplyBuffer
, the request thread waiting for that reply is awakened, and then the request thread can get the reply signal from the ReplyBuffer
.
If the signal does not fulfill any of these two requirements, it is simply discarded.
For each new request that is received from the ORB (from external clients), a new thread is created by the event manager. The reasons for threading the requests are:
In Orbix, request threads are created by applying a filter to the premarshalling of the request. The filter class appears as follows:
class ThreadPerRequestFilter : public CORBA::ThreadFilter { virtual int inRequestPreMarshal( CORBA::Request&, CORBA::Environment&); };
The only thing that is done by this filter is to create a new thread as is shown below. Note that macros are used for all thread functionality.
int ThreadPerRequestFilter:: inRequestPreMarshal(CORBA::Request& req, CORBA::Environment&) { THREAD_T tid; THREAD_CREATE(&tid, thread_attr, xRequestThread, (void*)&req) return -1; }
In the created thread, the request is allowed to continue its ordinary path, and the thread is terminated once the request is done:
void* xRequestThread(void* arg) { CORBA_CONTINUE_THREAD_DISPATCH(arg) return 0; }
One of the major tasks of the environment function is to keep track of all object references and how they are mapped to PId values. For this purpose a MappingTable
is produced, which contains pairs of object references and PId values.
Whenever a new object reference is found, the MappingTable
is searched for it. If there already is an entry, it is mapped directly to that PId value, but otherwise it is necessary to create a new PId value which only represents this object reference. The new mapping is also entered into the MappingTable
for future references.
PId values always contain a direct reference to their corresponding object reference. The situation is a bit different for objects. For an object corresponding to an SDL process instance, the PId value is known directly by the object, but if the object reference represents an object outside the SDL system, then there is no corresponding SDL process instance. Instead, a PId value with the same appearance as the environment's PId value is created for that object reference, and the only way to find out about this connection is to search the MappingTable
.
Some additions has been made to the Master Library to support the CORBA integration of SDL application. The Master Library itself is described in The Master Library, and only the additions will be discussed in this section.
The major addition to the Master Library is that two new library versions are available, SCTCORBA
and SCTCORBASIM
. All other additions to the Master Library are made only to support these new libraries.
The file structure of the Master Library is shown in Figure 518. No changes has been made to this structure, except that the directories SCTCORBA
and SCTCORBASIM
has been added, and that the INCLUDE
directory contains some additional files in the CORBA
directory.
There are also some additional files belonging to the CORBA integration, and these can be found in the directory $telelogic/sdt/include/ADT
:
idltypes.sdl
, which is a PR-file containing the predefined SDL versions of the basic IDL types, as was mentioned in Types.idltypes.sun
, which is a GR-file containing the same information as the idltypes.sdl
file, but in a graphical format.
Figure 518 : The CORBA libraries
|
Library Version MacrosTwo new library versions have been added to the Master Library (in the file scttypes.h
):
SCTCORBA
, which is an application capable of communicating with external clients and servers through CORBA.SCTCORBASIM
, which is debug version of an application capable of communicating with external clients and servers through CORBA. When using this kernel, a simulator can for example be used to trace the messaging inside the SDL system.A couple of configurations macros have been added:
XCORBA
, which is used to enclose all Master Library additions that are CORBA related. It should only be defined for the two libraries that were described above.XSOLARISTHREAD
, which is used to indicate that the Solaris thread package should be used. This macro should be defined in the makeoptions file (as part of sctIFDEF
; see The makeoptions File for more information).XDCETHREAD
, which is used to indicate that the DCE thread package should be used. This macro should be defined in the makeoptions file (as part of sctIFDEF
). XPOSIXTHREAD
, which is used to indicate that the POSIX thread package should be used. This setting is the default, so if no thread package is specified, POSIX threads are used.XORBIX
, which is used to enclose code that is Orbix specific. If another ORB than Orbix is used, this code must be altered.Since it is possible to make use of different thread packages, all thread function calls have been replaced by macros which makes it easier to switch between different packages, and also to add additional thread packages if that is needed.
These macros are defined in the file orbutil.hh
, which contains definitions for Solaris threads, POSIX threads, and DCE threads.
In order to make it easy to switch to other ORBs, some macros have been defined for calling ORB functions:
CORBA_DEACTIVATE_IMPL
, which is used to close the connection to the ORB.CORBA_IMPL_IS_READY
, which is used to establish the connection to the ORB.CORBA_IS_EVENT_PENDING
, which is used to check whether there are any pending requests from the ORB to be handled.CORBA_PROCESS_EVENTS
, which is used to continuously wait for, detect, and handle requests fro the ORB.CORBA_PROCESS_NEXT_EVENT
, which is used to process one request from the ORB. This macro is usually used in conjunction with CORBA_IS_EVENT_PENDING
.These macros are all defined in the file orb.hh
.
Some macros are used to handle the binding between an IDL C++ class and a C++ implementation class. The intention with these macros is to simplify an integration with another ORB:
ORB_CLASS_INHERIT
, which is used to handle the situations when the implementation class inherits the behavior from a general superclass. This macro is currently not used.ORB_CLASS_BIND
, which is used to handle the situations when a TIE mechanism is used, i.e., when the C++ implementation class and the IDL C++ class are tied together using a binding approach.ORB_CREATE_OBJECT
, which is used to create new objects whenever new process instances are created. These macros are all defined in the file orb.hh
.
The environment macros fall within either of two categories: variables or functions. The variable macros are very straightforward, while the function macros are redefinitions of already existing macros. They have been renamed, though, to avoid confusion:
ALLOC_CALL
, which is used to allocate a data area for a signal that is to be sent when the signal carries no parameters.#define ALLOC_CALL(SIG_NAME, SIG_IDNODE, \ RECEIVER, SIG_PAR_TYPE) \ CALL_PTR = xGetSignal(SIG_IDNODE, RECEIVER, xEnv);
ALLOC_CALL_PAR
, which is used to allocate a data area for a signal that is to be sent when the signal carries parameters.#define ALLOC_CALL_PAR(SIG_NAME, SIG_IDNODE, \ RECEIVER, SIG_PAR_TYPE) \ CALL_PTR = xGetSignal(SIG_IDNODE, RECEIVER, xEnv);
ALLOC_REPLY
, which is used to allocate a remote procedure reply when the reply carries no parameters.#define ALLOC_REPLY(SIG_NAME, SIG_IDNODE, \ RECEIVER, SIG_PAR_TYPE) \ REPLY_PTR = xGetSignal(SIG_IDNODE, RECEIVER,xEnv);
ALLOC_REPLY_PAR
, which is used to allocate a remote procedure reply when the reply carries parameters.#define ALLOC_REPLY_PAR(SIG_NAME, SIG_IDNODE, \ RECEIVER, SIG_PAR_TYPE) \ REPLY_PTR = xGetSignal(SIG_IDNODE, RECEIVER,xEnv);
These macros are all defined in the file orb.hh
.
The PId concept has been extended to support object references when the CORBA libraries are used. In the file scttypes.h
, the following definitions can be found:
#ifdef XCORBA typedef void *xObjectRef; #endif typedef struct { xPrsNode PrsP; #ifdef XNRINST int InstNr; #endif #if defined(XPRSOPT) && !defined(XNRINST) xbool InAvailList; #endif #ifdef XMSCE int GlobalInstanceId; #endif #ifdef XCORBA xObjectRef Object; #endif } xLocalPIdRec;
The Object
that is pointed at contains both a pointer to the C++ object representing the SDL process instance, and a pointer back the PId value (and is part of the MappingTable
).
The makeoptions file is used both to create new libraries, and when applications are compiled and linked. This also means that ORB specific information is added to it.
The definitions part of the makeoptions file for creating a CORBA application is shown below:
sctLIBNAME = CORBA sctIFDEF = -DSCTCORBA -DSUN_CXX \ -DXORBIX -DXSOLARISTHREAD sctuseinclude = $(sctdir)/../INCLUDE orbuseinclude = $(sctdir)/../INCLUDE/CORBA orbhome = $(ORBIX_HOME) sctlinkdir = $(sctdir) sctLINKMODULES = $(sctlinkdir)/sctsdl.o \ $(sctlinkdir)/sctpred.o \ $(sctlinkdir)/sctos.o \ $(sctlinkdir)/orbenv.o \ $(sctlinkdir)/orbutil.o sctLINKKERNEL = $(sctlinkdir)/sctworld.o \ -lorbixmt -lthread -lsocket -lnsl sctCC = CC sctCPPFLAGS = -I$(sctuseinclude) -I$(orbuseinclude) -I$(orbhome)/include sctCCFLAGS = -c -O sctLD = CC sctLDFLAGS = -O -L$(orbhome)/lib sctOEXTENSION = _acx.o sctEXTENSION = _acx.sct
This makeoptions file has the same general structure as the makeoptions files of other libraries, except that ORB specific additions have been made.
Aside from the usual definitions of the makeoptions file, the CORBA specific makeoptions file also contains a make rule part:
# implicit make rule for server c++ files %_i.o: %_i.cc $(sctCC) $(sctCPPFLAGS) $(sctCCFLAGS) \ $(sctIFDEF) $< # implicit make rule for client c++ files %_c.o: %_c.cc $(sctCC) $(sctCPPFLAGS) $(sctCCFLAGS) \ $(sctIFDEF) $< # implicit make rules for Orbix-generated C++ files %C.o: %C.cc $(sctCC) $(sctCPPFLAGS) $(sctCCFLAGS) $< %S.o: %S.cc $(sctCC) $(sctCPPFLAGS) $(sctCCFLAGS) $< # implicit make rules to generate Orbix C++ files orbIDL = $(orbhome)/bin/idl orbIDLFLAGS = %S.cc: %.idl $(orbIDL) $(orbIDLFLAGS) $< %C.cc: %.idl $(orbIDL) $(orbIDLFLAGS) $< %.hh: %.idl $(orbIDL) $(orbIDLFLAGS) $<
These rules are used to compile the files that are generated by sdtidl
, but also the files generated by the ORB.
Never compile directly in the installation directories! Make copies of the directories instead to avoid corrupting the original files. |
In order to create a new kernel, or sctworld.o
, for example if any of the Master Library files have been modified, the following steps should be performed:
$sdtdir
and $sctdir
to the appropriate directories.$sctdir
.sctworld.o
:make -f $sdtdir/Makefile SDTlib
The make template file is generated by sdtidl
whenever a server wrapper is generated, and should be used in the make process when creating a new application. It has the following general structure:
#-------------------------------------------------- # object files for this server (do not alter) objectimplOBJECTS = # object files for other servers (please add here) # use pairs like: <name>C.o <name>_c.o serverOBJECTS = # hooks into the make file (do not alter) USERTARGET = $(objectimplOBJECTS) \ $(serverOBJECTS) USERLIBRARIES = #--------------------------------------------------
The different parts of this file are as follows:
objectimplOBJECTS
, which are the object files that are part of the server side of an application. There are always only two files mention here, nameS.o
and name_i.o
, where the first file is the object file from the ORB specific files, and the second one is the object file from the server wrapper files. As soon as the SDL system can function as a server to other clients in the CORBA environment, these two entries are required.serverOBJECTS
, which are the object files that are part of the client side of an application. Two files should be mentioned here for each server that can be accessed: the ORB specific object file, and the server wrapper specific object file (i.e., nameC.o
and name_c.o
).USERTARGET
, which is a collection of all the object files used.When an SDL application works only as a server, i.e., when it does not make any requests to other servers through the ORB, the make template file is automatically created, and the serverOBJECTS
part should remain empty.
When an SDL application works both as a client and a server, it is necessary to manually add the entries for serverOBJECTS
. Each external server needs two entries, as was mentioned above.
When an SDL application works only as a client, i.e., when it is not possible to make a request to the SDL application, the make template file is not generated, but it is still needed.
It then has to be created and written according to the above description, but objectimplOBJECTS
should be left empty. It is necessary to add entries to serverOBJECTS
, though.
The file sdtsct.knl
is described in File sdtsct.knl; it is used to show in the Organizer which kernels that are available.
It is possible to add the CORBA libraries to this file, and suitable entries might be:
Library Name (Kernel) | Library Path | Comment |
---|---|---|
CORBA |
SCTCORBA |
|
CORBA Debug |
SCTCORBASIM |
|
In the make dialog it is then possible to use CORBA
and CORBA Debug
as standard kernels.