blob: 4ff69d3584138b8f013a5bfadeb587735bab8c7e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 Jan S. Rellermeyer, 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:
* Jan S. Rellermeyer - initial API and implementation
******************************************************************************/
package org.eclipse.ecf.internal.provider.r_osgi;
import ch.ethz.iks.r_osgi.*;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.ecf.core.*;
import org.eclipse.ecf.core.events.*;
import org.eclipse.ecf.core.identity.*;
import org.eclipse.ecf.core.security.IConnectContext;
import org.eclipse.ecf.provider.r_osgi.identity.*;
import org.eclipse.ecf.remoteservice.*;
import org.eclipse.ecf.remoteservice.events.IRemoteServiceRegisteredEvent;
import org.eclipse.ecf.remoteservice.events.IRemoteServiceUnregisteredEvent;
import org.eclipse.equinox.concurrent.future.*;
import org.osgi.framework.*;
import org.osgi.framework.Constants;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
* The R-OSGi remote service container adapter. Implements the adapter and the
* container interface.
*
* @author Jan S. Rellermeyer, ETH Zurich
*/
class R_OSGiRemoteServiceContainer implements IOSGiRemoteServiceContainerAdapter, IRemoteServiceContainerAdapter, IContainer, RemoteServiceListener {
// the bundle context.
private BundleContext context;
// the R-OSGi remote service instance.
private RemoteOSGiService remoteService;
// the list of subscribed container listeners.
private final List containerListeners = new ArrayList(0);
// the ID of this container.
R_OSGiID containerID;
// the ID of the remote peer to which the container is connected to, or
// null, if not yet connected.
private R_OSGiID connectedID;
// tracks the lifecycle of remote services.
private ServiceTracker remoteServicesTracker;
// service reference -> service registration
private Map remoteServicesRegs = new HashMap(0);
// the map of remote service listeners. Maps the listener to the service
// registration of the internal R-OSGi remote service listener service.
private Map remoteServiceListeners = new HashMap(0);
// Connect context to use for connect calls
private IConnectContext connectContext;
public R_OSGiRemoteServiceContainer(RemoteOSGiService service, final ID containerID) throws IDCreateException {
Assert.isNotNull(service);
Assert.isNotNull(containerID);
context = Activator.getDefault().getContext();
remoteService = service;
if (containerID instanceof StringID) {
this.containerID = createR_OSGiID(((StringID) containerID).getName());
} else if (containerID instanceof R_OSGiID) {
this.containerID = (R_OSGiID) containerID;
} else {
throw new IDCreateException("Incompatible ID " + containerID); //$NON-NLS-1$
}
startRegTracker();
}
private void startRegTracker() {
try {
final String filter = "(" + org.eclipse.ecf.remoteservice.Constants.SERVICE_CONTAINER_ID + "=" + containerID + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
remoteServicesTracker = new ServiceTracker(context, context.createFilter(filter), new ServiceTrackerCustomizer() {
public Object addingService(ServiceReference reference) {
return reference;
}
public void modifiedService(ServiceReference reference, Object service) {
// service got modified
return;
}
public void removedService(ServiceReference reference, Object service) {
// service got removed
}
});
remoteServicesTracker.open();
} catch (InvalidSyntaxException e) {
e.printStackTrace();
}
}
/**
* add a remote service listener. This method accepts an ECF remote service
* listener and registers a R-OSGi listener service as an adapter.
*
* @param listener
* the ECF remote service listener.
*
* @see org.eclipse.ecf.remoteservice.IRemoteServiceContainerAdapter#addRemoteServiceListener(org.eclipse.ecf.remoteservice.IRemoteServiceListener)
*/
public void addRemoteServiceListener(final IRemoteServiceListener listener) {
Assert.isNotNull(listener);
final RemoteServiceListener l = new RemoteServiceListener() {
public void remoteServiceEvent(final RemoteServiceEvent event) {
switch (event.getType()) {
case RemoteServiceEvent.REGISTERED :
listener.handleServiceEvent(new IRemoteServiceRegisteredEvent() {
IRemoteServiceReference reference = new RemoteServiceReferenceImpl(createRemoteServiceID(event.getRemoteReference()), event.getRemoteReference());
public String[] getClazzes() {
return event.getRemoteReference().getServiceInterfaces();
}
public ID getContainerID() {
return getReference().getContainerID();
}
public IRemoteServiceReference getReference() {
return reference;
}
public String toString() {
return "RemoteServiceRegisteredEvent(" + containerID + "," + getReference(); //$NON-NLS-1$ //$NON-NLS-2$
}
public ID getLocalContainerID() {
return getID();
}
});
return;
case RemoteServiceEvent.UNREGISTERING :
listener.handleServiceEvent(new IRemoteServiceUnregisteredEvent() {
IRemoteServiceReference reference = new RemoteServiceReferenceImpl(createRemoteServiceID(event.getRemoteReference()), event.getRemoteReference());
public String[] getClazzes() {
return event.getRemoteReference().getServiceInterfaces();
}
public ID getContainerID() {
return containerID;
}
public IRemoteServiceReference getReference() {
return reference;
}
public String toString() {
return "RemoteServiceUnregisteredEvent(" + containerID + "," + getReference(); //$NON-NLS-1$ //$NON-NLS-2$
}
public ID getLocalContainerID() {
return getID();
}
});
return;
}
}
};
// register the listener as a service (whiteboard pattern)
final ServiceRegistration reg = context.registerService(RemoteServiceListener.class.getName(), l, null);
// keep track of the listener so that it can be removed when requested.
remoteServiceListeners.put(listener, reg);
}
/**
* get a remote service by its remote service reference.
*
* @param reference
* the remote service reference.
* @return the IRemoteService object, encapsulating the service proxy and
* additional methods for asynchronous and other access methods.
* @see org.eclipse.ecf.remoteservice.IRemoteServiceContainerAdapter#getRemoteService(org.eclipse.ecf.remoteservice.IRemoteServiceReference)
*/
public IRemoteService getRemoteService(final IRemoteServiceReference reference) {
Assert.isNotNull(reference);
if (!(reference instanceof RemoteServiceReferenceImpl))
return null;
final RemoteServiceReferenceImpl impl = (RemoteServiceReferenceImpl) reference;
Object rs = remoteService.getRemoteService(impl.getR_OSGiServiceReference());
if (rs == null)
return null;
final RemoteServiceImpl rsImpl = new RemoteServiceImpl(impl, rs);
synchronized (refToImplMap) {
List remoteServiceImplList = (List) refToImplMap.get(reference);
if (remoteServiceImplList == null)
remoteServiceImplList = new ArrayList();
remoteServiceImplList.add(rsImpl);
refToImplMap.put(reference, remoteServiceImplList);
}
return rsImpl;
}
// <IRemoteServiceReference,List<RemoteServiceImpl>>
private Map refToImplMap = new HashMap();
public IRemoteServiceReference[] getRemoteServiceReferences(ID target, ID[] idFilter, String clazz, String filter) throws InvalidSyntaxException, ContainerConnectException {
// r-osgi does not support the idFilter, since it does not support pub/sub
return getRemoteServiceReferences(target, clazz, filter);
}
/**
* get remote service references.
*
* @param idFilter
* a filter that limits the results to services registered by one
* of the IDs.
* @param clazz
* the interface name of the remote service.
* @param filter
* LDAP filter string that is matched against the service
* properties.
* @return the matching remote service references.
* @throws InvalidSyntaxException
* @see org.eclipse.ecf.remoteservice.IRemoteServiceContainerAdapter#getRemoteServiceReferences(org.eclipse.ecf.core.identity.ID[],
* java.lang.String, java.lang.String)
*/
public IRemoteServiceReference[] getRemoteServiceReferences(final ID[] idFilter, final String clazz, final String filter) throws InvalidSyntaxException {
// r-osgi does not support the idFilter, since it does not support pub/sub
IRemoteFilter remoteFilter = (filter == null) ? null : createRemoteFilter(filter);
List results = getRemoteServiceReferencesConnected(clazz, remoteFilter);
if (results == null)
return null;
return (IRemoteServiceReference[]) results.toArray(new IRemoteServiceReference[] {});
}
public IRemoteServiceReference[] getRemoteServiceReferences(ID targetID, String clazz, String filter) throws InvalidSyntaxException, ContainerConnectException {
if (clazz == null)
return null;
IRemoteFilter remoteFilter = (filter == null) ? null : createRemoteFilter(filter);
synchronized (this) {
List results = new ArrayList();
if (getConnectedID() == null)
connect(targetID, connectContext);
results = getRemoteServiceReferencesConnected(clazz, remoteFilter);
if (results == null || results.size() == 0)
return null;
return (IRemoteServiceReference[]) results.toArray(new IRemoteServiceReference[] {});
}
}
public IRemoteServiceReference[] getAllRemoteServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
List results = new ArrayList();
// Get remote service references from locally registered services first
synchronized (remoteServicesRegs) {
for (Iterator i1 = remoteServicesRegs.keySet().iterator(); i1.hasNext();) {
ServiceReference ref = (ServiceReference) i1.next();
Dictionary refProperties = prepareProperties(ref);
if (clazz == null) {
results.add(createLocalRemoteServiceReference(ref));
} else {
IRemoteFilter rf = createRemoteFilter(filter != null
? "(&" + filter + "(" //$NON-NLS-1$ //$NON-NLS-2$
+ Constants.OBJECTCLASS + "=" + clazz + "))" //$NON-NLS-1$//$NON-NLS-2$
: "(" //$NON-NLS-1$
+ Constants.OBJECTCLASS + "=" + clazz + ")"); //$NON-NLS-1$//$NON-NLS-2$
if (rf.match(refProperties)) {
results.add(createLocalRemoteServiceReference(ref));
}
}
}
}
IRemoteFilter remoteFilter = (filter == null) ? null : createRemoteFilter(filter);
if (getConnectedID() != null) {
final RemoteServiceReference[] rrefs = remoteService.getRemoteServiceReferences(connectedID.getURI(), clazz, remoteFilter);
if (rrefs != null)
for (int i = 0; i < rrefs.length; i++)
results.add(getCachedRemoteServiceReference(rrefs[i]));
}
return (IRemoteServiceReference[]) results.toArray(new IRemoteServiceReference[] {});
}
private IRemoteServiceReference createLocalRemoteServiceReference(ServiceReference ref) {
return new LocalRemoteServiceReferenceImpl(createRemoteServiceID(containerID, (Long) ref.getProperty(Constants.SERVICE_ID)), ref);
}
private synchronized List getRemoteServiceReferencesConnected(final String clazz, IRemoteFilter filter) {
List results = new ArrayList();
if (connectedID == null) {
try {
IRemoteServiceReference[] refs = getAllRemoteServiceReferences(clazz, (filter == null) ? null : filter.toString());
if (refs == null)
return results;
for (int i = 0; i < refs.length; i++)
results.add(refs[i]);
} catch (InvalidSyntaxException e) {
// can't happen
}
} else {
RemoteServiceReference[] rrefs = remoteService.getRemoteServiceReferences(connectedID.getURI(), clazz, filter);
if (rrefs == null)
return results;
for (int i = 0; i < rrefs.length; i++)
results.add(getCachedRemoteServiceReference(rrefs[i]));
}
return results;
}
private Map cachedRemoteServiceReferences = new HashMap();
private IRemoteServiceReference getCachedRemoteServiceReference(RemoteServiceReference rref) {
IRemoteServiceReference result = null;
synchronized (cachedRemoteServiceReferences) {
result = (IRemoteServiceReference) cachedRemoteServiceReferences.get(rref);
if (result == null) {
result = new RemoteServiceReferenceImpl(createRemoteServiceID(rref), rref);
cachedRemoteServiceReferences.put(rref, result);
}
}
return result;
}
IRemoteServiceID createRemoteServiceID(R_OSGiID cID, Long l) {
return (IRemoteServiceID) IDFactory.getDefault().createID(getRemoteServiceNamespace(), new Object[] {cID, l});
}
IRemoteServiceID createRemoteServiceID(RemoteServiceReference rref) {
URI uri = rref.getURI();
String fragmentString = "#" + uri.getFragment(); //$NON-NLS-1$
String uriStr = uri.toString();
int fragmentLoc = uriStr.indexOf(fragmentString);
if (fragmentLoc != -1) {
uriStr = uriStr.substring(0, fragmentLoc);
}
return createRemoteServiceID(createR_OSGiID(uriStr), (Long) rref.getProperty(Constants.SERVICE_ID));
}
private R_OSGiID createR_OSGiID(String uriStr) {
return R_OSGiContainerInstantiator.createR_OSGiID(getConnectNamespace(), uriStr);
}
/**
* register a service object as a remote service.
*
* @param clazzes
* the names of the service interfaces under which the service
* will be registered.
* @param service
* the service object.
* @param properties
* the service properties.
* @see org.eclipse.ecf.remoteservice.IRemoteServiceContainerAdapter#registerRemoteService(java.lang.String[],
* java.lang.Object, java.util.Dictionary)
*/
public IRemoteServiceRegistration registerRemoteService(final String[] clazzes, final Object service, final Dictionary properties) {
return registerRemoteService(clazzes, service, properties, context);
}
/* (non-Javadoc)
* @see org.eclipse.ecf.remoteservice.IOSGiRemoteServiceContainerAdapter#registerRemoteService(java.lang.String[], org.osgi.framework.ServiceReference, java.util.Dictionary)
*/
public IRemoteServiceRegistration registerRemoteService(final String[] clazzes, final ServiceReference aServiceReference, final Dictionary properties) {
final Object service = context.getService(aServiceReference);
final BundleContext bundleContext = aServiceReference.getBundle().getBundleContext();
return registerRemoteService(clazzes, service, properties, bundleContext);
}
private String getPackageName(String className) {
int lastDotIndex = className.lastIndexOf("."); //$NON-NLS-1$
if (lastDotIndex == -1)
return ""; //$NON-NLS-1$
return className.substring(0, lastDotIndex);
}
private Version getPackageVersion(final Object service, String serviceInterface, String packageName) {
List<Class> interfaces = new ArrayList<Class>();
Class<?> serviceClass = service.getClass();
while (!serviceClass.equals(Object.class)) {
interfaces.addAll(Arrays.asList(serviceClass.getInterfaces()));
serviceClass = serviceClass.getSuperclass();
}
Class[] interfaceClasses = interfaces.toArray(new Class[interfaces.size()]);
if (interfaceClasses == null)
return null;
Class interfaceClass = null;
for (int i = 0; i < interfaceClasses.length; i++)
if (interfaceClasses[i].getName().equals(serviceInterface))
interfaceClass = interfaceClasses[i];
if (interfaceClass == null)
return null;
Bundle providingBundle = FrameworkUtil.getBundle(interfaceClass);
if (providingBundle == null)
return null;
return getVersionForPackage(providingBundle, packageName);
}
private Version getVersionForMatchingCapability(String packageName, BundleCapability capability) {
// If it's a package namespace (Import-Package)
Map<String, Object> attributes = capability.getAttributes();
// Then we get the package attribute
String p = (String) attributes.get(BundleRevision.PACKAGE_NAMESPACE);
// And compare it to the package name
if (p != null && packageName.equals(p))
return (Version) attributes.get(Constants.VERSION_ATTRIBUTE);
return null;
}
private Version getVersionForPackage(final Bundle providingBundle, String packageName) {
Version result = null;
BundleRevision providingBundleRevision = AccessController.doPrivileged(new PrivilegedAction<BundleRevision>() {
public BundleRevision run() {
return providingBundle.adapt(BundleRevision.class);
}
});
if (providingBundleRevision == null)
return null;
List<BundleCapability> providerCapabilities = providingBundleRevision.getDeclaredCapabilities(BundleRevision.PACKAGE_NAMESPACE);
for (BundleCapability c : providerCapabilities) {
result = getVersionForMatchingCapability(packageName, c);
if (result != null)
return result;
}
return result;
}
private IRemoteServiceRegistration registerRemoteService(final String[] clazzes, final Object service, final Dictionary properties, final BundleContext aContext) {
if (containerID == null) {
throw new IllegalStateException("Container is not connected"); //$NON-NLS-1$
}
final Dictionary props = properties == null ? new Hashtable() : clone(properties);
// add the hint property for R-OSGi that this service is intended to be
// accessed remotely.
props.put(RemoteOSGiService.R_OSGi_REGISTRATION, Boolean.TRUE);
// remove the RFC 119 hint, if present, to avoid loops
props.remove("osgi.remote.interfaces"); //$NON-NLS-1$
props.remove("service.exported.interfaces"); //$NON-NLS-1$
// ECF remote service properties
// container ID (ID)
props.put(org.eclipse.ecf.remoteservice.Constants.SERVICE_CONTAINER_ID, containerID);
// Object classes (String [])
props.put(org.eclipse.ecf.remoteservice.Constants.OBJECTCLASS, clazzes);
// service ranking (Integer). Allow this to be set by user
Integer serviceRanking = (Integer) props.get(org.eclipse.ecf.remoteservice.Constants.SERVICE_RANKING);
serviceRanking = (serviceRanking == null) ? new Integer(0) : serviceRanking;
props.put(org.eclipse.ecf.remoteservice.Constants.SERVICE_RANKING, serviceRanking);
for (String clazz : clazzes) {
// Add osgi-standard remote service version for each package
String packageName = getPackageName(clazz);
String packageVersionKey = "endpoint.package.version." + packageName; //$NON-NLS-1$
Version packageVersion = getPackageVersion(service, clazz, packageName);
if (packageVersion != null) {
props.put(packageVersionKey, packageVersion.toString());
}
}
final ServiceRegistration reg = aContext.registerService(clazzes, service, props);
// Set ECF remote service id property based upon local service property
reg.setProperties(prepareProperties(reg.getReference()));
synchronized (remoteServicesRegs) {
remoteServicesRegs.put(reg.getReference(), reg);
}
// Construct a IRemoteServiceID, and provide to new registration impl instance
return new RemoteServiceRegistrationImpl(this, createRemoteServiceID(containerID, (Long) reg.getReference().getProperty(Constants.SERVICE_ID)), reg);
}
Dictionary prepareProperties(ServiceReference reference) {
String[] propKeys = reference.getPropertyKeys();
Dictionary newDictionary = new Properties();
for (int i = 0; i < propKeys.length; i++) {
Object v = reference.getProperty(propKeys[i]);
newDictionary.put(propKeys[i], v);
// Make the remote service SERVICE_ID have the same value as OSGi SERVICE_ID
if (Constants.SERVICE_ID.equals(propKeys[i])) {
newDictionary.put(org.eclipse.ecf.remoteservice.Constants.SERVICE_ID, v);
}
}
return newDictionary;
}
/**
* remove a registered remote service listener.
*
* @param listener
* the remote service listener.
* @see org.eclipse.ecf.remoteservice.IRemoteServiceContainerAdapter#removeRemoteServiceListener(org.eclipse.ecf.remoteservice.IRemoteServiceListener)
*/
public void removeRemoteServiceListener(final IRemoteServiceListener listener) {
remoteServiceListeners.remove(listener);
}
/**
*
* @see org.eclipse.ecf.remoteservice.IRemoteServiceContainerAdapter#ungetRemoteService(org.eclipse.ecf.remoteservice.IRemoteServiceReference)
*/
public boolean ungetRemoteService(IRemoteServiceReference reference) {
if (!(reference instanceof RemoteServiceReferenceImpl))
return false;
RemoteServiceReferenceImpl impl = (RemoteServiceReferenceImpl) reference;
RemoteServiceReference rsr = impl.getR_OSGiServiceReference();
if (!rsr.isActive())
return false;
remoteService.ungetRemoteService(rsr);
synchronized (refToImplMap) {
List remoteServiceImplList = (List) refToImplMap.remove(reference);
if (remoteServiceImplList != null) {
for (Iterator i = remoteServiceImplList.iterator(); i.hasNext();) {
RemoteServiceImpl rsImpl = (RemoteServiceImpl) i.next();
if (rsImpl != null)
rsImpl.dispose();
i.remove();
}
}
}
return true;
}
/**
* returns an adapter for a given class. In this particular case, only the
* IRemoteServiceContainerAdapter interface and the IContainer interface are
* supported.
*
* @param adapter
* the class to adapt to.
* @return the adapter or null if the adaptation is not supported.
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
public Object getAdapter(final Class adapter) {
if (adapter.equals(IRemoteServiceContainerAdapter.class)) {
return this;
} else if (adapter.equals(IContainer.class)) {
return this;
}
return null;
}
// container part
/**
* add a container listener.
*
* @param listener
* the container listener.
*
* @see org.eclipse.ecf.core.IContainer#addListener(org.eclipse.ecf.core.IContainerListener)
*/
public void addListener(final IContainerListener listener) {
containerListeners.add(listener);
}
/**
* connect the container to a remote container instance.
*
* @param targetID
* the target ID to connect to.
* @param connectContext
* the connection context.
* @throws ContainerConnectException
* if the connecting fails.
* @see org.eclipse.ecf.core.IContainer#connect(org.eclipse.ecf.core.identity.ID,
* org.eclipse.ecf.core.security.IConnectContext)
*/
public synchronized void connect(final ID targetID, final IConnectContext cc) throws ContainerConnectException {
if (targetID == null)
throw new ContainerConnectException("targetID must not be null"); //$NON-NLS-1$
// Get and check namespace
String targetNamespace = targetID.getNamespace().getName();
if (!(targetNamespace.equals(getConnectNamespace().getName()) || targetNamespace.equals(StringID.class.getName()))) {
throw new ContainerConnectException("targetID is of incorrect connect namespace for this container"); //$NON-NLS-1$
}
// check that we are not connected
if (connectedID != null) {
// already connected to this target
if (connectedID.getName().equals(targetID.getName())) {
return;
}
throw new ContainerConnectException("Container is already connected to " + connectedID); //$NON-NLS-1$
}
this.connectContext = cc;
try {
final R_OSGiID target = (targetNamespace.equals(StringID.class.getName()) ? createR_OSGiID(((StringID) targetID).getName()) : ((R_OSGiID) targetID));
fireListeners(new ContainerConnectingEvent(containerID, connectedID));
final RemoteServiceReference[] refs = doConnect(target);
if (refs != null)
for (int i = 0; i < refs.length; i++)
checkImport(refs[i]);
connectedID = target;
startRegTracker();
} catch (IOException ioe) {
throw new ContainerConnectException(ioe);
} catch (IDCreateException e) {
throw new ContainerConnectException(e);
}
fireListeners(new ContainerConnectedEvent(containerID, connectedID));
}
private RemoteServiceReference[] doConnect(R_OSGiID targetID) throws IOException {
return remoteService.connect(targetID.getURI());
}
private void doDisconnect(R_OSGiID targetID) {
synchronized (cachedRemoteServiceReferences) {
cachedRemoteServiceReferences.clear();
}
remoteService.disconnect(targetID.getURI());
}
/**
* disconnect from the remote container.
*
* @see org.eclipse.ecf.core.IContainer#disconnect()
*/
public synchronized void disconnect() {
if (connectedID != null) {
fireListeners(new ContainerDisconnectingEvent(containerID, connectedID));
doDisconnect(connectedID);
connectedID = null;
fireListeners(new ContainerDisconnectedEvent(containerID, connectedID));
}
}
/**
* dispose the container.
*
* @see org.eclipse.ecf.core.IContainer#dispose()
*/
public void dispose() {
// unregister remote services
if (remoteServicesTracker != null) {
final ServiceReference[] refs = remoteServicesTracker.getServiceReferences();
if (refs != null) {
for (int i = 0; i < refs.length; i++) {
final ServiceRegistration reg = (ServiceRegistration) remoteServicesRegs.get(refs[i]);
if (reg != null) {
reg.unregister();
}
}
}
remoteServicesTracker.close();
remoteServicesTracker = null;
}
// unregister remote listeners
final ServiceRegistration[] lstn = (ServiceRegistration[]) remoteServiceListeners.values().toArray(new ServiceRegistration[remoteServiceListeners.size()]);
for (int i = 0; i < lstn.length; i++) {
try {
lstn[i].unregister();
} catch (Throwable t) {
// ignore and continue
}
}
if (connectedID != null) {
disconnect();
}
synchronized (refToImplMap) {
refToImplMap.clear();
}
fireListeners(new ContainerDisposeEvent(containerID));
containerListeners.clear();
}
/**
* get the connect namespace.
*
* @return the connect namespace.
* @see org.eclipse.ecf.core.IContainer#getConnectNamespace()
*/
public Namespace getConnectNamespace() {
return R_OSGiNamespace.getDefault();
}
/**
* get the ID to which the container is connected to. Can be
* <code>null</code> if the container is not yet connected.
*
* @return the ID or null.
* @see org.eclipse.ecf.core.IContainer#getConnectedID()
*/
public synchronized ID getConnectedID() {
return connectedID;
}
/**
* remove a registered container listener.
*
* @param listener
* the container listener.
* @see org.eclipse.ecf.core.IContainer#removeListener(org.eclipse.ecf.core.IContainerListener)
*/
public void removeListener(final IContainerListener listener) {
containerListeners.remove(listener);
}
/**
* get the ID of this container instance.
*
* @return the ID of this container.
* @see org.eclipse.ecf.core.identity.IIdentifiable#getID()
*/
public ID getID() {
return containerID;
}
/**
* fire the listeners.
*
* @param event
* the event.
*/
private void fireListeners(final IContainerEvent event) {
final IContainerListener[] listeners = (IContainerListener[]) containerListeners.toArray(new IContainerListener[containerListeners.size()]);
new Thread() {
public void run() {
for (int i = 0; i < listeners.length; i++) {
listeners[i].handleEvent(event);
}
}
}.start();
}
/**
* get the events from R-OSGi received through a RemoteServiceListener
* instance.
*
* @see ch.ethz.iks.r_osgi.RemoteServiceListener#remoteServiceEvent(ch.ethz.iks.r_osgi.RemoteServiceEvent)
*/
public void remoteServiceEvent(final RemoteServiceEvent event) {
if (event.getType() == RemoteServiceEvent.REGISTERED) {
checkImport(event.getRemoteReference());
}
}
/**
* check if the remote service should be automatically imported by this
* container.
*
* @param ref
* the remote service reference to check.
*/
private void checkImport(final RemoteServiceReference ref) {
final Object target = ref.getProperty(org.eclipse.ecf.remoteservice.Constants.SERVICE_REGISTRATION_TARGETS);
if (target instanceof ID && ((ID) target).equals(containerID)) {
remoteService.getRemoteService(ref);
} else if (target instanceof ID[]) {
final ID[] targets = (ID[]) target;
for (int i = 0; i < targets.length; i++) {
if (targets[i].equals(containerID)) {
remoteService.getRemoteService(ref);
}
}
}
}
/**
* Clone a dictionary instance to avoid modification by the caller of the
* registration method.
*
* @param props
* the dictionary instance.
* @return a clone.
*/
private Hashtable clone(final Dictionary props) {
final Hashtable clone = new Hashtable();
for (Enumeration e = props.keys(); e.hasMoreElements();) {
final Object key = e.nextElement();
clone.put(key, props.get(key));
}
return clone;
}
public IFuture asyncGetRemoteServiceReferences(final ID[] idFilter, final String clazz, final String filter) {
IExecutor executor = new ThreadsExecutor();
return executor.execute(new IProgressRunnable() {
public Object run(IProgressMonitor monitor) throws Exception {
return getRemoteServiceReferences(idFilter, clazz, filter);
}
}, null);
}
public IFuture asyncGetRemoteServiceReferences(final ID target, final String clazz, final String filter) {
IExecutor executor = new ThreadsExecutor();
return executor.execute(new IProgressRunnable() {
public Object run(IProgressMonitor monitor) throws Exception {
return getRemoteServiceReferences(target, clazz, filter);
}
}, null);
}
public IFuture asyncGetRemoteServiceReferences(final ID target, final ID[] idFilter, final String clazz, final String filter) {
IExecutor executor = new ThreadsExecutor();
return executor.execute(new IProgressRunnable() {
public Object run(IProgressMonitor monitor) throws Exception {
return getRemoteServiceReferences(target, idFilter, clazz, filter);
}
}, null);
}
public Namespace getRemoteServiceNamespace() {
return IDFactory.getDefault().getNamespaceByName(R_OSGiRemoteServiceNamespace.NAME);
}
public IRemoteFilter createRemoteFilter(String filter) throws InvalidSyntaxException {
return new RemoteFilterImpl(context, filter);
}
public IRemoteServiceID getRemoteServiceID(ID containerId, long containerRelativeId) {
return (IRemoteServiceID) IDFactory.getDefault().createID(getRemoteServiceNamespace(), new Object[] {containerID, new Long(containerRelativeId)});
}
public IRemoteServiceReference getRemoteServiceReference(IRemoteServiceID serviceId) {
if (serviceId == null)
return null;
ID cID = serviceId.getContainerID();
// If the container ID isn't relevant to us we ignore
if (cID instanceof R_OSGiID) {
// If it's not the same as who we're connected to, we ignore
if (cID.equals(getConnectedID())) {
final String filter = "(" + Constants.SERVICE_ID + "=" + serviceId + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
try {
// Get remote service references...I imagine this can/would block
RemoteServiceReference[] refs = remoteService.getRemoteServiceReferences(((R_OSGiID) cID).getURI(), null, context.createFilter(filter));
// There should be either zero or 1 remote service reference
if (refs == null || refs.length == 0)
return null;
return getCachedRemoteServiceReference(refs[0]);
} catch (InvalidSyntaxException e) {
// shouldn't happen as filter better be well formed
return null;
}
}
}
return null;
}
public void setConnectContextForAuthentication(IConnectContext connectContext) {
this.connectContext = connectContext;
}
public boolean setRemoteServiceCallPolicy(IRemoteServiceCallPolicy policy) {
// XXX...we need to see if r-OSGi has a means to implement this
return false;
}
void removeRegistration(ServiceRegistration reg) {
synchronized (remoteServicesRegs) {
remoteServicesRegs.remove(reg.getReference());
}
}
}