Package Framework.anchored

Source Code of Framework.anchored.ServiceInvoker

/*
Copyright (c) 2003-2008 ITerative Consulting Pty Ltd. All Rights Reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:

o Redistributions of source code must retain the above copyright notice, this list of conditions and
the following disclaimer.
 
o Redistributions in binary form must reproduce the above copyright notice, this list of conditions
and the following disclaimer in the documentation and/or other materials provided with the distribution.
   
o This jcTOOL Helper Class software, whether in binary or source form may not be used within,
or to derive, any other product without the specific prior written permission of the copyright holder

 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


*/
package Framework.anchored;

import java.lang.reflect.Method;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.springframework.remoting.rmi.RmiServiceExporter;

import Framework.AppContextHolder;
import Framework.ErrorMgr;
import Framework.FrameworkUtils;
import Framework.PropertiesMgr;
import Framework.UUIDGen;
import Framework.UsageException;
import Framework.remoting.PluggableRemoteInvocationExecutor;

/**
* The service invoker is a dynamic proxy to an instance of a class. An instance of this class
* will be exposed via RMI (or whatever) and when a method is invoked on the proxy, the <i>invoke</i>
* method on this class will be invoked. This will delegate through to the actual class.
*
*/
public class ServiceInvoker implements MethodInvoker{

  /** The port to use by default for the RMI communications */
  private static final int DEFAULT_RMI_PORT = 1199;
    private static Logger _log = Logger.getLogger(ServiceInvoker.class);
    /** The local RMI Registry to bind services to */
    private static Registry registry;
    /** The port of the local RMI Registry */
    private static int registryPort;

    /**
     * Creates a new RMI Registry on a specified port.The port can be specified by the RMIport
     * property, or by the RMIportRange property, which allows a set of ports to be attempted to
     * be used to communicate with the RMI server.
     * @throws RuntimeException When a registry can not be created on any of the specified ports
     */
    static final synchronized void initLocalRegistry() throws RemoteException {

      if( registry != null ) {
        return;
      }
     
        RemoteException exp = null;
        String portString = null;
        int lowestPort = DEFAULT_RMI_PORT;
        int highestPort = DEFAULT_RMI_PORT;
       
        // TF:09/05/2008:We need to make sure that we use the definition from
        // the properties mgr first, as this will ensure the properties mgr is initialised.
        // Otherwise, it is possible this class will be called from some startup code (eg
        // event manager) and the properties file is not loaded. As this property is normally
        // defined in the properties file, this leads to a null error)
      portString = PropertiesMgr.getProperty("RMIportRange");
      if (portString == null) {
        portString = System.getProperty("RMIportRange");
      }
      // TF:27/04/2009:First, see if there's a "RMIportRange" string that matches \d+-\d+, and
      // use this if there is.
      if (portString != null && portString.matches("\\d+-\\d+")) {
        String[] ports = portString.split("-");
        lowestPort = Integer.parseInt(ports[0]);
        highestPort = Integer.parseInt(ports[1]);
      }
      else {
        // No, or invalid, RMIportRange => Use RMIport if available
            portString = PropertiesMgr.getProperty("RMIport");
            if (portString == null) {
              portString = System.getProperty("RMIport");
            }
            else {
              highestPort = lowestPort = Integer.parseInt(portString);
            }
        }

        for (registryPort = lowestPort; registryPort <= highestPort; registryPort++) {
          try {
            _log.debug("Looking for an RMI Registry on port " + registryPort );
            registry = LocateRegistry.createRegistry(registryPort);
            _log.debug("Created an RMI Registry on port " + registryPort );
            break;
          }
          catch( RemoteException rex ) {
            _log.debug("Failed to create an RMI Registry on port " + registryPort);
             exp = rex;
            registry = null;
          }
        }
       
      if( registry == null ) {
          assert(exp != null);
          if (highestPort == lowestPort) {
          throw new RemoteException("Could not create an RMI Registry on port " + highestPort
              + ". The final exception was " + exp.getLocalizedMessage(), exp);
          }
          else {
          throw new RemoteException("Could not create an RMI Registry on ports "
              + lowestPort + " through to " + highestPort + " (inclusive).  "
              + "The final exception was " + exp.getLocalizedMessage(), exp);
          }
      }
      _log.info("Created an RMI Registry on port " + registryPort);
    }
   
    /**
     * Used for test purposes.
     * @return The RMI Registry all ServiceInvoker objects are exposed on.
     */
    static Registry getRegistry() {
      return registry;
    }
   
    /**
     * Used for test purposes.
     * Clear the RMI Registry that ServiceInvoker objects are exposed on.
     */
    static void clearRegistry() {
      registry = null;
    }
   
    /**
     * Used for test purposes.
     * @return The RMI Registry port that all ServiceInvoker objects are exposed on.
     */
    static int getRegistryPort() {
      return registryPort;
    }

    private Anchorable wrappedObject;
    private int port;
    // TF:17/03/2009:Changed this to keep a reference to the exporter so we can destroy it properly.
    RmiServiceExporter exporter = null;

    /**
     * A unique name for this object in the global scheme of things
     */
    private String objectName = null;

    public ServiceInvoker(Anchorable pObject) {
      this.wrappedObject = pObject;

        UUIDGen uid = new UUIDGen();
        uid.generate();
        this.objectName = "Anchored-" + pObject.getClass().getName() + "-" + uid.asCharPtr();
    }
   
    /**
     * This method will clean up the anchored object once it's finished being used as a server.
     */
    public void destroy() {
      if (exporter != null) {
        try {
          exporter.destroy();
        }
        catch (RemoteException e) {
          _log.error("Could not destroy exporter for " + this.toString(), e);
        }
        exporter = null;
      }
    }

    public void prepareForRemoteCall() {

      if (exporter == null) {
          try {
            initLocalRegistry();
            this.port = registryPort;

            // Now expose the skeleton to the stub over RMI
              // --------------------------------------------
              // create the exporter
              exporter = new RmiServiceExporter();
              //set the object into the exporter
              exporter.setService(this);
              // set the service name
              exporter.setServiceName(this.objectName);
              // set the service interface
              exporter.setServiceInterface(MethodInvoker.class);
              // create a pluggable exporter
              PluggableRemoteInvocationExecutor executor = new PluggableRemoteInvocationExecutor();
              // set the executor in the exporter
              exporter.setRemoteInvocationExecutor(executor);
              // set the RMI registry host
              //PM:31/1/08 host is not needed, localhost is the default
              //exporter.setRegistryHost(System.getProperty("RMIregistry.host"));
              // set the registry port
              // TF:17/03/2009:To control the port this server listens on, use the following line:
              // exporter.setServicePort(serverPort);
              exporter.setRegistry(registry);
              exporter.afterPropertiesSet();
          } catch (RemoteException e) {
              UsageException errorVar = new UsageException("Cannot export object to RMI at ["  + port + "]" , e);
              ErrorMgr.addError(errorVar);
              exporter = null;
              throw errorVar;
          }
      }
    }

    public AppContextHolder invoke(String objectId, String methodId, Object[] args, Map<String, Object>appContext) throws Throwable {
        if (!objectId.equals(objectName)) {
            UsageException errorVar = new UsageException("Expecting object id " + objectName + ", received " + objectId);
            ErrorMgr.addError(errorVar);
            throw errorVar;
        }
        Method invokedMethod = MethodMapper.getMethod(this.wrappedObject.getClass(), methodId);
        _log.debug("Invoking method " + invokedMethod + " on server");
       
        FrameworkUtils.setAppContextValues(appContext);
      Object result = invokedMethod.invoke(this.wrappedObject, args);
        AppContextHolder response = new AppContextHolder(result);

        // Now, for any input, output, etc annotated parameters, copy their values back
      Set<Integer> parameterIndicies = MethodMapper.getOutputParameters(invokedMethod);
      for (Integer parameterIndex : parameterIndicies) {
            response.setParameter("arg" + parameterIndex, args[parameterIndex]);
      }

        return response;
    }

    public String getObjectName() {
        return objectName;
    }

    public int getPort() {
        return port;
    }
   
    @Override
    public String toString() {
      return getClass().getSimpleName() + "[" + getObjectName() + "]";
    }
}

TOP

Related Classes of Framework.anchored.ServiceInvoker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.