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="[1.0,2.0)" +</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="[1.0,2.0)" +</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="[1.0,2.0)" +</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); +}
