| /**************************************************************************** |
| * 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.lang.reflect.Array; |
| import java.lang.reflect.InvocationTargetException; |
| import java.net.MalformedURLException; |
| 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 java.util.UUID; |
| |
| 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.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}. |
| * |
| * @since 4.8 |
| * |
| */ |
| public class EndpointDescriptionLocator implements IEndpointDescriptionLocator { |
| |
| private static final String LOCAL_PROPERTIES_PROFILE = EndpointDescriptionLocator.class.getName() |
| + ".localPropertiesProfile"; //$NON-NLS-1$ |
| |
| private static final String DEFAULT_PROPERTIES_FILE = System.getProperty( |
| EndpointDescriptionLocator.class.getName() + ".defaultPropertiesFilename", "default.properties"); //$NON-NLS-1$ //$NON-NLS-2$ |
| private static final String DEFAULT_PROPERTIES_URL = System |
| .getProperty(EndpointDescriptionLocator.class.getName() + ".defaultPropertiesUrl"); //$NON-NLS-1$ |
| |
| 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 + " ", //$NON-NLS-1$ //$NON-NLS-2$ |
| "fwk=" + getFrameworkUUID() + ", endpointListener=" //$NON-NLS-1$ //$NON-NLS-2$ |
| + 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=" //$NON-NLS-1$ |
| + getEndpointEventTypeAsString(endpointEvent.getType()) + " ", //$NON-NLS-1$ |
| "fwk=" + getFrameworkUUID() + ", endpointEventListener=" //$NON-NLS-1$ //$NON-NLS-2$ |
| + 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)) //$NON-NLS-1$ |
| continue; |
| 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) { |
| if (context != null) { |
| 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()); |
| } |
| } |
| return bundle; |
| } |
| |
| protected 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", //$NON-NLS-1$ |
| "EDEF file(s) not found. The EDEF files given by Remote-Service header value='" //$NON-NLS-1$ |
| + remoteServicesHeaderValue + "' in bundle='" + bundle.getSymbolicName() //$NON-NLS-1$ |
| + "' cannot be found for remote services discovery", //$NON-NLS-1$ |
| new FileNotFoundException("name=" + remoteServicesHeaderValue)); //$NON-NLS-1$ |
| } |
| // finally, handle them |
| if (endpointDescriptions.size() > 0) { |
| bundleDescriptionMap.put(Long.valueOf(bundle.getBundleId()), endpointDescriptions); |
| for (org.osgi.service.remoteserviceadmin.EndpointDescription ed : endpointDescriptions) { |
| addED(ed, null); |
| handleEndpointDescription(ed, true); |
| } |
| } |
| } |
| |
| protected org.osgi.service.remoteserviceadmin.EndpointDescription[] handleEndpointDescriptionFile(Bundle bundle, |
| URL fileURL) { |
| |
| trace("handleEndpointDescriptionFile", //$NON-NLS-1$ |
| "edef file detected. BundleId=" + bundle.getBundleId() + " fileURL=" + fileURL + " found"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| |
| InputStream ins = null; |
| Map<String, Object> mergeProperties = findOverrideProperties(bundle, fileURL); |
| 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, mergeProperties); |
| } 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(Long.valueOf(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(); |
| } |
| } |
| |
| /** |
| * @since 4.7 |
| */ |
| protected URL getPropsURLFromEDFileURL(URL edFileURL) { |
| String localPropertiesProfile = System.getProperty(LOCAL_PROPERTIES_PROFILE); |
| String profileSuffix = localPropertiesProfile != null ? "-" + localPropertiesProfile : ""; //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| String edFile = edFileURL.getFile(); |
| int slashIndex = edFile.lastIndexOf('/'); |
| String parentPath = ""; //$NON-NLS-1$ |
| if (slashIndex > -1) { |
| parentPath = edFile.substring(0, slashIndex) + "/"; //$NON-NLS-1$ |
| edFile = edFile.substring(slashIndex + 1); |
| } |
| int dotIndex = edFile.lastIndexOf('.'); |
| if (dotIndex > 0) { |
| edFile = edFile.substring(0, dotIndex); |
| } |
| // Now combine to create new path name/filename.ext |
| try { |
| return new URL(edFileURL.getProtocol(), edFileURL.getHost(), edFileURL.getPort(), |
| parentPath + edFile + profileSuffix + ".properties"); //$NON-NLS-1$ |
| } catch (MalformedURLException e) { |
| LogUtility.logError("getPropsURLFromEDFileURL", DebugOptions.ENDPOINT_DESCRIPTION_LOCATOR, getClass(), //$NON-NLS-1$ |
| "URL could not be used to load properties file"); //$NON-NLS-1$ |
| return null; |
| } |
| } |
| |
| /** |
| * @since 4.8 |
| */ |
| protected URL getDefaultPropsURLFromEDFileURL(URL edFileURL) { |
| try { |
| URL url = null; |
| if (DEFAULT_PROPERTIES_URL != null) { |
| url = new URL(DEFAULT_PROPERTIES_URL); |
| } else { |
| String edFile = edFileURL.getFile(); |
| int slashIndex = edFile.lastIndexOf('/'); |
| String parentPath = ""; //$NON-NLS-1$ |
| if (slashIndex > -1) { |
| parentPath = edFile.substring(0, slashIndex) + "/"; //$NON-NLS-1$ |
| } |
| url = new URL(edFileURL.getProtocol(), edFileURL.getHost(), edFileURL.getPort(), |
| parentPath + DEFAULT_PROPERTIES_FILE); |
| } |
| return url; |
| } catch (MalformedURLException e) { |
| LogUtility.logError("getDefaultPropsURLFromEDFileURL", DebugOptions.ENDPOINT_DESCRIPTION_LOCATOR, //$NON-NLS-1$ |
| getClass(), "URL could not be used to load properties file"); //$NON-NLS-1$ |
| return null; |
| } |
| } |
| |
| /** |
| * @since 4.8 |
| */ |
| protected static class EDEFProperties extends Properties { |
| |
| private static final long serialVersionUID = -7351470248095230347L; |
| |
| @Override |
| public synchronized Object put(Object key, Object value) { |
| String keyStr = (String) key; |
| String valueStr = (String) value; |
| EDEFPropertyValue propValue = null; |
| if (keyStr != null && valueStr != null) { |
| EDEFPropertyValue newValue = new EDEFPropertyValue(valueStr); |
| EDEFPropertyValue oldValue = (EDEFPropertyValue) this.get(keyStr); |
| if (oldValue == null) { |
| propValue = newValue; |
| } else { |
| propValue = oldValue.addPropertyValue(newValue); |
| } |
| super.put(keyStr, propValue); |
| } |
| return null; |
| } |
| } |
| |
| /** |
| * @since 4.8 |
| */ |
| protected EDEFProperties loadProperties(URL url) throws IOException { |
| EDEFProperties result = new EDEFProperties(); |
| try (InputStream ins = url.openStream()) { |
| result.load(ins); |
| } |
| return result; |
| } |
| |
| /** |
| * @since 4.8 |
| */ |
| public static class EDEFPropertyValue { |
| private static int nextInt = 0; |
| private static long nextLong = 0; |
| private static short nextShort = 0; |
| private static byte nextByte = 0; |
| private String type1; |
| private String type2; |
| private String value; |
| private Object resultValue; |
| |
| synchronized static int getNextInteger() { |
| if (nextInt == Integer.MAX_VALUE) { |
| nextInt = 0; |
| } |
| return ++nextInt; |
| } |
| |
| boolean isArray() { |
| return this.type1.equalsIgnoreCase("array"); //$NON-NLS-1$ |
| } |
| |
| boolean isSet() { |
| return this.type1.equalsIgnoreCase("set"); //$NON-NLS-1$ |
| } |
| |
| boolean isList() { |
| return this.type1.equalsIgnoreCase("list"); //$NON-NLS-1$ |
| } |
| |
| boolean isCollection() { |
| return isSet() || isList(); |
| } |
| |
| boolean isSimpleType() { |
| return !isSet() && !isList() && !isArray(); |
| } |
| |
| boolean hasTypeAgreement(EDEFPropertyValue otherValue) { |
| String otherType = (otherValue.isArray() || otherValue.isCollection()) ? otherValue.type2 |
| : otherValue.type1; |
| return (isArray() || isCollection()) ? this.type2.equalsIgnoreCase(otherType) |
| : this.type1.equalsIgnoreCase(otherType); |
| } |
| |
| EDEFPropertyValue addPropertyValue(EDEFPropertyValue newValue) { |
| if (!hasTypeAgreement(newValue)) { |
| LogUtility.logError("addEDEFPropertyValue", DebugOptions.ENDPOINT_DESCRIPTION_LOCATOR, getClass(), //$NON-NLS-1$ |
| "type disagreement between property values for old type1=" + this.type1 + ",type2=" + this.type2 //$NON-NLS-1$ //$NON-NLS-2$ |
| + ", and new type1=" + newValue.type1 + ",type2=" + newValue.type2); //$NON-NLS-1$ //$NON-NLS-2$ |
| return this; |
| } |
| // get old and new values |
| Object ov = this.getValue(); |
| Object nv = newValue.getValue(); |
| // If we've got a collection already |
| if (isCollection()) { |
| Collection oldVs = (Collection) ov; |
| // If newValue is also collection |
| if (newValue.isCollection()) { |
| // Then addAll |
| oldVs.addAll((Collection) nv); |
| } else if (newValue.isSimpleType()) { |
| // Add single element |
| oldVs.add(nv); |
| } |
| } else if (isArray()) { |
| // Get old length |
| int oldLength = Array.getLength(ov); |
| Object newResultValue = null; |
| if (newValue.isArray()) { |
| // new value is also array...get length |
| int newLength = Array.getLength(nv); |
| // Check to make sure that the type of elements is same (type2 for arrays) |
| newResultValue = Array.newInstance(ov.getClass().getComponentType(), oldLength + newLength); |
| // copy ov contents to newResultValue |
| System.arraycopy(ov, 0, newResultValue, 0, oldLength); |
| // append nv contents to newResultValue after ov contents |
| System.arraycopy(nv, 0, newResultValue, oldLength, newLength); |
| } else if (newValue.isSimpleType()) { |
| newResultValue = Array.newInstance(ov.getClass().getComponentType(), oldLength + 1); |
| System.arraycopy(ov, 0, newResultValue, 0, oldLength); |
| Array.set(newResultValue, oldLength, nv); |
| } |
| if (newResultValue != null) { |
| this.resultValue = newResultValue; |
| } |
| } |
| return this; |
| } |
| |
| synchronized static long getNextLong() { |
| if (nextLong == Long.MAX_VALUE) { |
| nextLong = 0; |
| } |
| return ++nextLong; |
| } |
| |
| synchronized static short getNextShort() { |
| if (nextShort == Short.MAX_VALUE) { |
| nextShort = 0; |
| } |
| return ++nextShort; |
| } |
| |
| synchronized static byte getNextByte() { |
| if (nextByte == Byte.MAX_VALUE) { |
| nextByte = 0; |
| } |
| return ++nextByte; |
| } |
| |
| public EDEFPropertyValue(String value) { |
| // Default type1 is String |
| this.type1 = "String"; //$NON-NLS-1$ |
| // Default type2 is String also |
| this.type2 = "String"; //$NON-NLS-1$ |
| // Split value with = |
| String[] valueArr = value.split("="); //$NON-NLS-1$ |
| // Split first one |
| if (valueArr.length > 1) { |
| // split second element in valueArr by : |
| String[] firstSplit = valueArr[0].split(":"); //$NON-NLS-1$ |
| // If more than one then type2 is second element in firstSplit |
| if (firstSplit.length > 1) { |
| this.type2 = firstSplit[1]; |
| } |
| // In either case type1 is firstSplit[0] |
| this.type1 = firstSplit[0]; |
| } |
| // Now set value to the last elemtn in the valueArr |
| this.value = valueArr[valueArr.length - 1]; |
| } |
| |
| private Object getSimpleValue(Class<?> simpleType, Object value) { |
| try { |
| return simpleType.getDeclaredMethod("valueOf", new Class[] { String.class }).invoke(null, value); //$NON-NLS-1$ |
| } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException |
| | NoSuchMethodException | SecurityException e) { |
| LogUtility.logWarning("getSimpleValue", DebugOptions.ENDPOINT_DESCRIPTION_LOCATOR, this.getClass(), //$NON-NLS-1$ |
| "Cannot create instance of simpleType=" + simpleType + ", value=" + value); //$NON-NLS-1$ //$NON-NLS-2$ |
| return null; |
| } |
| } |
| |
| boolean isUnique() { |
| return "unique".equals(this.type2); //$NON-NLS-1$ |
| } |
| |
| Object getSimpleValue(String simpleType, String value) { |
| switch (simpleType) { |
| case "long": //$NON-NLS-1$ |
| case "Long": //$NON-NLS-1$ |
| if ("unique".equalsIgnoreCase(this.type2)) { //$NON-NLS-1$ |
| return getNextLong(); |
| } else if ("nanoTime".equalsIgnoreCase(this.type2)) { //$NON-NLS-1$ |
| return System.nanoTime(); |
| } else if ("milliTime".equalsIgnoreCase(this.type2)) { //$NON-NLS-1$ |
| return System.currentTimeMillis(); |
| } |
| return getSimpleValue(Long.class, value); |
| case "double": //$NON-NLS-1$ |
| case "Double": //$NON-NLS-1$ |
| return getSimpleValue(Double.class, value); |
| case "float": //$NON-NLS-1$ |
| case "Float": //$NON-NLS-1$ |
| return getSimpleValue(Float.class, value); |
| case "int": //$NON-NLS-1$ |
| case "Integer": //$NON-NLS-1$ |
| if ("unique".equals(this.type2)) { //$NON-NLS-1$ |
| return getNextInteger(); |
| } |
| return getSimpleValue(Integer.class, value); |
| case "Byte": //$NON-NLS-1$ |
| case "byte": //$NON-NLS-1$ |
| if ("unique".equals(this.type2)) { //$NON-NLS-1$ |
| return getNextByte(); |
| } |
| return getSimpleValue(Byte.class, value); |
| case "char": //$NON-NLS-1$ |
| case "Character": //$NON-NLS-1$ |
| return getSimpleValue(Character.class, value.toCharArray()[0]); |
| case "boolean": //$NON-NLS-1$ |
| case "Boolean": //$NON-NLS-1$ |
| return getSimpleValue(Boolean.class, value); |
| case "short": //$NON-NLS-1$ |
| case "Short": //$NON-NLS-1$ |
| if ("unique".equals(this.type2)) { //$NON-NLS-1$ |
| return getNextShort(); |
| } |
| return getSimpleValue(Short.class, value); |
| case "uuid": //$NON-NLS-1$ |
| case "Uuid": //$NON-NLS-1$ |
| case "UUID": //$NON-NLS-1$ |
| // we don't care whether 'unique' is given or not |
| return UUID.randomUUID().toString(); |
| case "String": //$NON-NLS-1$ |
| case "string": //$NON-NLS-1$ |
| return value; |
| default: |
| return null; |
| } |
| } |
| |
| Object getArrayValues(String collectionValue) { |
| String[] elements = this.value.split("\\s*,\\s*"); //$NON-NLS-1$ |
| Object result = null; |
| for (int i = 0; i < elements.length; i++) { |
| Object elementValue = getSimpleValue(this.type2, elements[i]); |
| if (elementValue == null) { |
| LogUtility.logWarning("getArrayValues", DebugOptions.ENDPOINT_DESCRIPTION_LOCATOR, getClass(), //$NON-NLS-1$ |
| "array element=" + elements[i] + " could not be created"); //$NON-NLS-1$//$NON-NLS-2$ |
| continue; |
| } else { |
| if (i == 0) { |
| result = Array.newInstance(elementValue.getClass(), elements.length); |
| } |
| Array.set(result, i, elementValue); |
| } |
| } |
| return result; |
| } |
| |
| Collection<Object> getCollectionValues(Collection<Object> c, String collectionValue) { |
| String[] elements = this.value.split("\\s*,\\s*"); //$NON-NLS-1$ |
| for (String element : elements) { |
| Object elementValue = getSimpleValue(this.type2, element); |
| if (elementValue == null) { |
| LogUtility.logWarning("getCollectionValues", DebugOptions.ENDPOINT_DESCRIPTION_LOCATOR, getClass(), //$NON-NLS-1$ |
| "array element=" + element + " could not be created"); //$NON-NLS-1$//$NON-NLS-2$ |
| continue; |
| } else { |
| c.add(elementValue); |
| } |
| } |
| return c; |
| } |
| |
| public synchronized Object getValue() { |
| if (this.resultValue == null) { |
| switch (this.type1) { |
| case "array": //$NON-NLS-1$ |
| this.resultValue = getArrayValues(this.value); |
| break; |
| case "list": //$NON-NLS-1$ |
| this.resultValue = getCollectionValues(new ArrayList(), this.value); |
| break; |
| case "set": //$NON-NLS-1$ |
| this.resultValue = getCollectionValues(new HashSet(), this.value); |
| break; |
| default: |
| this.resultValue = getSimpleValue(this.type1, this.value); |
| break; |
| } |
| } |
| return this.resultValue; |
| } |
| } |
| |
| /** |
| * @since 4.8 |
| */ |
| protected Map<String, Object> processProperties(Properties props) { |
| Map<String, Object> result = new HashMap<String, Object>(); |
| if (props == null) { |
| return result; |
| } |
| props.forEach((k, v) -> { |
| String name = (String) k; |
| Object value = ((EDEFPropertyValue) v).getValue(); |
| if (value != null) { |
| result.put(name, value); |
| } else { |
| LogUtility.logWarning("processProperties", DebugOptions.ENDPOINT_DESCRIPTION_LOCATOR, getClass(), //$NON-NLS-1$ |
| "Invalid EDEFPropertyValue for name=" + name + ". Not added to processed properties"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| }); |
| return result; |
| } |
| |
| /** |
| * @since 4.7 |
| */ |
| protected Map<String, Object> findOverrideProperties(Bundle bundle, URL fileURL) { |
| Map<String, Object> mergedProps = new HashMap<String, Object>(); |
| URL defaultPropsFileURL = getDefaultPropsURLFromEDFileURL(fileURL); |
| if (defaultPropsFileURL != null) { |
| trace("handleEndpointDescriptionFile", //$NON-NLS-1$ |
| "Attempting to load default.properties. BundleId=" + bundle.getBundleId() + " defaultPropsFileURL=" //$NON-NLS-1$ //$NON-NLS-2$ |
| + defaultPropsFileURL); |
| try { |
| mergedProps = PropertiesUtil.mergePropertiesRaw(mergedProps, |
| processProperties(loadProperties(defaultPropsFileURL))); |
| trace("findOverrideProperties", "loaded default.properties file=" + defaultPropsFileURL.getFile() //$NON-NLS-1$ //$NON-NLS-2$ |
| + " properties loaded=" //$NON-NLS-1$ |
| + mergedProps); |
| } catch (IOException e) { |
| LogUtility.logWarning("findOverrideProperties", DebugOptions.ENDPOINT_DESCRIPTION_LOCATOR, getClass(), //$NON-NLS-1$ |
| "Could not load default properties file=" + defaultPropsFileURL + ",edef fileUrl=" //$NON-NLS-1$ //$NON-NLS-2$ |
| + fileURL.getFile()); |
| } |
| } |
| URL propsFileURL = getPropsURLFromEDFileURL(fileURL); |
| if (propsFileURL != null) { |
| trace("handleEndpointDescriptionFile", //$NON-NLS-1$ |
| "Attemping to load <file>.properties. BundleId=" + bundle.getBundleId() + " propsFileURL=" //$NON-NLS-1$ //$NON-NLS-2$ |
| + propsFileURL); |
| try { |
| mergedProps = PropertiesUtil.mergePropertiesRaw(mergedProps, |
| processProperties(loadProperties(propsFileURL))); |
| trace("findOverrideProperties", //$NON-NLS-1$ |
| "loaded override properties file=" + fileURL.getFile() + " merged Properties=" //$NON-NLS-1$ //$NON-NLS-2$ |
| + mergedProps); |
| } catch (IOException e) { |
| LogUtility.logWarning("findOverrideProperties", DebugOptions.ENDPOINT_DESCRIPTION_LOCATOR, getClass(), //$NON-NLS-1$ |
| "Could not load properties fileUrl=" + propsFileURL + ",fileUrl=" + fileURL.getFile()); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| return (!mergedProps.isEmpty()) ? mergedProps : null; |
| } |
| |
| 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", //$NON-NLS-1$ |
| "endpointDescription previously discovered...ignoring"); //$NON-NLS-1$ |
| } else { |
| // It was a modify/update |
| trace("handleEndpointDescription", //$NON-NLS-1$ |
| "endpointDescription updated. prev=" + prevEd + ", update=" + ed); //$NON-NLS-1$ //$NON-NLS-2$ |
| queueEndpointEvent(ed, EndpointEvent.MODIFIED); |
| } |
| } else |
| trace("handleService", "EndpointDescription is null for serviceID=" + serviceID); //$NON-NLS-1$ //$NON-NLS-2$ |
| } else |
| trace("handleService", //$NON-NLS-1$ |
| "DiscoveredEndpointDescription is null for serviceID=" + serviceID); //$NON-NLS-1$ |
| } else |
| trace("handleService", "Found previous EndpointDescription with same serviceID=" + serviceID //$NON-NLS-1$ //$NON-NLS-2$ |
| + ". Ignoring"); //$NON-NLS-1$ |
| } else { |
| // It was undiscovered |
| if (ed != null) { |
| removeED(ed); |
| handleEndpointDescription(ed, false); |
| } else |
| trace("handleService", //$NON-NLS-1$ |
| "Did not find serviceInfo with serviceID=" + serviceID + ". Ignoring"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| } |
| } |
| |
| 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"), //$NON-NLS-1$ |
| e); |
| return null; |
| } catch (NoClassDefFoundError e) { |
| logError(methodName, "NoClassDefFoundError calling IEndpointDescriptionFactory." //$NON-NLS-1$ |
| + ((discovered) ? "createDiscoveredEndpointDescription" //$NON-NLS-1$ |
| : "getUndiscoveredEndpointDescription"), //$NON-NLS-1$ |
| e); |
| 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()]); |
| } |
| |
| } |