Getting started

  1. Download the latest distribution from the SourceForge project site
  2. add the ejoe_0.3.x jar as well as xstream-1.1.3.jar and xpp3-1.1.3.4d_b4_min.jar to the classpath of your project
  3. implement de.netseeker.ejoe.ServerHandler or extend de.netseeker.ejoe.MultiObjectHandler
  4. create and start an instance of de.netseeker.ejoe.EJServer in your backend tier
  5. integrate de.netseeker.ejoe.EJClient into your frontend classes. For webapplications you can use it per request, per session or per global context. Recommended is a per session usage.

implementing a server handler

In this little example we will implement a server handler which will take a java.util.Map as input parameter. The map will contain a class identifier for a fictive class containing your business logic and a map of input objects for that fictive class. Let us assume your fictive class implements the following interface:

public interface Executable
{
	public java.util.Map execute( java.util.Map inputParams );
}
The server handler for that would look like this:
public class MyHandler implements ServerHandler
{
	 public Object handle( Object obj )
	 {
		//we expect a map so we cast the input object statically
		java.util.Map input = (java.util.Map)obj;
		//we expect an indentifier whith the key "ident"
		String ident = (String)input.get("ident");
		//we expect the parameters for our business bean with the key "params"
		java.util.Map params = (java.util.Map)input.get("params");
		try
		{
			//load the specified business class
			Executable exec = (Executable)Class.forName(ident).newInstance();
			//call it's execute method and return the result(s)
			return exec.execute( params );
		}
		catch( Exception e )
		{
			//if an exception occurs in an adapter implementation EJOE will serialize
			//that exception to the client automatically
			throw new RuntimeException ( e.getMessage() );
		}
	 }
}
Easy. Finally there are some things you should be aware of:
  • ServerHandlers MUST be threadsafe
  • ServerHandlers should strictly handle all Exceptions. Throw a RuntimeException if you will inform the client about an unexpected error or just return special identifiers for your errors. (Assumed your client is able to understand those identifiers)

instantiating and starting the server component

Create a new instance of de.netseeker.ejoe.EJServer and start it:

//we will use the server handler implementation from our example above
EJServer server = new EJServer( new MyHandler() );
server.start();
//if you want turn on support for remote classloading
//call server.enableRemoteClassLoading() or enableRemoteClassLoading( int port )
EJServer will now start supporting 20 concurrent connections, listen on port 12577 and allow persistent client connections. If you want use custom values take a look at the other contructors of EJServer.

instantiate and use the client component

Create a instance of de.netseeker.ejoe.EJClient

//create a client bound to a EJOE server on localhost and the default port (12577)
EJClient client = new EJClient("127.0.0.1", EJConstants.EJOE_PORT );
The code above will create a new instance of EJClient bound to a EJOE server on localhost and the default port (12577) using the default (de)serialization mechanism (de.netseeker.ejoe.adapter.XStreamAdapter). There are other contructors to customize the settings for the EJClient:
EJClient() //reads all settings from a file ejoe.properties which must be included in your classpath
public EJClient(String pathToConfigFile) //reads all settings from a custom file
public EJClient(String host, int port, SerializeAdapter adapter) //start the client with a custom serialization mechanism
public EJClient(String host, int port, int classLoaderPort, SerializeAdapter adapter) //same as above just with support for remote classloading
If you want use the configuration via property file, ejoe.properties has the following structure:
ejoe.adapter = somepackage.someadapter
ejoe.host = 127.0.0.1 //address of the EJOE server host
ejoe.port = 8887 // default is 12577
ejoe.compression = false|true //default is false
ejoe.remoteClassloader = false|true //default is false
ejoe.classLoaderPort = 8888 //default is 12578
Use the client:
Map input, params = new java.util.HashMap();
input.put("ident", "yourpackage.yourbusinessbean");
input.put("params", params);
params.put("somekey", somevalue);
params.put("nextkey", nextvalue);
...

Object result = client.execute( input );
//do something with the result - remember that the datatype of "result" is exactly what your business bean
//on the serverside has returned

remote classloading

EJOE contains support for remote classloading. Remote classloading is usually a neccessary feature if your server side returns object type, eg. custom beans, which are not included in the classpath on the clientside. EJOE can't deserialize such custom types without remote classloading. For remote classloading a custom classloader (de.netseeker.ejoe.EJClassLoader) is used. That classloader basically uses the same mechanism as EJClient to retrieve class informations from the server:

It sends the name of the required class to a special EJServer instance (which will get started automatically when you call EJServer.enableRemoteClassLoading() or enableRemoteClassLoading(int port) in your initialization code on serverside) and get's an ByteArray containing the class information back.

To enable remote classloading you must enable remote classloading in EJServer and use either the following constructor:

EJClient(String host, int port, int classLoaderPort, SerializeAdapter adapter)
or you provide a file called ejoe.properties on the client's classpath with:
ejoe.remoteClassloader = true //default is false
ejoe.classLoaderPort = someport //default is 12578, must be the same as EJServer uses for the class loader server
and use the default constructor:
	EJClient()
Be aware that EJClient will change the context classloader of the tread in which the client runs. Usually this is not a problem because the EJClassLoader delegates first to the former context classloader...