blob: d5cf2b19b41864cb62d54ddfb056bdcbd7cf16b2 [file] [log] [blame]
/****************************************************************************
* Copyright (c) 2010-2011 Composent, Inc. and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Composent, Inc. - initial API and implementation
*
* SPDX-License-Identifier: EPL-2.0
*****************************************************************************/
package org.eclipse.ecf.osgi.services.remoteserviceadmin;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.ecf.core.identity.Namespace;
import org.eclipse.ecf.discovery.IDiscoveryAdvertiser;
import org.eclipse.ecf.discovery.IDiscoveryLocator;
import org.eclipse.ecf.discovery.IServiceEvent;
import org.eclipse.ecf.discovery.IServiceInfo;
import org.eclipse.ecf.discovery.IServiceListener;
import org.eclipse.ecf.discovery.identity.IServiceID;
import org.eclipse.ecf.discovery.identity.IServiceTypeID;
import org.eclipse.ecf.internal.osgi.services.remoteserviceadmin.Activator;
import org.eclipse.ecf.internal.osgi.services.remoteserviceadmin.DebugOptions;
import org.eclipse.ecf.internal.osgi.services.remoteserviceadmin.LogUtility;
import org.eclipse.ecf.internal.osgi.services.remoteserviceadmin.PropertiesUtil;
import org.eclipse.equinox.concurrent.future.IExecutor;
import org.eclipse.equinox.concurrent.future.IProgressRunnable;
import org.eclipse.equinox.concurrent.future.ThreadsExecutor;
import org.eclipse.osgi.framework.eventmgr.CopyOnWriteIdentityMap;
import org.eclipse.osgi.framework.eventmgr.EventDispatcher;
import org.eclipse.osgi.framework.eventmgr.EventManager;
import org.eclipse.osgi.framework.eventmgr.ListenerQueue;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.remoteserviceadmin.EndpointDescription;
import org.osgi.service.remoteserviceadmin.EndpointEvent;
import org.osgi.service.remoteserviceadmin.EndpointEventListener;
import org.osgi.service.remoteserviceadmin.EndpointListener;
import org.osgi.util.tracker.BundleTracker;
import org.osgi.util.tracker.BundleTrackerCustomizer;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
* Implementation of EndpointDescription discovery mechanism, using any/all ECF
* discovery providers (implementers if {@link IDiscoveryLocator}.
*
*/
public class EndpointDescriptionLocator implements IEndpointDescriptionLocator {
private BundleContext context;
private IExecutor executor;
// service info factory default
private ServiceInfoFactory serviceInfoFactory;
private ServiceRegistration defaultServiceInfoFactoryRegistration;
// service info factory service tracker
private Object serviceInfoFactoryTrackerLock = new Object();
private ServiceTracker serviceInfoFactoryTracker;
// endpoint description factory default
private DiscoveredEndpointDescriptionFactory defaultEndpointDescriptionFactory;
private ServiceRegistration defaultEndpointDescriptionFactoryRegistration;
// endpoint description factory tracker
private Object endpointDescriptionFactoryTrackerLock = new Object();
private ServiceTracker endpointDescriptionFactoryTracker;
// endpointDescriptionReader default
private ServiceRegistration defaultEndpointDescriptionReaderRegistration;
// For processing synchronous notifications asynchronously
private EventManager eventManager;
private ListenerQueue eventQueue;
// ECF IDiscoveryLocator tracker
private ServiceTracker locatorServiceTracker;
// Locator listeners
private Map<IDiscoveryLocator, LocatorServiceListener> locatorListeners;
private ServiceTracker endpointListenerTracker;
private ServiceTracker endpointEventListenerTracker;
private ServiceTracker advertiserTracker;
private Object advertiserTrackerLock = new Object();
private BundleTracker bundleTracker;
private EndpointDescriptionBundleTrackerCustomizer bundleTrackerCustomizer;
private String frameworkUUID;
private ServiceRegistration<IEndpointDescriptionLocator> endpointLocatorReg;
private String getFrameworkUUID() {
return frameworkUUID;
}
public EndpointDescriptionLocator(BundleContext context) {
this.context = context;
this.executor = new ThreadsExecutor();
this.frameworkUUID = Activator.getDefault().getFrameworkUUID();
}
public void start() {
// For service info and endpoint description factories
// set the service ranking to Integer.MIN_VALUE
// so that any other registered factories will be preferred
final Properties properties = new Properties();
properties.put(Constants.SERVICE_RANKING,
Integer.valueOf(Integer.MIN_VALUE));
serviceInfoFactory = new ServiceInfoFactory();
defaultServiceInfoFactoryRegistration = context.registerService(
IServiceInfoFactory.class.getName(), serviceInfoFactory,
(Dictionary) properties);
defaultEndpointDescriptionFactory = new DiscoveredEndpointDescriptionFactory();
defaultEndpointDescriptionFactoryRegistration = context
.registerService(
IDiscoveredEndpointDescriptionFactory.class.getName(),
defaultEndpointDescriptionFactory,
(Dictionary) properties);
// setup/register default endpointDescriptionReader
defaultEndpointDescriptionReaderRegistration = context.registerService(
IEndpointDescriptionReader.class.getName(),
new EndpointDescriptionReader(), (Dictionary) properties);
// Create thread group, event manager, and eventQueue, and setup to
// dispatch EndpointListenerEvents
ThreadGroup eventGroup = new ThreadGroup(
"RSA EndpointDescriptionLocator ThreadGroup"); //$NON-NLS-1$
eventGroup.setDaemon(true);
eventManager = new EventManager(
"RSA EndpointDescriptionLocator Dispatcher", eventGroup); //$NON-NLS-1$
eventQueue = new ListenerQueue(eventManager);
CopyOnWriteIdentityMap listeners = new CopyOnWriteIdentityMap();
listeners.put(this, this);
eventQueue.queueListeners(listeners.entrySet(), new EventDispatcher() {
public void dispatchEvent(Object eventListener,
Object listenerObject, int eventAction, Object eventObject) {
final String logMethodName = "dispatchEvent"; //$NON-NLS-1$
// We now dispatch both EndpointListenerEvents
if (eventObject instanceof EndpointListenerEvent) {
final EndpointListenerEvent event = (EndpointListenerEvent) eventObject;
final EndpointListener endpointListener = event
.getEndpointListener();
final EndpointDescription endpointDescription = event
.getEndointDescription();
final String matchingFilter = event.getMatchingFilter();
try {
boolean discovered = event.isDiscovered();
trace("endpointListener.discovered=" + discovered + " ", "fwk=" + getFrameworkUUID() + ", endpointListener=" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ endpointListener
+ ", endpointDescription=" //$NON-NLS-1$
+ endpointDescription
+ ", matchingFilter=" //$NON-NLS-1$
+ matchingFilter);
if (discovered)
endpointListener.endpointAdded(endpointDescription,
matchingFilter);
else
endpointListener.endpointRemoved(
endpointDescription, matchingFilter);
} catch (Exception e) {
String message = "Exception in EndpointListener listener=" //$NON-NLS-1$
+ endpointListener + " description=" //$NON-NLS-1$
+ endpointDescription + " matchingFilter=" //$NON-NLS-1$
+ matchingFilter;
logError(logMethodName, message, e);
} catch (LinkageError e) {
String message = "LinkageError in EndpointListener listener=" //$NON-NLS-1$
+ endpointListener + " description=" //$NON-NLS-1$
+ endpointDescription + " matchingFilter=" //$NON-NLS-1$
+ matchingFilter;
logError(logMethodName, message, e);
} catch (AssertionError e) {
String message = "AssertionError in EndpointListener listener=" //$NON-NLS-1$
+ endpointListener + " description=" //$NON-NLS-1$
+ endpointDescription + " matchingFilter=" //$NON-NLS-1$
+ matchingFilter;
logError(logMethodName, message, e);
}
// and EndpointEventListenerEvents
} else if (eventObject instanceof EndpointEventListenerEvent) {
final EndpointEventListenerEvent event = (EndpointEventListenerEvent) eventObject;
final EndpointEventListener endpointEventListener = event
.getEndpointEventListener();
final EndpointEvent endpointEvent = event
.getEndpointEvent();
final String matchingFilter = event.getMatchingFilter();
try {
trace("endpointEventListener.discovered=" + getEndpointEventTypeAsString(endpointEvent.getType()) + " ", "fwk=" + getFrameworkUUID() + ", endpointEventListener=" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ endpointEventListener
+ ", endpointEvent=" //$NON-NLS-1$
+ endpointEvent + ", matchingFilter=" //$NON-NLS-1$
+ matchingFilter);
endpointEventListener.endpointChanged(endpointEvent,
matchingFilter);
} catch (Exception e) {
String message = "Exception in EndpointEventListener listener=" //$NON-NLS-1$
+ endpointEventListener + " event=" //$NON-NLS-1$
+ endpointEvent + " matchingFilter=" //$NON-NLS-1$
+ matchingFilter;
logError(logMethodName, message, e);
} catch (LinkageError e) {
String message = "LinkageError in EndpointEventListener listener=" //$NON-NLS-1$
+ endpointEventListener + " event=" //$NON-NLS-1$
+ endpointEvent + " matchingFilter=" //$NON-NLS-1$
+ matchingFilter;
logError(logMethodName, message, e);
} catch (AssertionError e) {
String message = "AssertionError in EndpointEventListener listener=" //$NON-NLS-1$
+ endpointEventListener + " event=" //$NON-NLS-1$
+ endpointEvent + " matchingFilter=" //$NON-NLS-1$
+ matchingFilter;
logError(logMethodName, message, e);
}
}
}
});
// Register the endpoint listener tracker, so that endpoint listeners
// that are subsequently added
// will then be notified of discovered endpoints
endpointListenerTracker = new ServiceTracker(context,
EndpointListener.class.getName(),
new ServiceTrackerCustomizer() {
public Object addingService(ServiceReference reference) {
if (context == null)
return null;
EndpointListener listener = (EndpointListener) context
.getService(reference);
if (listener == null)
return null;
Collection<org.osgi.service.remoteserviceadmin.EndpointDescription> allDiscoveredEndpointDescriptions = getEDs();
for (org.osgi.service.remoteserviceadmin.EndpointDescription ed : allDiscoveredEndpointDescriptions) {
EndpointDescriptionLocator.EndpointListenerHolder[] endpointListenerHolders = getMatchingEndpointListenerHolders(
new ServiceReference[] { reference }, ed);
if (endpointListenerHolders != null) {
for (int i = 0; i < endpointListenerHolders.length; i++) {
queueEndpointDescription(
endpointListenerHolders[i]
.getListener(),
endpointListenerHolders[i]
.getDescription(),
endpointListenerHolders[i]
.getMatchingFilter(), true);
}
}
}
return listener;
}
public void modifiedService(ServiceReference reference,
Object service) {
}
public void removedService(ServiceReference reference,
Object service) {
}
});
endpointListenerTracker.open();
// Register the endpoint event listener tracker, so that endpoint event
// listeners
// that are subsequently added
// will then be notified of discovered endpoints
endpointEventListenerTracker = new ServiceTracker(context,
EndpointEventListener.class.getName(),
new ServiceTrackerCustomizer() {
public Object addingService(ServiceReference reference) {
if (context == null)
return null;
EndpointEventListener listener = (EndpointEventListener) context
.getService(reference);
if (listener == null)
return null;
Collection<org.osgi.service.remoteserviceadmin.EndpointDescription> allDiscoveredEndpointDescriptions = getEDs();
for (org.osgi.service.remoteserviceadmin.EndpointDescription ed : allDiscoveredEndpointDescriptions) {
EndpointDescriptionLocator.EndpointEventListenerHolder[] endpointEventListenerHolders = getMatchingEndpointEventListenerHolders(
new ServiceReference[] { reference }, ed,
EndpointEvent.ADDED);
if (endpointEventListenerHolders != null) {
for (int i = 0; i < endpointEventListenerHolders.length; i++) {
queueEndpointDescription(
endpointEventListenerHolders[i]
.getListener(),
endpointEventListenerHolders[i]
.getDescription(),
endpointEventListenerHolders[i]
.getMatchingFilter(),
endpointEventListenerHolders[i]
.getType());
}
}
}
return listener;
}
public void modifiedService(ServiceReference reference,
Object service) {
}
public void removedService(ServiceReference reference,
Object service) {
}
});
endpointEventListenerTracker.open();
locatorListeners = new HashMap();
// Create locator service tracker, so new IDiscoveryLocators can
// be used to discover endpoint descriptions
locatorServiceTracker = new ServiceTracker(context,
IDiscoveryLocator.class.getName(),
new LocatorTrackerCustomizer());
locatorServiceTracker.open();
// Create bundle tracker for reading local/xml-file endpoint
// descriptions
bundleTrackerCustomizer = new EndpointDescriptionBundleTrackerCustomizer();
bundleTracker = new BundleTracker(context, Bundle.ACTIVE
| Bundle.STARTING, bundleTrackerCustomizer);
// This may trigger local endpoint description discovery
bundleTracker.open();
this.endpointLocatorReg = this.context.registerService(
IEndpointDescriptionLocator.class, this, null);
}
private void logError(String methodName, String message, Throwable e) {
LogUtility.logError(methodName,
DebugOptions.ENDPOINT_DESCRIPTION_LOCATOR, this.getClass(),
message, e);
}
private void trace(String methodName, String message) {
LogUtility.trace(methodName, DebugOptions.ENDPOINT_DESCRIPTION_LOCATOR,
this.getClass(), message);
}
public void close() {
if (this.endpointLocatorReg != null) {
this.endpointLocatorReg.unregister();
this.endpointLocatorReg = null;
}
if (bundleTracker != null) {
bundleTracker.close();
bundleTracker = null;
}
if (bundleTrackerCustomizer != null) {
bundleTrackerCustomizer.close();
bundleTrackerCustomizer = null;
}
// shutdown locatorListeners
synchronized (locatorListeners) {
for (IDiscoveryLocator l : locatorListeners.keySet()) {
LocatorServiceListener locatorListener = locatorListeners
.get(l);
if (locatorListener != null) {
l.removeServiceListener(locatorListener);
locatorListener.close();
}
}
locatorListeners.clear();
}
Object[] locators = locatorServiceTracker.getServices();
if (locators != null) {
for (int i = 0; i < locators.length; i++) {
// Add service listener to locator
shutdownLocator((IDiscoveryLocator) locators[i]);
}
}
if (endpointListenerTracker != null) {
endpointListenerTracker.close();
endpointListenerTracker = null;
}
if (endpointEventListenerTracker != null) {
endpointEventListenerTracker.close();
endpointEventListenerTracker = null;
}
// Shutdown asynchronous event manager
if (eventManager != null) {
eventManager.close();
eventManager = null;
}
synchronized (endpointDescriptionFactoryTrackerLock) {
if (endpointDescriptionFactoryTracker != null) {
endpointDescriptionFactoryTracker.close();
endpointDescriptionFactoryTracker = null;
}
}
if (defaultEndpointDescriptionFactoryRegistration != null) {
defaultEndpointDescriptionFactoryRegistration.unregister();
defaultEndpointDescriptionFactoryRegistration = null;
}
if (defaultEndpointDescriptionFactory != null) {
defaultEndpointDescriptionFactory.close();
defaultEndpointDescriptionFactory = null;
}
synchronized (serviceInfoFactoryTrackerLock) {
if (serviceInfoFactoryTracker != null) {
serviceInfoFactoryTracker.close();
serviceInfoFactoryTracker = null;
}
}
if (defaultServiceInfoFactoryRegistration != null) {
defaultServiceInfoFactoryRegistration.unregister();
defaultServiceInfoFactoryRegistration = null;
}
if (serviceInfoFactory != null) {
serviceInfoFactory.close();
serviceInfoFactory = null;
}
if (defaultEndpointDescriptionReaderRegistration != null) {
defaultEndpointDescriptionReaderRegistration.unregister();
defaultEndpointDescriptionReaderRegistration = null;
}
if (locatorServiceTracker != null) {
locatorServiceTracker.close();
locatorServiceTracker = null;
}
synchronized (advertiserTrackerLock) {
if (advertiserTracker != null) {
advertiserTracker.close();
advertiserTracker = null;
}
}
synchronized (edToServiceIDMap) {
edToServiceIDMap.clear();
}
this.executor = null;
this.context = null;
}
public IDiscoveryAdvertiser[] getDiscoveryAdvertisers() {
return AccessController
.doPrivileged(new PrivilegedAction<IDiscoveryAdvertiser[]>() {
public IDiscoveryAdvertiser[] run() {
synchronized (advertiserTrackerLock) {
if (advertiserTracker == null) {
advertiserTracker = new ServiceTracker(context,
IDiscoveryAdvertiser.class.getName(),
null);
advertiserTracker.open();
}
}
ServiceReference[] advertiserRefs = advertiserTracker
.getServiceReferences();
if (advertiserRefs == null)
return null;
List<IDiscoveryAdvertiser> results = new ArrayList<IDiscoveryAdvertiser>();
for (int i = 0; i < advertiserRefs.length; i++) {
results.add((IDiscoveryAdvertiser) context
.getService(advertiserRefs[i]));
}
return results.toArray(new IDiscoveryAdvertiser[results
.size()]);
}
});
}
private void openLocator(IDiscoveryLocator locator) {
if (context == null)
return;
synchronized (locatorListeners) {
LocatorServiceListener locatorListener = new LocatorServiceListener(
locator);
locatorListeners.put(locator, locatorListener);
processInitialLocatorServices(locator, locatorListener);
}
}
private void shutdownLocator(IDiscoveryLocator locator) {
if (locator == null || context == null)
return;
synchronized (locatorListeners) {
LocatorServiceListener locatorListener = locatorListeners
.remove(locator);
if (locatorListener != null)
locatorListener.close();
}
}
void queueEndpointDescription(
EndpointEventListener listener,
org.osgi.service.remoteserviceadmin.EndpointDescription endpointDescription,
String matchingFilter, int eventType) {
if (eventQueue == null)
return;
synchronized (eventQueue) {
eventQueue.dispatchEventAsynchronous(0,
new EndpointEventListenerEvent(listener, new EndpointEvent(
eventType, endpointDescription), matchingFilter));
}
}
void queueEndpointDescription(
EndpointListener listener,
org.osgi.service.remoteserviceadmin.EndpointDescription endpointDescription,
String matchingFilters, boolean discovered) {
if (eventQueue == null)
return;
synchronized (eventQueue) {
eventQueue
.dispatchEventAsynchronous(0, new EndpointListenerEvent(
listener, endpointDescription, matchingFilters,
discovered));
}
}
void queueEndpointEvent(
org.osgi.service.remoteserviceadmin.EndpointDescription endpointDescription,
int type) {
EndpointEventListenerHolder[] endpointEventListenerHolders = getMatchingEndpointEventListenerHolders(
endpointDescription, type);
if (endpointEventListenerHolders != null) {
for (int i = 0; i < endpointEventListenerHolders.length; i++) {
queueEndpointDescription(
endpointEventListenerHolders[i].getListener(),
endpointEventListenerHolders[i].getDescription(),
endpointEventListenerHolders[i].getMatchingFilter(),
endpointEventListenerHolders[i].getType());
}
} else {
LogUtility.logWarning(
"queueEndpointDescription", //$NON-NLS-1$
DebugOptions.ENDPOINT_DESCRIPTION_LOCATOR, this.getClass(),
"No matching EndpointEventListeners found for event type" //$NON-NLS-1$
+ getEndpointEventTypeAsString(type)
+ " endpointDescription=" + endpointDescription); //$NON-NLS-1$
}
}
String getEndpointEventTypeAsString(int eventType) {
if (eventType == EndpointEvent.ADDED)
return "added"; //$NON-NLS-1$
if (eventType == EndpointEvent.MODIFIED)
return "modified"; //$NON-NLS-1$
if (eventType == EndpointEvent.MODIFIED_ENDMATCH)
return "modified endmatch"; //$NON-NLS-1$
if (eventType == EndpointEvent.REMOVED)
return "removed"; //$NON-NLS-1$
return "unknown"; //$NON-NLS-1$
}
void queueEndpointDescription(
org.osgi.service.remoteserviceadmin.EndpointDescription endpointDescription,
boolean discovered) {
EndpointListenerHolder[] endpointListenerHolders = getMatchingEndpointListenerHolders(endpointDescription);
if (endpointListenerHolders != null) {
for (int i = 0; i < endpointListenerHolders.length; i++) {
queueEndpointDescription(
endpointListenerHolders[i].getListener(),
endpointListenerHolders[i].getDescription(),
endpointListenerHolders[i].getMatchingFilter(),
discovered);
}
} else {
// For old-style notification, we ignore this since it's probably using EndpointEvents
}
}
private void processInitialLocatorServices(final IDiscoveryLocator locator,
final LocatorServiceListener locatorListener) {
IProgressRunnable runnable = new IProgressRunnable() {
public Object run(IProgressMonitor arg0) throws Exception {
IServiceInfo[] serviceInfos = null;
try {
serviceInfos = locator.getServices();
} catch (Exception e) {
logError(
"processInitialLocatorServices", "Exception in locator.getServices()", e); //$NON-NLS-1$ //$NON-NLS-2$
}
if (serviceInfos != null)
for (int i = 0; i < serviceInfos.length; i++) {
locatorListener.handleService(serviceInfos[i], true);
}
return null;
}
};
executor.execute(runnable, null);
}
void shutdownLocators() {
Object[] locators = locatorServiceTracker.getServices();
if (locators != null) {
for (int i = 0; i < locators.length; i++) {
// Add service listener to locator
shutdownLocator((IDiscoveryLocator) locators[i]);
}
}
}
private class EndpointEventListenerEvent {
private EndpointEventListener endpointEventListener;
private EndpointEvent event;
private String matchingFilter;
public EndpointEventListenerEvent(
EndpointEventListener endpointEventListener,
EndpointEvent event, String matchingFilter) {
this.endpointEventListener = endpointEventListener;
this.event = event;
this.matchingFilter = matchingFilter;
}
public EndpointEventListener getEndpointEventListener() {
return endpointEventListener;
}
public EndpointEvent getEndpointEvent() {
return event;
}
public String getMatchingFilter() {
return matchingFilter;
}
}
private class EndpointListenerEvent {
private EndpointListener endpointListener;
private org.osgi.service.remoteserviceadmin.EndpointDescription endpointDescription;
private String matchingFilter;
private boolean discovered;
public EndpointListenerEvent(
EndpointListener endpointListener,
org.osgi.service.remoteserviceadmin.EndpointDescription endpointDescription,
String matchingFilter, boolean discovered) {
this.endpointListener = endpointListener;
this.endpointDescription = endpointDescription;
this.matchingFilter = matchingFilter;
this.discovered = discovered;
}
public EndpointListener getEndpointListener() {
return endpointListener;
}
public org.osgi.service.remoteserviceadmin.EndpointDescription getEndointDescription() {
return endpointDescription;
}
public String getMatchingFilter() {
return matchingFilter;
}
public boolean isDiscovered() {
return discovered;
}
}
private class LocatorTrackerCustomizer implements ServiceTrackerCustomizer {
/*
* (non-Javadoc)
*
* @see
* org.osgi.util.tracker.ServiceTrackerCustomizer#addingService(org.
* osgi.framework.ServiceReference)
*/
public Object addingService(ServiceReference reference) {
IDiscoveryLocator locator = (IDiscoveryLocator) context
.getService(reference);
if (locator != null)
openLocator(locator);
return locator;
}
public void modifiedService(ServiceReference reference, Object service) {
}
public void removedService(ServiceReference reference, Object service) {
shutdownLocator((IDiscoveryLocator) service);
}
}
public IServiceInfoFactory getServiceInfoFactory() {
return AccessController
.doPrivileged(new PrivilegedAction<IServiceInfoFactory>() {
public IServiceInfoFactory run() {
synchronized (serviceInfoFactoryTrackerLock) {
if (serviceInfoFactoryTracker == null) {
serviceInfoFactoryTracker = new ServiceTracker(
context, IServiceInfoFactory.class
.getName(), null);
serviceInfoFactoryTracker.open();
}
}
return (IServiceInfoFactory) serviceInfoFactoryTracker
.getService();
}
});
}
public IDiscoveredEndpointDescriptionFactory getDiscoveredEndpointDescriptionFactory() {
synchronized (endpointDescriptionFactoryTrackerLock) {
if (context == null)
return null;
if (endpointDescriptionFactoryTracker == null) {
endpointDescriptionFactoryTracker = new ServiceTracker(context,
IDiscoveredEndpointDescriptionFactory.class.getName(),
null);
endpointDescriptionFactoryTracker.open();
}
return (IDiscoveredEndpointDescriptionFactory) endpointDescriptionFactoryTracker
.getService();
}
}
private Object endpointListenerServiceTrackerLock = new Object();
private Object endpointEventListenerServiceTrackerLock = new Object();
protected EndpointListenerHolder[] getMatchingEndpointListenerHolders(
final EndpointDescription description) {
return AccessController
.doPrivileged(new PrivilegedAction<EndpointListenerHolder[]>() {
public EndpointListenerHolder[] run() {
synchronized (endpointListenerServiceTrackerLock) {
return getMatchingEndpointListenerHolders(
endpointListenerTracker
.getServiceReferences(),
description);
}
}
});
}
/**
* @param description description
* @param type type
* @return EndpointEventListenerHolder[] matching endpoint event listener holders
* @since 4.1
*/
protected EndpointEventListenerHolder[] getMatchingEndpointEventListenerHolders(
final EndpointDescription description, final int type) {
return AccessController
.doPrivileged(new PrivilegedAction<EndpointEventListenerHolder[]>() {
public EndpointEventListenerHolder[] run() {
synchronized (endpointEventListenerServiceTrackerLock) {
return getMatchingEndpointEventListenerHolders(
endpointEventListenerTracker
.getServiceReferences(),
description, type);
}
}
});
}
/**
* @since 4.1
*/
public class EndpointEventListenerHolder {
private EndpointEventListener listener;
private EndpointDescription description;
private String matchingFilter;
private int type;
public EndpointEventListenerHolder(EndpointEventListener l,
EndpointDescription d, String f, int t) {
this.listener = l;
this.description = d;
this.matchingFilter = f;
this.type = t;
}
public EndpointEventListener getListener() {
return listener;
}
public EndpointDescription getDescription() {
return description;
}
public String getMatchingFilter() {
return matchingFilter;
}
public int getType() {
return type;
}
}
public class EndpointListenerHolder {
private EndpointListener listener;
private EndpointDescription description;
private String matchingFilter;
public EndpointListenerHolder(EndpointListener l,
EndpointDescription d, String f) {
this.listener = l;
this.description = d;
this.matchingFilter = f;
}
public EndpointListener getListener() {
return listener;
}
public EndpointDescription getDescription() {
return description;
}
public String getMatchingFilter() {
return matchingFilter;
}
}
/**
* @param refs service references
* @param description description
* @param type type
* @return EndpointEventListenerHolder[] matching endpoint event listener holders
* @since 4.1
*/
public EndpointEventListenerHolder[] getMatchingEndpointEventListenerHolders(
ServiceReference[] refs, EndpointDescription description, int type) {
if (refs == null)
return null;
List results = new ArrayList();
for (int i = 0; i < refs.length; i++) {
EndpointEventListener listener = (EndpointEventListener) context
.getService(refs[i]);
if (listener == null)
continue;
List<String> filters = PropertiesUtil.getStringPlusProperty(
getMapFromProperties(refs[i]),
EndpointEventListener.ENDPOINT_LISTENER_SCOPE);
// Only proceed if there is a filter present
if (filters.size() > 0) {
String matchingFilter = isMatch(description, filters);
if (matchingFilter != null)
results.add(new EndpointEventListenerHolder(listener,
description, matchingFilter, type));
}
}
return (EndpointEventListenerHolder[]) results
.toArray(new EndpointEventListenerHolder[results.size()]);
}
public EndpointListenerHolder[] getMatchingEndpointListenerHolders(
ServiceReference[] refs, EndpointDescription description) {
if (refs == null)
return null;
List results = new ArrayList();
for (int i = 0; i < refs.length; i++) {
EndpointListener listener = (EndpointListener) context
.getService(refs[i]);
if (listener == null)
continue;
List<String> filters = PropertiesUtil.getStringPlusProperty(
getMapFromProperties(refs[i]),
EndpointListener.ENDPOINT_LISTENER_SCOPE);
if (filters.size() > 0) {
String matchingFilter = isMatch(description, filters);
if (matchingFilter != null)
results.add(new EndpointListenerHolder(listener,
description, matchingFilter));
}
}
return (EndpointListenerHolder[]) results
.toArray(new EndpointListenerHolder[results.size()]);
}
private String isMatch(EndpointDescription description, List<String> filters) {
for (String filter : filters) {
if (filter == null || "".equals(filter))continue; //$NON-NLS-1$
try {
if (description.matches(filter))
return filter;
} catch (IllegalArgumentException e) {
logError("isMatch", "invalid endpoint listener filter=" //$NON-NLS-1$ //$NON-NLS-2$
+ filters, e);
}
}
return null;
}
private Map getMapFromProperties(ServiceReference ref) {
Map<String, Object> results = new TreeMap<String, Object>(
String.CASE_INSENSITIVE_ORDER);
String[] keys = ref.getPropertyKeys();
if (keys != null) {
for (int i = 0; i < keys.length; i++) {
results.put(keys[i], ref.getProperty(keys[i]));
}
}
return results;
}
class EndpointDescriptionBundleTrackerCustomizer implements
BundleTrackerCustomizer {
private static final String REMOTESERVICE_MANIFESTHEADER = "Remote-Service"; //$NON-NLS-1$
private static final String XML_FILE_PATTERN = "*.xml"; //$NON-NLS-1$
private Map<Long, Collection<org.osgi.service.remoteserviceadmin.EndpointDescription>> bundleDescriptionMap = Collections
.synchronizedMap(new HashMap<Long, Collection<org.osgi.service.remoteserviceadmin.EndpointDescription>>());
private Object endpointDescriptionReaderTrackerLock = new Object();
private ServiceTracker endpointDescriptionReaderTracker;
private IEndpointDescriptionReader getEndpointDescriptionReader() {
synchronized (endpointDescriptionReaderTrackerLock) {
if (endpointDescriptionReaderTracker == null) {
endpointDescriptionReaderTracker = new ServiceTracker(
context,
IEndpointDescriptionReader.class.getName(), null);
endpointDescriptionReaderTracker.open();
}
}
return (IEndpointDescriptionReader) endpointDescriptionReaderTracker
.getService();
}
public Object addingBundle(Bundle bundle, BundleEvent event) {
handleAddingBundle(bundle);
return bundle;
}
private void handleAddingBundle(Bundle bundle) {
if (context == null)
return;
String remoteServicesHeaderValue = (String) bundle.getHeaders()
.get(REMOTESERVICE_MANIFESTHEADER);
if (remoteServicesHeaderValue != null) {
// First parse into comma-separated values
String[] paths = remoteServicesHeaderValue.split(","); //$NON-NLS-1$
if (paths != null)
for (int i = 0; i < paths.length; i++)
handleEndpointDescriptionPath(bundle, paths[i].trim());
}
}
private void handleEndpointDescriptionPath(Bundle bundle,
String remoteServicesHeaderValue) {
// if it's empty, ignore
if ("".equals(remoteServicesHeaderValue)) //$NON-NLS-1$
return;
Enumeration<URL> e = null;
// if it endswith a '/', then scan for *.xml files
if (remoteServicesHeaderValue.endsWith("/")) { //$NON-NLS-1$
e = bundle.findEntries(remoteServicesHeaderValue,
XML_FILE_PATTERN, false);
} else {
// Break into path and filename/pattern
int lastSlashIndex = remoteServicesHeaderValue.lastIndexOf('/');
if (lastSlashIndex == -1) {
// no slash...might be a file name or pattern, assumed to be
// at root of bundle
e = bundle.findEntries(
"/", remoteServicesHeaderValue, false); //$NON-NLS-1$
} else {
String path = remoteServicesHeaderValue.substring(0,
lastSlashIndex);
if ("".equals(path)) { //$NON-NLS-1$
// path is empty so assume it's root
path = "/"; //$NON-NLS-1$
}
String filePattern = remoteServicesHeaderValue
.substring(lastSlashIndex + 1);
e = bundle.findEntries(path, filePattern, false);
}
}
// Now process any found
Collection<org.osgi.service.remoteserviceadmin.EndpointDescription> endpointDescriptions = new ArrayList<org.osgi.service.remoteserviceadmin.EndpointDescription>();
if (e != null) {
while (e.hasMoreElements()) {
org.osgi.service.remoteserviceadmin.EndpointDescription[] eps = handleEndpointDescriptionFile(
bundle, e.nextElement());
if (eps != null)
for (int i = 0; i < eps.length; i++)
endpointDescriptions.add(eps[i]);
}
} else {
// logError
logError(
"handleEndpointDescriptionPath", "EDEF file(s) not found. The EDEF files given by Remote-Service header value='" + remoteServicesHeaderValue + "' in bundle='" + bundle.getSymbolicName() + "' cannot be found for remote services discovery", new FileNotFoundException("name=" + remoteServicesHeaderValue)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
}
// finally, handle them
if (endpointDescriptions.size() > 0) {
bundleDescriptionMap.put(new Long(bundle.getBundleId()),
endpointDescriptions);
for (org.osgi.service.remoteserviceadmin.EndpointDescription ed : endpointDescriptions) {
addED(ed, null);
handleEndpointDescription(ed, true);
}
}
}
private org.osgi.service.remoteserviceadmin.EndpointDescription[] handleEndpointDescriptionFile(
Bundle bundle, URL fileURL) {
InputStream ins = null;
try {
IEndpointDescriptionReader endpointDescriptionReader = getEndpointDescriptionReader();
if (endpointDescriptionReader == null)
throw new NullPointerException(
"No endpointDescriptionReader available for handleEndpointDescriptionFile fileURL=" //$NON-NLS-1$
+ fileURL);
ins = fileURL.openStream();
return endpointDescriptionReader.readEndpointDescriptions(ins);
} catch (Throwable e) {
logError("handleEndpointDescriptionFile", //$NON-NLS-1$
"Exception creating endpoint descriptions from fileURL=" //$NON-NLS-1$
+ fileURL, e);
return null;
} finally {
if (ins != null)
try {
ins.close();
} catch (IOException e) {
logError("handleEndpointDescriptionFile", //$NON-NLS-1$
"Exception closing endpointDescription input fileURL=" //$NON-NLS-1$
+ fileURL, e);
}
}
}
private void logError(String method, String message, Throwable t) {
LogUtility.logError(method,
DebugOptions.ENDPOINT_DESCRIPTION_LOCATOR, this.getClass(),
new Status(IStatus.ERROR, Activator.PLUGIN_ID,
IStatus.ERROR, message, t));
}
public void modifiedBundle(Bundle bundle, BundleEvent event,
Object object) {
}
public void removedBundle(Bundle bundle, BundleEvent event,
Object object) {
handleRemovedBundle(bundle);
}
private void handleRemovedBundle(Bundle bundle) {
Collection<org.osgi.service.remoteserviceadmin.EndpointDescription> endpointDescriptions = bundleDescriptionMap
.remove(new Long(bundle.getBundleId()));
if (endpointDescriptions != null)
for (org.osgi.service.remoteserviceadmin.EndpointDescription ed : endpointDescriptions) {
removeED(ed);
handleEndpointDescription(ed, false);
}
}
public void close() {
synchronized (endpointDescriptionReaderTrackerLock) {
if (endpointDescriptionReaderTracker != null) {
endpointDescriptionReaderTracker.close();
endpointDescriptionReaderTracker = null;
}
}
bundleDescriptionMap.clear();
}
}
private Map<EndpointDescription, IServiceID> edToServiceIDMap = new HashMap<EndpointDescription, IServiceID>();
Set<EndpointDescription> getEDs() {
synchronized (edToServiceIDMap) {
return edToServiceIDMap.keySet();
}
}
EndpointDescription findED(IServiceID serviceID) {
synchronized (edToServiceIDMap) {
for (EndpointDescription ed : getEDs()) {
IServiceID sid = edToServiceIDMap.get(ed);
if (sid != null
&& sid.getLocation().equals(serviceID.getLocation()))
return ed;
}
}
return null;
}
void updateED(EndpointDescription existing, EndpointDescription update,
IServiceID updateServiceID) {
synchronized (edToServiceIDMap) {
edToServiceIDMap.remove(existing);
edToServiceIDMap.put(update, updateServiceID);
}
}
void addED(org.osgi.service.remoteserviceadmin.EndpointDescription ed,
IServiceID serviceID) {
synchronized (edToServiceIDMap) {
edToServiceIDMap.put(ed, serviceID);
}
}
void removeED(org.osgi.service.remoteserviceadmin.EndpointDescription ed) {
synchronized (edToServiceIDMap) {
edToServiceIDMap.remove(ed);
}
}
boolean containsED(EndpointDescription ed) {
synchronized (edToServiceIDMap) {
return getEDs().contains(ed);
}
}
Set<EndpointDescription> getEDsForNamespace(Namespace namespace) {
Set<EndpointDescription> results = new HashSet<EndpointDescription>();
synchronized (edToServiceIDMap) {
for (EndpointDescription ed : edToServiceIDMap.keySet()) {
IServiceID svcID = edToServiceIDMap.get(ed);
if (svcID != null
&& svcID.getNamespace().getName()
.equals(namespace.getName()))
results.add(ed);
}
}
return results;
}
/**
* @since 4.3
*/
public IServiceID getNetworkDiscoveredServiceID(
org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription endpointDescription) {
synchronized (edToServiceIDMap) {
return edToServiceIDMap.get(endpointDescription);
}
}
void handleEndpointDescription(EndpointDescription endpointDescription,
boolean discovered) {
if (discovered) {
queueEndpointEvent(endpointDescription, EndpointEvent.ADDED);
queueEndpointDescription(endpointDescription, discovered);
} else {
queueEndpointEvent(endpointDescription, EndpointEvent.REMOVED);
queueEndpointDescription(endpointDescription, discovered);
}
}
class LocatorServiceListener implements IServiceListener {
private IDiscoveryLocator locator;
public LocatorServiceListener(IDiscoveryLocator locator) {
this.locator = locator;
if (locator != null)
this.locator.addServiceListener(this);
}
Collection<EndpointDescription> getEndpointDescriptions() {
return (this.locator == null) ? Collections.EMPTY_SET
: getEDsForNamespace(this.locator.getServicesNamespace());
}
public void serviceDiscovered(IServiceEvent anEvent) {
handleService(anEvent.getServiceInfo(), true);
}
public void serviceUndiscovered(IServiceEvent anEvent) {
handleService(anEvent.getServiceInfo(), false);
}
void handleService(IServiceInfo serviceInfo, boolean discovered) {
if (locator == null)
return;
IServiceID serviceID = serviceInfo.getServiceID();
// Make sure this is an OSGi Remote Service
if (Arrays.asList(serviceID.getServiceTypeID().getServices())
.contains(RemoteConstants.DISCOVERY_SERVICE_TYPE)) {
trace("handleService", "fwk=" + getFrameworkUUID() + " serviceInfo=" + serviceInfo //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ ", discovered=" + discovered + ", locator=" + locator); //$NON-NLS-1$ //$NON-NLS-2$
synchronized (edToServiceIDMap) {
// Try to find ED from ServiceID, whether discovered or
// undiscovered
org.osgi.service.remoteserviceadmin.EndpointDescription ed = findED(serviceID);
if (discovered) {
// The IServiceInfo was discovered/added
if (ed == null) {
// Deserialize EndpointDescription from service
// properties
DiscoveredEndpointDescription discoveredEndpointDescription = getDiscoveredEndpointDescription(
serviceID, serviceInfo, true);
// Make sure that the discoveredEndpointDescription
// is non-null
if (discoveredEndpointDescription != null) {
ed = discoveredEndpointDescription
.getEndpointDescription();
if (ed != null) {
EndpointDescription prevEd = isEndpointDescriptionUpdate(
ed, serviceID);
if (prevEd == null) {
if (!containsED(ed)) {
addED(ed, serviceID);
handleEndpointDescription(ed, true);
} else
trace("handleEndpointDescription", "endpointDescription previously discovered...ignoring"); //$NON-NLS-1$ //$NON-NLS-2$
} else {
// It was a modify/update
trace("handleEndpointDescription", "endpointDescription updated. prev=" + prevEd + ", update=" + ed); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
queueEndpointEvent(ed,
EndpointEvent.MODIFIED);
}
} else
trace("handleService", "EndpointDescription is null for serviceID=" + serviceID); //$NON-NLS-1$ //$NON-NLS-2$
} else
trace("handleService", "DiscoveredEndpointDescription is null for serviceID=" + serviceID); //$NON-NLS-1$ //$NON-NLS-2$
} else
trace("handleService", "Found previous EndpointDescription with same serviceID=" + serviceID + ". Ignoring"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} else {
// It was undiscovered
if (ed != null) {
removeED(ed);
handleEndpointDescription(ed, false);
} else
trace("handleService", "Did not find serviceInfo with serviceID=" + serviceID + ". Ignoring"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
}
}
EndpointDescription isEndpointDescriptionUpdate(
EndpointDescription endpointDescription,
IServiceID updateServiceID) {
if (endpointDescription instanceof org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription) {
org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription ed = (org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription) endpointDescription;
Long receivedTS = ed.getTimestamp();
if (receivedTS != null) {
String receivedId = ed.getId();
boolean update = false;
org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription ped = null;
for (EndpointDescription previousEndpoint : getEndpointDescriptions()) {
if (previousEndpoint instanceof org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription) {
ped = (org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription) previousEndpoint;
// Test pedId against receivedId...we only care
// about
// matches
if (!ped.getId().equals(receivedId))
continue;
Long pedTS = ped.getTimestamp();
// Now, it's only an update if the received
// timestamp is
// after the
// previous timestamp
if (pedTS != null
&& pedTS.longValue() < receivedTS
.longValue())
update = true;
}
}
if (update) {
updateED(ped, ed, updateServiceID);
return ed;
}
}
} else {
Map<String, Object> edProperties = endpointDescription
.getProperties();
Long receivedTS = PropertiesUtil
.getOSGiEndpointModifiedValue(edProperties);
if (receivedTS != null) {
String receivedId = endpointDescription.getId();
boolean update = false;
EndpointDescription ped = null;
for (EndpointDescription previousEndpoint : getEndpointDescriptions()) {
ped = previousEndpoint;
// If the previously discovered endpoint id does not
// equal
// the receivedId, then we haven't found it
if (!previousEndpoint.getId().equals(receivedId))
continue;
// If we have found it, get the property value if
// present
Long pedTS = (Long) previousEndpoint.getProperties()
.get(RemoteConstants.OSGI_ENDPOINT_MODIFIED);
// If it wasn't there before then this is definitely an
// update
if (pedTS == null)
update = true;
else if (pedTS.longValue() == receivedTS.longValue())
return null;
else if (pedTS == null
|| pedTS.longValue() < receivedTS.longValue())
update = true;
}
if (update) {
updateED(ped, endpointDescription, updateServiceID);
return endpointDescription;
}
}
}
return null;
}
private DiscoveredEndpointDescription getDiscoveredEndpointDescription(
IServiceID serviceId, IServiceInfo serviceInfo,
boolean discovered) {
// Get IEndpointDescriptionFactory
final String methodName = "getDiscoveredEndpointDescription"; //$NON-NLS-1$
IDiscoveredEndpointDescriptionFactory factory = getDiscoveredEndpointDescriptionFactory();
try {
// Else get endpoint description factory to create
// EndpointDescription
// for given serviceID and serviceInfo
return (discovered) ? factory
.createDiscoveredEndpointDescription(locator,
serviceInfo)
: factory.removeDiscoveredEndpointDescription(locator,
serviceId);
} catch (Exception e) {
logError(
methodName,
"Exception calling IEndpointDescriptionFactory." //$NON-NLS-1$
+ ((discovered) ? "createDiscoveredEndpointDescription" //$NON-NLS-1$
: "getUndiscoveredEndpointDescription"), e); //$NON-NLS-1$
return null;
} catch (NoClassDefFoundError e) {
logError(
methodName,
"NoClassDefFoundError calling IEndpointDescriptionFactory." //$NON-NLS-1$
+ ((discovered) ? "createDiscoveredEndpointDescription" //$NON-NLS-1$
: "getUndiscoveredEndpointDescription"), e); //$NON-NLS-1$
return null;
}
}
public synchronized void close() {
if (locator != null) {
locator.removeServiceListener(this);
locator = null;
}
}
public boolean triggerDiscovery() {
return false;
}
}
/**
* @since 4.3
*/
public void discoverEndpoint(
org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription endpointDescription) {
addED(endpointDescription, null);
queueEndpointEvent(endpointDescription, EndpointEvent.ADDED);
}
/**
* @since 4.3
*/
public void updateEndpoint(
org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription endpointDescription) {
updateED(endpointDescription, endpointDescription, null);
queueEndpointEvent(endpointDescription, EndpointEvent.MODIFIED);
}
/**
* @since 4.3
*/
public void undiscoverEndpoint(
org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription endpointDescription) {
removeED(endpointDescription);
queueEndpointEvent(endpointDescription, EndpointEvent.REMOVED);
}
/**
* @since 4.3
*/
public org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription[] getDiscoveredEndpoints() {
List<org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription> results = new ArrayList<org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription>();
for (EndpointDescription ed : getEDs()) {
if (ed instanceof org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription)
results.add((org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription) ed);
}
return results
.toArray(new org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription[results
.size()]);
}
}