BEA Logo BEA WebLogic Enterprise Release 5.0

  Corporate Info  |  News  |  Solutions  |  Products  |  Partners  |  Services  |  Events  |  Download  |  How To Buy

 

   WLE Doc Home   |   CORBA Programming & Related Topics   |   Previous   |   Next   |   Contents   |   Index

Joint Client/Server Applications

This chapter contains the following topics:

This chapter describes programming requirements for joint client/server applications. For a description of the BEAWrapper package and the Callbacks interface API, see the Javadoc.

Introduction

For either a WebLogic Enterprise client applications or a joint client/server application (that is, a client that can receive and process object invocations), create a Java client main() method. The main() method uses WebLogic Enterprise environmental objects to establish connections, set up security, and start transactions.

WebLogic Enterprise clients invoke operations on objects. In the case of DII, client code creates the DII Request object and then invokes one of two operations on the DII Request. In the case of static invocation, client code performs the invocation by performing what looks like an ordinary Java invocation (which ends up calling code in the generated client stub). Additionally, the client programmer uses ORB interfaces defined by OMG and WebLogic Enterprise environmental objects that are supplied with the WebLogic Enterprise software to perform functions unique to WebLogic Enterprise.

For WebLogic Enterprise joint client/server applications, the client code must be structured so that it can act as a server for callback WebLogic Enterprise objects only. Such clients do not use the TP Framework and are not subject to WebLogic Enterprise system administration. Besides the programming implications, this means that joint client/server applications do not have the same scalability and reliability as WebLogic Enterprise servers, nor do they have the state management and transaction behavior available in the TP Framework. If a user wants to have those characteristics, the application must be structured in such a way that the object implementations are in a WebLogic Enterprise server, rather than in a client.

The following sections describe the mechanisms you use to add callback support to a WebLogic Enterprise client. In some cases, the mechanisms are contrasted with the WebLogic Enterprise server mechanisms that use the TP Framework.

Main Program and Server Initialization

In a WebLogic Enterprise Java server, you use the buildjavaserver command to create the main program for the server. The server main program takes care of all WebLogic Enterprise- and CORBA-related initialization of the server functions. However, since you implement the Server object, you have an opportunity to customize the way in which the server application is initialized and shut down. The server main program automatically invokes methods on the Server object at the appropriate times.

In contrast, for a WebLogic Enterprise joint client/server application (as for a WebLogic Enterprise client), you create the main program and are responsible for all initialization. You do not need to provide a Server object because you have complete control over the main program and you can provide initialization and shutdown code in any way that is convenient.

The specific initialization needed for a joint client/server application is discussed in the section "Servants" on page 11-3.

Servants

Servants (method code) for WebLogic Enterprise joint client/server applications are very similar to servants for WebLogic Enterprise servers. All business logic is written the same way. The differences result from not using the TP Framework, which includes the Server , TP , and Tobj_Servant classes. Therefore, the main difference is that you use CORBA functions directly instead of indirectly through the TP Framework.

In WebLogic Enterprise Java server applications, servants are created dynamically. However, in WebLogic Enterprise joint client/server applications, the user application is responsible for creating a servant before any requests arrive; thus, the Server class is not needed. Typically, the program creates a servant, initializes it, and then activates the object. The process of activation, which associates the servant with an object ID (either user supplied or system generated), results in the creation of an object reference that the server application subsequently can provide to another process. Such an object might be used to handle callbacks. Thus, the servant already exists, and the object is already active, before a request for that object arrives.

Instead of invoking the TP interface to perform certain operations, client servants directly invoke the ORB and the BOA (for clients that are based on the Java JDK ORB). Alternately, since much of the interaction with the ORB and the BOA is the same for all applications, the join client/server library (wleclient.jar ) provides a convenience wrapper object (Callbacks ) that does the same things using a single operation. In addition, the wrapper objects also provide extra POA-like life span policies for ObjectIds , see "Callback Object Models Supported" on page 11-4 and "Preparing Callback Objects using BEAWrapper Callbacks" on page 11-6.

Servant Inheritance from Skeletons

In a WLE client, as well as in a WLE server, a user-written Java implementation class inherits from the same skeleton class name generated by the idltojava compiler. For example, given the IDL:

interface Hospital{ };

The skeleton generated by idltojava contains a skeleton class, _HospitalImplBase , from which the user-written class inherits, as in:

class HospitalImpl extends _HospitalImplBase {};

In a WLE server application, the skeleton class inherits from the TP Framework class com.beasys.Tobj_Servant , which in turn inherits from the CORBA-defined class org.omg.PortableServer.Servant .

The inheritance tree for a callback object implementation in a joint client/server application is different from that of a client. The skeleton class does not inherit from the TP Framework class, but instead inherits from the org.omg.CORBA.DynamicImplementation class, which in turn inherits from the org.omg.CORBA.portable.ObjectImpl class.

Not having the Tobj_Servant class in the inheritance tree for a servant means that the servant does not have the activate_object and deactivate_object methods. In a WLE server application, these methods are invoked by the TP Framework to dynamically initialize and save a servant's state before invoking a method on the servant. For a joint client/server application, user code must explicitly create a servant and initialize a servant's state; therefore, the Tobj_Servant operations are not needed.

Callback Object Models Supported

WebLogic Enterprise software supports the three kinds of callback objects. These object types are described here primarily in terms of their behavioral characteristics rather than in the details about how the ORB and the wrapper classes handle them.

The three kinds of callback objects are:

In C++, these object models are established by using combinations of the following POA policies, which control both the types of objects and the types of object references that are possible:

However, since the ORB used for Java server applications does not provide a POA, the WLE system provides a Callbacks wrapper class that emulates these POA policies.

Preparing Callback Objects using BEAWrapper Callbacks

Because the code to prepare for callback objects is nearly identical for every joint client/server application, and because the Java JDK ORB does not implement a POA, WLE provides a wrapper class in the joint client/server library that is virtually identical to the wrapper class provided in C++. This wrapper class emulates the POA policies needed to support the three types of callback objects.

The following code shows the Callback wrapper interfaces.

package com.beasys.BEAWrapper;

class Callbacks{
public Callbacks ();

public Callbacks (org.omg.CORBA.Object init_orb);

public org.omg.CORBA.Object start_transient (
org.omg.PortableServer.ObjectImpl servant,
java.lang.String rep_id)
throws ServantAlreadyActive,
org.omg.CORBA.BAD_PARAMETER;

public org.omg.CORBA.Object start_persistent_systemid (
org.omg.PortableServer.ObjectImpl servant,
java.lang.String rep_id,
org.omg.CORBA.StringHolder stroid)
throws ServantAlreadyActive,
org.omg.CORBA.BAD_PARAMETER,
org.omg.CORBA.IMP_LIMIT;

public org.omg.CORBA.Object restart_persistent_systemid (
org.omg.PortableServer.ObjectImpl servant,
java.lang.String rep_id,
java.lang.String stroid)
throws ServantAlreadyActive,
ObjectAlreadyActive,
org.omg.CORBA.BAD_PARAMETER,
org.omg.CORBA.IMP_LIMIT;

public org.omg.CORBA.Object start_persistent_userid (
org.omg.PortableServer.ObjectImpl servant,
java.lang.String rep_id,
java.lang.String stroid)
throws ServantAlreadyActive,
ObjectAlreadyActive,
org.omg.CORBA.BAD_PARAMETER,
org.omg.CORBA.IMP_LIMIT;
public void stop_object(
org.omg.PortableServer.ObjectImpl
servant);

public String get_string_oid ()
throws NotInRequest;

public void stop_all_objects();
};

Threading Considerations in the Main Program

When a program acts as both a client and a server in a Java client, those two parts can execute concurrently in different threads. Since Java as an execution environment is inherently multithreaded, there is no reason to invoke the org.omg.CORBA.orb.work_pending and org.omg.CORBA.orb.perform_work methods from a Java client. In fact, if the Java client tries to invoke these methods, these methods throw an org.omg.CORBA.NO_IMPLEMENT exception. The client does not need to invoke the org.omg.CORBA.orb.run method. As in any multithreaded environment, any code that may execute concurrently (client and servant code for a callback) in the client application must be coded to be thread safe. This is a departure from C++ clients, which are currently single-threaded.

Multiple Threads

In Java, the client starts up in the main thread. The client can then set up callback objects via an invocation to any of the (re) start_ xxxx methods provided by the Callbacks wrapper class. The wrapper class handles registering the servant and its associated OID in the ORB's object manager. The application is then free to pass the object reference returned by the (re) start_ xxxx method to an application that needs to call back to the servant.

Note: The ORB requires an explicit invocation to one of the (re) start_ xxxx methods to effectively initialize the servant and create a valid object reference that can be marshaled properly to another application. This is a deviation from the base JDK 1.2 ORB behavior that allows implicit object reference creation via an internal invocation to the orb.connect method when marshaling an object reference, if the application has not yet done so.

Invocations on the callback object are handled by the ORB. As each request is received, the ORB validates the request against the object manager and spawns a thread for that request. Multiple requests can be made simultaneously to the same object because the ORB creates a new thread for each request; that is why the Servant code of the Callback must be written thread safe. As each request terminates, the thread that runs the servant also terminates.

The main client thread can make as many client invocations as necessary. An invocation to the stop_ (all_) object methods merely takes the object out of the object manager's list, thereby preventing any further invocations on it. Any invocation to a stopped object fails as if it never existed.

If the client application needs to retrieve the results of a callback from another thread, the client application must use normal thread synchronization techniques to do so.

If any thread (client main or servant) in the WLE remote-like client application exits, all the client process activity is stopped, and the Java execution environment terminates. We recommend only to invoke the return method to terminate a thread.

Java Client ORB Initialization

A client application must initialize the ORB with the BEA-supplied properties. This is so that the ORB will utilize the BEA-supplied classes and methods that support the Callbacks wrapper class and the Bootstrap object. You can find these classes in wleclient.jar , which is installed in $TUXDIR/udataobj/java/jdk (on Solaris) or %TUXDIR%\udataobj\java\jdk (on Windows NT). The application must set certain system properties to do this, as shown in the following example:

Properties prop = new Properties(System.getProperties());
prop.put("org.omg.CORBA.ORBClass","com.beasys.CORBA.iiop.ORB");
prop.put("org.omg.CORBA.ORBSingletonClass",
"com.beasys.CORBA.idl.ORBSingleton");
System.setProperties(prop);
// Initialize the ORB.
ORB orb = ORB.init(args, prop);

IIOP Support

IIOP is the protocol used for communication between ORBs. IIOP allows ORBs from different vendors to interoperate. For Java server applications, a port number must be supplied at the client for persistent or user ID object reference policies.

Java Applet Support

IIOP support for applets that want to receive callbacks or callouts is limited due to applet security mechanisms. Any applet run-time environment that allows an applet to create and listen on sockets (via their proprietary environment or protocol) will be able to act as WLE joint client/server applications. If the applet run-time environment restricts socket communication, then the applet cannot be a joint client/server application to a WLE application.

Port Numbers for Persistent Object References

WLE Java server applications support only GIOP V1.0, as described in Chapter 13 of the OMG CORBA 2.2 specification.

For a WLE Java remote joint client/server application to support IIOP, the object references created for the server component must contain a host and a port. For transient object references, any port is sufficient and can be obtained by the ORB dynamically; however, this is not sufficient for persistent object references.

Persistent references must be served on the same port after the ORB restarts. That is, the ORB must be prepared to accept requests on the same port with which it created the object reference. Therefore, there must be some way to configure the ORB to use a particular port.

Java clients that expect to act as servers for callbacks of persistent references must now be started with a specified port. This is done by setting the system property org.omg.CORBA.ORBPort, as in the following commands:

For Windows NT:

java -DTOBJADDR=//host:port
-Dorg.omg.CORBA.ORBPort=xxxx
-classpath=%CLASSPATH% client

For Unix:

java -DTOBJADDR=//host:port
-Dorg.omg.CORBA.ORBPort=xxxx
-classpath=$CLASSPATH client

Typically, a system administrator assigns the port number for the client from the user range of port numbers, rather from the dynamic range. This keeps the joint client/server applications from using conflicting ports.

If a WLE remote joint client/server application tries to create a persistent object reference without having set a port (as in the preceding command line), the operation raises an exception, IMP_LIMIT , informing the user that a truly persistent object reference cannot be created.

Callbacks Interface API

For a complete description of the BEAWrapper.Callbacks interface API, see the Javadoc.