/* * Copyright (c) 2006, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* This class works more or less like the org.osgi.framework.util.ServiceTracker * except that it adds a few extra "events". The code is partly based on the current * a in-house modification of the current osgi ServiceTracker. */ package org.knopflerfish.bundle.component; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; class ExtendedServiceTracker implements ServiceListener { /* the filter */ protected Filter filter; /* the current bundle context */ protected BundleContext context; /* all tracked service references */ private ArrayList tracking = new ArrayList(); /* all service objects */ private HashMap objects = new HashMap(); ExtendedServiceTracker(BundleContext context, Filter filter) { this.context = context; this.filter = filter; } void open() { try { ServiceReference[] refs = context.getServiceReferences(null, filter.toString()); context.addServiceListener(this, filter.toString()); if (refs == null) { return ; } for (int i = 0; i < refs.length; i++) { serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, refs[i])); } } catch (InvalidSyntaxException e) { /* this can not happen, since we * could have created the filter in that case */ } } void close() { context.removeServiceListener(this); try{ synchronized (tracking) { for (Iterator iter = objects.keySet().iterator(); iter.hasNext(); ) { context.ungetService((ServiceReference)iter.next()); } } } catch (IllegalStateException e) { /* ignored. */} tracking = new ArrayList(); objects = new HashMap(); } public void serviceChanged(ServiceEvent event) { ServiceReference ref = event.getServiceReference(); switch (event.getType()) { case ServiceEvent.REGISTERED: { Object cache = null; try { cache = addingService(ref); } catch(Throwable e) {} includeService(ref, cache); addedService(ref, cache); // Should be safe to throw the exception }; break; case ServiceEvent.UNREGISTERING: { synchronized(tracking) { if (!tracking.contains(ref)) { // in this case we have removed this reference from the tracker. return ; } } Object object = objects.get(ref); try { removingService(ref, object); } catch (Throwable ignored) { } excludeService(ref); removedService(ref, object); } } } protected Object addingService(ServiceReference ref) { //return context.getService(ref); return null; } protected void addedService(ServiceReference ref, Object service) { } protected void removingService(ServiceReference ref, Object service) { } protected void removedService(ServiceReference ref, Object object) { } private void excludeService(ServiceReference ref) { synchronized (tracking) { if (tracking.remove(ref)) { objects.remove(ref); } } } private void includeService(ServiceReference ref, Object cached) { synchronized(tracking) { if (tracking.isEmpty()) { tracking.add(0, ref); if (cached != null) { objects.put(ref, cached); } return ; } Object tmp = ref.getProperty(Constants.SERVICE_RANKING); int refInt = (tmp instanceof Integer) ? ((Integer)tmp).intValue() : 0; Long refId = (Long)ref.getProperty(Constants.SERVICE_ID); int i = 0; for (int n = tracking.size(); i < n; i++) { ServiceReference challenger = (ServiceReference)tracking.get(i); tmp = challenger.getProperty(Constants.SERVICE_RANKING); int challengerInt = (tmp instanceof Integer) ? ((Integer)tmp).intValue() : 0; if (challengerInt < refInt) { break ; } else if (challengerInt == refInt) { Long challengerId = (Long)challenger.getProperty(Constants.SERVICE_ID); if (refId.compareTo(challengerId) < 0) { break; } } } tracking.add(i, ref); if (cached != null) { objects.put(ref, cached); } } } void ungetService(ServiceReference ref) { synchronized(tracking) { objects.remove(ref); context.ungetService(ref); } } Object getService() { synchronized(tracking) { if (tracking.isEmpty()) { return null; } return getService((ServiceReference)tracking.get(0)); } } Object getService(ServiceReference ref) { synchronized(tracking) { if (objects.containsKey(ref)) { return objects.get(ref); } else { Object o = context.getService(ref); if (o != null) { objects.put(ref, o); return o; } } } return null; } ServiceReference getServiceReference() { synchronized(tracking) { return (ServiceReference) (tracking.isEmpty() ? null : tracking.get(0)); } } ServiceReference[] getServiceReferences() { synchronized (tracking) { int n = tracking.size(); ServiceReference[] refs = new ServiceReference[n]; for (int i = 0; i < n; i++) { refs[i] = (ServiceReference)tracking.get(i); } return refs; } } Object[] getServices() { synchronized(tracking) { if (tracking.isEmpty()) { return null; } ArrayList retval = new ArrayList(); int i = 0; for (Iterator iter = tracking.iterator(); iter.hasNext(); i++) { ServiceReference ref = (ServiceReference)iter.next(); if (!objects.containsKey(ref)) { retval.add(i,objects.get(ref)); } else { Object o = context.getService(ref); if (o != null) { objects.put(ref, o); retval.add(i, o); } } } return retval.toArray(new Object[0]); } } void remove(ServiceReference ref) { serviceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, ref)); } int size() { return tracking.size(); } }