Package org.eclipse.ecf.remoteservice

Source Code of org.eclipse.ecf.remoteservice.AbstractRemoteService$AsyncArgs

/*******************************************************************************
* Copyright (c) 2010 Composent, Inc. and others. All rights reserved. This
* program and the accompanying materials are made available under the terms of
* the Eclipse Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*   Composent, Inc. - initial API and implementation
******************************************************************************/
package org.eclipse.ecf.remoteservice;

import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.*;
import org.eclipse.core.runtime.*;
import org.eclipse.ecf.core.jobs.JobsExecutor;
import org.eclipse.ecf.core.util.ECFException;
import org.eclipse.ecf.internal.remoteservice.Activator;
import org.eclipse.ecf.remoteservice.asyncproxy.*;
import org.eclipse.ecf.remoteservice.events.IRemoteCallCompleteEvent;
import org.eclipse.ecf.remoteservice.events.IRemoteCallEvent;
import org.eclipse.equinox.concurrent.future.*;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceException;
import org.osgi.util.tracker.ServiceTracker;

/**
* Abstract remote service implementation.  Clients may subclass to avoid re-implementing
* methods from IRemoteService.
*
* @since 4.1
*/
//@ProviderType
public abstract class AbstractRemoteService extends AbstractAsyncProxyRemoteService implements IRemoteService, InvocationHandler {

  protected static final Object[] EMPTY_ARGS = new Object[0];

  /**
   * @since 8.2
   */
  protected int futureExecutorServiceMaxThreads = Integer.parseInt(System.getProperty("ecf.remoteservice.futureExecutorServiceMaxThreads", "10")); //$NON-NLS-1$ //$NON-NLS-2$

  /**
   * @since 8.2
   */
  protected ExecutorService futureExecutorService;

  /**
   * @since 8.2
   */
  protected ExecutorService getFutureExecutorService(IRemoteCall call) {
    synchronized (this) {
      if (futureExecutorService == null)
        futureExecutorService = Executors.newFixedThreadPool(futureExecutorServiceMaxThreads);
    }
    return futureExecutorService;
  }

  /**
   * @since 8.2
   */
  protected void setFutureExecutorService(ExecutorService executorService) {
    this.futureExecutorService = executorService;
  }

  /**
   * @since 8.2
   */
  protected IExecutor iFutureExecutor;

  /**
   * @since 8.2
   */
  protected IExecutor getIFutureExecutor(IRemoteCall call) {
    synchronized (this) {
      if (iFutureExecutor == null)
        iFutureExecutor = new JobsExecutor("RSJobs[rsID=" + getRemoteServiceID() + "]"); //$NON-NLS-1$ //$NON-NLS-2$
    }
    return iFutureExecutor;
  }

  /**
   * @since 8.2
   */
  protected void setIFutureExecutor(IExecutor executor) {
    this.iFutureExecutor = executor;
  }

  protected abstract String[] getInterfaceClassNames();

  protected abstract IRemoteServiceID getRemoteServiceID();

  protected abstract IRemoteServiceReference getRemoteServiceReference();

  protected Class loadInterfaceClass(String className) throws ClassNotFoundException {
    return loadInterfaceClass(this.getClass().getClassLoader(), className);
  }

  /**
   * @since 6.0
   */
  protected Class loadInterfaceClass(ClassLoader cl, String className) throws ClassNotFoundException {
    return Class.forName(className, true, cl);
  }

  protected IRemoteService getRemoteService() {
    return this;
  }

  protected long getDefaultTimeout() {
    return IRemoteCall.DEFAULT_TIMEOUT;
  }

  @Override
  protected IFuture callAsync(AbstractAsyncProxyRemoteCall call) {
    return callAsync((IRemoteCall) call);
  }

  public IFuture callAsync(final IRemoteCall call) {
    IExecutor executor = getIFutureExecutor(call);
    if (executor == null)
      throw new ServiceException("iFuture executor is null.  Cannot callAsync remote method=" + call.getMethod()); //$NON-NLS-1$
    return executor.execute(new IProgressRunnable() {
      public Object run(IProgressMonitor monitor) throws Exception {
        return callSync(call);
      }
    }, null);
  }

  @SuppressWarnings("unchecked")
  public Object getProxy() throws ECFException {
    List classes = new ArrayList();
    ClassLoader cl = this.getClass().getClassLoader();
    try {
      // Get clazz from reference
      final String[] clazzes = getInterfaceClassNames();
      for (int i = 0; i < clazzes.length; i++)
        classes.add(loadInterfaceClass(cl, clazzes[i]));
    } catch (final Exception e) {
      ECFException except = new ECFException("Failed to create proxy", e); //$NON-NLS-1$
      logWarning("Exception in remote service getProxy", except); //$NON-NLS-1$
      throw except;
    } catch (final NoClassDefFoundError e) {
      ECFException except = new ECFException("Failed to load proxy interface class", e); //$NON-NLS-1$
      logWarning("Could not load class for getProxy", except); //$NON-NLS-1$
      throw except;
    }
    return getProxy(cl, (Class[]) classes.toArray(new Class[classes.size()]));
  }

  /**
   * @since 6.0
   */
  protected void addRemoteServiceProxyToProxy(List classes) {
    IRemoteServiceReference rsReference = getRemoteServiceReference();
    // add IRemoteServiceProxy interface to set of interfaces supported by this proxy
    if (rsReference != null && rsReference.getProperty(Constants.SERVICE_PREVENT_RSPROXY) == null)
      classes.add(IRemoteServiceProxy.class);
  }

  private boolean nameAlreadyPresent(String className, List classes) {
    for (Iterator i = classes.iterator(); i.hasNext();) {
      Class c = (Class) i.next();
      if (className.equals(c.getName()))
        return true;
    }
    return false;
  }

  /**
   * @since 8.3
   */
  protected List addAsyncProxyClasses(ClassLoader cl, Class[] interfaces) {
    List intfs = Arrays.asList(interfaces);
    List results = new ArrayList();
    if (getRemoteServiceReference().getProperty(Constants.SERVICE_PREVENT_ASYNCPROXY) == null) {
      for (Iterator i = intfs.iterator(); i.hasNext();) {
        Class intf = (Class) i.next();
        String intfName = convertInterfaceNameToAsyncInterfaceName(intf.getName());
        if (intfName != null && !nameAlreadyPresent(intfName, intfs)) {
          Class asyncClass = findAsyncRemoteServiceProxyClass(cl, intf);
          // Only add if async
          if (asyncClass != null && !intfs.contains(asyncClass))
            results.add(asyncClass);
        }
      }
    }
    results.addAll(intfs);
    return results;
  }

  /**
   * @since 6.0
   */
  @SuppressWarnings("unchecked")
  public Object getProxy(ClassLoader cl, Class[] interfaces) throws ECFException {
    // Now add any async p
    List classes = addAsyncProxyClasses(cl, interfaces);

    addRemoteServiceProxyToProxy(classes);
    // create and return proxy
    try {
      return createProxy(cl, (Class[]) classes.toArray(new Class[classes.size()]));
    } catch (final Exception e) {
      ECFException except = new ECFException("Failed to create proxy", e); //$NON-NLS-1$
      logWarning("Exception in remote service getProxy", except); //$NON-NLS-1$
      throw except;
    } catch (final NoClassDefFoundError e) {
      ECFException except = new ECFException("Failed to load proxy interface class", e); //$NON-NLS-1$
      logWarning("Could not load class for getProxy", except); //$NON-NLS-1$
      throw except;
    }
  }

  /**
   * @since 8.0
   */
  public class ProxyClassLoader extends ClassLoader {

    private ClassLoader cl;

    public ProxyClassLoader(ClassLoader cl) {
      this.cl = cl;
    }

    public Class loadClass(String name) throws ClassNotFoundException {
      try {
        return cl.loadClass(name);
      } catch (ClassNotFoundException e) {
        // If the classloader passed in upon construction cannot
        // find the class, then use this bundle's classloader to
        // try to load the class
        Activator a = Activator.getDefault();
        if (a == null)
          throw e;
        BundleContext context = a.getContext();
        if (context == null)
          throw e;
        return context.getBundle().loadClass(name);
      }
    }
  }

  /**
   * @since 8.0
   */
  protected IRemoteServiceProxyCreator getRemoteServiceProxyCreator() {
    ServiceTracker st = new ServiceTracker(Activator.getDefault().getContext(), IRemoteServiceProxyCreator.class, null);
    st.open();
    IRemoteServiceProxyCreator result = (IRemoteServiceProxyCreator) st.getService();
    st.close();
    return result;
  }

  /**
   * @since 6.0
   */
  protected Object createProxy(ClassLoader cl, Class[] classes) {
    IRemoteServiceProxyCreator proxyCreator = getRemoteServiceProxyCreator();
    if (proxyCreator != null)
      return proxyCreator.createProxy(new ProxyClassLoader(cl), classes, this);
    return Proxy.newProxyInstance(new ProxyClassLoader(cl), classes, this);
  }

  protected Object createProxy(Class[] classes) {
    return createProxy(this.getClass().getClassLoader(), classes);
  }

  /**
   * @since 3.3
   */
  protected Class findAsyncRemoteServiceProxyClass(Class c) {
    String proxyClassName = convertInterfaceNameToAsyncInterfaceName(c.getName());
    try {
      return Class.forName(proxyClassName);
    } catch (ClassNotFoundException e) {
      logInfo("No async remote service interface found with name=" + proxyClassName + " for proxy service class=" + c.getName(), e); //$NON-NLS-1$ //$NON-NLS-2$
      return null;
    } catch (NoClassDefFoundError e) {
      logWarning("Async remote service interface with name=" + proxyClassName + " could not be loaded for proxy service class=" + c.getName(), e); //$NON-NLS-1$ //$NON-NLS-2$
      return null;
    }
  }

  /**
   * @since 6.0
   */
  protected Class findAsyncRemoteServiceProxyClass(ClassLoader cl, Class c) {
    String proxyClassName = convertInterfaceNameToAsyncInterfaceName(c.getName());
    if (proxyClassName == null)
      return null;
    try {
      return Class.forName(proxyClassName, true, cl);
    } catch (ClassNotFoundException e) {
      //logInfo("No async remote service interface found with name=" + proxyClassName + " for remote service class=" + c.getName(), e); //$NON-NLS-1$ //$NON-NLS-2$
      return null;
    } catch (NoClassDefFoundError e) {
      logWarning("Async remote service interface with name=" + proxyClassName + " could not be loaded for proxy service class=" + c.getName(), e); //$NON-NLS-1$ //$NON-NLS-2$
      return null;
    }
  }

  protected String convertInterfaceNameToAsyncInterfaceName(String interfaceName) {
    if (interfaceName == null)
      return null;
    String asyncProxyName = (String) getRemoteServiceReference().getProperty(Constants.SERVICE_ASYNC_RSPROXY_CLASS_ + interfaceName);
    if (asyncProxyName != null)
      return asyncProxyName;
    if (interfaceName.endsWith(IAsyncRemoteServiceProxy.ASYNC_INTERFACE_SUFFIX))
      return interfaceName;
    return interfaceName + IAsyncRemoteServiceProxy.ASYNC_INTERFACE_SUFFIX;
  }

  protected Object[] getCallParametersForProxyInvoke(String callMethod, Method proxyMethod, Object[] args) {
    return args == null ? EMPTY_ARGS : args;
  }

  protected long getCallTimeoutForProxyInvoke(String callMethod, Method proxyMethod, Object[] args) {
    return IRemoteCall.DEFAULT_TIMEOUT;
  }

  protected String getCallMethodNameForProxyInvoke(Method method, Object[] args) {
    return method.getName();
  }

  protected Object invokeObject(Object proxy, final Method method, final Object[] args) throws Throwable {
    String methodName = method.getName();
    if (methodName.equals("toString")) { //$NON-NLS-1$
      final String[] clazzes = getInterfaceClassNames();
      String proxyClass = (clazzes.length == 1) ? clazzes[0] : Arrays.asList(clazzes).toString();
      return proxyClass + ".proxy@" + getRemoteServiceID(); //$NON-NLS-1$
    } else if (methodName.equals("hashCode")) { //$NON-NLS-1$
      return new Integer(hashCode());
    } else if (methodName.equals("equals")) { //$NON-NLS-1$
      if (args == null || args.length == 0)
        return Boolean.FALSE;
      try {
        return new Boolean(Proxy.getInvocationHandler(args[0]).equals(this));
      } catch (IllegalArgumentException e) {
        return Boolean.FALSE;
      }
      // This handles the use of IRemoteServiceProxy.getRemoteService method
    } else if (methodName.equals("getRemoteService")) { //$NON-NLS-1$
      return getRemoteService();
    } else if (methodName.equals("getRemoteServiceReference")) { //$NON-NLS-1$
      return getRemoteServiceReference();
    }
    return null;
  }

  protected Object invokeSync(IRemoteCall call) throws ECFException {
    return callSync(call);
  }

  /**
   * @since 8.3
   */
  protected boolean isAsync(Object proxy, Method method, Object[] args) {
    return (Arrays.asList(method.getDeclaringClass().getInterfaces()).contains(IAsyncRemoteServiceProxy.class) || method.getName().endsWith(IAsyncRemoteServiceProxy.ASYNC_METHOD_SUFFIX));
  }

  /**
   * @since 8.3
   */
  protected IRemoteCall createRemoteCall(final String callMethod, final Object[] callParameters, final long callTimeout) {
    return new IRemoteCall() {
      public String getMethod() {
        return callMethod;
      }

      public Object[] getParameters() {
        return callParameters;
      }

      public long getTimeout() {
        return callTimeout;
      }
    };
  }

  public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
    // methods declared by Object
    try {
      // If the method is from Class Object, or from IRemoteServiceProxy
      // then return result
      Object resultObject = invokeObject(proxy, method, args);
      if (resultObject != null)
        return resultObject;
      if (isAsync(proxy, method, args))
        return invokeAsync(method, args);
      // else call synchronously/block and return result
      final String callMethod = getCallMethodNameForProxyInvoke(method, args);
      final Object[] callParameters = getCallParametersForProxyInvoke(callMethod, method, args);
      final long callTimeout = getCallTimeoutForProxyInvoke(callMethod, method, args);
      final IRemoteCall remoteCall = createRemoteCall(callMethod, callParameters, callTimeout);
      return invokeSync(remoteCall);
    } catch (Throwable t) {
      if (t instanceof ServiceException)
        throw t;
      // rethrow as service exception
      throw new ServiceException("Service exception on remote service proxy rsid=" + getRemoteServiceID(), ServiceException.REMOTE, t); //$NON-NLS-1$
    }
  }

  /**
   * @since 8.4
   */
  public class AsyncArgs {
    private IRemoteCallListener listener;
    private Object[] args;
    private Class returnType;

    public AsyncArgs(Object[] originalArgs, Class returnType) {
      this.listener = null;
      this.args = originalArgs;
      this.returnType = returnType;
    }

    public AsyncArgs(IRemoteCallListener listener, Object[] originalArgs) {
      this.listener = listener;
      if (this.listener != null) {
        int asynchArgsLength = originalArgs.length - 1;
        this.args = new Object[asynchArgsLength];
        System.arraycopy(originalArgs, 0, args, 0, asynchArgsLength);
      } else
        this.args = originalArgs;
    }

    public IRemoteCallListener getListener() {
      return listener;
    }

    public Object[] getArgs() {
      return args;
    }

    public Class getReturnType() {
      return returnType;
    }
  }

  /**
   * @since 8.4
   */
  protected RemoteCall getAsyncRemoteCall(String invokeMethodName, Object[] asyncArgs) {
    return new RemoteCall(invokeMethodName, asyncArgs, IRemoteCall.DEFAULT_TIMEOUT);
  }

  /**
   * @since 3.3
   */
  protected Object invokeAsync(final Method method, final Object[] args) throws Throwable {
    final String invokeMethodName = getAsyncInvokeMethodName(method);
    final AsyncArgs asyncArgs = getAsyncArgs(method, args);
    RemoteCall remoteCall = getAsyncRemoteCall(invokeMethodName, asyncArgs.getArgs());
    IRemoteCallListener listener = asyncArgs.getListener();
    return (listener != null) ? callAsyncWithResult(remoteCall, listener) : callFuture(remoteCall, asyncArgs.getReturnType());
  }

  /**
   * @since 8.2
   */
  protected Object callAsyncWithResult(IRemoteCall call, IRemoteCallListener listener) {
    callAsync(call, listener);
    return null;
  }

  /**
   * @since 8.4
   */
  @Override
  protected void callCompletableAsync(AbstractAsyncProxyRemoteCall call, final IAsyncProxyCompletable completable) {
    callAsync((IRemoteCall) call, new IRemoteCallListener() {
      public void handleEvent(IRemoteCallEvent event) {
        if (event instanceof IRemoteCallCompleteEvent) {
          IRemoteCallCompleteEvent cce = (IRemoteCallCompleteEvent) event;
          completable.handleComplete(cce.getResponse(), cce.hadException(), cce.getException());
        }
      }
    });
  }

  /**
   * @since 8.4
   */
  @Override
  protected Future callFutureAsync(AbstractAsyncProxyRemoteCall call) {
    return callFutureAsync((IRemoteCall) call);
  }

  /**
   * @since 8.2
   */
  protected Future callFutureAsync(final IRemoteCall call) {
    ExecutorService executorService = getFutureExecutorService(call);
    if (executorService == null)
      throw new ServiceException("future executor service is null.  .  Cannot callAsync remote method=" + call.getMethod()); //$NON-NLS-1$
    return executorService.submit(new Callable() {
      public Object call() throws Exception {
        return callSync(call);
      }
    });
  }

  /**
   * @since 3.3
   */
  protected AsyncArgs getAsyncArgs(Method method, Object[] args) {
    IRemoteCallListener listener = null;
    Class returnType = method.getReturnType();
    // If the return type is of type java.util.concurrent.Future, then we return
    if (Future.class.isAssignableFrom(returnType) || IFuture.class.isAssignableFrom(returnType))
      return new AsyncArgs(args, returnType);
    // If the provided args do *not* include an IRemoteCallListener then we have a problem
    if (args == null || args.length == 0)
      throw new IllegalArgumentException("Async calls must include a IRemoteCallListener instance as the last argument"); //$NON-NLS-1$
    // Get the last arg
    Object lastArg = args[args.length - 1];
    // If it's an IRemoteCallListener implementer directly, then just cast and return
    if (lastArg instanceof IRemoteCallListener) {
      listener = (IRemoteCallListener) lastArg;
    }
    // If it's an implementation of IAsyncCallback, then create a new listener based upon
    // callback and return
    if (lastArg instanceof IAsyncCallback) {
      listener = new CallbackRemoteCallListener((IAsyncCallback) lastArg);
    }
    // If the last are is not an instance of IRemoteCallListener then there is a problem
    if (listener == null)
      throw new IllegalArgumentException("Last argument must be an instance of IRemoteCallListener"); //$NON-NLS-1$
    return new AsyncArgs(listener, args);
  }

  /**
   * @since 3.3
   */
  protected String getAsyncInvokeMethodName(Method method) {
    String methodName = method.getName();
    return methodName.endsWith(IAsyncRemoteServiceProxy.ASYNC_METHOD_SUFFIX) ? methodName.substring(0, methodName.length() - IAsyncRemoteServiceProxy.ASYNC_METHOD_SUFFIX.length()) : methodName;
  }

  private void logInfo(String message, Throwable e) {
    Activator a = Activator.getDefault();
    if (a != null)
      a.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, message, e));
  }

  protected void logWarning(String string, Throwable e) {
    Activator a = Activator.getDefault();
    if (a != null)
      a.log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, string, e));
  }

  /**
   * @since 8.2
   */
  public void dispose() {
    synchronized (this) {
      if (futureExecutorService != null) {
        futureExecutorService.shutdownNow();
        futureExecutorService = null;
      }
      iFutureExecutor = null;
    }
  }
}
TOP

Related Classes of org.eclipse.ecf.remoteservice.AbstractRemoteService$AsyncArgs

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.