| Client.java |
/***************************************
* *
* JBoss: The OpenSource J2EE WebOS *
* *
* Distributable under LGPL license. *
* See terms of license at gnu.org. *
* *
***************************************/
package org.jboss.remoting;
import EDU.oswego.cs.dl.util.concurrent.Executor;
import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
import EDU.oswego.cs.dl.util.concurrent.ThreadFactory;
import org.jboss.logging.Logger;
import org.jboss.remoting.invocation.InternalInvocation;
import org.jboss.remoting.invocation.OnewayInvocation;
import org.jboss.remoting.marshal.Marshaller;
import org.jboss.remoting.marshal.UnMarshaller;
import org.jboss.remoting.transport.ClientInvoker;
import org.jboss.util.id.GUID;
import java.util.List;
import java.util.Map;
/**
* Client is a convience method for invoking remote methods for a given subsystem
*
* @author <a href="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>
* @author <a href="mailto:telrod@e2technologies.net">Tom Elrod</a>
* @version $Revision: 1.10.8.2 $
*/
public class Client
{
/**
* Indicated the max number of threads used within oneway thread pool.
*/
/**
* Specifies the number of work threads in the pool for
* executing one way invocations on the client.
* Value is 10.
*/
public static final int MAX_NUM_ONEWAY_THREADS = 10;
private static final Logger log = Logger.getLogger(Client.class);
private ClientInvoker invoker;
private ClassLoader classloader;
private String subsystem;
private String sessionId = new GUID().toString();
private static PooledExecutor onewayExecutor;
private static int onewayThreadCounter = 0;
public static final String RAW = "RAW_PAYLOAD";
public Client(InvokerLocator locator) throws Exception
{
this(locator, null);
}
public Client(InvokerLocator locator, String subsystem)
throws Exception
{
this(Thread.currentThread().getContextClassLoader(), locator, subsystem);
}
public Client(ClassLoader cl, InvokerLocator locator, String subsystem)
throws Exception
{
this(cl, InvokerRegistry.createClientInvoker(locator), subsystem);
}
public Client(ClassLoader cl, ClientInvoker invoker, String subsystem)
throws Exception
{
this.classloader = cl;
this.subsystem = subsystem == null ? null : subsystem.toUpperCase();
this.invoker = invoker;
}
/**
* This will set the session id used when making invocations on
* server invokers. There is a default unique id automatically
* generated for each Client instance, so unless you have a good reason to set
* this, do not set this.
*
* @param sessionId
*/
public void setSessionId(String sessionId)
{
this.sessionId = sessionId;
}
public String getSessionId()
{
return this.sessionId;
}
public boolean isConnected()
{
return (this.invoker != null && this.invoker.isConnected());
}
public void connect() throws Exception
{
this.invoker.connect();
}
public void disconnect()
{
this.invoker.disconnect();
}
public ClientInvoker getInvoker()
{
return invoker;
}
public void setInvoker(ClientInvoker invoker)
{
this.invoker = invoker;
}
public String getSubsystem()
{
return subsystem;
}
public void setSubsystem(String subsystem)
{
this.subsystem = subsystem;
}
/**
* This should be set when want to override the default behavior of automatically
* getting s suitable locator. This should be used want want to control what type
* of callbacks to receive (pull or push). Set to null to poll for callback messages.
* This can also be used to receive callbacks using another transport and subsystem,
* if desired.
*
* @param locator
*/
private void setClientLocator(InvokerLocator locator) throws Exception
{
if (invoker != null)
{
invoker.setClientLocator(locator);
}
else
{
throw new Exception("Can not set client locator because client invoker is null.");
}
}
/**
* Invokes the server invoker handler with the payload parameter passed.
* @param param
* @return
* @throws Throwable
*/
public Object invoke(Object param) throws Throwable
{
return invoke(param, null);
}
/**
* invoke the method remotely
*
* @param param - payload for the server invoker handler
* @param metadata - any extra metadata that may be needed by the transport (i.e. GET or POST if using
* http invoker) or if need to pass along extra data to the server invoker handler.
* @return
* @throws Throwable
*/
public Object invoke(Object param, Map metadata)
throws Throwable
{
/**
* Using a local variable for the invoker as work around so don't have
* to sync method (and take performance hit)
* Although this may cause having multiple instances of invoker in existance at
* one time, should avoid having reference changed by another thread while in
* execution path for method.
*/
ClientInvoker localInvoker = invoker;
if (localInvoker != null)
{
if (localInvoker.isConnected() == false)
{
if (log.isDebugEnabled())
{
log.debug("invoke called, but our invoker is disconnected, discarding and fetching another fresh invoker for: " + invoker.getLocator());
}
localInvoker = InvokerRegistry.createClientInvoker(localInvoker.getLocator());
connect();
}
}
else
{
throw new Exception("Can not perform invoke because invoker is null.");
}
Object ret = localInvoker.invoke(new InvocationRequest(sessionId, subsystem, param, metadata, null, null));
this.invoker = localInvoker;
return ret;
}
/**
* Will invoke a oneway call to server without a return object. This should be used when not expecting a
* return value from the server and wish to achieve higher performance, since the client will not wait for
* a return.
* <b>
* This is done one of two ways. The first is to pass true as the clientSide param. This will cause the
* execution of the remote call to be excuted in a new thread on the client side and will return the calling thread
* before making call to server side. Although, this is optimal for performance, will not know about any problems
* contacting server.
* <p/>
* The second, is to pass false as the clientSide param. This will allow the current calling thread to make
* the call to the remote server, at which point, the server side processing of the thread will be executed on
* the remote server in a new executing thread and the client thread will return. This is a little slower, but
* will know that the call made it to the server.
*
* @param param
* @param sendPayload
* @param clientSide
*/
public void invokeOneway(final Object param, final Map sendPayload, boolean clientSide) throws Throwable
{
if (clientSide)
{
Executor executor = getOnewayExecutor();
Runnable onewayRun = new Runnable()
{
public void run()
{
try
{
invoke(param, sendPayload);
}
catch (Throwable e)
{
// throw away exception since can't get it back to original caller
log.error("Error executing client oneway invocation request: " + param, e);
}
}
};
executor.execute(onewayRun);
}
else
{
OnewayInvocation invocation = new OnewayInvocation(param);
invoke(invocation, sendPayload);
}
}
private synchronized static Executor getOnewayExecutor()
{
if (onewayExecutor == null)
{
onewayExecutor = new PooledExecutor(MAX_NUM_ONEWAY_THREADS);
onewayExecutor.setKeepAliveTime(3000);
onewayExecutor.waitWhenBlocked();
onewayExecutor.setThreadFactory(new ThreadFactory()
{
public Thread newThread(Runnable runnable)
{
return new Thread(runnable, "Remoting client oneway " + onewayThreadCounter++);
}
});
}
return onewayExecutor;
}
/**
* Same as calling invokeOneway(Object param, Map sendPayload, boolean clientSide) with
* clientSide param being false. Therefore, client thread will not return till it has made
* remote call.
*
* @param param
* @param sendPayload
*/
public void invokeOneway(Object param, Map sendPayload) throws Throwable
{
invokeOneway(param, sendPayload, false);
}
/**
* Adds the specified handler as a callback listener for pull (sync) callbacks.
* The invoker server will then collect the callbacks for this specific handler.
* The callbacks can be retrieved by calling the getCallbacks() method.
* Note: this will cause the client invoker's client locator to be set to null.
*
* @param callbackHandler
* @throws Throwable
*/
public void addListener(InvokerCallbackHandler callbackHandler) throws Throwable
{
addListener(callbackHandler, null);
}
/**
* Adds the specified handler as a callback listener for push (async) callbacks.
* The invoker server will then callback on this handler (via the server invoker
* specified by the clientLocator) when it gets a callback from the server handler.
* Note: passing a null clientLocator will cause the client invoker's client
* locator to be set to null.
*
* @param callbackHandler
* @param clientLocator
* @throws Throwable
*/
public void addListener(InvokerCallbackHandler callbackHandler,
InvokerLocator clientLocator) throws Throwable
{
addListener(callbackHandler, clientLocator, null);
}
/**
* Adds the specified handler as a callback listener for push (async) callbacks.
* The invoker server will then callback on this handler (via the server invoker
* specified by the clientLocator) when it gets a callback from the server handler.
* Note: passing a null clientLocator will cause the client invoker's client
* locator to be set to null.
*
* @param callbackHandler interface to call on with callback
* @param clientLocator locator for callback server to callback on
* @param callbackHandlerObject will be included in the callback object passed upon callback
* @throws Throwable
*/
public void addListener(InvokerCallbackHandler callbackHandler,
InvokerLocator clientLocator, Object callbackHandlerObject) throws Throwable
{
invoker.setClientLocator(clientLocator);
if (clientLocator != null)
{
Client client = new Client(clientLocator, subsystem);
client.setSessionId(getSessionId());
client.connect();
client.invoke(new InternalInvocation(InternalInvocation.ADDCLIENTLISTENER,
new Object[]{callbackHandler, callbackHandlerObject}),
null);
client.disconnect();
}
// now call server to add listener
invoke(new InternalInvocation(InternalInvocation.ADDLISTENER, null), null);
}
/**
* Removes callback handler as a callback listener from the server (and client in
* the case that it was setup to receive async callbacks). See addListener().
*
* @param callbackHandler
* @throws Throwable
*/
public void removeListener(InvokerCallbackHandler callbackHandler) throws Throwable
{
// connect to the given client locator and remove handler as listener
InvokerLocator locator = invoker.getClientLocator();
if (locator != null) // async callback
{
Client client = new Client(locator, subsystem);
client.setSessionId(getSessionId());
client.connect();
client.invoke(new InternalInvocation(InternalInvocation.REMOVECLIENTLISTENER,
new Object[]{callbackHandler}),
null);
client.disconnect();
}
// now call server to remove listener
invoke(new InternalInvocation(InternalInvocation.REMOVELISTENER, null), null);
}
public List getCallbacks() throws Throwable
{
return (List) invoke(new InternalInvocation(InternalInvocation.GETCALLBACKS, null), null);
}
public void setMarshaller(Marshaller marshaller)
{
if (invoker != null && marshaller != null)
{
invoker.setMarshaller(marshaller);
}
}
public void setUnMarshaller(UnMarshaller unmarshaller)
{
if (invoker != null && unmarshaller != null)
{
invoker.setUnMarshaller(unmarshaller);
}
}
}
| Client.java |