| /******************************************************************************* |
| * Copyright (c) 2010 Composent, Inc. and others. All rights reserved. This |
| * program and the accompanying materials are made available under the terms of |
| * the Eclipse Public License v1.0 which accompanies this distribution, and is |
| * available at http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Composent, Inc. - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.ecf.internal.osgi.services.distribution; |
| |
| import java.util.ArrayList; |
| import java.util.Dictionary; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.ecf.core.util.LogHelper; |
| import org.eclipse.ecf.core.util.SystemLogService; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleActivator; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.Filter; |
| import org.osgi.framework.ServiceFactory; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.framework.ServiceRegistration; |
| import org.osgi.framework.hooks.service.EventListenerHook; |
| import org.osgi.service.log.LogService; |
| 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.service.remoteserviceadmin.RemoteServiceAdminListener; |
| import org.osgi.util.tracker.ServiceTracker; |
| |
| public class Activator implements BundleActivator { |
| |
| public static final String PLUGIN_ID = "org.eclipse.ecf.osgi.services.distribution"; //$NON-NLS-1$ |
| |
| public static final boolean autoCreateProxyContainer = new Boolean( |
| System.getProperty( |
| "org.eclipse.ecf.osgi.services.distribution.autoCreateProxyContainer", //$NON-NLS-1$ |
| "true")).booleanValue(); //$NON-NLS-1$ |
| |
| public static final boolean autoCreateHostContainer = new Boolean( |
| System.getProperty( |
| "org.eclipse.ecf.osgi.services.distribution.autoCreateHostContainer", //$NON-NLS-1$ |
| "true")).booleanValue(); //$NON-NLS-1$ |
| |
| public static final String defaultHostConfigType = System.getProperty( |
| "org.eclipse.ecf.osgi.services.distribution.defaultConfigType", //$NON-NLS-1$ |
| "ecf.generic.server"); //$NON-NLS-1$ |
| |
| private static final String PROP_USE_DS = "equinox.use.ds"; //$NON-NLS-1$ |
| |
| private static Activator plugin; |
| private BundleContext context; |
| |
| private ServiceTracker logServiceTracker = null; |
| private LogService logService = null; |
| |
| private BasicTopologyManagerImpl basicTopologyManagerImpl; |
| private ServiceRegistration endpointListenerReg; |
| private ServiceRegistration endpointEventListenerReg; |
| private Map<Bundle, List<EndpointEventHolder>> bundleEndpointEventListenerMap = new HashMap<Bundle, List<EndpointEventHolder>>(); |
| |
| private BasicTopologyManagerComponent basicTopologyManagerComp; |
| private ServiceRegistration eventListenerHookRegistration; |
| private ServiceRegistration eventAdminListenerRegistration; |
| |
| private static final boolean disableBasicTopologyManager = new Boolean( |
| System.getProperty( |
| "org.eclipse.ecf.osgi.services.distribution.disableBasicTopologyManager", //$NON-NLS-1$ |
| "false")).booleanValue(); //$NON-NLS-1$ |
| |
| private OSGiTopologyManagerImpl osgiTopologyManagerImpl; |
| |
| public static Activator getDefault() { |
| return plugin; |
| } |
| |
| public BundleContext getContext() { |
| return context; |
| } |
| |
| protected LogService getLogService() { |
| if (this.context == null) |
| return null; |
| if (logServiceTracker == null) { |
| logServiceTracker = new ServiceTracker(this.context, |
| LogService.class.getName(), null); |
| logServiceTracker.open(); |
| } |
| logService = (LogService) logServiceTracker.getService(); |
| if (logService == null) |
| logService = new SystemLogService(PLUGIN_ID); |
| return logService; |
| } |
| |
| public void log(IStatus status) { |
| if (logService == null) |
| logService = getLogService(); |
| if (logService != null) |
| logService.log(null, LogHelper.getLogCode(status), |
| LogHelper.getLogMessage(status), status.getException()); |
| } |
| |
| public void log(ServiceReference sr, IStatus status) { |
| log(sr, LogHelper.getLogCode(status), LogHelper.getLogMessage(status), |
| status.getException()); |
| } |
| |
| public void log(ServiceReference sr, int level, String message, Throwable t) { |
| if (logService == null) |
| logService = getLogService(); |
| if (logService != null) |
| logService.log(sr, level, message, t); |
| } |
| |
| class EndpointEventHolder { |
| private final EndpointDescription endpointDescription; |
| private final String filter; |
| |
| public EndpointEventHolder(EndpointDescription d, String f) { |
| this.endpointDescription = d; |
| this.filter = f; |
| } |
| |
| public EndpointDescription getEndpoint() { |
| return this.endpointDescription; |
| } |
| |
| public String getFilter() { |
| return this.filter; |
| } |
| } |
| |
| public class ProxyEndpointEventListener implements EndpointEventListener { |
| |
| private final Bundle bundle; |
| |
| public ProxyEndpointEventListener(Bundle b) { |
| this.bundle = b; |
| } |
| |
| public void endpointChanged(EndpointEvent event, String filter) { |
| int type = event.getType(); |
| if (type == EndpointEvent.ADDED) { |
| synchronized (bundleEndpointEventListenerMap) { |
| List<EndpointEventHolder> endpointEventHolders = bundleEndpointEventListenerMap |
| .get(this.bundle); |
| if (endpointEventHolders == null) |
| // create new one |
| endpointEventHolders = new ArrayList<EndpointEventHolder>(); |
| endpointEventHolders.add(new EndpointEventHolder(event |
| .getEndpoint(), filter)); |
| bundleEndpointEventListenerMap.put(this.bundle, |
| endpointEventHolders); |
| } |
| } else if (type == EndpointEvent.REMOVED) { |
| synchronized (bundleEndpointEventListenerMap) { |
| List<EndpointEventHolder> endpointEventHolders = bundleEndpointEventListenerMap |
| .get(this.bundle); |
| if (endpointEventHolders != null) { |
| for (Iterator<EndpointEventHolder> i = endpointEventHolders |
| .iterator(); i.hasNext();) { |
| EndpointEventHolder eh = i.next(); |
| EndpointDescription oldEd = eh.getEndpoint(); |
| EndpointDescription newEd = event.getEndpoint(); |
| if (oldEd.equals(newEd)) |
| i.remove(); |
| } |
| if (endpointEventHolders.size() == 0) |
| bundleEndpointEventListenerMap.remove(this.bundle); |
| } |
| |
| } |
| } |
| // Actually call underlying listener |
| deliverSafe(event, filter); |
| } |
| |
| public BasicTopologyManagerImpl getBasicTopologyManagerImpl() { |
| return Activator.this.basicTopologyManagerImpl; |
| } |
| |
| private void logError(String methodName, String message, Throwable e) { |
| getDefault().log( |
| new Status(IStatus.ERROR, Activator.PLUGIN_ID, |
| IStatus.ERROR, Activator.class.getName() + ":" //$NON-NLS-1$ |
| + ((methodName == null) ? "<unknown>" //$NON-NLS-1$ |
| : methodName) + ":" //$NON-NLS-1$ |
| + ((message == null) ? "<empty>" //$NON-NLS-1$ |
| : message), e)); |
| } |
| |
| private void deliverSafe(EndpointEvent endpointEvent, |
| String matchingFilter) { |
| EndpointEventListener listener = Activator.this.basicTopologyManagerImpl; |
| if (listener == null) |
| return; |
| try { |
| listener.endpointChanged(endpointEvent, matchingFilter); |
| } catch (Exception e) { |
| String message = "Exception in EndpointEventListener listener=" //$NON-NLS-1$ |
| + listener + " event=" //$NON-NLS-1$ |
| + endpointEvent + " matchingFilter=" //$NON-NLS-1$ |
| + matchingFilter; |
| logError("deliverSafe", message, e); //$NON-NLS-1$ |
| } catch (LinkageError e) { |
| String message = "LinkageError in EndpointEventListener listener=" //$NON-NLS-1$ |
| + listener + " event=" //$NON-NLS-1$ |
| + endpointEvent + " matchingFilter=" //$NON-NLS-1$ |
| + matchingFilter; |
| logError("deliverSafe", message, e); //$NON-NLS-1$ |
| } catch (AssertionError e) { |
| String message = "AssertionError in EndpointEventListener listener=" //$NON-NLS-1$ |
| + listener + " event=" //$NON-NLS-1$ |
| + endpointEvent + " matchingFilter=" //$NON-NLS-1$ |
| + matchingFilter; |
| logError("deliverSafe", message, e); //$NON-NLS-1$ |
| } |
| } |
| |
| public void deliverRemoveEventForBundle(EndpointEventHolder eventHolder) { |
| deliverSafe( |
| new EndpointEvent(EndpointEvent.REMOVED, |
| eventHolder.getEndpoint()), eventHolder.getFilter()); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext |
| * ) |
| */ |
| public void start(final BundleContext ctxt) throws Exception { |
| // Always set plugin and context |
| plugin = this; |
| this.context = ctxt; |
| // If BasicTopologyManager has been disabled (default), then |
| // use OSGiTopologyManager |
| if (disableBasicTopologyManager) { |
| osgiTopologyManagerImpl = new OSGiTopologyManagerImpl(context); |
| |
| Properties props = new Properties(); |
| props.put( |
| org.osgi.service.remoteserviceadmin.EndpointEventListener.ENDPOINT_LISTENER_SCOPE, |
| osgiTopologyManagerImpl.getScope()); |
| |
| // Register as deprecated EndpointListener |
| endpointListenerReg = getContext().registerService( |
| EndpointListener.class.getName(), osgiTopologyManagerImpl, |
| (Dictionary) props); |
| |
| // Also register as EndpointEventListener |
| endpointEventListenerReg = getContext().registerService( |
| EndpointEventListener.class.getName(), |
| osgiTopologyManagerImpl, (Dictionary) props); |
| |
| // export any previously registered remote services by calling |
| // activate |
| osgiTopologyManagerImpl.activate(); |
| |
| } else { |
| // Create basicTopologyManagerImpl |
| basicTopologyManagerImpl = new BasicTopologyManagerImpl(context); |
| |
| // Register basicTopologyManagerImpl as EndpointListener always, so |
| // that |
| // gets notified when Endpoints are discovered |
| Properties props = new Properties(); |
| props.put( |
| org.osgi.service.remoteserviceadmin.EndpointEventListener.ENDPOINT_LISTENER_SCOPE, |
| basicTopologyManagerImpl.getScope()); |
| |
| // Register as deprecated EndpointListener |
| // endpointListenerReg = getContext().registerService( |
| // EndpointListener.class.getName(), basicTopologyManagerImpl, |
| // (Dictionary) props); |
| |
| // As per section 122.6.3/Tracking providers -Tracking providers |
| // An |
| // Endpoint Event |
| // Listener or Endpoint Listener must track the bundles that provide |
| // it |
| // with |
| // Endpoint Descriptions. If a bundle that provided Endpoint |
| // Descriptions is |
| // stopped, all Endpoint Descriptions that were provided by that |
| // bundle |
| // must |
| // be removed. This can be implemented straightforwardly with a |
| // Service |
| // Factory |
| endpointEventListenerReg = getContext().registerService( |
| EndpointEventListener.class.getName(), |
| new ServiceFactory() { |
| public Object getService(Bundle bundle, |
| ServiceRegistration registration) { |
| return new ProxyEndpointEventListener(bundle); |
| } |
| |
| public void ungetService(Bundle bundle, |
| ServiceRegistration registration, Object service) { |
| ProxyEndpointEventListener peel = (service instanceof ProxyEndpointEventListener) ? (ProxyEndpointEventListener) service |
| : null; |
| if (peel == null) |
| return; |
| synchronized (bundleEndpointEventListenerMap) { |
| List<EndpointEventHolder> endpointEventHolders = bundleEndpointEventListenerMap |
| .get(bundle); |
| if (endpointEventHolders != null) |
| for (EndpointEventHolder eh : endpointEventHolders) |
| peel.deliverRemoveEventForBundle(eh); |
| } |
| } |
| }, (Dictionary) props); |
| |
| // Like EventAdmin, if equinox ds is running, then we simply return |
| // (no |
| // more to do) |
| if (Boolean.valueOf(context.getProperty(PROP_USE_DS)) |
| .booleanValue()) |
| return; // If this property is set we assume DS is being used. |
| |
| // The following code is to make sure that we don't do any more if |
| // EventListenerHook has already been registered for us by DS |
| // Create serviceFilter for EventListenerHook classname |
| String serviceName = EventListenerHook.class.getName(); |
| Filter serviceFilter = context |
| .createFilter("(objectclass=" + serviceName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ |
| // if this bundle has already registered EventListenerHook service |
| // via |
| // ds, then |
| // we're done |
| ServiceReference[] refs = context.getBundle() |
| .getRegisteredServices(); |
| if (refs != null) { |
| for (int i = 0; i < refs.length; i++) |
| if (serviceFilter.match(refs[i])) |
| return; // We found a service registered by this bundle |
| // already so we return |
| } |
| |
| // Otherwise (no DS), we create a basicTopologyManagerComponent |
| basicTopologyManagerComp = new BasicTopologyManagerComponent(); |
| // bind the topology manager to it |
| basicTopologyManagerComp |
| .bindEndpointEventListener(basicTopologyManagerImpl); |
| // Register RemoteServiceAdminListener |
| eventAdminListenerRegistration = this.context.registerService( |
| RemoteServiceAdminListener.class, basicTopologyManagerComp, |
| null); |
| // register the basic topology manager as EventListenerHook service |
| eventListenerHookRegistration = this.context.registerService( |
| EventListenerHook.class, basicTopologyManagerComp, null); |
| // export any previously registered remote services by calling |
| // activate |
| basicTopologyManagerComp.activate(); |
| |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) |
| */ |
| public void stop(BundleContext ctxt) throws Exception { |
| if (eventListenerHookRegistration != null) { |
| eventListenerHookRegistration.unregister(); |
| eventListenerHookRegistration = null; |
| } |
| if (basicTopologyManagerComp != null) { |
| basicTopologyManagerComp |
| .unbindEndpointEventListener(basicTopologyManagerImpl); |
| basicTopologyManagerComp = null; |
| } |
| if (endpointEventListenerReg != null) { |
| endpointEventListenerReg.unregister(); |
| endpointEventListenerReg = null; |
| } |
| if (endpointListenerReg != null) { |
| endpointListenerReg.unregister(); |
| endpointListenerReg = null; |
| } |
| if (eventAdminListenerRegistration != null) { |
| eventAdminListenerRegistration.unregister(); |
| eventAdminListenerRegistration = null; |
| } |
| synchronized (bundleEndpointEventListenerMap) { |
| bundleEndpointEventListenerMap.clear(); |
| } |
| if (basicTopologyManagerImpl != null) { |
| basicTopologyManagerImpl.close(); |
| basicTopologyManagerImpl = null; |
| } |
| if (logServiceTracker != null) { |
| logServiceTracker.close(); |
| logServiceTracker = null; |
| logService = null; |
| } |
| this.context = null; |
| plugin = null; |
| } |
| |
| } |