/**
  * Close this {@code BundleTracker}.
  *
  * <p>This method should be called when this {@code BundleTracker} should end the tracking of
  * bundles.
  *
  * <p>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);
     }
   }
 }
 /**
  * Open this {@code BundleTracker} and begin tracking bundles.
  *
  * <p>Bundle which match the state criteria specified when this {@code BundleTracker} was created
  * are now tracked by this {@code BundleTracker}.
  *
  * @throws java.lang.IllegalStateException If the {@code BundleContext} with which this {@code
  *     BundleTracker} was created is no longer valid.
  * @throws java.lang.SecurityException If the caller and this class do not have the appropriate
  *     {@code 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 */
 }
 /**
  * Remove a bundle from this {@code BundleTracker}.
  *
  * <p>The specified bundle will be removed from this {@code BundleTracker} . If the specified
  * bundle was being tracked then the {@code BundleTrackerCustomizer.removedBundle} method will be
  * called for that bundle.
  *
  * @param bundle The {@code 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 if this {@code BundleTracker} is empty.
  *
  * @return {@code true} if this {@code BundleTracker} is not tracking any bundles.
  * @since 1.5
  */
 public boolean isEmpty() {
   final Tracked t = tracked();
   if (t == null) {
     /* if BundleTracker is not open */
     return true;
   }
   synchronized (t) {
     return t.isEmpty();
   }
 }
 /**
  * Returns the tracking count for this {@code BundleTracker}.
  *
  * <p>The tracking count is initialized to 0 when this {@code BundleTracker} is opened. Every time
  * a bundle is added, modified or removed from this {@code BundleTracker} the tracking count is
  * incremented.
  *
  * <p>The tracking count can be used to determine if this {@code 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 {@code BundleTracker} since the previous tracking count was
  * collected.
  *
  * @return The tracking count for this {@code BundleTracker} or -1 if this {@code 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();
   }
 }
 /**
  * Return the number of bundles being tracked by this {@code 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 customized object for the specified {@code Bundle} if the specified bundle is being
  * tracked by this {@code BundleTracker}.
  *
  * @param bundle The {@code Bundle} being tracked.
  * @return The customized object for the specified {@code Bundle} or {@code null} if the specified
  *     {@code Bundle} is not being tracked.
  */
 public T getObject(Bundle bundle) {
   final Tracked t = tracked();
   if (t == null) {
     /* if BundleTracker is not open */
     return null;
   }
   synchronized (t) {
     return t.getCustomizedObject(bundle);
   }
 }
 /**
  * Return a {@code Map} with the {@code Bundle}s and customized objects for all bundles being
  * tracked by this {@code BundleTracker}.
  *
  * @return A {@code Map} with the {@code Bundle}s and customized objects for all services being
  *     tracked by this {@code BundleTracker}. If no bundles are being tracked, then the returned
  *     map is empty.
  * @since 1.5
  */
 public Map<Bundle, T> getTracked() {
   Map<Bundle, T> map = new HashMap<Bundle, T>();
   final Tracked t = tracked();
   if (t == null) {
     /* if BundleTracker is not open */
     return map;
   }
   synchronized (t) {
     return t.copyEntries(map);
   }
 }
 /**
  * Return an array of {@code Bundle}s for all bundles being tracked by this {@code BundleTracker}.
  *
  * @return An array of {@code Bundle}s or {@code 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 t.copyKeys(new Bundle[length]);
   }
 }