/******************************************************************************* * 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; } }