Package org.eclipse.ecf.provider.remoteservice.generic

Source Code of org.eclipse.ecf.provider.remoteservice.generic.RegistrySharedObject

/*******************************************************************************
* 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.provider.remoteservice.generic;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.security.*;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.ecf.core.ContainerConnectException;
import org.eclipse.ecf.core.events.*;
import org.eclipse.ecf.core.identity.*;
import org.eclipse.ecf.core.jobs.JobsExecutor;
import org.eclipse.ecf.core.security.IConnectContext;
import org.eclipse.ecf.core.sharedobject.*;
import org.eclipse.ecf.core.sharedobject.events.ISharedObjectActivatedEvent;
import org.eclipse.ecf.core.status.SerializableStatus;
import org.eclipse.ecf.core.util.*;
import org.eclipse.ecf.internal.provider.remoteservice.Activator;
import org.eclipse.ecf.internal.provider.remoteservice.IRemoteServiceProviderDebugOptions;
import org.eclipse.ecf.remoteservice.*;
import org.eclipse.ecf.remoteservice.events.*;
import org.eclipse.equinox.concurrent.future.*;
import org.eclipse.osgi.framework.eventmgr.*;
import org.osgi.framework.InvalidSyntaxException;

public class RegistrySharedObject extends BaseSharedObject implements IRemoteServiceContainerAdapter {

  /**
   * @since 3.3
   */
  protected static final int ADD_REGISTRATION_REQUEST_TIMEOUT = new Integer(System.getProperty("org.eclipse.ecf.provider.remoteservice.addRegistrationRequestTimeout", "7000")).intValue(); //$NON-NLS-1$ //$NON-NLS-2$

  private static int uniqueRequestId = 0;

  private static Integer createNextRequestId() {
    return new Integer(uniqueRequestId++);
  }

  /**
   * registry impl for local remote service registrations
   */
  protected RemoteServiceRegistryImpl localRegistry;
  /**
   * map of registry impls for remote registrys  key:  ID (identifier of remote container), value: RemoteServiceRegistryImpl (copy of remote service registry for remote container
   */
  protected final Map remoteRegistrys = Collections.synchronizedMap(new HashMap());
  /**
   * List of remote service listeners (added to/removed from by addRemoteServiceListener/removeRemoteServiceListener
   */
  protected final List serviceListeners = new ArrayList();
  /**
   * Map of add registration requests.  key:  Integer (unique Request id), value: AddRegistrationRequest
   */
  protected Map addRegistrationRequests = new Hashtable();
  /**
   * Add registration request default timeout
   * @since 3.0
   */
  protected int addRegistrationRequestTimeout = ADD_REGISTRATION_REQUEST_TIMEOUT;
  /**
   * List of invocation requests...instances of Request
   */
  protected List requests = Collections.synchronizedList(new ArrayList());

  /**
   * Connect context to be used for connect.
   * @since 3.0
   */
  protected IConnectContext connectContext;
  /**
   * @since 3.3
   */
  protected final Object rsConnectLock = new Object();
  /**
   * Whether or not we are connected
   * @since 3.3
   */
  protected boolean rsConnected = false;
  /**
   * Add registration request default timeout.
   * @since 3.3
   */
  protected int rsConnectTimeout = ADD_REGISTRATION_REQUEST_TIMEOUT;
  /**
   * ListenerQueue for asynchronously dispatching remote service registration/unregistration
   * events
   * @since 3.3
   */
  private ListenerQueue rsListenerDispatchQueue;
  /**
   * Queue lock so that rsListenerDispatchQueue above can be lazily instantiated
   * @since 3.3
   */
  private final Object rsQueueLock = new Object();

  /**
   * EventManager for the rsListenerDispatchEventManager
   * @since 3.3
   */
  private EventManager rsListenerDispatchEventManager;

  /**
   * @since 3.4
   */
  protected long registryUpdateRequestTimeout = new Long(System.getProperty("org.eclipse.ecf.provider.remoteservice.registryUpdateRequestTimeout", "5000")).longValue(); //$NON-NLS-1$ //$NON-NLS-2$

  private Hashtable pendingUpdateContainers = new Hashtable();
  private List registryUpdateRequests = new ArrayList();

  // system property allowing the executorType to be configured.  Currently types are:  jobs, threads, immediate.
  private static final String DEFAULT_EXECUTOR_TYPE = System.getProperty("org.eclipse.ecf.provider.remoteservice.executorType", "jobs"); //$NON-NLS-1$ //$NON-NLS-2$

  private IExecutor requestExecutor;

  private Object remoteServiceCallPolicyLock = new Object();
  private IRemoteServiceCallPolicy remoteServiceCallPolicy;

  public RegistrySharedObject() {
    //
  }

  // IRemoteServiceContainerAdapter methods
  /**
   * @since 3.4
   */
  public IRemoteServiceReference[] getRemoteServiceReferences(ID target, ID[] idFilter, String clazz, String filter) throws InvalidSyntaxException, ContainerConnectException {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "getRemoteServiceReferences", new Object[] {target, idFilter, clazz, filter}); //$NON-NLS-1$
    final IRemoteFilter remoteFilter = (filter == null) ? null : new RemoteFilterImpl(filter);
    // First, if we need to connect, then do so
    if (target != null)
      connectToRemoteServiceTarget(target);
    // Wait for any pending remote registry updates...whether we've connected or not
    waitForPendingUpdates(idFilter);
    // Now we lookup remote service references
    final List references = new ArrayList();
    // first from remote registrys
    addReferencesFromRemoteRegistrys(idFilter, clazz, remoteFilter, references);
    // then from the local registry
    addReferencesFromLocalRegistry(idFilter, clazz, remoteFilter, references);
    // And we return the result
    final IRemoteServiceReference[] result = (IRemoteServiceReference[]) references.toArray(new IRemoteServiceReference[references.size()]);
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "getRemoteServiceReferences", result); //$NON-NLS-1$
    return (result.length == 0) ? null : result;
  }

  /* (non-Javadoc)
   * @see org.eclipse.ecf.remoteservice.IRemoteServiceContainerAdapter#getRemoteServiceReferences(org.eclipse.ecf.core.identity.ID[], java.lang.String, java.lang.String)
   */
  public IRemoteServiceReference[] getRemoteServiceReferences(ID[] idFilter, String clazz, String filter) throws InvalidSyntaxException {
    try {
      return getRemoteServiceReferences(null, idFilter, clazz, filter);
    } catch (ContainerConnectException e) {
      // can't occur, because first parameter is null
      return null;
    }
  }

  /**
   * @since 3.0
   */
  public IRemoteServiceReference[] getRemoteServiceReferences(ID targetID, String clazz, String filter) throws InvalidSyntaxException, ContainerConnectException {
    return getRemoteServiceReferences(targetID, null, clazz, filter);
  }

  /**
   * @since 3.0
   */
  public IRemoteServiceReference[] getAllRemoteServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
    final IRemoteServiceReference[] result = getRemoteServiceReferences((ID[]) null, clazz, filter);
    if (result == null)
      return null;
    return (result.length == 0) ? null : result;
  }

  /* Begin implementation of IRemoteServiceContainerAdapter public interface */
  /* (non-Javadoc)
   * @see org.eclipse.ecf.remoteservice.IRemoteServiceContainerAdapter#addRemoteServiceListener(org.eclipse.ecf.remoteservice.IRemoteServiceListener)
   */
  public void addRemoteServiceListener(IRemoteServiceListener listener) {
    synchronized (serviceListeners) {
      serviceListeners.add(listener);
    }
  }

  /* (non-Javadoc)
   * @see org.eclipse.ecf.remoteservice.IRemoteServiceContainerAdapter#removeRemoteServiceListener(org.eclipse.ecf.remoteservice.IRemoteServiceListener)
   */
  public void removeRemoteServiceListener(IRemoteServiceListener listener) {
    synchronized (serviceListeners) {
      serviceListeners.remove(listener);
    }
  }

  /**
   * @since 4.1
   */
  protected RemoteServiceImpl createRemoteService(RemoteServiceRegistrationImpl registration) {
    return new RemoteServiceImpl(this, registration);
  }

  /* (non-Javadoc)
   * @see org.eclipse.ecf.remoteservice.IRemoteServiceContainerAdapter#getRemoteService(org.eclipse.ecf.remoteservice.IRemoteServiceReference)
   */
  public IRemoteService getRemoteService(IRemoteServiceReference reference) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "getRemoteService", reference); //$NON-NLS-1$
    final RemoteServiceRegistrationImpl registration = getRemoteServiceRegistrationImpl(reference);
    if (registration == null)
      return null;
    final RemoteServiceImpl remoteService = createRemoteService(registration);
    synchronized (refToImplMap) {
      List remoteServiceImplList = (List) refToImplMap.get(reference);
      if (remoteServiceImplList == null)
        remoteServiceImplList = new ArrayList();
      remoteServiceImplList.add(remoteService);
      refToImplMap.put(reference, remoteServiceImplList);
    }
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "getRemoteService", remoteService); //$NON-NLS-1$
    return remoteService;
  }

  /* (non-Javadoc)
   * @see org.eclipse.ecf.remoteservice.IRemoteServiceContainerAdapter#registerRemoteService(java.lang.String[], java.lang.Object, java.util.Dictionary)
   */
  public IRemoteServiceRegistration registerRemoteService(String[] clazzes, Object service, Dictionary properties) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "registerRemoteService", new Object[] {clazzes, service, properties}); //$NON-NLS-1$
    if (service == null) {
      throw new NullPointerException("service cannot be null"); //$NON-NLS-1$
    }
    final int size = clazzes.length;

    if (size == 0) {
      throw new IllegalArgumentException("service classes list is empty"); //$NON-NLS-1$
    }

    final String[] copy = new String[clazzes.length];
    for (int i = 0; i < clazzes.length; i++) {
      copy[i] = new String(clazzes[i].getBytes());
    }
    clazzes = copy;

    final String invalidService = checkServiceClass(clazzes, service);
    if (invalidService != null) {
      throw new IllegalArgumentException("Service=" + invalidService + " is invalid"); //$NON-NLS-1$ //$NON-NLS-2$
    }
    // Add to local registry
    final RemoteServiceRegistrationImpl reg = new RemoteServiceRegistrationImpl();
    synchronized (localRegistry) {
      reg.publish(this, localRegistry, service, clazzes, properties);
      // Only send add registrations if we are connected
      if (isConnected()) {
        final ID[] targets = getTargetsFromProperties(properties);
        RemoteServiceRegistrationImpl[] regs = new RemoteServiceRegistrationImpl[] {reg};
        if (targets == null)
          sendAddRegistrations(null, null, regs);
        else
          for (int i = 0; i < targets.length; i++)
            sendAddRegistrations(targets[i], null, regs);
      }
    }

    fireRemoteServiceListeners(createRegisteredEvent(reg));
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "registerRemoteService", reg); //$NON-NLS-1$
    return reg;
  }

  // <IRemoteServiceReference,List<RemoteServiceImpl>>
  private Map refToImplMap = new HashMap();

  /* (non-Javadoc)
   * @see org.eclipse.ecf.remoteservice.IRemoteServiceContainerAdapter#ungetRemoteService(org.eclipse.ecf.remoteservice.IRemoteServiceReference)
   */
  public boolean ungetRemoteService(IRemoteServiceReference ref) {
    if (ref == null)
      return false;
    IRemoteServiceID serviceID = ref.getID();
    if (serviceID == null)
      return false;
    synchronized (refToImplMap) {
      List remoteServiceImplList = (List) refToImplMap.remove(ref);
      if (remoteServiceImplList != null) {
        for (Iterator i = remoteServiceImplList.iterator(); i.hasNext();) {
          RemoteServiceImpl rsImpl = (RemoteServiceImpl) i.next();
          if (rsImpl != null)
            rsImpl.dispose();
          i.remove();
        }
        return true;
      }
    }
    return false;
  }

  /**
   * @since 3.0
   */
  public IFuture asyncGetRemoteServiceReferences(final ID[] idFilter, final String clazz, final String filter) {
    IExecutor executor = new JobsExecutor("asyncGetRemoteServiceReferences"); //$NON-NLS-1$
    return executor.execute(new IProgressRunnable() {
      public Object run(IProgressMonitor monitor) throws Exception {
        return getRemoteServiceReferences(idFilter, clazz, filter);
      }
    }, null);
  }

  /**
   * @since 3.4
   */
  public IFuture asyncGetRemoteServiceReferences(final ID target, final ID[] idFilter, final String clazz, final String filter) {
    IExecutor executor = new JobsExecutor("asyncGetRemoteServiceReferences"); //$NON-NLS-1$
    return executor.execute(new IProgressRunnable() {
      public Object run(IProgressMonitor monitor) throws Exception {
        return getRemoteServiceReferences(target, idFilter, clazz, filter);
      }
    }, null);
  }

  /**
   * @since 3.0
   */
  public IFuture asyncGetRemoteServiceReferences(final ID target, final String clazz, final String filter) {
    IExecutor executor = new JobsExecutor("asyncGetRemoteServiceReferences"); //$NON-NLS-1$
    return executor.execute(new IProgressRunnable() {
      public Object run(IProgressMonitor monitor) throws Exception {
        return getRemoteServiceReferences(target, clazz, filter);
      }
    }, null);
  }

  /**
   * @since 3.0
   */
  public Namespace getRemoteServiceNamespace() {
    return IDFactory.getDefault().getNamespaceByName(RemoteServiceNamespace.NAME);
  }

  /**
   * @since 3.0
   */
  public IRemoteFilter createRemoteFilter(String filter) throws InvalidSyntaxException {
    return new RemoteFilterImpl(filter);
  }

  /**
   * @since 3.0
   */
  public IRemoteServiceReference getRemoteServiceReference(IRemoteServiceID serviceId) {
    ID containerID = serviceId.getContainerID();
    if (containerID == null)
      return null;
    RemoteServiceRegistrationImpl registration = null;
    waitForPendingUpdates(new ID[] {containerID});
    ID localContainerID = getLocalContainerID();
    if (containerID.equals(localContainerID)) {
      synchronized (localRegistry) {
        registration = localRegistry.findRegistrationForServiceId(serviceId.getContainerRelativeID());
        if (registration != null)
          return registration.getReference();
      }
    } else {
      synchronized (remoteRegistrys) {
        final ArrayList registrys = new ArrayList(remoteRegistrys.values());
        for (final Iterator i = registrys.iterator(); i.hasNext();) {
          final RemoteServiceRegistryImpl registry = (RemoteServiceRegistryImpl) i.next();
          registration = registry.findRegistrationForServiceId(serviceId.getContainerRelativeID());
        }
      }
    }
    return (registration == null) ? null : registration.getReference();
  }

  /**
   * @since 3.0
   */
  public IRemoteServiceID getRemoteServiceID(ID containerId, long containerRelativeId) {
    if (containerId == null)
      return null;
    ID localContainerID = getLocalContainerID();
    if (containerId.equals(localContainerID)) {
      synchronized (localRegistry) {
        RemoteServiceRegistrationImpl reg = localRegistry.findRegistrationForServiceId(containerRelativeId);
        if (reg != null)
          return reg.getID();
      }
    } else {
      synchronized (remoteRegistrys) {
        final ArrayList registrys = new ArrayList(remoteRegistrys.values());
        for (final Iterator i = registrys.iterator(); i.hasNext();) {
          final RemoteServiceRegistryImpl registry = (RemoteServiceRegistryImpl) i.next();
          RemoteServiceRegistrationImpl reg = registry.findRegistrationForServiceId(containerRelativeId);
          if (reg != null)
            return reg.getID();
        }
      }
    }
    return null;
  }

  /**
   * @since 3.0
   */
  public void setConnectContextForAuthentication(IConnectContext connectContext) {
    this.connectContext = connectContext;
  }

  // End IRemoteServiceContainerAdapter methods

  // ISharedObject overrides

  /* (non-Javadoc)
   * @see org.eclipse.ecf.core.sharedobject.BaseSharedObject#initialize()
   */
  public void initialize() throws SharedObjectInitException {
    super.initialize();
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "initialize"); //$NON-NLS-1$
    ID localContainerID = getLocalContainerID();
    localRegistry = (localContainerID == null) ? new RemoteServiceRegistryImpl() : new RemoteServiceRegistryImpl(localContainerID);
    super.addEventProcessor(new IEventProcessor() {
      public boolean processEvent(Event arg0) {
        if (arg0 instanceof IContainerConnectedEvent) {
          handleContainerConnectedEvent((IContainerConnectedEvent) arg0);
        } else if (arg0 instanceof IContainerDisconnectedEvent) {
          handleContainerDisconnectedEvent((IContainerDisconnectedEvent) arg0);
        } else if (arg0 instanceof IContainerEjectedEvent) {
          handleContainerEjectedEvent((IContainerEjectedEvent) arg0);
        } else if (arg0 instanceof ISharedObjectActivatedEvent) {
          // If it's us that's being activated, then we do something about it
          if (getID().equals(((ISharedObjectActivatedEvent) arg0).getActivatedID()))
            handleRegistryActivatedEvent();
        }
        return false;
      }
    });
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "initialize"); //$NON-NLS-1$
  }

  /* (non-Javadoc)
   * @see org.eclipse.ecf.core.sharedobject.BaseSharedObject#dispose(org.eclipse.ecf.core.identity.ID)
   */
  public void dispose(ID containerID) {
    synchronized (rsQueueLock) {
      if (rsListenerDispatchEventManager != null) {
        rsListenerDispatchEventManager.close();
        rsListenerDispatchEventManager = null;
        rsListenerDispatchQueue = null;
      }
    }
    synchronized (refToImplMap) {
      refToImplMap.clear();
    }
    synchronized (remoteRegistrys) {
      remoteRegistrys.clear();
    }
    synchronized (serviceListeners) {
      serviceListeners.clear();
    }
    synchronized (addRegistrationRequests) {
      addRegistrationRequests.clear();
    }
    synchronized (requests) {
      requests.clear();
    }
    synchronized (pendingUpdateContainers) {
      pendingUpdateContainers.clear();
    }
    synchronized (registryUpdateRequests) {
      registryUpdateRequests.clear();
    }
    synchronized (localRegistry) {
      localRegistry.unpublishServices();
      localRegistryUnregistrationTargets.clear();
    }
    super.dispose(containerID);
  }

  // End ISharedObject overrides
  /**
   * @since 3.3
   */
  protected int getRSConnectTimeout() {
    return rsConnectTimeout;
  }

  /**
   * @since 3.4
   */
  protected long getRegistryUpdateRequestTimeout() {
    return registryUpdateRequestTimeout;
  }

  private void sendRegistryUpdateRequestAndWait(ID targetContainerID) {
    synchronized (registryUpdateRequests) {
      // create request id
      Integer requestId = createNextRequestId();
      // add it to the registryUpdateRequests list
      registryUpdateRequests.add(requestId);
      // send registry update request message to targetContainerID
      sendRegistryUpdateRequest(targetContainerID, requestId);
      // Get timeout
      long timeOut = System.currentTimeMillis() + getRegistryUpdateRequestTimeout();
      while ((timeOut - System.currentTimeMillis()) >= 0) {
        if (!registryUpdateRequests.contains(requestId)) {
          Trace.trace(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.DEBUG, this.getClass(), "sendRegistryUpdateRequestAndWait", "localContainerID=" + getLocalContainerID() + " returning because response received"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
          return;
        }
        try {
          registryUpdateRequests.wait(500);
        } catch (InterruptedException e) {
          return;
        }
      }
      Trace.trace(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.DEBUG, this.getClass(), "sendRegistryUpdateRequestAndWait", "localContainerID=" + getLocalContainerID() + " returning because of timeout"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    }
  }

  private void addReferencesFromRemoteRegistrys(ID[] idFilter, String clazz, IRemoteFilter remoteFilter, List referencesFound) {
    // If no idFilter, then we add all known references from all remote registrys
    if (idFilter == null) {
      synchronized (remoteRegistrys) {
        final ArrayList registrys = new ArrayList(remoteRegistrys.values());
        for (final Iterator i = registrys.iterator(); i.hasNext();) {
          final RemoteServiceRegistryImpl registry = (RemoteServiceRegistryImpl) i.next();
          // Add IRemoteServiceReferences from each remote registry
          addReferencesFromRegistry(clazz, remoteFilter, registry, referencesFound);
        }
      }
      // Otherwise there is a filter
    } else {
      for (int i = 0; i < idFilter.length; i++) {
        ID targetContainerID = idFilter[i];
        // Skip if the targetContainerID is null
        if (targetContainerID == null)
          continue;
        sendRegistryUpdateRequestAndWait(targetContainerID);
        synchronized (remoteRegistrys) {
          RemoteServiceRegistryImpl remoteRegistryForContainer = (RemoteServiceRegistryImpl) remoteRegistrys.get(targetContainerID);
          if (remoteRegistryForContainer != null)
            addReferencesFromRegistry(clazz, remoteFilter, remoteRegistryForContainer, referencesFound);
        }
      }
    }
  }

  private void addReferencesFromLocalRegistry(ID[] idFilter, String clazz, IRemoteFilter remoteFilter, List referencesFound) {
    ID localContainerID = getLocalContainerID();
    if (idFilter == null || Arrays.asList(idFilter).contains(localContainerID)) {
      synchronized (localRegistry) {
        // Add any from local registry
        addReferencesFromRegistry(clazz, remoteFilter, localRegistry, referencesFound);
      }
    }
  }

  /**
   * @since 3.0
   */
  protected int getAddRegistrationRequestTimeout() {
    return addRegistrationRequestTimeout;
  }

  /**
   * @since 3.3 for preventing issues like bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=304427
   */
  protected void connectToRemoteServiceTarget(ID targetID) throws ContainerConnectException {
    ISharedObjectContext context = getContext();
    ID connectedID = context.getConnectedID();
    // If we're already connected to something then we don't need to connect...and we return
    if (connectedID != null)
      return;

    synchronized (rsConnectLock) {
      // we just try to connect to target with our given connectContext
      context.connect(targetID, connectContext);
      // wait to receive connected event
      // Wait until we receive the IContainerConnectedEvent on the shared object thread
      int rsTimeout = getRSConnectTimeout();
      long endTime = System.currentTimeMillis() + rsTimeout;
      while (!rsConnected && (endTime >= System.currentTimeMillis())) {
        try {
          // wait for asynchronous notification of getting connected
          rsConnectLock.wait(rsTimeout / 10);
        } catch (InterruptedException e) {
          throw new ContainerConnectException("No notification of registry connect complete for connect targetID=" + targetID); //$NON-NLS-1$
        }
      }
      if (!rsConnected)
        throw new ContainerConnectException("Could not complete registry connect for targetID=" + targetID); //$NON-NLS-1$
    }
  }

  protected Serializable getAddRegistrationRequestCredentials(AddRegistrationRequest request) {
    return null;
  }

  protected ID[] getTargetsFromProperties(Dictionary properties) {
    if (properties == null)
      return null;
    List results = new ArrayList();
    Object o = properties.get(Constants.SERVICE_REGISTRATION_TARGETS);
    if (o != null) {
      if (o instanceof ID)
        results.add(o);
      if (o instanceof ID[]) {
        ID[] targets = (ID[]) o;
        for (int i = 0; i < targets.length; i++)
          results.add(targets[i]);
      }
    }
    if (results.size() == 0)
      return null;
    return (ID[]) results.toArray(new ID[] {});
  }

  protected ISharedObjectContext getSOContext() {
    return super.getContext();
  }

  /**
   * @since 3.4
   */
  protected void handleRegistryActivatedEvent() {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "handleRegistryActivatedEvent"); //$NON-NLS-1$
    // Only do something with this if we're already connected
    ID[] members = getGroupMemberIDs();
    ID localContainerID = getLocalContainerID();
    ID connectedID = getConnectedID();
    Trace.trace(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.DEBUG, this.getClass(), "handleRegistryActivatedEvent", "localContainerID=" + getLocalContainerID() + ",members=" + Arrays.asList(members)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    // Only do this if we've already been connected
    if (isConnected()) {
      for (int i = 0; i < members.length; i++) {
        // Don't do this for us
        if (!members[i].equals(localContainerID)) {
          // Add the target to the set of pending update containers.  These are the ones we expect
          // to hear from about their registry contents
          addPendingContainers(new ID[] {members[i]});
          // And send a registry update to the given target
          sendRegistryUpdate(members[i]);
          // If we are now connected, then set our registry connected
          if (connectedID.equals(members[i]))
            setRegistryConnected(true);
        }
      }
    }
  }

  /**
   * @since 3.3
   */
  protected void handleContainerEjectedEvent(IContainerEjectedEvent arg0) {
    handleTargetGoneEvent(arg0.getTargetID());
  }

  /**
   * @since 3.4
   */
  protected void clearRemoteRegistrys() {
    List registrations = new ArrayList();
    synchronized (remoteRegistrys) {
      for (Iterator i = remoteRegistrys.keySet().iterator(); i.hasNext();) {
        ID containerID = (ID) i.next();
        RemoteServiceRegistryImpl registry = (RemoteServiceRegistryImpl) remoteRegistrys.get(containerID);
        if (registry != null) {
          removeRemoteRegistry(containerID);
          RemoteServiceRegistrationImpl[] regs = registry.getRegistrations();
          if (regs != null) {
            for (int j = 0; j < regs.length; j++) {
              registry.unpublishService(regs[j]);
              registrations.add(regs[j]);
            }
          }
        }
      }
    }
    for (Iterator i = registrations.iterator(); i.hasNext();) {
      fireRemoteServiceListeners(createUnregisteredEvent((RemoteServiceRegistrationImpl) i.next()));
    }
  }

  private void handleTargetGoneEvent(ID targetID) {
    RemoteServiceRegistrationImpl registrations[] = null;
    synchronized (remoteRegistrys) {
      final RemoteServiceRegistryImpl registry = getRemoteRegistry(targetID);
      if (registry != null) {
        removeRemoteRegistry(targetID);
        registrations = registry.getRegistrations();
        if (registrations != null) {
          for (int i = 0; i < registrations.length; i++) {
            registry.unpublishService(registrations[i]);
          }
        }
      }
    }
    // Remove from pending updates
    removePendingContainers(targetID);

    if (!isConnected())
      setRegistryConnected(false);

    ID localContainerID = getLocalContainerID();
    if (localContainerID == null) {
      synchronized (localRegistry) {
        localRegistry.setContainerID(null);
      }
    }
    // Do notification outside synchronized block
    if (registrations != null) {
      for (int i = 0; i < registrations.length; i++) {
        fireRemoteServiceListeners(createUnregisteredEvent(registrations[i]));
      }
    }
  }

  /**
   * @since 3.3
   */
  protected void setRegistryConnected(boolean connected) {
    synchronized (rsConnectLock) {
      rsConnected = connected;
      rsConnectLock.notify();
    }
  }

  protected void handleContainerDisconnectedEvent(IContainerDisconnectedEvent event) {
    handleTargetGoneEvent(event.getTargetID());
  }

  protected void sendRegistryUpdate(ID targetContainerID) {
    sendRegistryUpdate(targetContainerID, null);
  }

  /**
   * @since 3.4
   */
  protected void sendRegistryUpdate(ID targetContainerID, Integer requestId) {
    synchronized (localRegistry) {
      final RemoteServiceRegistrationImpl registrations[] = localRegistry.getRegistrations();
      sendAddRegistrations(targetContainerID, requestId, registrations);
    }
  }

  private void addPendingContainers(ID[] ids) {
    if (ids == null)
      return;
    ID localContainerID = getLocalContainerID();
    synchronized (pendingUpdateContainers) {
      for (int i = 0; i < ids.length; i++) {
        if (!ids[i].equals(localContainerID)) {
          pendingUpdateContainers.put(ids[i], ids[i]);
        }
      }
    }
  }

  private boolean removePendingContainers(ID id) {
    if (id == null)
      return false;
    ID localContainerID = getLocalContainerID();
    synchronized (pendingUpdateContainers) {
      Object result = pendingUpdateContainers.remove(id);
      Trace.trace(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.DEBUG, this.getClass(), "removePendingContainers", "localContainerID=" + localContainerID + ",REMOVED=" + result + ",pendingUpdateContainers=" + pendingUpdateContainers); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
      pendingUpdateContainers.notify();
      return result != null;
    }
  }

  private boolean anyPending(ID[] idFilter) {
    if (idFilter == null)
      return pendingUpdateContainers.size() > 0;
    for (int i = 0; i < idFilter.length; i++) {
      if (pendingUpdateContainers.containsKey(idFilter[i]))
        return true;
    }
    return false;
  }

  private void waitForPendingUpdates(ID[] idFilter) {
    long timeout = getAddRegistrationRequestTimeout();
    long endTime = System.currentTimeMillis() + timeout;
    synchronized (pendingUpdateContainers) {
      // If there are any requred
      while (anyPending(idFilter) && (endTime >= System.currentTimeMillis())) {
        try {
          pendingUpdateContainers.wait(timeout / 10);
        } catch (InterruptedException e) {
          // just return
          return;
        }
      }
    }
  }

  protected void handleContainerConnectedEvent(IContainerConnectedEvent event) {
    handleTargetConnected(event.getTargetID());
  }

  /**
   * @since 3.4
   */
  protected void handleTargetConnected(ID targetID) {
    Trace.trace(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.DEBUG, this.getClass(), "handleTargetConnected", "localContainerID=" + getLocalContainerID() + ",targetID=" + targetID); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    // Add the target to the set of pending update containers.  These are the ones we expect
    // to hear from about their registry contents
    addPendingContainers(new ID[] {targetID});
    // And send a registry update to the given target
    sendRegistryUpdate(targetID);
    // If we are now connected, then set our registry connected
    if (getConnectedID().equals(targetID))
      setRegistryConnected(true);
  }

  // generic
  private Request createRequest(RemoteServiceRegistrationImpl remoteRegistration, IRemoteCall call, IRemoteCallListener listener) {
    return new Request(this.getLocalContainerID(), remoteRegistration.getServiceId(), RemoteCallImpl.createRemoteCall(null, call.getMethod(), call.getParameters(), call.getTimeout()), listener);
  }

  void doFireRemoteServiceListeners(IRemoteServiceEvent event) {
    List entries;
    synchronized (serviceListeners) {
      entries = new ArrayList(serviceListeners);
    }
    for (final Iterator i = entries.iterator(); i.hasNext();) {
      final IRemoteServiceListener l = (IRemoteServiceListener) i.next();
      l.handleServiceEvent(event);
    }
  }

  protected void fireRemoteServiceListeners(IRemoteServiceEvent event) {
    synchronized (rsQueueLock) {
      if (rsListenerDispatchQueue == null) {
        ID containerID = getLocalContainerID();
        String threadGroupName = "RSRegistry Dispatcher for containerID=" + containerID; //$NON-NLS-1$
        ThreadGroup eventGroup = new ThreadGroup(threadGroupName);
        eventGroup.setDaemon(true);
        rsListenerDispatchEventManager = new EventManager(threadGroupName, eventGroup);
        rsListenerDispatchQueue = new ListenerQueue(rsListenerDispatchEventManager);
        CopyOnWriteIdentityMap listeners = new CopyOnWriteIdentityMap();
        listeners.put(this, this);

        rsListenerDispatchQueue.queueListeners(listeners.entrySet(), new EventDispatcher() {
          public void dispatchEvent(Object eventListener, Object listenerObject, int eventAction, Object eventObject) {
            doFireRemoteServiceListeners((IRemoteServiceEvent) eventObject);
          }
        });
      }
    }
    rsListenerDispatchQueue.dispatchEventAsynchronous(0, event);
  }

  private RemoteServiceRegistrationImpl getRemoteServiceRegistrationImpl(IRemoteServiceReference reference) {
    if (reference instanceof RemoteServiceReferenceImpl) {
      final RemoteServiceReferenceImpl ref = (RemoteServiceReferenceImpl) reference;
      if (!ref.isActive()) {
        return null;
      }
      return ref.getRegistration();
    }
    return null;
  }

  private void addReferencesFromRegistry(String clazz, IRemoteFilter remoteFilter, RemoteServiceRegistryImpl registry, List references) {
    final IRemoteServiceReference[] rs = registry.lookupServiceReferences(clazz, remoteFilter);
    if (rs != null) {
      for (int j = 0; j < rs.length; j++) {
        references.add(rs[j]);
      }
    }
  }

  protected Object callSynch(RemoteServiceRegistrationImpl registration, IRemoteCall call) throws ECFException {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "callSynch", new Object[] {registration, call}); //$NON-NLS-1$
    boolean doneWaiting = false;
    Response response = null;
    try {
      // First send request
      final Request request = sendCallRequest(registration, call);
      long requestId = request.getRequestId();
      Trace.trace(Activator.PLUGIN_ID, "callSync request sent with requestid=" + requestId); //$NON-NLS-1$
      // Then get the specified timeout and calculate when we should
      // timeout in real time
      final long timeout = call.getTimeout() + System.currentTimeMillis();
      // Now loop until timeout time has elapsed
      while ((timeout - System.currentTimeMillis()) > 0 && !doneWaiting) {
        synchronized (request) {
          if (request.isDone()) {
            Trace.trace(Activator.PLUGIN_ID, "callSynch.request/response done for requestId=" + requestId); //$NON-NLS-1$
            doneWaiting = true;
            response = request.getResponse();
            if (response == null)
              throw new ECFException("Invalid response for requestId=" + requestId); //$NON-NLS-1$
          } else {
            Trace.trace(Activator.PLUGIN_ID, "Waiting " + RESPONSE_WAIT_INTERVAL + " for response to request: " + requestId); //$NON-NLS-1$ //$NON-NLS-2$
            request.wait(RESPONSE_WAIT_INTERVAL);
          }
        }
      }
      if (!doneWaiting)
        throw new ECFException("Request timed out after " + Long.toString(call.getTimeout()) + "ms", new TimeoutException(call.getTimeout())); //$NON-NLS-1$ //$NON-NLS-2$
    } catch (final IOException e) {
      log(CALL_REQUEST_ERROR_CODE, CALL_REQUEST_ERROR_MESSAGE, e);
      throw new ECFException("Error sending request", e); //$NON-NLS-1$
    } catch (final InterruptedException e) {
      log(CALL_REQUEST_TIMEOUT_ERROR_CODE, CALL_REQUEST_TIMEOUT_ERROR_MESSAGE, e);
      throw new ECFException("Wait for response interrupted", e); //$NON-NLS-1$
    }
    // Success...now get values and return
    Object result = null;
    if (response.hadException())
      throw new ECFException("Exception in remote call", response.getException()); //$NON-NLS-1$
    result = response.getResponse();

    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "callSynch", result); //$NON-NLS-1$
    return result;

  }

  protected void fireCallStartEvent(IRemoteCallListener listener, final long requestId, final IRemoteServiceReference reference, final IRemoteCall call) {
    if (listener != null) {
      listener.handleEvent(new IRemoteCallStartEvent() {
        public long getRequestId() {
          return requestId;
        }

        public IRemoteCall getCall() {
          return call;
        }

        public IRemoteServiceReference getReference() {
          return reference;
        }

        public String toString() {
          final StringBuffer buf = new StringBuffer("IRemoteCallStartEvent["); //$NON-NLS-1$
          buf.append(";reference=").append(reference).append(";call=").append(call).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
          return buf.toString();
        }
      });
    }
  }

  protected void fireCallCompleteEvent(IRemoteCallListener listener, final long requestId, final Object response, final boolean hadException, final Throwable exception) {
    if (listener != null) {
      listener.handleEvent(new IRemoteCallCompleteEvent() {
        public long getRequestId() {
          return requestId;
        }

        public Throwable getException() {
          return exception;
        }

        public Object getResponse() {
          return response;
        }

        public boolean hadException() {
          return hadException;
        }

        public String toString() {
          final StringBuffer buf = new StringBuffer("IRemoteCallCompleteEvent["); //$NON-NLS-1$
          buf.append(";response=").append(response).append(";hadException=").append(hadException).append(";exception=").append(exception).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
          return buf.toString();
        }
      });
    }
  }

  static String checkServiceClass(final String[] clazzes, final Object serviceObject) {
    final ClassLoader cl = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
      public Object run() {
        return serviceObject.getClass().getClassLoader();
      }
    });
    for (int i = 0; i < clazzes.length; i++) {
      try {
        final Class serviceClazz = cl == null ? Class.forName(clazzes[i]) : cl.loadClass(clazzes[i]);
        if (!serviceClazz.isInstance(serviceObject)) {
          return clazzes[i];
        }
      } catch (final ClassNotFoundException e) {
        // This check is rarely done
        if (extensiveCheckServiceClass(clazzes[i], serviceObject.getClass())) {
          return clazzes[i];
        }
      }
    }
    return null;
  }

  private static boolean extensiveCheckServiceClass(String clazz, Class serviceClazz) {
    if (clazz.equals(serviceClazz.getName())) {
      return false;
    }
    final Class[] interfaces = serviceClazz.getInterfaces();
    for (int i = 0; i < interfaces.length; i++) {
      if (!extensiveCheckServiceClass(clazz, interfaces[i])) {
        return false;
      }
    }
    final Class superClazz = serviceClazz.getSuperclass();
    if (superClazz != null) {
      if (!extensiveCheckServiceClass(clazz, superClazz)) {
        return false;
      }
    }
    return true;
  }

  /**
   * Message send and handlers
   */
  private static final String FIRE_REQUEST = "handleFireRequest"; //$NON-NLS-1$

  private static final String FIRE_REQUEST_ERROR_MESSAGE = "exception sending fire request message"; //$NON-NLS-1$

  private static final int FIRE_REQUEST_ERROR_CODE = 202;

  private static final String CALL_REQUEST = "handleCallRequest"; //$NON-NLS-1$

  private static final String CALL_REQUEST_ERROR_MESSAGE = "exception sending call request message"; //$NON-NLS-1$

  private static final int CALL_REQUEST_ERROR_CODE = 203;

  private static final String CALL_REQUEST_TIMEOUT_ERROR_MESSAGE = "timeout for remote call"; //$NON-NLS-1$

  private static final int CALL_REQUEST_TIMEOUT_ERROR_CODE = 204;

  private static final String UNREGISTER = "handleUnregister"; //$NON-NLS-1$

  private static final String UNREGISTER_ERROR_MESSAGE = "exception sending service unregister message"; //$NON-NLS-1$

  private static final int UNREGISTER_ERROR_CODE = 206;

  private static final int MSG_INVOKE_ERROR_CODE = 207;

  private static final String CALL_RESPONSE = "handleCallResponse"; //$NON-NLS-1$

  private static final String CALL_RESPONSE_ERROR_MESSAGE = "Exception sending response"; //$NON-NLS-1$

  private static final int CALL_RESPONSE_ERROR_CODE = 210;

  private static final String REQUEST_NOT_FOUND_ERROR_MESSAGE = "request not found for response"; //$NON-NLS-1$

  private static final int REQUEST_NOT_FOUND_ERROR_CODE = 211;

  private static final long RESPONSE_WAIT_INTERVAL = 5000;

  private static final String ADD_REGISTRATION = "handleAddRegistration"; //$NON-NLS-1$

  private static final String ADD_REGISTRATIONS = "handleAddRegistrations"; //$NON-NLS-1$

  private static final String ADD_REGISTRATION_ERROR_MESSAGE = "exception sending add service registration message"; //$NON-NLS-1$

  private static final int ADD_REGISTRATION_ERROR_CODE = 212;

  private static final String ADD_REGISTRATION_REFUSED = "handleAddRegistrationRefused"; //$NON-NLS-1$

  private static final String ADD_REGISTRATION_REFUSED_ERROR_MESSAGE = "Error sending addRegistration refused"; //$NON-NLS-1$

  private static final int ADD_REGISTRATION_REFUSED_ERROR_CODE = 214;

  private static final String REQUEST_SERVICE = "handleRequestService"; //$NON-NLS-1$

  private static final int REQUEST_SERVICE_ERROR_CODE = 213;

  private static final String REQUEST_SERVICE_ERROR_MESSAGE = "Error sending requestServiceReference"; //$NON-NLS-1$

  private static final String REGISTRY_UPDATE_REQUEST = "handleRegistryUpdateRequest"; //$NON-NLS-1$

  /**
   * @since 3.4
   */
  protected void sendRegistryUpdateRequest(ID receiver, Integer requestId) {
    ID localContainerID = getLocalContainerID();
    Trace.trace(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.DEBUG, this.getClass(), "sendRegistryUpdateRequest", "localContainerID=" + localContainerID + ",targetContainerID=" + receiver + ",requestId=" + requestId); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
    try {
      sendSharedObjectMsgTo(receiver, SharedObjectMsg.createMsg(null, REGISTRY_UPDATE_REQUEST, new Object[] {localContainerID, requestId}));
    } catch (IOException e) {
      log(ADD_REGISTRATION_ERROR_CODE, "Exception sending registry update request/2 message", e); //$NON-NLS-1$
    }
  }

  /**
   * @since 3.4
   */
  protected void handleRegistryUpdateRequest(ID remoteContainerID, Integer requestId) {
    Trace.trace(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.DEBUG, this.getClass(), "handleRegistryUpdateRequest", "localContainerID=" + getLocalContainerID() + ",remoteContainerID=" + remoteContainerID + ",requestId=" + requestId); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
    sendRegistryUpdate(remoteContainerID, requestId);
  }

  protected void sendRegistryUpdateRequest() {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "sendRegistryUpdateRequest"); //$NON-NLS-1$
    try {
      sendSharedObjectMsgTo(null, SharedObjectMsg.createMsg(REGISTRY_UPDATE_REQUEST, getLocalContainerID()));
    } catch (final IOException e) {
      log(CALL_RESPONSE_ERROR_CODE, CALL_RESPONSE_ERROR_MESSAGE, e);
    }
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "sendRegistryUpdateRequest"); //$NON-NLS-1$
  }

  protected void handleRegistryUpdateRequest(ID remoteContainerID) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), REGISTRY_UPDATE_REQUEST);
    if (remoteContainerID == null)
      return;
    sendRegistryUpdate(remoteContainerID);
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), REGISTRY_UPDATE_REQUEST);
  }

  private boolean removeRegistryUpdateRequest(Integer requestId) {
    if (requestId == null)
      return false;
    synchronized (registryUpdateRequests) {
      boolean result = registryUpdateRequests.remove(requestId);
      Trace.trace(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.DEBUG, this.getClass(), "removeRegistryUpdateRequest", "localContainerID=" + getLocalContainerID() + ", REMOVED requestId=" + requestId); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
      registryUpdateRequests.notify();
      return result;
    }
  }

  protected AddRegistrationRequest sendAddRegistrationRequest(ID receiver, AddRegistrationRequest request, Serializable credentials) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "sendAddRegistrationRequest", new Object[] {receiver, request, credentials}); //$NON-NLS-1$
    Assert.isNotNull(receiver);
    Assert.isNotNull(request);
    try {
      sendSharedObjectMsgTo(receiver, SharedObjectMsg.createMsg(null, REQUEST_SERVICE, new Object[] {getLocalContainerID(), request, request.getId(), credentials}));
    } catch (final IOException e) {
      log(REQUEST_SERVICE_ERROR_CODE, REQUEST_SERVICE_ERROR_MESSAGE, e);
    }
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "sendAddRegistrationRequest"); //$NON-NLS-1$
    return request;
  }

  protected void checkRequestServiceAuthorization(ID remoteContainerID, AddRegistrationRequest request, Serializable credentials) throws AccessControlException {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "checkRequestServiceAuthorization", new Object[] {remoteContainerID, request, credentials}); //$NON-NLS-1$
    return;
  }

  protected void handleRequestService(ID remoteContainerID, AddRegistrationRequest request, Integer requestId, Serializable credentials) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "handleRequestServiceReference", new Object[] {remoteContainerID, request, requestId, credentials}); //$NON-NLS-1$
    if (remoteContainerID == null || requestId == null)
      return;
    if (request == null)
      return;
    IRemoteFilter rf = null;
    try {
      rf = (request.getFilter() == null) ? null : new RemoteFilterImpl(request.getFilter());
    } catch (InvalidSyntaxException e) {
      // log and set rf to null and ignore
      log("handleRequestService invalid syntax exception for filter", e); //$NON-NLS-1$
      rf = null;
    }
    try {
      checkRequestServiceAuthorization(remoteContainerID, request, credentials);
    } catch (AccessControlException e) {
      // Log and return...i.e. do nothing
      log("handleRequestService. checkRequestServiceAuthorization exception", e); //$NON-NLS-1$
      sendAddRegistrationRequestRefused(remoteContainerID, requestId, e);
      return;
    }
    String service = request.getService();
    synchronized (localRegistry) {
      RemoteServiceRegistrationImpl[] regs = null;
      if (service == null) {
        regs = localRegistry.getRegistrations();
      } else {
        RemoteServiceReferenceImpl[] srs = (RemoteServiceReferenceImpl[]) localRegistry.lookupServiceReferences(request.getService(), rf);
        List regsList = new ArrayList();
        if (srs != null && srs.length > 0) {
          for (int i = 0; i < srs.length; i++) {
            RemoteServiceRegistrationImpl impl = getRemoteServiceRegistrationImpl(srs[i]);
            if (impl != null)
              regsList.add(impl);
          }
        }
        if (regsList.size() > 0) {
          regs = (RemoteServiceRegistrationImpl[]) regsList.toArray(new RemoteServiceRegistrationImpl[] {});
        }
      }
      sendAddRegistrations(remoteContainerID, requestId, regs);
    }
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "handleRequestService"); //$NON-NLS-1$
  }

  protected void sendAddRegistration(ID receiver, RemoteServiceRegistrationImpl reg) {
    sendAddRegistration(receiver, null, reg);
  }

  protected void sendAddRegistration(ID receiver, Integer requestId, RemoteServiceRegistrationImpl reg) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "sendAddRegistration", new Object[] {receiver, requestId, reg}); //$NON-NLS-1$
    try {
      sendSharedObjectMsgTo(receiver, SharedObjectMsg.createMsg(null, ADD_REGISTRATION, getLocalContainerID(), requestId, reg));
    } catch (final IOException e) {
      log(ADD_REGISTRATION_ERROR_CODE, ADD_REGISTRATION_ERROR_MESSAGE, e);
    }
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "sendAddRegistration"); //$NON-NLS-1$
  }

  /**
   * @since 3.3
   */
  protected void sendAddRegistrations(ID receiver, Integer requestId, RemoteServiceRegistrationImpl[] regs) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "sendAddRegistrations", new Object[] {receiver, requestId, regs}); //$NON-NLS-1$
    try {
      sendSharedObjectMsgTo(receiver, SharedObjectMsg.createMsg(null, ADD_REGISTRATIONS, getLocalContainerID(), requestId, regs));
      // if the receiver is in response to an explicit remote request (receiver != null && requestId != null)
      // then for all registrations add a target for unregistration, so that upon unregistration we can
      if (receiver != null && requestId != null) {
        for (int i = 0; i < regs.length; i++)
          addTargetForUnregister(regs[i], receiver);
      }
    } catch (final IOException e) {
      log(ADD_REGISTRATION_ERROR_CODE, ADD_REGISTRATION_ERROR_MESSAGE, e);
    }
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "sendAddRegistrations"); //$NON-NLS-1$
  }

  protected void sendAddRegistrationRequestRefused(ID receiver, Integer requestId, Exception except) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "sendAddRegistrationRequestRefused", new Object[] {receiver, except}); //$NON-NLS-1$
    try {
      sendSharedObjectMsgTo(receiver, SharedObjectMsg.createMsg(null, ADD_REGISTRATION_REFUSED, getLocalContainerID(), requestId, except));
    } catch (final IOException e) {
      log(ADD_REGISTRATION_REFUSED_ERROR_CODE, ADD_REGISTRATION_REFUSED_ERROR_MESSAGE, e);
    }
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "sendAddRegistrationRequestRefused"); //$NON-NLS-1$
  }

  protected void handleAddRegistrationRequestRefused(ID remoteContainerID, Integer requestId, AccessControlException e) {
    if (remoteContainerID == null || requestId == null)
      return;
    // else lookup AddRegistrationRequest and notify
    notifyAddRegistrationResponse(remoteContainerID, requestId, e);
  }

  protected void handleAddRegistration(ID remoteContainerID, final RemoteServiceRegistrationImpl registration) {
    handleAddRegistration(remoteContainerID, null, registration);
  }

  /**
   * @since 3.3
   */
  protected void handleAddRegistrations(ID remoteContainerID, Integer requestId, final RemoteServiceRegistrationImpl[] registrations) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), ADD_REGISTRATIONS, new Object[] {remoteContainerID, registrations});
    ID localContainerID = getLocalContainerID();
    if (remoteContainerID == null || localContainerID == null || localContainerID.equals(remoteContainerID)) {
      return;
    }
    List addedRegistrations = new ArrayList();
    if (registrations != null) {
      synchronized (remoteRegistrys) {
        // Find registry for remoteContainer
        RemoteServiceRegistryImpl registry = getRemoteRegistry(remoteContainerID);
        // If there's not one already then lazily make one and add it
        if (registry == null) {
          registry = new RemoteServiceRegistryImpl(remoteContainerID);
          addRemoteRegistry(registry);
        }
        for (int i = 0; i < registrations.length; i++) {
          RemoteServiceRegistrationImpl[] regs = registry.getRegistrations();
          List regList = Arrays.asList(regs);
          if (!regList.contains(registrations[i])) {
            addedRegistrations.add(registrations[i]);
            registry.publishService(registrations[i]);
          }
        }
      }
    }

    // remove pending containers
    removePendingContainers(remoteContainerID);
    // remove from pending update requests
    if (requestId != null)
      removeRegistryUpdateRequest(requestId);

    for (Iterator i = addedRegistrations.iterator(); i.hasNext();) {
      fireRemoteServiceListeners(createRegisteredEvent((RemoteServiceRegistrationImpl) i.next()));
    }
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), ADD_REGISTRATIONS);
  }

  protected void handleAddRegistration(ID remoteContainerID, Integer requestId, final RemoteServiceRegistrationImpl registration) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), ADD_REGISTRATION, new Object[] {remoteContainerID, registration});
    ID localContainerID = getLocalContainerID();
    if (remoteContainerID == null || localContainerID == null || localContainerID.equals(remoteContainerID)) {
      return;
    }
    boolean added = false;
    synchronized (remoteRegistrys) {
      // Find registry for remoteContainer
      RemoteServiceRegistryImpl registry = getRemoteRegistry(remoteContainerID);
      // If there's not one already then lazily make one and add it
      if (registry == null) {
        registry = new RemoteServiceRegistryImpl(remoteContainerID);
        addRemoteRegistry(registry);
      }
      // publish service in this registry. At this point it's ready to go
      RemoteServiceRegistrationImpl[] regs = registry.getRegistrations();
      List regList = Arrays.asList(regs);
      if (!regList.contains(registration)) {
        added = true;
        registry.publishService(registration);
      }
      notifyAddRegistrationResponse(remoteContainerID, requestId, null);
    }
    // notify IRemoteServiceListeners
    if (added)
      fireRemoteServiceListeners(createRegisteredEvent(registration));
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), ADD_REGISTRATION);
  }

  /**
   * @param requestId
   * @since 3.2
   */
  protected void notifyAddRegistrationResponse(ID remoteContainerID, Integer requestId, AccessControlException exception) {
    if (remoteContainerID == null)
      return;
    if (requestId == null)
      return;
    AddRegistrationRequest request = removeAddRegistrationRequest(requestId);
    if (request != null)
      request.notifyResponse(exception);
  }

  private AddRegistrationRequest removeAddRegistrationRequest(Integer requestId) {
    synchronized (addRegistrationRequests) {
      return (AddRegistrationRequest) addRegistrationRequests.remove(requestId);
    }
  }

  protected Request sendCallRequest(RemoteServiceRegistrationImpl remoteRegistration, final IRemoteCall call) throws IOException {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "sendCallRequest", new Object[] {remoteRegistration, call}); //$NON-NLS-1$
    final Request request = createRequest(remoteRegistration, call, null);
    addRequest(request);
    try {
      sendSharedObjectMsgTo(remoteRegistration.getContainerID(), SharedObjectMsg.createMsg(CALL_REQUEST, request));
    } catch (final IOException e) {
      removeRequest(request);
      throw e;
    }
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "sendCallRequest", request); //$NON-NLS-1$
    return request;
  }

  private IExecutor getRequestExecutor(Request request) {
    if (requestExecutor == null) {
      requestExecutor = createRequestExecutor(request);
    }
    return requestExecutor;
  }

  /**
   * @since 3.4
   */
  protected IExecutor createRequestExecutor(final Request request) {
    IExecutor executor = null;
    if (DEFAULT_EXECUTOR_TYPE.equals("jobs")) { //$NON-NLS-1$
      executor = new JobsExecutor("Remote Request Handler") { //$NON-NLS-1$
        protected String createJobName(String executorName, int jobCounter, IProgressRunnable runnable) {
          return executorName + " - " + request.getCall().getMethod() + ":" + request.getRequestId(); //$NON-NLS-1$ //$NON-NLS-2$
        }
      };
    } else if (DEFAULT_EXECUTOR_TYPE.equals("immediate")) { //$NON-NLS-1$
      executor = new ImmediateExecutor();
    } else if (DEFAULT_EXECUTOR_TYPE.equals("threads")) { //$NON-NLS-1$
      executor = new ThreadsExecutor() {
        protected String createThreadName(IProgressRunnable runnable) {
          return "Remote Request Handler - " + request.getCall().getMethod() + ":" + request.getRequestId(); //$NON-NLS-1$ //$NON-NLS-2$
        }
      };
    }
    return executor;
  }

  /**
   * @since 3.4
   */
  protected void executeRequest(IExecutor executor, final Request request, final ID responseTarget, final RemoteServiceRegistrationImpl localRegistration, final boolean respond) {
    IProgressRunnable runnable = new IProgressRunnable() {
      public Object run(IProgressMonitor monitor) throws Exception {
        final RemoteCallImpl call = request.getCall();
        Response response = null;
        Object result = null;
        try {
          // Get remote service call policy
          IRemoteServiceCallPolicy callPolicy = getRemoteServiceCallPolicy();
          // If it's set, then check remote call *before* actual invocation
          if (callPolicy != null)
            callPolicy.checkRemoteCall(responseTarget, localRegistration, call);

          result = localRegistration.callService(call);
          response = new Response(request.getRequestId(), result);
          // Invocation target exception happens if the local method being invoked throws (cause)
        } catch (InvocationTargetException e) {
          Throwable cause = e.getCause();
          response = new Response(request.getRequestId(), getSerializableException(cause));
          logRemoteCallException("Invocation target exception invoking remote service.  Remote request=" + request, cause); //$NON-NLS-1$
          // This is to catch most other problems
        } catch (Exception e) {
          response = new Response(request.getRequestId(), getSerializableException(e));
          logRemoteCallException("Unexpected exception invoking remote service.  Remote request=" + request, e); //$NON-NLS-1$
        } catch (NoClassDefFoundError e) {
          response = new Response(request.getRequestId(), getSerializableException(e));
          logRemoteCallException("No class def found error invoking remote service.  Remote request=" + request, e); //$NON-NLS-1$
        }
        // Now send response back to responseTarget (original requestor)
        if (respond)
          sendCallResponse(responseTarget, response);
        return null;
      }
    };
    // Now actually execute the runnable asynchronously using the executor
    executor.execute(runnable, new NullProgressMonitor());
  }

  private void sendErrorResponse(ID responseTarget, long requestId, String message, Throwable e) {
    logRemoteCallException(message, e);
    Response response = new Response(requestId, e);
    sendCallResponse(responseTarget, response);
  }

  protected void handleCallRequest(Request request) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "handleCallRequest", request); //$NON-NLS-1$
    // If request is null, it's bogus, give up/do not respond
    if (request == null) {
      log("handleCallRequest", new NullPointerException("Request cannot be null")); //$NON-NLS-1$//$NON-NLS-2$
      return;
    }

    final ID responseTarget = request.getRequestContainerID();
    // If response target is null then the request is bogus and we give up/do not respond
    if (responseTarget == null) {
      log("handleCallRequest", new NullPointerException("Response target cannot be null")); //$NON-NLS-1$ //$NON-NLS-2$
      return;
    }

    final RemoteServiceRegistrationImpl localRegistration = getLocalRegistrationForRequest(request);
    // If localRegistration not found for request, then it's a bogus request and we respond with NPE
    if (localRegistration == null) {
      sendErrorResponse(responseTarget, request.getRequestId(), "handleCallRequest", new NullPointerException("local service registration not found for remote request=" + request)); //$NON-NLS-1$ //$NON-NLS-2$
      return;
    }

    IExecutor executor = getRequestExecutor(request);
    if (executor == null) {
      sendErrorResponse(responseTarget, request.getRequestId(), "handleCallRequest", new NullPointerException("request executor is not available and so no requests can be processed")); //$NON-NLS-1$ //$NON-NLS-2$
      return;
    }

    // Else we've got a local service and we execute it using executor
    executeRequest(executor, request, responseTarget, localRegistration, true);

    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "handleCallRequest"); //$NON-NLS-1$
  }

  /**
   * @since 3.4
   */
  protected void logRemoteCallException(String message, Throwable e) {
    //Activator.getDefault().log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, SERVICE_INVOKE_ERROR_CODE, message, e));
  }

  private Throwable getSerializableException(Throwable e) {
    // Just use the SerializableStatus
    SerializableStatus ss = new SerializableStatus(0, Activator.PLUGIN_ID, null, e);
    return ss.getException();
  }

  protected void sendCallRequestWithListener(RemoteServiceRegistrationImpl remoteRegistration, IRemoteCall call, IRemoteCallListener listener) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "sendCallRequestWithListener", new Object[] {remoteRegistration, call, listener}); //$NON-NLS-1$
    final Request request = createRequest(remoteRegistration, call, listener);
    fireCallStartEvent(listener, request.getRequestId(), remoteRegistration.getReference(), call);
    try {
      addRequest(request);
      sendSharedObjectMsgTo(remoteRegistration.getContainerID(), SharedObjectMsg.createMsg(CALL_REQUEST, request));
    } catch (final IOException e) {
      log(CALL_REQUEST_ERROR_CODE, CALL_REQUEST_ERROR_MESSAGE, e);
      removeRequest(request);
      fireCallCompleteEvent(listener, request.getRequestId(), null, true, e);
    }
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "sendCallRequestWithListener"); //$NON-NLS-1$
  }

  protected void log(int code, String method, Throwable e) {
    Activator.getDefault().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, code, method, e));
  }

  protected void sendCallResponse(ID responseTarget, Response response) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "sendCallResponse", new Object[] {responseTarget, response}); //$NON-NLS-1$
    try {
      sendSharedObjectMsgTo(responseTarget, SharedObjectMsg.createMsg(CALL_RESPONSE, response));
    } catch (final IOException e) {
      log(CALL_RESPONSE_ERROR_CODE, CALL_RESPONSE_ERROR_MESSAGE, e);
      // Also print to standard error, just in case
      e.printStackTrace(System.err);
    }
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "sendCallResponse"); //$NON-NLS-1$
  }

  protected void handleCallResponse(Response response) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), CALL_RESPONSE, new Object[] {response});
    final Request request = getRequest(response.getRequestId());
    if (request == null) {
      log(REQUEST_NOT_FOUND_ERROR_CODE, REQUEST_NOT_FOUND_ERROR_MESSAGE, new NullPointerException());
      return;
    }
    removeRequest(request);
    final IRemoteCallListener listener = request.getListener();
    if (listener != null) {
      fireCallCompleteEvent(listener, request.getRequestId(), response.getResponse(), response.hadException(), response.getException());
      return;
    }
    synchronized (request) {
      request.setResponse(response);
      request.setDone(true);
      request.notify();
    }
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), CALL_RESPONSE);
  }

  protected Request sendFireRequest(RemoteServiceRegistrationImpl remoteRegistration, IRemoteCall call) throws ECFException {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "sendFireRequest", new Object[] {remoteRegistration, call}); //$NON-NLS-1$
    final Request request = createRequest(remoteRegistration, call, null);
    try {
      sendSharedObjectMsgTo(remoteRegistration.getContainerID(), SharedObjectMsg.createMsg(FIRE_REQUEST, request));
    } catch (final IOException e) {
      log(FIRE_REQUEST_ERROR_CODE, FIRE_REQUEST_ERROR_MESSAGE, e);
      throw new ECFException("IOException sending fire request", e); //$NON-NLS-1$
    }
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "sendFireRequest", request); //$NON-NLS-1$
    return request;
  }

  protected void handleFireRequest(Request request) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), FIRE_REQUEST, new Object[] {request});

    // If request is null, it's bogus, give up/do not respond
    if (request == null) {
      log("handleFireRequest", new NullPointerException("Request cannot be null")); //$NON-NLS-1$//$NON-NLS-2$
      return;
    }

    final ID responseTarget = request.getRequestContainerID();
    // If response target is null then the request is bogus and we give up/do not respond
    if (responseTarget == null) {
      log("handleFireRequest", new NullPointerException("Response target cannot be null")); //$NON-NLS-1$ //$NON-NLS-2$
      return;
    }

    final RemoteServiceRegistrationImpl localRegistration = getLocalRegistrationForRequest(request);
    // If localRegistration not found for request, then it's a bogus request and we respond with NPE
    if (localRegistration == null) {
      sendErrorResponse(responseTarget, request.getRequestId(), "handleFireRequest", new NullPointerException("local service registration not found for remote request=" + request)); //$NON-NLS-1$ //$NON-NLS-2$
      return;
    }

    IExecutor executor = getRequestExecutor(request);
    if (executor == null) {
      sendErrorResponse(responseTarget, request.getRequestId(), "handleFireRequest", new NullPointerException("request executor is not available and so no requests can be processed")); //$NON-NLS-1$ //$NON-NLS-2$
      return;
    }

    // Else we've got a local service and we execute it using executor
    executeRequest(executor, request, responseTarget, localRegistration, false);

    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), FIRE_REQUEST);
  }

  // RemoteServiceRegistrationImpl -> List<ID>
  private Map localRegistryUnregistrationTargets = new HashMap();

  private void addTargetForUnregister(RemoteServiceRegistrationImpl serviceRegistration, ID targetContainerID) {
    List existingTargets = (List) localRegistryUnregistrationTargets.get(serviceRegistration);
    if (existingTargets == null) {
      existingTargets = new ArrayList();
    }
    existingTargets.add(targetContainerID);
    Trace.trace(Activator.PLUGIN_ID, "addTargetForUnregister localContainerID=" + getLocalContainerID() + ",targetContainerID=" + targetContainerID + ",serviceRegistration=" + serviceRegistration); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    localRegistryUnregistrationTargets.put(serviceRegistration, existingTargets);
  }

  private void sendUnregisterToTargets(RemoteServiceRegistrationImpl serviceRegistration, ID[] otherTargets) {
    List allTargets = new ArrayList();
    // First add in otherTargets
    if (otherTargets != null) {
      allTargets.addAll(Arrays.asList(otherTargets));
    }
    // Then add any explicitly registered targets
    List registeredTargets = (List) localRegistryUnregistrationTargets.remove(serviceRegistration);
    if (registeredTargets != null) {
      allTargets.addAll(registeredTargets);
    }
    // Now allTargets should have all the container IDs of unregistration messages so we send to all
    for (Iterator i = allTargets.iterator(); i.hasNext();) {
      ID unregistrationTarget = (ID) i.next();
      ID registrationLocalContainerID = serviceRegistration.getContainerID();
      Long serviceId = new Long(serviceRegistration.getServiceId());
      Trace.trace(Activator.PLUGIN_ID, "sendUnregisterToTargets " + "localContainerID=" + getLocalContainerID() + ",targetContainerID=" + unregistrationTarget + ",serviceRegistration=" + serviceRegistration); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
      try {
        this.sendSharedObjectMsgTo(unregistrationTarget, SharedObjectMsg.createMsg(UNREGISTER, new Object[] {registrationLocalContainerID, serviceId}));
      } catch (final IOException e) {
        log(UNREGISTER_ERROR_CODE, UNREGISTER_ERROR_MESSAGE, e);
      }
    }
  }

  protected void sendUnregister(RemoteServiceRegistrationImpl serviceRegistration) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "sendUnregister", new Object[] {serviceRegistration}); //$NON-NLS-1$
    synchronized (localRegistry) {
      localRegistry.unpublishService(serviceRegistration);
      if (isConnected()) {
        final ID containerID = serviceRegistration.getContainerID();
        final Long serviceId = new Long(serviceRegistration.getServiceId());
        // Get targetIds from serviceRegistration properties
        ID[] targetIds = getTargetsFromProperties(serviceRegistration.properties);
        // If none/null, then send unregister message to all group members
        if (targetIds == null) {
          try {
            this.sendSharedObjectMsgTo(null, SharedObjectMsg.createMsg(UNREGISTER, new Object[] {containerID, serviceId}));
          } catch (final IOException e) {
            log(UNREGISTER_ERROR_CODE, UNREGISTER_ERROR_MESSAGE, e);
          }
        }
        // And send unregister explicitly to targets
        sendUnregisterToTargets(serviceRegistration, targetIds);
      }
    }
    fireRemoteServiceListeners(createUnregisteredEvent(serviceRegistration));
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "sendUnregister"); //$NON-NLS-1$
  }

  protected void handleUnregister(ID containerID, Long serviceId) {
    Trace.entering(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_ENTERING, this.getClass(), "handleUnregister", new Object[] {containerID, serviceId}); //$NON-NLS-1$
    RemoteServiceRegistrationImpl registration = null;
    synchronized (remoteRegistrys) {
      // get registry for given containerID
      final RemoteServiceRegistryImpl serviceRegistry = (RemoteServiceRegistryImpl) remoteRegistrys.get(containerID);
      if (serviceRegistry != null) {
        registration = serviceRegistry.findRegistrationForServiceId(serviceId.longValue());
        if (registration != null) {
          serviceRegistry.unpublishService(registration);
          // If there are no remaining registration for this remote service registry,
          // then remove the registry from the remoteRegistrys
          RemoteServiceRegistrationImpl[] registrations = serviceRegistry.getRegistrations();
          Trace.trace(Activator.PLUGIN_ID, "handleUnregister localContainerID=" + getLocalContainerID() + ",registrationRemoved=" + registration + ",containerID=" + containerID); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
          if (registrations.length == 0) {
            remoteRegistrys.remove(containerID);
          }
        }
      }
    }
    if (registration != null)
      fireRemoteServiceListeners(createUnregisteredEvent(registration));
    Trace.exiting(Activator.PLUGIN_ID, IRemoteServiceProviderDebugOptions.METHODS_EXITING, this.getClass(), "handleUnregister"); //$NON-NLS-1$
  }

  protected IRemoteServiceUnregisteredEvent createUnregisteredEvent(final RemoteServiceRegistrationImpl registration) {
    return new IRemoteServiceUnregisteredEvent() {

      public String[] getClazzes() {
        return registration.getClasses();
      }

      public ID getLocalContainerID() {
        return RegistrySharedObject.this.getLocalContainerID();
      }

      public ID getContainerID() {
        return registration.getContainerID();
      }

      public IRemoteServiceReference getReference() {
        return registration.getReference();
      }

      public String toString() {
        final StringBuffer buf = new StringBuffer("RemoteServiceUnregisteredEvent["); //$NON-NLS-1$
        buf.append("localContainerID=").append(getLocalContainerID()); //$NON-NLS-1$
        buf.append(";containerID=").append(registration.getContainerID()); //$NON-NLS-1$
        buf.append(";clazzes=").append(Arrays.asList(registration.getClasses())); //$NON-NLS-1$
        buf.append(";reference=").append(registration.getReference()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$
        return buf.toString();
      }
    };
  }

  protected IRemoteServiceRegisteredEvent createRegisteredEvent(final RemoteServiceRegistrationImpl registration) {
    return new IRemoteServiceRegisteredEvent() {

      public ID getLocalContainerID() {
        return RegistrySharedObject.this.getLocalContainerID();
      }

      public String[] getClazzes() {
        return registration.getClasses();
      }

      public ID getContainerID() {
        return registration.getContainerID();
      }

      public IRemoteServiceReference getReference() {
        return registration.getReference();
      }

      public String toString() {
        final StringBuffer buf = new StringBuffer("RemoteServiceRegisteredEvent["); //$NON-NLS-1$
        buf.append("localContainerID=").append(getLocalContainerID()); //$NON-NLS-1$
        buf.append(";containerID=").append(registration.getContainerID()); //$NON-NLS-1$
        buf.append(";clazzes=").append(Arrays.asList(registration.getClasses())); //$NON-NLS-1$
        buf.append(";reference=").append(registration.getReference()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$
        return buf.toString();
      }
    };
  }

  /**
   * End message send/handlers
   */

  protected RemoteServiceRegistryImpl addRemoteRegistry(RemoteServiceRegistryImpl registry) {
    return (RemoteServiceRegistryImpl) remoteRegistrys.put(registry.getContainerID(), registry);
  }

  protected RemoteServiceRegistryImpl getRemoteRegistry(ID containerID) {
    return (RemoteServiceRegistryImpl) remoteRegistrys.get(containerID);
  }

  protected RemoteServiceRegistryImpl removeRemoteRegistry(ID containerID) {
    return (RemoteServiceRegistryImpl) remoteRegistrys.remove(containerID);
  }

  /**
   *
   * @since 3.2
   */
  protected RemoteServiceRegistrationImpl getLocalRegistrationForRequest(Request request) {
    synchronized (localRegistry) {
      return localRegistry.findRegistrationForServiceId(request.getServiceId());
    }
  }

  /**
   * @since 3.2
   */
  protected boolean addRequest(Request request) {
    synchronized (requests) {
      return requests.add(request);
    }
  }

  /**
   * @since 3.2
   */
  protected Request getRequest(long requestId) {
    synchronized (requests) {
      for (final Iterator i = requests.iterator(); i.hasNext();) {
        final Request req = (Request) i.next();
        final long reqId = req.getRequestId();
        if (reqId == requestId) {
          return req;
        }
      }
    }
    return null;
  }

  /**
   * @since 3.2
   */
  protected boolean removeRequest(Request request) {
    synchronized (requests) {
      return requests.remove(request);
    }
  }

  protected void logException(int code, String message, Throwable e) {
    Activator.getDefault().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, code, message, e));
  }

  protected boolean handleSharedObjectMsg(SharedObjectMsg msg) {
    try {
      msg.invoke(this);
      return true;
    } catch (final Exception e) {
      logException(MSG_INVOKE_ERROR_CODE, "Exception invoking shared object message=" + msg, e); //$NON-NLS-1$
    }
    return false;
  }

  /**
   * @since 4.0
   */
  protected IRemoteServiceCallPolicy getRemoteServiceCallPolicy() {
    synchronized (remoteServiceCallPolicyLock) {
      return remoteServiceCallPolicy;
    }
  }

  /**
   * @since 4.0
   */
  public boolean setRemoteServiceCallPolicy(IRemoteServiceCallPolicy policy) {
    synchronized (remoteServiceCallPolicyLock) {
      this.remoteServiceCallPolicy = policy;
      return true;
    }
  }

}
TOP

Related Classes of org.eclipse.ecf.provider.remoteservice.generic.RegistrySharedObject

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.