All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.osgi.util.tracker.BundleTracker Maven / Gradle / Ivy

/*
 * Copyright (c) OSGi Alliance (2007, 2008). All Rights Reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.osgi.util.tracker;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.SynchronousBundleListener;

/**
 * The BundleTracker class simplifies tracking bundles much like
 * the ServiceTracker simplifies tracking services.
 * 

* A BundleTracker is constructed with state criteria and a * BundleTrackerCustomizer object. A BundleTracker can * use the BundleTrackerCustomizer to select which bundles are * tracked and to create a customized object to be tracked with the bundle. The * BundleTracker can then be opened to begin tracking all bundles * whose state matches the specified state criteria. *

* The getBundles method can be called to get the * Bundle objects of the bundles being tracked. The * getObject method can be called to get the customized object for * a tracked bundle. *

* The BundleTracker class is thread-safe. It does not call a * BundleTrackerCustomizer while holding any locks. * BundleTrackerCustomizer implementations must also be * thread-safe. * * @ThreadSafe * @version $Revision: 5894 $ * @since 1.4 */ public class BundleTracker implements BundleTrackerCustomizer { /* set this to true to compile in debug messages */ static final boolean DEBUG = false; /** * The Bundle Context used by this BundleTracker. */ protected final BundleContext context; /** * The BundleTrackerCustomizer object for this tracker. */ final BundleTrackerCustomizer customizer; /** * Tracked bundles: Bundle object -> customized Object and * BundleListener object */ private volatile Tracked tracked; /** * Accessor method for the current Tracked object. This method is only * intended to be used by the unsynchronized methods which do not modify the * tracked field. * * @return The current Tracked object. */ private Tracked tracked() { return tracked; } /** * State mask for bundles being tracked. This field contains the ORed values * of the bundle states being tracked. */ final int mask; /** * Create a BundleTracker for bundles whose state is present in * the specified state mask. * *

* Bundles whose state is present on the specified state mask will be * tracked by this BundleTracker. * * @param context The BundleContext against which the tracking * is done. * @param stateMask The bit mask of the ORing of the bundle * states to be tracked. * @param customizer The customizer object to call when bundles are added, * modified, or removed in this BundleTracker. If * customizer is null, then this * BundleTracker will be used as the * BundleTrackerCustomizer and this * BundleTracker will call the * BundleTrackerCustomizer methods on itself. * @see Bundle#getState() */ public BundleTracker(BundleContext context, int stateMask, BundleTrackerCustomizer customizer) { this.context = context; this.mask = stateMask; this.customizer = (customizer == null) ? this : customizer; } /** * Open this BundleTracker and begin tracking bundles. * *

* Bundle which match the state criteria specified when this * BundleTracker was created are now tracked by this * BundleTracker. * * @throws java.lang.IllegalStateException If the BundleContext * with which this BundleTracker was created is no * longer valid. * @throws java.lang.SecurityException If the caller and this class do not * have the appropriate * AdminPermission[context bundle,LISTENER], and the * Java Runtime Environment supports permissions. */ public void open() { final Tracked t; synchronized (this) { if (tracked != null) { return; } if (DEBUG) { System.out.println("BundleTracker.open"); //$NON-NLS-1$ } t = new Tracked(); synchronized (t) { context.addBundleListener(t); Bundle[] bundles = context.getBundles(); if (bundles != null) { int length = bundles.length; for (int i = 0; i < length; i++) { int state = bundles[i].getState(); if ((state & mask) == 0) { /* null out bundles whose states are not interesting */ bundles[i] = null; } } /* set tracked with the initial bundles */ t.setInitial(bundles); } } tracked = t; } /* Call tracked outside of synchronized region */ t.trackInitial(); /* process the initial references */ } /** * Close this BundleTracker. * *

* This method should be called when this BundleTracker should * end the tracking of bundles. * *

* This implementation calls {@link #getBundles()} to get the list of * tracked bundles to remove. */ public void close() { final Bundle[] bundles; final Tracked outgoing; synchronized (this) { outgoing = tracked; if (outgoing == null) { return; } if (DEBUG) { System.out.println("BundleTracker.close"); //$NON-NLS-1$ } outgoing.close(); bundles = getBundles(); tracked = null; try { context.removeBundleListener(outgoing); } catch (IllegalStateException e) { /* In case the context was stopped. */ } } if (bundles != null) { for (int i = 0; i < bundles.length; i++) { outgoing.untrack(bundles[i], null); } } } /** * Default implementation of the * BundleTrackerCustomizer.addingBundle method. * *

* This method is only called when this BundleTracker has been * constructed with a null BundleTrackerCustomizer argument. * *

* This implementation simply returns the specified Bundle. * *

* This method can be overridden in a subclass to customize the object to be * tracked for the bundle being added. * * @param bundle The Bundle being added to this * BundleTracker object. * @param event The bundle event which caused this customizer method to be * called or null if there is no bundle event associated * with the call to this method. * @return The specified bundle. * @see BundleTrackerCustomizer#addingBundle(Bundle, BundleEvent) */ public Object addingBundle(Bundle bundle, BundleEvent event) { return bundle; } /** * Default implementation of the * BundleTrackerCustomizer.modifiedBundle method. * *

* This method is only called when this BundleTracker has been * constructed with a null BundleTrackerCustomizer argument. * *

* This implementation does nothing. * * @param bundle The Bundle whose state has been modified. * @param event The bundle event which caused this customizer method to be * called or null if there is no bundle event associated * with the call to this method. * @param object The customized object for the specified Bundle. * @see BundleTrackerCustomizer#modifiedBundle(Bundle, BundleEvent, Object) */ public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) { /* do nothing */ } /** * Default implementation of the * BundleTrackerCustomizer.removedBundle method. * *

* This method is only called when this BundleTracker has been * constructed with a null BundleTrackerCustomizer argument. * *

* This implementation does nothing. * * @param bundle The Bundle being removed. * @param event The bundle event which caused this customizer method to be * called or null if there is no bundle event associated * with the call to this method. * @param object The customized object for the specified bundle. * @see BundleTrackerCustomizer#removedBundle(Bundle, BundleEvent, Object) */ public void removedBundle(Bundle bundle, BundleEvent event, Object object) { /* do nothing */ } /** * Return an array of Bundles for all bundles being tracked by * this BundleTracker. * * @return An array of Bundles or null if no * bundles are being tracked. */ public Bundle[] getBundles() { final Tracked t = tracked(); if (t == null) { /* if BundleTracker is not open */ return null; } synchronized (t) { int length = t.size(); if (length == 0) { return null; } return (Bundle[]) t.getTracked(new Bundle[length]); } } /** * Returns the customized object for the specified Bundle if * the specified bundle is being tracked by this BundleTracker. * * @param bundle The Bundle being tracked. * @return The customized object for the specified Bundle or * null if the specified Bundle is not * being tracked. */ public Object getObject(Bundle bundle) { final Tracked t = tracked(); if (t == null) { /* if BundleTracker is not open */ return null; } synchronized (t) { return t.getCustomizedObject(bundle); } } /** * Remove a bundle from this BundleTracker. * * The specified bundle will be removed from this BundleTracker * . If the specified bundle was being tracked then the * BundleTrackerCustomizer.removedBundle method will be called * for that bundle. * * @param bundle The Bundle to be removed. */ public void remove(Bundle bundle) { final Tracked t = tracked(); if (t == null) { /* if BundleTracker is not open */ return; } t.untrack(bundle, null); } /** * Return the number of bundles being tracked by this * BundleTracker. * * @return The number of bundles being tracked. */ public int size() { final Tracked t = tracked(); if (t == null) { /* if BundleTracker is not open */ return 0; } synchronized (t) { return t.size(); } } /** * Returns the tracking count for this BundleTracker. * * The tracking count is initialized to 0 when this * BundleTracker is opened. Every time a bundle is added, * modified or removed from this BundleTracker the tracking * count is incremented. * *

* The tracking count can be used to determine if this * BundleTracker has added, modified or removed a bundle by * comparing a tracking count value previously collected with the current * tracking count value. If the value has not changed, then no bundle has * been added, modified or removed from this BundleTracker * since the previous tracking count was collected. * * @return The tracking count for this BundleTracker or -1 if * this BundleTracker is not open. */ public int getTrackingCount() { final Tracked t = tracked(); if (t == null) { /* if BundleTracker is not open */ return -1; } synchronized (t) { return t.getTrackingCount(); } } /** * Inner class which subclasses AbstractTracked. This class is the * SynchronousBundleListener object for the tracker. * * @ThreadSafe * @since 1.4 */ class Tracked extends AbstractTracked implements SynchronousBundleListener { /** * Tracked constructor. */ Tracked() { super(); } /** * BundleListener method for the BundleTracker * class. This method must NOT be synchronized to avoid deadlock * potential. * * @param event BundleEvent object from the framework. */ public void bundleChanged(final BundleEvent event) { /* * Check if we had a delayed call (which could happen when we * close). */ if (closed) { return; } final Bundle bundle = event.getBundle(); final int state = bundle.getState(); if (DEBUG) { System.out .println("BundleTracker.Tracked.bundleChanged[" + state + "]: " + bundle); //$NON-NLS-1$ //$NON-NLS-2$ } if ((state & mask) != 0) { track(bundle, event); /* * If the customizer throws an unchecked exception, it is safe * to let it propagate */ } else { untrack(bundle, event); /* * If the customizer throws an unchecked exception, it is safe * to let it propagate */ } } /** * Call the specific customizer adding method. This method must not be * called while synchronized on this object. * * @param item Item to be tracked. * @param related Action related object. * @return Customized object for the tracked item or null * if the item is not to be tracked. */ Object customizerAdding(final Object item, final Object related) { return customizer .addingBundle((Bundle) item, (BundleEvent) related); } /** * Call the specific customizer modified method. This method must not be * called while synchronized on this object. * * @param item Tracked item. * @param related Action related object. * @param object Customized object for the tracked item. */ void customizerModified(final Object item, final Object related, final Object object) { customizer.modifiedBundle((Bundle) item, (BundleEvent) related, object); } /** * Call the specific customizer removed method. This method must not be * called while synchronized on this object. * * @param item Tracked item. * @param related Action related object. * @param object Customized object for the tracked item. */ void customizerRemoved(final Object item, final Object related, final Object object) { customizer.removedBundle((Bundle) item, (BundleEvent) related, object); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy