Modified: 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/State.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/State.java?rev=797561&r1=797560&r2=797561&view=diff
==============================================================================
--- 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/State.java
 (original)
+++ 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/State.java
 Fri Jul 24 17:06:37 2009
@@ -1,7 +1,5 @@
 /*
- * $Header: 
/cvshome/build/org.osgi.util.measurement/src/org/osgi/util/measurement/State.java,v
 1.8 2006/06/16 16:31:34 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2002, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2002, 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.
@@ -27,12 +25,13 @@
  * <p>
  * A <code>State</code> object is immutable so that it may be easily shared.
  * 
- * @version $Revision: 1.8 $
+ * @Immutable
+ * @version $Revision: 5715 $
  */
 public class State {
-       final int               value;
-       final long              time;
-       final String    name;
+       private final int               value;
+       private final long              time;
+       private final String    name;
 
        /**
         * Create a new <code>State</code> object.
@@ -108,9 +107,9 @@
         * @return A hash code value for this object.
         */
        public int hashCode() {
-               int hash = value;
+               int hash = 31 * 17 + value;
                if (name != null) {
-                       hash ^= name.hashCode();
+                       hash = 31 * hash + name.hashCode();
                }
                return hash;
        }

Modified: 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Unit.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Unit.java?rev=797561&r1=797560&r2=797561&view=diff
==============================================================================
--- 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Unit.java
 (original)
+++ 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/Unit.java
 Fri Jul 24 17:06:37 2009
@@ -1,7 +1,5 @@
 /*
- * $Header: 
/cvshome/build/org.osgi.util.measurement/src/org/osgi/util/measurement/Unit.java,v
 1.15 2006/06/16 16:31:34 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2002, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2002, 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.
@@ -30,7 +28,8 @@
  * +63. Any operation which produces an exponent outside of this range will
  * result in a <code>Unit</code> object with undefined exponents.
  * 
- * @version $Revision: 1.15 $
+ * @Immutable
+ * @version $Revision: 5715 $
  */
 /*
  * This local class maintains the information about units. It can calculate new
@@ -279,9 +278,11 @@
        private final static Unit[]     allUnits        = new Unit[] {m, s, kg, 
K, A, mol,
                        cd, rad, m_s, m_s2, m2, m3, Hz, N, Pa, J, W, C, V, F, 
Ohm, S, Wb,
                        T, lx, Gy, kat, unity                   };
+       
+       /* @GuardedBy("this") */
        private static Hashtable        base;
-       private String                          name;
-       private long                            type;
+       private final String            name;
+       private final long                      type;
 
        /**
         * Creates a new <code>Unit</code> instance.
@@ -290,6 +291,9 @@
         * @param type the type of the <code>Unit</code>
         */
        private Unit(String name, long type) {
+               if (name == null) {
+                       name = computeName(type);
+               }
                this.name = name;
                this.type = type;
                //System.out.println( name + " " + Long.toHexString( type ) );
@@ -338,7 +342,7 @@
         * @return This object's hash code.
         */
        public int hashCode() {
-               return (int) ((type >>> 32) ^ type);
+               return 31 * 17 + (int) (type ^ (type >>> 32));
        }
 
        /**
@@ -435,16 +439,12 @@
         * 
         * @return the <code>Unit</code>
         */
-       static Unit find(long type) {
+       static synchronized Unit find(long type) {
                if (base == null) {
-                       synchronized (Unit.class) {
-                               if (base == null) {
-                                       int size = allUnits.length;
-                                       base = new Hashtable(size << 1);
-                                       for (int i = 0; i < size; i++) {
-                                               base.put(allUnits[i], 
allUnits[i]);
-                                       }
-                               }
+                       int size = allUnits.length;
+                       base = new Hashtable(size << 1);
+                       for (int i = 0; i < size; i++) {
+                               base.put(allUnits[i], allUnits[i]);
                        }
                }
                Unit unit = new Unit(null, type);
@@ -462,43 +462,39 @@
         * @return A <code>String</code> object representing the 
<code>Unit</code>
         */
        public String toString() {
-               if (name == null) {
-                       int m = (int) (((type >> m_SHIFT) & MASK) - ZERO);
-                       int s = (int) (((type >> s_SHIFT) & MASK) - ZERO);
-                       int kg = (int) (((type >> kg_SHIFT) & MASK) - ZERO);
-                       int K = (int) (((type >> K_SHIFT) & MASK) - ZERO);
-                       int A = (int) (((type >> A_SHIFT) & MASK) - ZERO);
-                       int mol = (int) (((type >> mol_SHIFT) & MASK) - ZERO);
-                       int cd = (int) (((type >> cd_SHIFT) & MASK) - ZERO);
-                       int rad = (int) (((type >> rad_SHIFT) & MASK) - ZERO);
-                       StringBuffer numerator = new StringBuffer();
-                       StringBuffer denominator = new StringBuffer();
-                       addSIname(m, "m", numerator, denominator);
-                       addSIname(s, "s", numerator, denominator);
-                       addSIname(kg, "kg", numerator, denominator);
-                       addSIname(K, "K", numerator, denominator);
-                       addSIname(A, "A", numerator, denominator);
-                       addSIname(mol, "mol", numerator, denominator);
-                       addSIname(cd, "cd", numerator, denominator);
-                       addSIname(rad, "rad", numerator, denominator);
-                       if (denominator.length() > 0) {
-                               if (numerator.length() == 0) {
-                                       numerator.append("1");
-                               }
-                               numerator.append("/");
-                               numerator.append((Object) denominator); /*
-                                                                               
                                 * we use (Object) to
-                                                                               
                                 * avoid using new 1.4
-                                                                               
                                 * method
-                                                                               
                                 * append(StringBuffer)
-                                                                               
                                 */
-                       }
-                       name = numerator.toString();
-               }
                return name;
        }
 
-       private void addSIname(int si, String name, StringBuffer numerator,
+       private static String computeName(long type) {
+               int m = (int) (((type >> m_SHIFT) & MASK) - ZERO);
+               int s = (int) (((type >> s_SHIFT) & MASK) - ZERO);
+               int kg = (int) (((type >> kg_SHIFT) & MASK) - ZERO);
+               int K = (int) (((type >> K_SHIFT) & MASK) - ZERO);
+               int A = (int) (((type >> A_SHIFT) & MASK) - ZERO);
+               int mol = (int) (((type >> mol_SHIFT) & MASK) - ZERO);
+               int cd = (int) (((type >> cd_SHIFT) & MASK) - ZERO);
+               int rad = (int) (((type >> rad_SHIFT) & MASK) - ZERO);
+               StringBuffer numerator = new StringBuffer();
+               StringBuffer denominator = new StringBuffer();
+               addSIname(m, "m", numerator, denominator);
+               addSIname(s, "s", numerator, denominator);
+               addSIname(kg, "kg", numerator, denominator);
+               addSIname(K, "K", numerator, denominator);
+               addSIname(A, "A", numerator, denominator);
+               addSIname(mol, "mol", numerator, denominator);
+               addSIname(cd, "cd", numerator, denominator);
+               addSIname(rad, "rad", numerator, denominator);
+               if (denominator.length() > 0) {
+                       if (numerator.length() == 0) {
+                               numerator.append("1");
+                       }
+                       numerator.append("/");
+                       numerator.append(denominator.toString()); 
+               }
+               return numerator.toString();
+       }
+       
+       private static void addSIname(int si, String name, StringBuffer 
numerator,
                        StringBuffer denominator) {
                if (si != 0) {
                        StringBuffer sb = (si > 0) ? numerator : denominator;

Added: 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/package.html
URL: 
http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/package.html?rev=797561&view=auto
==============================================================================
--- 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/package.html
 (added)
+++ 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/package.html
 Fri Jul 24 17:06:37 2009
@@ -0,0 +1,10 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Measurement Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.util.measurement; version=&quot;[1.0,2.0)&quot;
+</pre>
+</BODY>

Added: 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/packageinfo
URL: 
http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/packageinfo?rev=797561&view=auto
==============================================================================
--- 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/packageinfo
 (added)
+++ 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/measurement/packageinfo
 Fri Jul 24 17:06:37 2009
@@ -0,0 +1 @@
+version 1.0.1
\ No newline at end of file

Modified: 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/mobile/UserPromptCondition.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/mobile/UserPromptCondition.java?rev=797561&r1=797560&r2=797561&view=diff
==============================================================================
--- 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/mobile/UserPromptCondition.java
 (original)
+++ 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/mobile/UserPromptCondition.java
 Fri Jul 24 17:06:37 2009
@@ -1,7 +1,5 @@
 /*
- * $Header: 
/cvshome/build/org.osgi.util.mobile/src/org/osgi/util/mobile/UserPromptCondition.java,v
 1.26 2006/07/10 08:18:30 pnagy Exp $
- *
- * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 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.

Added: 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/mobile/package.html
URL: 
http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/mobile/package.html?rev=797561&view=auto
==============================================================================
--- 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/mobile/package.html 
(added)
+++ 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/mobile/package.html 
Fri Jul 24 17:06:37 2009
@@ -0,0 +1,10 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Mobile Conditions Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.util.mobile; version=&quot;[1.0,2.0)&quot;
+</pre>
+</BODY>

Added: 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/mobile/packageinfo
URL: 
http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/mobile/packageinfo?rev=797561&view=auto
==============================================================================
--- 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/mobile/packageinfo 
(added)
+++ 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/mobile/packageinfo 
Fri Jul 24 17:06:37 2009
@@ -0,0 +1 @@
+version 1.0
\ No newline at end of file

Modified: 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/Position.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/Position.java?rev=797561&r1=797560&r2=797561&view=diff
==============================================================================
--- 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/Position.java
 (original)
+++ 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/Position.java
 Fri Jul 24 17:06:37 2009
@@ -1,7 +1,5 @@
 /*
- * $Header: 
/cvshome/build/org.osgi.util.position/src/org/osgi/util/position/Position.java,v
 1.9 2006/07/12 21:21:35 hargrave Exp $
- *
- * Copyright (c) OSGi Alliance (2002, 2006). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2002, 2009). 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.
@@ -35,16 +33,19 @@
  * hashCode() because it is not clear how missing values should be handled. It
  * is up to the user of a position to determine how best to compare two 
position
  * objects. A <code>Position</code> object is immutable.
+ * 
+ * @Immutable
+ * @version $Revision: 6860 $
  */
 public class Position {
-       private Measurement     altitude;
-       private Measurement     longitude;
-       private Measurement     latitude;
-       private Measurement     speed;
-       private Measurement     track;
+       private final Measurement       altitude;
+       private final Measurement       longitude;
+       private final Measurement       latitude;
+       private final Measurement       speed;
+       private final Measurement       track;
 
        /**
-        * Contructs a <code>Position</code> object with the given values.
+        * Constructs a <code>Position</code> object with the given values.
         * 
         * @param lat a <code>Measurement</code> object specifying the latitude 
in
         *        radians, or null
@@ -63,33 +64,87 @@
                        if (!Unit.rad.equals(lat.getUnit())) {
                                throw new IllegalArgumentException("Invalid 
Latitude");
                        }
-                       this.latitude = lat;
                }
                if (lon != null) {
                        if (!Unit.rad.equals(lon.getUnit())) {
                                throw new IllegalArgumentException("Invalid 
Longitude");
                        }
-                       this.longitude = lon;
                }
-               normalizeLatLon();
                if (alt != null) {
                        if (!Unit.m.equals(alt.getUnit())) {
                                throw new IllegalArgumentException("Invalid 
Altitude");
                        }
-                       this.altitude = alt;
                }
                if (speed != null) {
                        if (!Unit.m_s.equals(speed.getUnit())) {
                                throw new IllegalArgumentException("Invalid 
Speed");
                        }
-                       this.speed = speed;
                }
                if (track != null) {
                        if (!Unit.rad.equals(track.getUnit())) {
                                throw new IllegalArgumentException("Invalid 
Track");
                        }
-                       this.track = normalizeTrack(track);
                }
+
+               /*
+                * Verify the longitude and latitude parameters so they fit the 
normal
+                * coordinate system. A latitude is between -90 (south) and +90 
(north).
+                * A longitude is between -180 (Western hemisphere) and +180 
(eastern
+                * hemisphere). This method first normalizes the latitude and 
longitude
+                * between +/- 180. If the |latitude| > 90, then the longitude 
is added
+                * 180 and the latitude is normalized to fit +/-90. (Example 
are with
+                * degrees though radians are used) <br> No normalization takes 
place
+                * when either lon or lat is null.
+                */
+               normalizeLatLon: {
+                       if (lat == null || lon == null) {
+                               break normalizeLatLon;
+                       }
+                       double dlat = lat.getValue();
+                       double dlon = lon.getValue();
+                       if (dlon >= -LON_RANGE && dlon < LON_RANGE && dlat >= 
-LAT_RANGE
+                                       && dlat <= LAT_RANGE) {
+                               break normalizeLatLon;
+                       }
+                       dlon = normalize(dlon, LON_RANGE);
+                       dlat = normalize(dlat, LAT_RANGE * 2.0D); // First over 
180 degree
+                       // Check if we have to move to other side of the earth
+                       if (dlat > LAT_RANGE || dlat < -LAT_RANGE) {
+                               dlon = normalize(dlon - LON_RANGE, LON_RANGE);
+                               dlat = normalize((LAT_RANGE * 2.0D) - dlat, 
LAT_RANGE);
+                       }
+                       lon = new Measurement(dlon, lon.getError(), 
lon.getUnit(), lon
+                                       .getTime());
+                       lat = new Measurement(dlat, lat.getError(), 
lat.getUnit(), lat
+                                       .getTime());
+               }
+
+               /*
+                * Normalize track to be a value such that: 0 <= value < +2PI. 
This
+                * corresponds to 0 deg to +360 deg. 0 is North, 0.5PI is East, 
PI is
+                * South, 1.5PI is West
+                */
+               normalizeTrack: {
+                       if (track == null) {
+                               break normalizeTrack;
+                       }
+                       double dtrack = track.getValue();
+                       if ((0.0D <= dtrack) && (dtrack < TRACK_RANGE)) {
+                               break normalizeTrack; /* value is already 
normalized */
+                       }
+                       dtrack %= TRACK_RANGE;
+                       if (dtrack < 0.0D) {
+                               dtrack += TRACK_RANGE;
+                       }
+                       track = new Measurement(dtrack, track.getError(), 
track.getUnit(),
+                                       track.getTime());
+               }
+
+               this.latitude = lat;
+               this.longitude = lon;
+               this.altitude = alt;
+               this.speed = speed;
+               this.track = track;
        }
 
        /**
@@ -153,37 +208,6 @@
        private static final double     LAT_RANGE       = Math.PI / 2.0D;
 
        /**
-        * Verify the longitude and latitude parameters so they fit the normal
-        * coordinate system. A latitude is between -90 (south) and +90 
(north). A A
-        * longitude is between -180 (Western hemisphere) and +180 (eastern
-        * hemisphere). This method first normalizes the latitude and longitude
-        * between +/- 180. If the |latitude| > 90, then the longitude is added 
180
-        * and the latitude is normalized to fit +/-90. (Example are with 
degrees
-        * though radians are used) <br>
-        * No normalization takes place when either lon or lat is null.
-        */
-       private void normalizeLatLon() {
-               if (longitude == null || latitude == null)
-                       return;
-               double dlon = longitude.getValue();
-               double dlat = latitude.getValue();
-               if (dlon >= -LON_RANGE && dlon < LON_RANGE && dlat >= -LAT_RANGE
-                               && dlat <= LAT_RANGE)
-                       return;
-               dlon = normalize(dlon, LON_RANGE);
-               dlat = normalize(dlat, LAT_RANGE * 2.0D); // First over 180 
degree
-               // Check if we have to move to other side of the earth
-               if (dlat > LAT_RANGE || dlat < -LAT_RANGE) {
-                       dlon = normalize(dlon - LON_RANGE, LON_RANGE);
-                       dlat = normalize((LAT_RANGE * 2.0D) - dlat, LAT_RANGE);
-               }
-               longitude = new Measurement(dlon, longitude.getError(), 
longitude
-                               .getUnit(), longitude.getTime());
-               latitude = new Measurement(dlat, latitude.getError(), latitude
-                               .getUnit(), latitude.getTime());
-       }
-
-       /**
         * This function normalizes the a value according to a range. This is 
not
         * simple modulo (as I thought when I started), but requires some 
special
         * handling. For positive numbers we subtract 2*range from the number so
@@ -201,7 +225,7 @@
         * @param value The value that needs adjusting
         * @param range -range = < value < range
         */
-       private double normalize(double value, double range) {
+       private static double normalize(double value, double range) {
                double twiceRange = 2.0D * range;
                while (value >= range) {
                        value -= twiceRange;
@@ -213,25 +237,4 @@
        }
 
        private static final double     TRACK_RANGE     = Math.PI * 2.0D;
-
-       /**
-        * Normalize track to be a value such that: 0 <= value < +2PI. This
-        * corresponds to 0 deg to +360 deg. 0 is North 0.5*PI is East PI is 
South
-        * 1.5*PI is West
-        * 
-        * @param track Value to be normalized
-        * @return Normalized value
-        */
-       private Measurement normalizeTrack(Measurement track) {
-               double value = track.getValue();
-               if ((0.0D <= value) && (value < TRACK_RANGE)) {
-                       return track; /* value is already normalized */
-               }
-               value %= TRACK_RANGE;
-               if (value < 0.0D) {
-                       value += TRACK_RANGE;
-               }
-               return new Measurement(value, track.getError(), 
track.getUnit(), track
-                               .getTime());
-       }
 }

Added: 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/package.html
URL: 
http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/package.html?rev=797561&view=auto
==============================================================================
--- 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/package.html
 (added)
+++ 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/package.html
 Fri Jul 24 17:06:37 2009
@@ -0,0 +1,10 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Position Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.util.position; version=&quot;[1.0,2.0)&quot;
+</pre>
+</BODY>

Added: 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/packageinfo
URL: 
http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/packageinfo?rev=797561&view=auto
==============================================================================
--- 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/packageinfo
 (added)
+++ 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/position/packageinfo
 Fri Jul 24 17:06:37 2009
@@ -0,0 +1 @@
+version 1.0.1
\ No newline at end of file

Added: 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/AbstractTracked.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/AbstractTracked.java?rev=797561&view=auto
==============================================================================
--- 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/AbstractTracked.java
 (added)
+++ 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/AbstractTracked.java
 Fri Jul 24 17:06:37 2009
@@ -0,0 +1,449 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Abstract class to track items. If a Tracker is reused (closed then 
reopened),
+ * then a new AbstractTracked object is used. This class acts a map of tracked
+ * item -> customized object. Subclasses of this class will act as the listener
+ * object for the tracker. This class is used to synchronize access to the
+ * tracked items. This is not a public class. It is only for use by the
+ * implementation of the Tracker class.
+ * 
+ * @ThreadSafe
+ * @version $Revision: 5871 $
+ * @since 1.4
+ */
+abstract class AbstractTracked {
+       /* set this to true to compile in debug messages */
+       static final boolean            DEBUG   = false;
+
+       /**
+        * Map of tracked items to customized objects.
+        * 
+        * @GuardedBy this
+        */
+       private final Map                       tracked;
+
+       /**
+        * Modification count. This field is initialized to zero and 
incremented by
+        * modified.
+        * 
+        * @GuardedBy this
+        */
+       private int                                     trackingCount;
+
+       /**
+        * List of items in the process of being added. This is used to deal 
with
+        * nesting of events. Since events may be synchronously delivered, 
events
+        * can be nested. For example, when processing the adding of a service 
and
+        * the customizer causes the service to be unregistered, notification 
to the
+        * nested call to untrack that the service was unregistered can be made 
to
+        * the track method.
+        * 
+        * Since the ArrayList implementation is not synchronized, all access to
+        * this list must be protected by the same synchronized object for
+        * thread-safety.
+        * 
+        * @GuardedBy this
+        */
+       private final List                      adding;
+
+       /**
+        * true if the tracked object is closed.
+        * 
+        * This field is volatile because it is set by one thread and read by
+        * another.
+        */
+       volatile boolean                        closed;
+
+       /**
+        * Initial list of items for the tracker. This is used to correctly 
process
+        * the initial items which could be modified before they are tracked. 
This
+        * is necessary since the initial set of tracked items are not 
"announced"
+        * by events and therefore the event which makes the item untracked 
could be
+        * delivered before we track the item.
+        * 
+        * An item must not be in both the initial and adding lists at the same
+        * time. An item must be moved from the initial list to the adding list
+        * "atomically" before we begin tracking it.
+        * 
+        * Since the LinkedList implementation is not synchronized, all access 
to
+        * this list must be protected by the same synchronized object for
+        * thread-safety.
+        * 
+        * @GuardedBy this
+        */
+       private final LinkedList        initial;
+
+       /**
+        * AbstractTracked constructor.
+        */
+       AbstractTracked() {
+               tracked = new HashMap();
+               trackingCount = 0;
+               adding = new ArrayList(6);
+               initial = new LinkedList();
+               closed = false;
+       }
+
+       /**
+        * Set initial list of items into tracker before events begin to be
+        * received.
+        * 
+        * This method must be called from Tracker's open method while 
synchronized
+        * on this object in the same synchronized block as the add listener 
call.
+        * 
+        * @param list The initial list of items to be tracked. 
<code>null</code>
+        *        entries in the list are ignored.
+        * @GuardedBy this
+        */
+       void setInitial(Object[] list) {
+               if (list == null) {
+                       return;
+               }
+               int size = list.length;
+               for (int i = 0; i < size; i++) {
+                       Object item = list[i];
+                       if (item == null) {
+                               continue;
+                       }
+                       if (DEBUG) {
+                               System.out.println("AbstractTracked.setInitial: 
" + item); //$NON-NLS-1$
+                       }
+                       initial.add(item);
+               }
+       }
+
+       /**
+        * Track the initial list of items. This is called after events can 
begin to
+        * be received.
+        * 
+        * This method must be called from Tracker's open method while not
+        * synchronized on this object after the add listener call.
+        * 
+        */
+       void trackInitial() {
+               while (true) {
+                       Object item;
+                       synchronized (this) {
+                               if (closed || (initial.size() == 0)) {
+                                       /*
+                                        * if there are no more initial items
+                                        */
+                                       return; /* we are done */
+                               }
+                               /*
+                                * move the first item from the initial list to 
the adding list
+                                * within this synchronized block.
+                                */
+                               item = initial.removeFirst();
+                               if (tracked.get(item) != null) {
+                                       /* if we are already tracking this item 
*/
+                                       if (DEBUG) {
+                                               System.out
+                                                               
.println("AbstractTracked.trackInitial[already tracked]: " + item); 
//$NON-NLS-1$
+                                       }
+                                       continue; /* skip this item */
+                               }
+                               if (adding.contains(item)) {
+                                       /*
+                                        * if this item is already in the 
process of being added.
+                                        */
+                                       if (DEBUG) {
+                                               System.out
+                                                               
.println("AbstractTracked.trackInitial[already adding]: " + item); //$NON-NLS-1$
+                                       }
+                                       continue; /* skip this item */
+                               }
+                               adding.add(item);
+                       }
+                       if (DEBUG) {
+                               
System.out.println("AbstractTracked.trackInitial: " + item); //$NON-NLS-1$
+                       }
+                       trackAdding(item, null); /*
+                                                                        * 
Begin tracking it. We call trackAdding
+                                                                        * 
since we have already put the item in the
+                                                                        * 
adding list.
+                                                                        */
+               }
+       }
+
+       /**
+        * Called by the owning Tracker object when it is closed.
+        */
+       void close() {
+               closed = true;
+       }
+
+       /**
+        * Begin to track an item.
+        * 
+        * @param item Item to be tracked.
+        * @param related Action related object.
+        */
+       void track(final Object item, final Object related) {
+               final Object object;
+               synchronized (this) {
+                       if (closed) {
+                               return;
+                       }
+                       object = tracked.get(item);
+                       if (object == null) { /* we are not tracking the item */
+                               if (adding.contains(item)) {
+                                       /* if this item is already in the 
process of being added. */
+                                       if (DEBUG) {
+                                               System.out
+                                                               
.println("AbstractTracked.track[already adding]: " + item); //$NON-NLS-1$
+                                       }
+                                       return;
+                               }
+                               adding.add(item); /* mark this item is being 
added */
+                       }
+                       else { /* we are currently tracking this item */
+                               if (DEBUG) {
+                                       System.out
+                                                       
.println("AbstractTracked.track[modified]: " + item); //$NON-NLS-1$
+                               }
+                               modified(); /* increment modification count */
+                       }
+               }
+
+               if (object == null) { /* we are not tracking the item */
+                       trackAdding(item, related);
+               }
+               else {
+                       /* Call customizer outside of synchronized region */
+                       customizerModified(item, related, object);
+                       /*
+                        * If the customizer throws an unchecked exception, it 
is safe to
+                        * let it propagate
+                        */
+               }
+       }
+
+       /**
+        * Common logic to add an item to the tracker used by track and
+        * trackInitial. The specified item must have been placed in the adding 
list
+        * before calling this method.
+        * 
+        * @param item Item to be tracked.
+        * @param related Action related object.
+        */
+       private void trackAdding(final Object item, final Object related) {
+               if (DEBUG) {
+                       System.out.println("AbstractTracked.trackAdding: " + 
item); //$NON-NLS-1$
+               }
+               Object object = null;
+               boolean becameUntracked = false;
+               /* Call customizer outside of synchronized region */
+               try {
+                       object = customizerAdding(item, related);
+                       /*
+                        * If the customizer throws an unchecked exception, it 
will
+                        * propagate after the finally
+                        */
+               }
+               finally {
+                       synchronized (this) {
+                               if (adding.remove(item) && !closed) {
+                                       /*
+                                        * if the item was not untracked during 
the customizer
+                                        * callback
+                                        */
+                                       if (object != null) {
+                                               tracked.put(item, object);
+                                               modified(); /* increment 
modification count */
+                                               notifyAll(); /* notify any 
waiters */
+                                       }
+                               }
+                               else {
+                                       becameUntracked = true;
+                               }
+                       }
+               }
+               /*
+                * The item became untracked during the customizer callback.
+                */
+               if (becameUntracked && (object != null)) {
+                       if (DEBUG) {
+                               System.out
+                                               
.println("AbstractTracked.trackAdding[removed]: " + item); //$NON-NLS-1$
+                       }
+                       /* Call customizer outside of synchronized region */
+                       customizerRemoved(item, related, object);
+                       /*
+                        * If the customizer throws an unchecked exception, it 
is safe to
+                        * let it propagate
+                        */
+               }
+       }
+
+       /**
+        * Discontinue tracking the item.
+        * 
+        * @param item Item to be untracked.
+        * @param related Action related object.
+        */
+       void untrack(final Object item, final Object related) {
+               final Object object;
+               synchronized (this) {
+                       if (initial.remove(item)) { /*
+                                                                               
 * if this item is already in the list
+                                                                               
 * of initial references to process
+                                                                               
 */
+                               if (DEBUG) {
+                                       System.out
+                                                       
.println("AbstractTracked.untrack[removed from initial]: " + item); 
//$NON-NLS-1$
+                               }
+                               return; /*
+                                                * we have removed it from the 
list and it will not be
+                                                * processed
+                                                */
+                       }
+
+                       if (adding.remove(item)) { /*
+                                                                               
 * if the item is in the process of
+                                                                               
 * being added
+                                                                               
 */
+                               if (DEBUG) {
+                                       System.out
+                                                       
.println("AbstractTracked.untrack[being added]: " + item); //$NON-NLS-1$
+                               }
+                               return; /*
+                                                * in case the item is 
untracked while in the process of
+                                                * adding
+                                                */
+                       }
+                       object = tracked.remove(item); /*
+                                                                               
         * must remove from tracker before
+                                                                               
         * calling customizer callback
+                                                                               
         */
+                       if (object == null) { /* are we actually tracking the 
item */
+                               return;
+                       }
+                       modified(); /* increment modification count */
+               }
+               if (DEBUG) {
+                       System.out.println("AbstractTracked.untrack[removed]: " 
+ item); //$NON-NLS-1$
+               }
+               /* Call customizer outside of synchronized region */
+               customizerRemoved(item, related, object);
+               /*
+                * If the customizer throws an unchecked exception, it is safe 
to let it
+                * propagate
+                */
+       }
+
+       /**
+        * Returns the number of tracked items.
+        * 
+        * @return The number of tracked items.
+        * 
+        * @GuardedBy this
+        */
+       int size() {
+               return tracked.size();
+       }
+
+       /**
+        * Return the customized object for the specified item
+        * 
+        * @param item The item to lookup in the map
+        * @return The customized object for the specified item.
+        * 
+        * @GuardedBy this
+        */
+       Object getCustomizedObject(final Object item) {
+               return tracked.get(item);
+       }
+
+       /**
+        * Return the list of tracked items.
+        * 
+        * @param list An array to contain the tracked items.
+        * @return The specified list if it is large enough to hold the tracked
+        *         items or a new array large enough to hold the tracked items.
+        * @GuardedBy this
+        */
+       Object[] getTracked(final Object[] list) {
+               return tracked.keySet().toArray(list);
+       }
+
+       /**
+        * Increment the modification count. If this method is overridden, the
+        * overriding method MUST call this method to increment the tracking 
count.
+        * 
+        * @GuardedBy this
+        */
+       void modified() {
+               trackingCount++;
+       }
+
+       /**
+        * Returns the tracking count for this <code>ServiceTracker</code> 
object.
+        * 
+        * The tracking count is initialized to 0 when this object is opened. 
Every
+        * time an item is added, modified or removed from this object the 
tracking
+        * count is incremented.
+        * 
+        * @GuardedBy this
+        * @return The tracking count for this object.
+        */
+       int getTrackingCount() {
+               return trackingCount;
+       }
+
+       /**
+        * 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 <code>null</code> 
if
+        *         the item is not to be tracked.
+        */
+       abstract Object customizerAdding(final Object item, final Object 
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.
+        */
+       abstract void customizerModified(final Object item, final Object 
related,
+                       final Object 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.
+        */
+       abstract void customizerRemoved(final Object item, final Object related,
+                       final Object object);
+}

Added: 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/BundleTracker.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/BundleTracker.java?rev=797561&view=auto
==============================================================================
--- 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/BundleTracker.java
 (added)
+++ 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/BundleTracker.java
 Fri Jul 24 17:06:37 2009
@@ -0,0 +1,471 @@
+/*
+ * 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 <code>BundleTracker</code> class simplifies tracking bundles much like
+ * the <code>ServiceTracker</code> simplifies tracking services.
+ * <p>
+ * A <code>BundleTracker</code> is constructed with state criteria and a
+ * <code>BundleTrackerCustomizer</code> object. A <code>BundleTracker</code> 
can
+ * use the <code>BundleTrackerCustomizer</code> to select which bundles are
+ * tracked and to create a customized object to be tracked with the bundle. The
+ * <code>BundleTracker</code> can then be opened to begin tracking all bundles
+ * whose state matches the specified state criteria.
+ * <p>
+ * The <code>getBundles</code> method can be called to get the
+ * <code>Bundle</code> objects of the bundles being tracked. The
+ * <code>getObject</code> method can be called to get the customized object for
+ * a tracked bundle.
+ * <p>
+ * The <code>BundleTracker</code> class is thread-safe. It does not call a
+ * <code>BundleTrackerCustomizer</code> while holding any locks.
+ * <code>BundleTrackerCustomizer</code> 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 <code>BundleTracker</code>.
+        */
+       protected final BundleContext   context;
+
+       /**
+        * The <code>BundleTrackerCustomizer</code> object for this tracker.
+        */
+       final BundleTrackerCustomizer   customizer;
+
+       /**
+        * Tracked bundles: <code>Bundle</code> object -> customized Object and
+        * <code>BundleListener</code> 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 <code>BundleTracker</code> for bundles whose state is 
present in
+        * the specified state mask.
+        * 
+        * <p>
+        * Bundles whose state is present on the specified state mask will be
+        * tracked by this <code>BundleTracker</code>.
+        * 
+        * @param context The <code>BundleContext</code> against which the 
tracking
+        *        is done.
+        * @param stateMask The bit mask of the <code>OR</code>ing of the bundle
+        *        states to be tracked.
+        * @param customizer The customizer object to call when bundles are 
added,
+        *        modified, or removed in this <code>BundleTracker</code>. If
+        *        customizer is <code>null</code>, then this
+        *        <code>BundleTracker</code> will be used as the
+        *        <code>BundleTrackerCustomizer</code> and this
+        *        <code>BundleTracker</code> will call the
+        *        <code>BundleTrackerCustomizer</code> 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 <code>BundleTracker</code> and begin tracking bundles.
+        * 
+        * <p>
+        * Bundle which match the state criteria specified when this
+        * <code>BundleTracker</code> was created are now tracked by this
+        * <code>BundleTracker</code>.
+        * 
+        * @throws java.lang.IllegalStateException If the 
<code>BundleContext</code>
+        *         with which this <code>BundleTracker</code> 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]</code>, 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 <code>BundleTracker</code>.
+        * 
+        * <p>
+        * This method should be called when this <code>BundleTracker</code> 
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);
+                       }
+               }
+       }
+
+       /**
+        * Default implementation of the
+        * <code>BundleTrackerCustomizer.addingBundle</code> method.
+        * 
+        * <p>
+        * This method is only called when this <code>BundleTracker</code> has 
been
+        * constructed with a <code>null BundleTrackerCustomizer</code> 
argument.
+        * 
+        * <p>
+        * This implementation simply returns the specified <code>Bundle</code>.
+        * 
+        * <p>
+        * This method can be overridden in a subclass to customize the object 
to be
+        * tracked for the bundle being added.
+        * 
+        * @param bundle The <code>Bundle</code> being added to this
+        *        <code>BundleTracker</code> object.
+        * @param event The bundle event which caused this customizer method to 
be
+        *        called or <code>null</code> 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
+        * <code>BundleTrackerCustomizer.modifiedBundle</code> method.
+        * 
+        * <p>
+        * This method is only called when this <code>BundleTracker</code> has 
been
+        * constructed with a <code>null BundleTrackerCustomizer</code> 
argument.
+        * 
+        * <p>
+        * This implementation does nothing.
+        * 
+        * @param bundle The <code>Bundle</code> whose state has been modified.
+        * @param event The bundle event which caused this customizer method to 
be
+        *        called or <code>null</code> 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
+        * <code>BundleTrackerCustomizer.removedBundle</code> method.
+        * 
+        * <p>
+        * This method is only called when this <code>BundleTracker</code> has 
been
+        * constructed with a <code>null BundleTrackerCustomizer</code> 
argument.
+        * 
+        * <p>
+        * This implementation does nothing.
+        * 
+        * @param bundle The <code>Bundle</code> being removed.
+        * @param event The bundle event which caused this customizer method to 
be
+        *        called or <code>null</code> 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 <code>Bundle</code>s for all bundles being 
tracked by
+        * this <code>BundleTracker</code>.
+        * 
+        * @return An array of <code>Bundle</code>s or <code>null</code> 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 <code>Bundle</code> 
if
+        * the specified bundle is being tracked by this 
<code>BundleTracker</code>.
+        * 
+        * @param bundle The <code>Bundle</code> being tracked.
+        * @return The customized object for the specified <code>Bundle</code> 
or
+        *         <code>null</code> if the specified <code>Bundle</code> 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 <code>BundleTracker</code>.
+        * 
+        * The specified bundle will be removed from this 
<code>BundleTracker</code>
+        * . If the specified bundle was being tracked then the
+        * <code>BundleTrackerCustomizer.removedBundle</code> method will be 
called
+        * for that bundle.
+        * 
+        * @param bundle The <code>Bundle</code> 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
+        * <code>BundleTracker</code>.
+        * 
+        * @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 <code>BundleTracker</code>.
+        * 
+        * The tracking count is initialized to 0 when this
+        * <code>BundleTracker</code> is opened. Every time a bundle is added,
+        * modified or removed from this <code>BundleTracker</code> the tracking
+        * count is incremented.
+        * 
+        * <p>
+        * The tracking count can be used to determine if this
+        * <code>BundleTracker</code> 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</code>
+        * since the previous tracking count was collected.
+        * 
+        * @return The tracking count for this <code>BundleTracker</code> or -1 
if
+        *         this <code>BundleTracker</code> 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
+        * <code>SynchronousBundleListener</code> object for the tracker.
+        * 
+        * @ThreadSafe
+        * @since 1.4
+        */
+       class Tracked extends AbstractTracked implements 
SynchronousBundleListener {
+               /**
+                * Tracked constructor.
+                */
+               Tracked() {
+                       super();
+               }
+
+               /**
+                * <code>BundleListener</code> method for the 
<code>BundleTracker</code>
+                * class. This method must NOT be synchronized to avoid deadlock
+                * potential.
+                * 
+                * @param event <code>BundleEvent</code> 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 
<code>null</code>
+                *         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);
+               }
+       }
+}

Added: 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/BundleTrackerCustomizer.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/BundleTrackerCustomizer.java?rev=797561&view=auto
==============================================================================
--- 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/BundleTrackerCustomizer.java
 (added)
+++ 
felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/BundleTrackerCustomizer.java
 Fri Jul 24 17:06:37 2009
@@ -0,0 +1,104 @@
+/*
+ * 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.BundleEvent;
+
+/**
+ * The <code>BundleTrackerCustomizer</code> interface allows a
+ * <code>BundleTracker</code> to customize the <code>Bundle</code>s that are
+ * tracked. A <code>BundleTrackerCustomizer</code> is called when a bundle is
+ * being added to a <code>BundleTracker</code>. The
+ * <code>BundleTrackerCustomizer</code> can then return an object for the
+ * tracked bundle. A <code>BundleTrackerCustomizer</code> is also called when a
+ * tracked bundle is modified or has been removed from a
+ * <code>BundleTracker</code>.
+ * 
+ * <p>
+ * The methods in this interface may be called as the result of a
+ * <code>BundleEvent</code> being received by a <code>BundleTracker</code>.
+ * Since <code>BundleEvent</code>s are received synchronously by the
+ * <code>BundleTracker</code>, it is highly recommended that implementations of
+ * these methods do not alter bundle states while being synchronized on any
+ * object.
+ * 
+ * <p>
+ * The <code>BundleTracker</code> class is thread-safe. It does not call a
+ * <code>BundleTrackerCustomizer</code> while holding any locks.
+ * <code>BundleTrackerCustomizer</code> implementations must also be
+ * thread-safe.
+ * 
+ * @ThreadSafe
+ * @version $Revision: 5874 $
+ * @since 1.4
+ */
+public interface BundleTrackerCustomizer {
+       /**
+        * A bundle is being added to the <code>BundleTracker</code>.
+        * 
+        * <p>
+        * This method is called before a bundle which matched the search 
parameters
+        * of the <code>BundleTracker</code> is added to the
+        * <code>BundleTracker</code>. This method should return the object to 
be
+        * tracked for the specified <code>Bundle</code>. The returned object is
+        * stored in the <code>BundleTracker</code> and is available from the
+        * {...@link BundleTracker#getObject(Bundle) getObject} method.
+        * 
+        * @param bundle The <code>Bundle</code> being added to the
+        *        <code>BundleTracker</code>.
+        * @param event The bundle event which caused this customizer method to 
be
+        *        called or <code>null</code> if there is no bundle event 
associated
+        *        with the call to this method.
+        * @return The object to be tracked for the specified 
<code>Bundle</code>
+        *         object or <code>null</code> if the specified 
<code>Bundle</code>
+        *         object should not be tracked.
+        */
+       public Object addingBundle(Bundle bundle, BundleEvent event);
+
+       /**
+        * A bundle tracked by the <code>BundleTracker</code> has been modified.
+        * 
+        * <p>
+        * This method is called when a bundle being tracked by the
+        * <code>BundleTracker</code> has had its state modified.
+        * 
+        * @param bundle The <code>Bundle</code> whose state has been modified.
+        * @param event The bundle event which caused this customizer method to 
be
+        *        called or <code>null</code> if there is no bundle event 
associated
+        *        with the call to this method.
+        * @param object The tracked object for the specified bundle.
+        */
+       public void modifiedBundle(Bundle bundle, BundleEvent event,
+                       Object object);
+
+       /**
+        * A bundle tracked by the <code>BundleTracker</code> has been removed.
+        * 
+        * <p>
+        * This method is called after a bundle is no longer being tracked by 
the
+        * <code>BundleTracker</code>.
+        * 
+        * @param bundle The <code>Bundle</code> that has been removed.
+        * @param event The bundle event which caused this customizer method to 
be
+        *        called or <code>null</code> if there is no bundle event 
associated
+        *        with the call to this method.
+        * @param object The tracked object for the specified bundle.
+        */
+       public void removedBundle(Bundle bundle, BundleEvent event,
+                       Object object);
+}


Reply via email to