/***************************************
 *                                     *
 *  JBoss: The OpenSource J2EE WebOS   *
 *                                     *
 *  Distributable under LGPL license.  *
 *  See terms of license at gnu.org.   *
 *                                     *
 ***************************************/
package org.jboss.remoting.transport.local;

import org.jboss.remoting.AbstractInvoker;
import org.jboss.remoting.ConnectionFailedException;
import org.jboss.remoting.InvocationRequest;
import org.jboss.remoting.InvokerLocator;
import org.jboss.remoting.InvokerRegistry;
import org.jboss.remoting.ServerInvoker;
import org.jboss.remoting.marshal.Marshaller;
import org.jboss.remoting.marshal.UnMarshaller;
import org.jboss.remoting.transport.ClientInvoker;

/**
 * LocalClientInvoker does not use any transport protocol for invoking
 * the ServerInvoker, instead will make call directly on it locally.
 * This increases performance since no serialization required as well
 * as needed for push callbacks where InvokerCallbackHandler is in
 * same JVM as the callback server.
 *
 * @author <a href="mailto:telrod@vocalocity.net">Tom Elrod</a>
 * @version $Revision: 1.3.8.2 $
 */
public class LocalClientInvoker extends AbstractInvoker implements ClientInvoker
{
   private ServerInvoker serverInvoker;

   public LocalClientInvoker(InvokerLocator locator)
   {
      super(locator);
   }

   /**
    * transport a request against a remote ServerInvoker
    *
    * @param invocation
    * @return
    * @throws Throwable
    */
   public Object invoke(InvocationRequest invocation) throws Throwable
   {
      if (log.isDebugEnabled())
      {
         log.debug("Using local client invoker for invocation.");
      }

      Object ret = null;
      if (serverInvoker != null)
      {
         ret = serverInvoker.invoke(invocation);
      }
      else
      {
         throw new ConnectionFailedException("Error invoking on server because " +
               "no local server to call upon.");
      }

      return ret;
   }

   /**
    * subclasses must provide this method to return true if their remote connection is connected and
    * false if disconnected.  in some transports, such as SOAP, this method may always return true, since the
    * remote connectivity is done on demand and not kept persistent like other transports (such as socket-based
    * transport).
    *
    * @return boolean true if connected, false if not
    */
   public boolean isConnected()
   {
      return serverInvoker != null;
   }

   /**
    * connect to the remote invoker
    *
    * @throws ConnectionFailedException
    */
   public void connect() throws ConnectionFailedException
   {
      // nothing to be done here.  Should already have reference to serverInvoker
   }

   /**
    * disconnect from the remote invoker.  Once disconnect called
    * will not be able to re-connect by calling connect since will
    * loose reference to server invoker.
    */
   public void disconnect()
   {
      /**
       * Need to remove myself from registry so will not keep
       * reference to me since I am of no use now (since serverInvoker
       * reference is null).  Will have to create a new one.
       */
      InvokerRegistry.destroyClientInvoker(getLocator());
      serverInvoker = null;
   }

   public void setMarshaller(Marshaller marshaller)
   {
      // No op since is local, do not need marshaller
   }

   public Marshaller getMarshaller()
   {
      return null;
   }

   public void setUnMarshaller(UnMarshaller unmarshaller)
   {
      // No op since is local, do not need unmarshaller
   }

   public UnMarshaller getUnMarshaller()
   {
      return null;
   }

   /**
    * This will set the local reference to the server invoker.
    * This is needed to so can make calls directly against server.
    *
    * @param svrInvoker
    */
   public void setServerInvoker(ServerInvoker svrInvoker)
   {
      this.serverInvoker = svrInvoker;
   }
}