|
|
This topic includes the following sections:
Server-to-server communication allows WebLogic Enterprise (WLE) applications to invoke remote objects and handle invocations from those remote objects (referred to as callback objects). The remote objects can be either inside or outside of a WLE domain.
WebLogic Enterprise (WLE) RMI supports client-to-server, client-to-client, and server-to-client invocations, with callbacks from server-side objects to clients. Clients can be applets or full Java client applications.
In simple usage, client applications invoke methods on a remote object. The server applications implement the methods of the remote object. The remote objects in the server application live within the WLE domain that supports security and transactions. These remote objects in the server application are referred to as WLE objects.
Server applications can act as client applications of other server applications. Server-to-server communication allows client applications to act as server applications for requests from other client applications or from WLE server applications.
The server-to-server communication functionality is available through a callback object. A callback object has two purposes:
Understanding Server-to-Server Communication
Joint Client/Server Applications
Callback objects are not subject to WLE administration, they should be used when transactional behavior, security, reliability, and scalability are not important.
Callback objects are implemented in joint client/server applications. A joint client/server application consists of the following:
Figure 4-1 shows the structure of a joint client/server application.
Joint client/server applications use RMI on IIOP to communicate with the WLE server in an asymmetric fashion. As indicated in the figure, the following operations are executed:
Figure 4-1 Structure of a Joint Client/Server Application
Use of callback objects in Java applets is limited due to Java applet security mechanisms. Any Java applet run-time environment that allows a Java applet to create and listen on sockets (via the proprietary environment or protocol of the Java applet) can act as a joint client/server application. However, if the Java applet run-time environment restricts socket communication, the Java applet cannot act as a joint client/server application.
Joint client/server applications use RMI on IIOP to communicate with the WLE server applications which work in an asymmetric fashion, as shown in Listing 4-1. Joint client/server applications can invoke methods on any callback object, and are not restricted to invoking callback objects implemented in joint client/server applications connected to an ISH. Asymmetric IIOP forces the WLE infrastructure to search for an available ISH to handle the invocation. The ISL controlling the ISH must have been configured with the -O option to support callbacks
For information on the IIOP Server Listener (ISL), see the Administration Guide in WebLogic Enterprise online documentation.
For a more detailed description of asymmetric IIOP, see the CORBA Java Programming Reference in the WebLogic Enterprise online documentation.
For more information about management and configuration on remote client applications, see Managing Remote Client Applications (WLE Systems) in the WebLogic Enterprise online documentation.
Note: A remote joint client/server is a client that implements server objects to be used as callback objects. The server role of the remote joint client/server is considerably less robust than that of a WLE server. Neither the client nor the server has any of the WLE administrative and infrastructure components, such as tmadmin , JNDI registration, and ISL/ISH (hence, none of scalability and reliability attributes of WLE).
In WLE, a particularly useful feature of RMI is that you can use it to do client callbacks from Enterprise Java Bean (EJB) servers. Clients cannot advertise EJB implementations, but they can advertise RMI implementations. So if a client wants to be called back from an EJB instance, it should create an RMI object and pass the reference to the EJB instance. The EJB instance can then invoke the client back by using the RMI reference.
In practical use, being able to use a remote object as a parameter or a return value for a remotely invoked method is convenient for such things as updating the display of an applet in response to server-side events. For example, you could simply export the applet itself as a remote object that registers an interest in server-side events, and whose display changes in response to those events.
Writing source code for RMI applications that use client-side callbacks differs from standard RMI applications in that you have to include some additional code for a client interface. The remote client must implement the client interface. Also, the remote (server) object will now include objects received from the client and method invocations on those objects.
Figure 4-2 shows the structure of an RMI application that uses client callbacks.
Figure 4-3 shows pseudo-code to illustrate the client-server interaction in a callback scenario.
The following sections provide a code example of a simple application that illustrates RMI client callbacks.
Listing 4-1 shows the client interface. The client interface declares two business methods: IsGoodObject
and IsRightValue
.
Listing 4-1
CallbackClientIntf.java - A Client Interface
/* Copyright (c) 1999 BEA Systems, Inc. All Rights Reserved */ The RMI Client Interface
import java.rmi.*;
/**
* CallbackClientIntf interface contains following methods
* IsGoodObject(Obj, Obj): compare 2 objects,
* IsRightValue(long, long): compare 2 longs,
*/
public interface CallbackClientIntf extends Remote
{
public static final String NAME = "CallbackClientIntf";
public boolean IsGoodObject(Object Obj1, Object Obj2) throws RemoteException;
public boolean IsRightValue(long val1, long val2)
throws RemoteException, Exception;
} // end CallbackClientIntf
Listing 4-2 shows the RMI client implementing the client interface.
As shown in the bold code, the client does the following:
public boolean IsGoodObject(Object Obj1, Object Obj2) . .
.
.
public boolean IsRightValue(long val1, long val2) . .
.
.
Object o = getContext(url).lookup(Callback.NAME);
server = (Callback)PortableRemoteObject.narrow(o, Callback.class);
int s = server.register(new CallbackClient());
String errMsg = server.sendObject(new DataObject("dataobj"));
The sendObject method does a callback on the client object.
String errMsg = server.sendLong(12345);
The sendLong method does a callback on the client object.
Listing 4-2 CallbackClient.java - A Client That Implements the Client Interface
/* Copyright (c) 1999 BEA Systems, Inc. All Rights Reserved */
import java.util.Hashtable;
import java.rmi.RemoteException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
/**
* CallbackClient will do following steps:
* 1. server.register(ClientObj): send a client object to server
* 2. server.sendObject(DataObj): send a dataobject to server.
* server invokes ClientObj.IsGoodObject(obj, obj)
* 3. server.sendLong(value): send a long number to server.
* server invokes ClientObj.IsRightValue(val, val)
*/
public class CallbackClient implements CallbackClientIntf
{
static Callback server; // An instance of the CallbackClientIntf
//*************************************************************
// Implement methods of CallbackClientIntf
// Compare 2 objects, this method is for clientobject
public boolean IsGoodObject(Object Obj1, Object Obj2) throws RemoteException
{
return (Obj1.equals(Obj2));
}
// Compare 2 longs, this method is for clientobject
public boolean IsRightValue(long val1, long val2) throws RemoteException
{
return (val1 == val2);
}
//*************************************************************
private static void usage()
{
System.out.println("Usage: java CallbackClient corbaloc://<host>:<port>");
System.exit(1);
}
private static Context getContext(String url) throws NamingException
{
Hashtable env = new Hashtable();
env.put(Context.PROVIDER_URL, url);
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.beasys.jndi.WLEInitialContextFactory");
return new InitialContext(env);
}
public static void main(String argv[])
{
if (argv.length < 1) usage();
String url = argv[0];
try
{
Object o = getContext(url).lookup(Callback.NAME);
server = (Callback)PortableRemoteObject.narrow(o, Callback.class);
}catch(Exception e)
{
System.out.println("exception in lookup server obj" + e);
}
//1: register ClientObject to server
try
{
int s = server.register(new CallbackClient());
if (s == Callback.FAILURE)
{
System.out.println("1. Couldn't send client object to server");
System.exit(1);
}
else
System.out.println("1. Success sending ClientObject to server");
}
catch(Exception e)
{
System.out.println("exception in rmiRegister: "+e);
System.exit(1);
}
//2: invoke business method from server
// send a dataobject to server
try
{
String errMsg = server.sendObject(new DataObject("dataobj"));
if (!errMsg.equals("")) {
System.out.println("2. "+errMsg);
} else {
System.out.println("2. success on send data object to server");
System.out.println(" and server callback client using ClientObject");
}
}
catch(Exception e)
{
System.out.println("exception in sendObject(obj): "+e);
}
//3: invoke business method from server
// send a string to server
try
{
String errMsg = server.sendLong(12345);
if (!errMsg.equals("")) {
System.out.println("3. "+errMsg);
} else {
System.out.println("3. success on send long value to server");
System.out.println(" and server callback client using ClientObject");
}
}
catch(Exception e)
{
System.out.println("Exception in sendLong(value): "+e);
Listing 4-3 shows the RMI remote interface, in which we declare the business methods:
public int register(Object callbackObj) throws RemoteException;
public String sendObject(Object Obj)throws RemoteException;
public String sendLong(long val) throws RemoteException, Exception;
Listing 4-3 Callback.java - A RMI Remote Server Interface
/* Copyright (c) 1999 BEA Systems, Inc. All Rights Reserved */
import java.rmi.*;
/**
* Callback interface contains following methods
* register(callBack): send clientcallback obj to server
* sendObject(Obj): send an object to server
* sendLong(Val): send a long value to server
*/
public interface Callback extends Remote
{
public static final String NAME = "Callback";
public static final int FAILURE = -1;
public static final int SUCCESS = 0;
public int register(Object callbackObj) throws RemoteException;
public String sendObject(Object Obj)throws RemoteException;
public String sendLong(long val) throws RemoteException, Exception;
} // end Callback
Listing 4-4 shows the remote object implementation of the business methods in the RMI remote interface.
Listing 4-4 CallbackImpl.java - A Remote Object that Implements the RMI Remote Interface
/* Copyright (c) 1999 BEA Systems, Inc. All Rights Reserved */
import java.util.Hashtable;
import java.rmi.*;
import java.rmi.server.*;
import javax.naming.*;
/**
* Implements the methods defined in the Callback remote interface.
*/
public class CallbackImpl implements Callback
{
private Object callbackObj; // Object on client to verify parameters.
// remember clientobject sent to server
public int register(Object callbackObj) // throws RemoteException
{
if (callbackObj == null) return Callback.FAILURE;
this.callbackObj = callbackObj;
return Callback.SUCCESS;
}
// send regular dataobject to server
// This method returns empty string on success or else error message.
public String sendObject(Object Obj) throws RemoteException
{
// client call_back
Object tmpObj = new DataObject("dataobj");
if (!(callbackObj instanceof CallbackClientIntf))
return "ClientObject is not instance of CallbackClientIntf at server side";
// client call_back object
if (((CallbackClientIntf)callbackObj).IsGoodObject(Obj, tmpObj))
return "";
else
return "fail on send dataobject to server";
}
// send native type long to server
// This method returns empty string on success or else error message.
public String sendLong(long val) throws RemoteException, Exception
{
// client call_back
if (!(callbackObj instanceof CallbackClientIntf))
return "ClientObject is not instance of CallbackClientIntf at server side";
// client call_back object
if (((CallbackClientIntf)callbackObj).IsRightValue(val, 12345))
return "";
else
return "fail on send long value to server";
}
/**
* The main() method creates an instance of CallbackImpl class
* and invokes the rebind() method of JNDI to register the
* new objects. It registers the objects with the name Callback
* and also inform you that it has successfully completed
* the registration process.
*/
public static void main(String args[])
{
try{
Hashtable env = new Hashtable();
env.put(Context.PROVIDER_URL,"");
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.beasys.jndi.WLEInitialContextFactory");
Context ctx = new InitialContext(env);
ctx.rebind(Callback.NAME, new CallbackImpl());
System.out.println("CallbackImpl created and bound in JNDI to name "
+ Callback.NAME);
}
catch (Exception e)
{
System.out.println("caught exception:"+e);
}
}//end main()
} // end CallbackImpl
If you would like to run the callback example, do the following:
Include these Java source files in your rmi_callback directory.
Include these files in your rmi_callback directory as well. Optionally, you might also want to copy the file cleanup.cmd shown in Listing 4-10. This provides a convenient way to remove generated files after running the example.
javac *.java
java weblogic.rmic CallbackImpl CallbackClient
buildjavaserver testserver.xml
Environment Variable |
Example Setting |
---|---|
For example, on Windows NT:
set TUXCONFIG=D:\work\rmi_callback\tuxconfig
|
tmloadcf -y Callback.ubb tmboot -y java CallbackClient corbaloc://<YourMachineID>
:10000 For example:
java CallbackClient corbaloc://SAMS
:10000 If the example runs successfully, the following messages are displayed on the screen:
1. Success sending ClientObject to server tmshutdown -y
2. success on send data object to server
and server callback client using ClientObject
3. success on send long value to server
and server callback client using ClientObject
The following files are provided for your convenience. You can cut and paste the code for each file into an appropriately named ASCII file, and use the files to build and run the callback example in your WLE environment. The files provided here are:
Notice that this example uses a startup properties file to register RMI implementations at startup. (The Hello World example shown in Getting Started with RMI - a Hello World Example, registers the RMI implementations by means of ServerImpl.java
in a different way.) For more information on using a startup properties file, see Using a Startup Properties File,
Listing 4-5
Callback.ubb
# Copyright (c) 2000 BEA Systems, Inc. All Rights Reserved
*RESOURCES
IPCKEY 80952
MASTER SITE1
MODEL SHM
LDBAL Y
*MACHINES
SAMS LMID=SITE1 #CHANGEME
TUXDIR="d:\wledir" #CHANGEME
APPDIR="d:\work\rmi_callback" #CHANGEME
TUXCONFIG="d:\work\rmi_callback\tuxconfig" #CHANGEME
MAXWSCLIENTS=5
*GROUPS
DEFAULT: LMID=SITE1
STDGRP GRPNO=1 OPENINFO=NONE
*SERVERS
DEFAULT: RESTART=Y MAXGEN=5 REPLYQ=Y CLOPT="-A"
TMSYSEVT SRVGRP=STDGRP SRVID=1 RESTART=Y
TMFFNAME SRVGRP=STDGRP SRVID=2
CLOPT="-A -- -N -M"
TMFFNAME SRVGRP=STDGRP SRVID=3
CLOPT="-A -- -N"
TMFFNAME SRVGRP=STDGRP SRVID=4
CLOPT="-A -- -F"
ISL SRVGRP=STDGRP SRVID=5
CLOPT="-A -- -O -n //SAMS:10000" #CHANGEME
JavaServer SRVGRP=STDGRP SRVID=6
CLOPT="-A -- -M 0 testserver.jar"
*SERVICES
*INTERFACES
Listing 4-6 DataObject.java
/* Copyright (c) 1999 BEA Systems, Inc. All Rights Reserved */
/**
* DataObject is to test WLE RMI client callback
*/
public class DataObject implements java.io.Serializable
{
private String s;
DataObject(String s)
{
this.s = s;
}
public String toString()
{
return s;
}
public boolean equals(Object Obj)
{
return (((DataObject)Obj).s.equals(s));
}
}
Listing 4-7 ServerImpl.java
/* Copyright (c) 1999 BEA Systems, Inc. All Rights Reserved */
import com.beasys.rmi.Startup;
import java.io.*;
import java.util.Properties;
/*
* The ServerImpl class provides code to initialize and stop the server
* invocation. ServerImpl is specified in the buildjavaserver XML input
* file as the name of the server object.
*/
public class ServerImpl extends com.beasys.Tobj.Server {
public boolean initialize(String[] args) {
Properties p = new Properties();
try {
p.load(getClass().getResourceAsStream("startup.properties"));
} catch (IOException ioe) {
ioe.printStackTrace();
return false;
}
try {
Startup.main(p);
return true;
} catch (Exception e) {
return false;
}
}
public void release() {}
}
Listing 4-8 startup.properties
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# SYSTEM STARTUP FILES - Client callback
# ------------------------------------------------
#
# Register a startup class by giving it a virtual name and
# supplying its full pathname.
# weblogic.system.startupClass.[virtual_name]=[full_pathname]
#
# Add arguments for the startup class
# weblogic.system.startupArgs.[virtual_name]=[space separated arguments]
weblogic.system.startupClass.Callback=CallbackImpl
Listing 4-9 TestServer.xml
<?xml version = "1.0" ?>
<!-- Copyright (c) 1999 BEA Systems, Inc.
-->
<!DOCTYPE M3-SERVER SYSTEM "m3.dtd">
<M3-SERVER server-descriptor-name = "testserver.ser"
server-implementation = "ServerImpl" >
<ARCHIVE name = "testserver.jar">
<CLASS name="Callback"/>
<CLASS name="CallbackClientIntf"/>
<CLASS name="DataObject"/>
<CLASS name="Callback_WLStub"/>
<CLASS name="Callback_WLSkel"/>
<CLASS name="CallbackClientIntf_WLStub"/>
<CLASS name="CallbackClientIntf_WLSkel"/>
<CLASS name="CallbackImpl"/>
<FILE name="startup.properties" prefix=""/>
</ARCHIVE>
</M3-SERVER>
Listing 4-10 Cleanup.cmd
rm *.class
rm *.jar
rm *.ser
rm tuxconfig
rm stderr
rm stdout
rm tmsysevt.dat
rm -rf .adm
|
Copyright © 1999 BEA Systems, Inc. All rights reserved.
|