Sun ONE Application Server 7, Update 1 Developer's Guide to Clients |
C++ ClientsThis module describes how to develop and deploy C++ clients that uses third-party ORBs.
This module contains the following sections:
Introducing C++ Clients
Sun ONE Application Server relies on the Sun ONE built-in ORB to support access to EJBs via RMI/IIOP. Java programs and other components, such as servlets and applets can use the existing RMI/IIOP support to access EJB components housed in Sun ONE Application Server.
A C++ client can access EJB components via IIOP. However, this can not be achieved using the Sun ONE ORB due to the absence of a Sun ONE ORB for C++ clients. A C++ client requires an ORB implementation on its side; the Sun ONE ORB has only a Java version of the implementation. This forces the C++ client developers to use a third-party ORB on the client side.
Developing a C++ Client
This section describes the steps to develop a C++ client using ORBacus 4.1 runtime and development environment. This C++ client will call methods of an EJB that are deployed to Sun ONE Application Server.
This section describes the following topics:
Configuring C++ Clients to Access Sun ONE Application Server
This section describes how to configure C++ clients to access Sun ONE Application Server. In the code example here, C++ client accesses the third party ORB ORBacus 4.1.
This section presents the following topics:
Software Requirements
The following software are necessary for the development of a C++ client:
SOLARIS:
- Solaris 2.8
- ORBacus 4.1 for C++ on Solaris
- Sun Workshop 6 Update 2 (C++ 5.2)
- Sun ONE Application Server
- JavaTM 2 Platform, Standard Edition (J2SETM platform) 1.4
Windows:
- Windows 2000
- ORBacus 4.1 for C++ on WIN 2000
- VC++ Version 6.0
- Sun ONE Application Server
- J2SE 1.4 for WIN 2000
Preparing for C++ Client Development
You must perform the following tasks before you start developing a C++ client:
- Make sure that all the required software are installed. For more information on the software required for C++ client development, see "Software Requirements".
- Install Java Development Kit (JDK) 1.4.
- Install ORBacus 4.1.
For instructions on installing ORBacus 4.1, see the ORBacus documentation.
- SOLARIS:
Set the PATH to CC (C++ compiler of Sun workshop 6.2), rmic (RMI compiler), idl compiler of ORBacus.
export PATH=<SUNworkshoppath>/SUNWspro/WS6U2/bin:<JDK_HOME>bin::$PATH
export ORBACUS_LICENSE=path to ORBacus 4.1 license file directory/licenses.txt
export LD_LIBRARY_PATH=path to ORBacus home/libWindows:
Set the PATH to cl (VC++ compiler of MicroSoft visual studio), rmic of JDK1.4, idl compiler of ORBacus.
These can be set at the command prompt as follows:
set PATH=C:Programfiles\MicrosoftVisualStudio\VC98·in;
C:\J2SDK_Forte\jdk1.4.0·in;C:\ORBacus_IDL;%PATH%set ORBACUS_LICENSE=path/licenses.txt.
You can also set the PATH from the Environmental Settings dialog box.
- Install Sun ONE Application Server and test for basic functionality.
- Deploy the sample application Cart - BookCartApp.ear.
You can deploy this application using the Administration interface. It is not mandatory to deploy the application, but a recommended step. For detailed information on deploying this application, see the Sun ONE Application Server Administrator's Guide.
Assumptions and Limitations
For Java data types such as, HashTable or other custom Java classes that have to be passed by value, you have to provide native C++ implementation or provide a wrapper over existing C++ implementation of those classes (such as STL) that conforms to the IDL files generated for the Java classes.
Creating a C++ Client
This section describes the procedure to create a C++ client that uses a third party ORB. The developed C++ client application can then be deployed to Sun ONE Application Server. The following are the major steps involved in creating a C++ client:
Generating the IDL Files
- Create a directory for C++ client development. For example:
mkdir cppclient
cd cppclient
- Generate IDL files corresponding to remote and home interfaces of the EJB components, helper classes, and other third party classes used by J2EE applications.
Use the rmic tool, which is part of JDKTM 1.4, for generating IDL files.
Generate the IDL files corresponding to home and remote interface of all the EJB components.
When the IDL files corresponding to home and remote references are generated, the IDL files corresponding to the classes mentioned as part of the method signature are also generated. Thus, the separate IDL generation of those classes are not required. Generate only the classes which do not figure as part of the method signature separately.
For example:
rmic -classpath
instance_dir/applications/j2ee-apps/BookCartApp_1/BookCartAppEjb_jar:install_dir/lib/appserv-ext.jar
-idl samples.rmi_iiop.cpp.ejb.CartHomermic -classpath instance_dir/applications/j2ee-apps/BookCartApp_1/BookCartAppEjb_jar:install_dir/lib/appserv-ext.jar
-idl samples.rmi_iiop.cpp.ejb.Cartrmic -classpath instance_dir/applications/j2ee-apps/BookCartApp_1/BookCartAppEjb_jar:install_dir/lib/appserv-ext.jar
-idl samples.rmi_iiop.cpp.ejb.InterfaceTestClass
-classpath - contains the path to all the classes against which IDL is being generated. If the classes appearing as arguments to the method are part of a different package, include those paths also. Include the path to appserv-ext.jar in the classes.
The generated IDL files will be stored under directories corresponding to the package of the classes.
For example, the Cart.class will be mapped to Cart.idl and will be under /cppclient/samples/rmi_iiop/cpp/ejb/ directory.
Similarly, classes corresponding to JDK are generated under java/lang,java/io,javax/rmi/ejb,org/omg/ and other similar directories.
- Generate the valuetypes corresponding to the classes native to J2SDK.
As mentioned in Step 2, when IDL specific to application classes such as, home interface, remote interface, and other classes part of the application are generated, it also generates the IDLs corresponding to the classes native to the JDK.
The classes of JDK that are serializable get mapped as IDL value types. You have to provide the implementation for these valuetypes using the IDL-to-CPP compiler.
This will create C++ classes corresponding to the classes native to JDK. However, these C++ files have only dummy methods apart from protected methods that have implementation of accessor and modifier methods. If you need to manipulate the C++ objects, you need to add new methods to the generated C++ files.
If the Java class has any member variables, then the value type implementation of that class will have accessor and modifier methods and they are protected. You can add new public methods in the implementation class of valuetypes to access and modify those member variables by calling the corresponding protected methods.
Subsequently, compile these classes to generate an object file or as a shared library. This is a one time effort and you do not require perform for every J2EE application that you develop. You may re-use these implementations.
- Develop the library for the valuetype implementations.
The following steps describe the procedure to develop your own library for the valuetype implementations. All these valuetype implementations can be grouped as a library. This library should contain object files (valuetype implementation), the header(.h) and the IDL (.idl) files.
Modify the IDL files as required by following the guidelines given in the next step.
Generate cpp files for all the IDL files corresponding to the Java classes using the IDL compiler supplied with ORBacus. For example,
idl --impl-all -I. -Iclasspath to IDL files -Iorbacus_home/idl/ -Iorbacus_home/idl/OB *.idl
Implement the valuetype types, if required.
This is required only if you need to manipulate the object. For example, collection classes like Vector, Hashtable, etc., proper implementation has to be provided as lists so that elements can be retrieved and added to the list.
Compile the cpp file to generate an object file or a shared library.
Note Generate the Java language classes before processing other IDL files. Implement all the IDL files corresponding to the JDK before proceeding with application specific IDL files.
- Modify the generated IDL files such as the EJBs, helper classes, and third-party classes corresponding to the application.
The generated IDL files do not compile directly. You need to manually modify the IDL files for generating a CPP file. The list below explains the situations when you need to modify the IDL files:
Note This is not a complete list and you may need to make suitable modification to IDL files for successful generation of IDL files to CPP files.
Delete the duplicate variables defined.
For example, in Employee.idl, employee_ is defined twice as: private::CORBA::WStringValue employee_; attribute::CORBA::WStringValue employee_;
Either of the duplicate entries can be deleted. Deleting the following attribute is recommended:
attribute::CORBA::WStringValue employee_;Change the custom valuetypes to non-custom valuetypes.
For example, Valuetype Exception inherits from Throwable, which is a custom valuetype. Remove the tag custom from the Throwable valuetype definition.
There will be cases where the same IDL file will be included more than once. This will result in improper generation of the CPP files. Comment such multiple includes.
For example, Exception.idl under java/lang has java/lang/Throwable.idl included twice. Comment the second include.
The IDL file may compile even when multiple includes are present. However, the generated CPP file will be incorrect.
There will be cases where other IDL files are included circularly.
Some of the abstract valuetypes would be inheriting from java::io::Serializable. Remove such inheritance.
For example, in InterfaceTest.idl, InterfaceTest is an abstract valuetype and it inherits from java::io::Serializable. Remove this inheritance.
Generating CPP Files from IDL Files
To generate the .cpp files form the .idl files, perform the following steps:
- Go to the path where the IDL files are generated. Include the following paths to the idl command:
The paths are included by the -I option.
- Execute the following command with the paths mentioned in Step 1, with --impl-all options idl_file_name.
For example,
idl --impl-all -Iclasspath_to_java_classes_IDL -I/cppclient -I/orbacus_home/idl/ -I/orbacus_home/idl/OB -I. ComplexObject.idl
You must first include the classpath to Java classes IDL files.
- Execute the above command for all the IDL files corresponding to the application in all the directories.
- Modify the generated classes.
Some of the cpp files should be manually modified. The situations under which modifications are required are given below:
There can be clashes in the namespaces that appear in the code generated from IDL to CPP using the IDL tool.
The following examples illustrate the scenarios:
Example 1
The class, ClassDesc, generated under javax/rmi/CORBA uses the classes such as, CORBA::ValueBase. The class, CORBA::ValueBase, is part of the ORB implementation and is defined under the namespace, CORBA.
ClassDesc is defined under the namespace, javax::rmi::CORBA. If a reference to ValueBase as CORBA::ValueBase is made inside this class, it looks for its definition under the javax::rmi::CORBA namespace.
This fails as it is defined under the namespace CORBA and not javax::rmi::CORBA. To force it to look in the namespace CORBA, change the syntax to javax::rmi::CORBA::ValueBase.
Example 2
In the class example generated under the java/lang directory, there are references to the Exception class.
There are two types of exceptions: CORBA::Exception and java::lang::Exception. Change to java::lang::Exception from CORBA::Exception. These kind of code changes are required for the classes to compile properly.
Note You need not compile the classes corresponding to the skeletons, as they will not be used to implement the valuetypes.
- Implement the valuetypes.
The --impl-all option to the IDL command also generates the code for the valuetype implementation, including the factories for creating the value types. The valuetype implementation will have most of the methods as protected.
Therefore, they cannot be accessed directly and add new methods to the valuetype implementation that are public. These methods call the protected methods to achieve the desired functionality. The client programs will call these newly added methods depending on the functionality.
However, sometimes these public methods are also generated by the IDL. In such cases implementation can be provided in these methods by calling the protected methods without adding new methods.
This type of generation is dependent on whether the variables are defined as private or attribute in the IDL files. For example, Employee.class gets mapped as Employee valuetype. The implementation which is Employee.cpp generated for this valuetype as part of IDL command consists of the method, employee_() as protected. Since this cannot be accessed directly, we have to add getEmployeeName() as a public method in the Employee_impl.cpp and Employee.h. This method calls employee_() method to achieve the functionality of returning the EmployeeName.
Note You may have to add additional methods to achieve specific functionality and to change the state of the object. These are determined by your application design and the required functionality.
- Compile the value type implementations and other generated cpp files. You need to write the makefile to generate a cpp file.
Windows:
Use the /GR option.
- Develop the client program as required by design and functionality.
Include the header files of all the valuetypes. The following code illustrates the steps:
samples::rmi_iiop::cpp::ejb::ComplexObjectFactory_impl
*complexObjectVf = new samples::rmi_iiop::cpp::ejb::ComplexObjectFactory_impl();// initializing the ORB
CORBA::ORB_var orb = CORBA::ORB_init(argc,argv);
// registering the value factories. This is required for //unmarshalling the valuetypes
orb->register_value_factory( samples::rmi_iiop::cpp::ejb::ComplexObject::_OB_id(),complexObjectVf);
Register the valuefactories after orbinit(). The registration of the valuefactories are very essential. If they are not registered, it results in marshalling exceptions and the ORB fails to unmarshall valuetypes.
- Compile and link the client program with the previously generated object files.
Windows
Use /GR option.
- Run the client program.
Provide the NameService URL to the program. You can pass this as the -ORBconfig <config file> property to the client. The configuration file contains the NameService URL as follows:
ooc.orb.service.NameService=corbaloc::green.india.sun.com:1050/NameService
For other ways to pass the NameService URL, refer to the ORBacus documentation.
For example, c++client -ORBconfig = config_file_path/config_file_name
Sample Applications
RMI/IIOP sample applications have been bundled with Sun ONE Application Server. These samples have been augmented with detailed setup instructions for deploying the application to Sun ONE Application Server. The setup documentation and source code are available at the following location:
install_dir/samples/rmi-iiop/