ClassiX® provides an interface to communicate with external systems and to communicate among multiple ClassiX® systems. This communication is limited to sending a message to ClassiX®. It is possible to attach any amount of parameters as numbers or strings to this message1. These parameters are put into the stack, just as it is usually done in InstantView®. That way, it is also possible to build a service-oriented architecture with ClassiX® or to integrate it into an already existing service-oriented environment.
Every ClassiX® instance that provides at least one service needs to log into the CORBA naming service. In case of TAO, the naming service is a program or a window service. The naming service just needs to run on any computer somewhere on the network.
Naming service as well as any other ClassiX® instance use IP multicast to find the naming service on the network. Alternatively, it is possible to set the naming service address via environment variable NameServiceIOR:
SET NameServiceIOR=iioploc://hostname:port/NameService
The environment variable needs to be set on every machine, running the naming service and/or a ClassiX® instance.
Alternatively, the command line parameter -ORBInitRef
NameService=iioploc://hostname:port/NameService can be used, or according
to TAO docu -ORBInitRef NameService=corbaloc:iiop:hostname:port/NameService.
Here, it is required to enter valid values for hostname and port, corbaloc, iiop
and NameService are just entered. This option
applies for "normal" client and server programs. To start NamingService with a
specific address, the following command line option can be used: -ORBEndpoint iiop://hostname:port.
interface CX_REMOTEMSG_RECEIVER_CORBA
{
exception Timeout
{};
typedef sequence<string> MarshaledStack;
void AcceptMsg_CORBA(in string message, in MarshaledStack stack);
// A variant of the the two-parameter AcceptMsg_CORBA method above. This method expects that the sender
// passes an object reference to itself.
void AcceptMsg_CORBA_BiDi(in string message, in MarshaledStack stack, in CX_REMOTEMSG_RECEIVER_CORBA sender);
// A variant of the the two-parameter AcceptMsg_CORBA method above. This call sends a message synchronously
// and returns another stack with the result send in ClassiX as NULL SendMsg(MSG ,REMOTE)
MarshaledStack SendMsg_CORBA(in string message, in MarshaledStack stack) raises (Timeout);
void Ping();
};This service has a method, which adopts a message name and a stack. The stack may even be empty. Additionally, there is the method "Ping()", which works like some sort of dummy. This dummy can be used by other ClassiX® instances to quickly test on the network, whether a given instance replies or not. In ClassiX®, the ping method is implemented empty.
ClassiX® generates such an object and registers it in the CORBA naming service. Each ClassiX® instance provides this service only once.
This service gets logged into the naming service within a structure. A folder "ClassiX" will be created below the root, and below this folder (optionally) a folder for the current ClassiX project. Under this - under the name "RemoteMsg" - there is a service provided for all servers to receive messages. This folder contains the current ClassiX® instances. The name is a combination of computer name, IP address, ClassiX® instance PID, user ID, log in date and the database name(s), separated via " | ". Example (RemoteMsg and Namen (TH...) have been exchanged in this picture, a project is not indicated)

The actual instances provide different services. So far, only the service "RemoteMsg" has been implemented. From the technical point of view, a service is an object, which provides one or more methods. This is the interface of such an object. This object provides the service of receiving a message.
About the CORBA terminology in reference to the names: The CORBA service, which provides name connection of names on the network is called naming service, but also NamingService, Namingservice, NameService, ... sometimes also with Corba or Corba- in front of the name. A CORBA name can consist of multiple name components. The name component choice can establish a hierarchy. The root, which has no explicit name at all at the very top. A name component can be either a naming context. In this case, further name components can be in the hierarchy under this name. Or it can identify an "object" under which no further names are possible. The name contexts only have to be registered
Name context needs to be registered in the naming service before the applications. There is an implementation, a so-called servant, behind the objects. A servant implements a CORBA interface. In ClassiX, objects, which are registered below the naming context RemoteMsg, implements the interface CX_REMOTEMSG_RECEIVER_CORBA (see also next paragraph). The interface implementation doesn't need to be the same everywhere. Cxsendmsg for example implements the same interface as ClassiX, but in a different way. To differentiate these objects, they can be hung-up in different projects (see above, middle part of the name tree) or have unique names.
Not every CORBA application has to implement a servant, but CORBA can provide an object reference (not to be mistaken for a reference in C++). Via this, it is possible to call functions outright.
Calling the AcceptMsg_CORBA function (interface above), the argument "message" contains the message name in clear text (e.g. SELECT). The same applies for the other methods.
"stack" contains the stack, which should be found by the message receiver. The last sequence element is in the stack top, meaning the elements are pushed front to back in the stack. An element is always coded as CORBA string. The following table explains the assignment between string and type:
| Type | String | Example |
|---|---|---|
| Integer | i<Integer> | i123 |
| String | s"<String>" | s"Example" |
| NULL-Objekt | n | n |
| [ | m1 | m1 |
| ] | m2 | m2 |
| Persistent Object | p<String> | p<0|38|0|228|10000> |
| Persistent Collection | c<String> | c<0|38|0|228|10000> |
At the moment, only integers and strings and ZERO objects can be transferred. If required, vectors can be implemented quickly.
Of course, the stack can also be empty. Stack build-up depends on the message sent. Receiver and sender will have to agree on this.
In ClassiX® , the CX_DB_UTILITY method GetLocation() provides the string, which describes an object or a persistent collection. Example:
CreatePersObject(CX_PERSON) GetManager(OBJECT) Call(GetDBUtility) Call(GetLocation) // Now, a string with a stringifized persitstent object address is in the stack
AcceptMsg_CORBA returns immediately and
returns no result. The triggered InstantView®
code is executed asynchronously at a later point in time.
It is still possible to achieve the return of a result, with a message passing another applications result. This application doesn't have to be a ClassiX® instance. It can be anything, as long it
Example: An application XYZ generates an object with the
interface above and logs into the naming service under the name "ClassiX/RemoteMsg/XYZ".
After, XYZ of the required sends the amount. The message will now be processed
in InstantView® code.
The result will be sent to XYZ via
CX_CORBA_MANAGER::SendMsg.
Alternatively (and easier to implement), it is possible to
use the method SendMsg_CORBA. This method processes the message
synchronously and only returns if either
To process CORBA messages, ClassiX® generates an own thread. That way, messages are received at any time, no matter what InstantView® code is currently being processed.
New messages are put at the very end of the queue, so they will be processed only when there is no outstanding command to be executed. This means it is not possible to specify, when a message will be processed. It can only be guaranteed, that messages will be processed in the same order in which they arrive. It needs to be considered, that CORBA does not always guarantee that the message first to be sent is also the first to arrive.
Multiple ClassiX-® servers can be started with the same project name. The client (e.g. cxsendmsg) can look for "ClassiX/<Project>/RemoteMsg" using the naming service and use any instance that is logged in.
The code below shows the sending of a message to a ClassiX® instance. In addition to this code, the sources, which have been generated by the IDL compiler (interface above), are required.
// If ACE/TAO is used as CORBA implementation, the following includes are necessary:
#include <tao/corba.h>
#include <CosNamingC.h>
// Include the sources generated by the IDL compiler
#include "cxRemoteMsgC.h"
// This example sends the message "HELLO" together with a greeting string to a foreign ClassiX® instance
const char *ClassiXInstance = "COMPUTERNAME 123";
// Initialize ACE/TAO CORBA
ACE::init();
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv, "ClassiX SendMsg");
// Prepare parameters for AcceptMsg_CORBA
const char *message = "HELLO";
CX_REMOTEMSG_RECEIVER_CORBA::MarshaledStack stack;
stack.length(1);
stack[0] = CORBA::string_dup("s\"Hello World!\"");
// Get reference to initial naming context
CosNaming::NamingContext_var naming_root;
CORBA::Object_var naming_obj = orb->resolve_initial_references("NameService");
naming_root = CosNaming::NamingContext::_narrow(naming_obj.in());
// Look up receiver object, i.e. the service "RemoteMsg" of the desired ClassiX® instance
CosNaming::Name name;
name.length(4);
name[0].id = CORBA::string_dup("ClassiX");
name[2].id = CORBA::string_dup("Project");
name[2].id = CORBA::string_dup("RemoteMsg");
name[1].id = CORBA::string_dup(ClassiXInstance);
CORBA::Object_var obj = naming_root->resolve(name);
// Call AcceptMsg_CORBA
CX_REMOTEMSG_RECEIVER_CORBA_var receiver = CX_REMOTEMSG_RECEIVER_CORBA::_narrow(obj.in());
receiver->AcceptMsg_CORBA(message, stack);A ClassiX® instance has to generate a Remote- or a CORBA Manager and call the respective EnableRemoteMsg method of these objects before CORBA messages get processed or messages can be sent via CORBA. These objects SendMsg methods are being used to send messages. Since CORBA is only one of many possible interfaces for message-based communication, the ClassiX® programming interface got split up into two parts. One part, which makes the basic function of all network interfaces usable (the remote manager) and one further part, which provides the specific CORBA functionality. That way, the InstantView programmer can often ignore the concrete network interface - the business operations are implemented in the same way.
As an example it will be shown here, how to receive a list of ClassiX® instances on the network using the CORBA manager. Core operation is calling the CORBA manager RemoteClient method. This method returns a vector of instances, which have been registered in the CORBA naming service.
The example shows, how this vector gets run through and how the instance, which identifies the local ClassiX®, gets picked. For this, the variable 'thisComputer' got allocated with the computer name (GetComputerName), and 'thisPID' with the process ID (GetPID). Furthermore, it is assumed, that the local instance has been registered according to the scheme above, so that the CORBA name in fact includes computer name and PID.
Var(CorbaManager)
GetManager(CORBA) -> CorbaManager
CorbaManager Call(RemoteClients) #
iterate {
Dup thisComputer StringFind if {
// found 'thisComputer'-substring
Dup thisPID StringFind if {
// found 'thisPID'-substring
break // found the right string
}
}
Drop // wrong name
}
// store the correct name
-> thisComputer
After executing this code, 'thisComputer' includes no longer the computer name, but instead the ClassiX® instance CORBA name.
_________________________________________________________________________________________________________________________________
1 In the future, it is also possible to implement transmission of other InstantView types, such as vectors and ZERO objects.
Last changed on 2007-05-04