diff options
author | Thomas Watson | 2008-12-19 21:10:00 +0000 |
---|---|---|
committer | Thomas Watson | 2008-12-19 21:10:00 +0000 |
commit | c0bf408b216d2511900a0e48b4185d50fb6017e2 (patch) | |
tree | cc91e6e2a43514f5088471048125db7503fed0b8 /bundles/org.eclipse.osgi/core/composite/org/eclipse/osgi/internal/composite/CompositeServiceTracker.java | |
parent | f1a814066412e3ae14174179eea848452496bb34 (diff) | |
download | rt.equinox.framework-c0bf408b216d2511900a0e48b4185d50fb6017e2.tar.gz rt.equinox.framework-c0bf408b216d2511900a0e48b4185d50fb6017e2.tar.xz rt.equinox.framework-c0bf408b216d2511900a0e48b4185d50fb6017e2.zip |
Bug 254021 Implement new LinkBundleFactory service (rfc 138)
Diffstat (limited to 'bundles/org.eclipse.osgi/core/composite/org/eclipse/osgi/internal/composite/CompositeServiceTracker.java')
-rw-r--r-- | bundles/org.eclipse.osgi/core/composite/org/eclipse/osgi/internal/composite/CompositeServiceTracker.java | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/bundles/org.eclipse.osgi/core/composite/org/eclipse/osgi/internal/composite/CompositeServiceTracker.java b/bundles/org.eclipse.osgi/core/composite/org/eclipse/osgi/internal/composite/CompositeServiceTracker.java new file mode 100644 index 000000000..a9a449b40 --- /dev/null +++ b/bundles/org.eclipse.osgi/core/composite/org/eclipse/osgi/internal/composite/CompositeServiceTracker.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2008 IBM Corporation 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.osgi.internal.composite; + +import java.util.*; +import org.eclipse.osgi.util.ManifestElement; +import org.osgi.framework.*; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + +class CompositeServiceTracker implements ServiceTrackerCustomizer { + final BundleContext sourceContext; + final BundleContext targetContext; + final ServiceTracker[] trackers; + final String[] filters; + /* @GuardedBy("serviceComposites") */ + final HashMap serviceComposites = new HashMap(); + + public CompositeServiceTracker(BundleContext sourceContext, BundleContext targetContext, String serviceFilters) { + this.sourceContext = sourceContext; + this.targetContext = targetContext; + filters = ManifestElement.getArrayFromList(serviceFilters, ","); //$NON-NLS-1$ + trackers = new ServiceTracker[filters.length]; + } + + synchronized void open() { + for (int i = 0; i < trackers.length; i++) { + try { + trackers[i] = new ServiceTracker(sourceContext, sourceContext.createFilter(filters[i]), this); + trackers[i].open(); + } catch (InvalidSyntaxException e) { + // TODO log + // we will skip this filter; note that trackers may have null entries + } + } + } + + synchronized void close() { + for (int i = 0; i < trackers.length; i++) { + if (trackers[i] != null) + trackers[i].close(); + } + } + + public Object addingService(ServiceReference reference) { + ServiceLink serviceLink; + int useCount; + synchronized (serviceComposites) { + serviceLink = (ServiceLink) serviceComposites.get(reference); + if (serviceLink == null) { + serviceLink = new ServiceLink(reference); + serviceComposites.put(reference, serviceLink); + } + useCount = serviceLink.incrementUse(); + } + // register service outside of the sync block + if (useCount == 1) + serviceLink.register(); + return serviceLink; + } + + public void modifiedService(ServiceReference reference, Object service) { + ServiceLink serviceLink = (ServiceLink) service; + Dictionary serviceProps = null; + synchronized (serviceComposites) { + serviceProps = serviceLink.getRefreshProperties(); + } + // set service properties out side the sync block + if (serviceProps != null) + ((ServiceLink) service).setServiceProperties(serviceProps); + } + + public void removedService(ServiceReference reference, Object service) { + int useCount; + synchronized (serviceComposites) { + useCount = ((ServiceLink) service).decrementUse(); + if (useCount == 0) + serviceComposites.remove(reference); + } + // unregister outside the sync block + if (useCount == 0) + ((ServiceLink) service).unregister(); + } + + class ServiceLink implements ServiceFactory { + private final ServiceReference reference; + private volatile ServiceRegistration registration; + /* @GuardedBy("this") */ + private Object service; + /* @GuardedBy("serviceLinks") */ + private int useCount; + + ServiceLink(ServiceReference reference) { + this.reference = reference; + } + + /* @GuardedBy("serviceLinks") */ + Dictionary getRefreshProperties() { + Dictionary result = getServiceProperties(); + if (useCount <= 1) + return result; + // need to do an expensive properties check to avoid multiple registration property changes + String[] originalKeys = registration.getReference().getPropertyKeys(); + for (int i = 0; i < originalKeys.length; i++) { + if (!Constants.OBJECTCLASS.equals(originalKeys[i]) && !Constants.SERVICE_ID.equals(originalKeys[i])) + // identity compare is done on purpose here to catch any kind of change + if (registration.getReference().getProperty(originalKeys[i]) != result.get(originalKeys[i])) + return result; + } + for (Enumeration eKeys = result.keys(); eKeys.hasMoreElements();) { + String key = (String) eKeys.nextElement(); + if (!Constants.OBJECTCLASS.equals(key) && !Constants.SERVICE_ID.equals(key)) + // identity compare is done on purpose here to catch any kind of change + if (result.get(key) != registration.getReference().getProperty(key)) + return result; + } + return null; + } + + /* @GuardedBy("serviceLinks") */ + int decrementUse() { + return --useCount; + } + + /* @GuardedBy("serviceLinks") */ + int incrementUse() { + return ++useCount; + } + + /* @GuardedBy("serviceLinks") */ + int getUse() { + return useCount; + } + + void setServiceProperties(Dictionary props) { + ServiceRegistration current = registration; + if (current != null) + current.setProperties(props); + } + + void register() { + Dictionary props = getServiceProperties(); + registration = targetContext.registerService((String[]) props.get(Constants.OBJECTCLASS), this, props); + } + + void unregister() { + ServiceRegistration current = registration; + if (current != null) + current.unregister(); + } + + private Dictionary getServiceProperties() { + String[] keys = reference.getPropertyKeys(); + Hashtable serviceProps = new Hashtable(keys.length); + for (int i = 0; i < keys.length; i++) + serviceProps.put(keys[i], reference.getProperty(keys[i])); + return serviceProps; + } + + public synchronized Object getService(Bundle bundle, ServiceRegistration reg) { + if (service == null) + service = sourceContext.getService(reference); + return service; + } + + public void ungetService(Bundle bundle, ServiceRegistration reg, Object serv) { + // nothing + } + } +} |