You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2009/07/24 19:06:44 UTC

svn commit: r797561 [8/9] - in /felix/trunk: org.osgi.compendium/ org.osgi.compendium/src/main/java/info/dmtree/ org.osgi.compendium/src/main/java/info/dmtree/notification/ org.osgi.compendium/src/main/java/info/dmtree/notification/spi/ org.osgi.compen...

Modified: felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTracker.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTracker.java?rev=797561&r1=797560&r2=797561&view=diff
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTracker.java (original)
+++ felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTracker.java Fri Jul 24 17:06:37 2009
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.util.tracker/src/org/osgi/util/tracker/ServiceTracker.java,v 1.29 2007/02/19 19:04:33 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 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.
@@ -18,53 +16,61 @@
 
 package org.osgi.util.tracker;
 
-import java.util.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 
-import org.osgi.framework.*;
+import org.osgi.framework.AllServiceListener;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
 
 /**
  * The <code>ServiceTracker</code> class simplifies using services from the
  * Framework's service registry.
  * <p>
- * A <code>ServiceTracker</code> object is constructed with search criteria
- * and a <code>ServiceTrackerCustomizer</code> object. A
- * <code>ServiceTracker</code> object can use the
- * <code>ServiceTrackerCustomizer</code> object to customize the service
- * objects to be tracked. The <code>ServiceTracker</code> object can then be
- * opened to begin tracking all services in the Framework's service registry
- * that match the specified search criteria. The <code>ServiceTracker</code>
- * object correctly handles all of the details of listening to
- * <code>ServiceEvent</code> objects and getting and ungetting services.
+ * A <code>ServiceTracker</code> object is constructed with search criteria and
+ * a <code>ServiceTrackerCustomizer</code> object. A <code>ServiceTracker</code>
+ * can use a <code>ServiceTrackerCustomizer</code> to customize the service
+ * objects to be tracked. The <code>ServiceTracker</code> can then be opened to
+ * begin tracking all services in the Framework's service registry that match
+ * the specified search criteria. The <code>ServiceTracker</code> correctly
+ * handles all of the details of listening to <code>ServiceEvent</code>s and
+ * getting and ungetting services.
  * <p>
- * The <code>getServiceReferences</code> method can be called to get
- * references to the services being tracked. The <code>getService</code> and
- * <code>getServices</code> methods can be called to get the service objects
- * for the tracked service.
+ * The <code>getServiceReferences</code> method can be called to get references
+ * to the services being tracked. The <code>getService</code> and
+ * <code>getServices</code> methods can be called to get the service objects for
+ * the tracked service.
  * <p>
  * The <code>ServiceTracker</code> class is thread-safe. It does not call a
- * <code>ServiceTrackerCustomizer</code> object while holding any locks.
+ * <code>ServiceTrackerCustomizer</code> while holding any locks.
  * <code>ServiceTrackerCustomizer</code> implementations must also be
  * thread-safe.
  * 
  * @ThreadSafe
- * @version $Revision: 1.29 $
+ * @version $Revision: 6386 $
  */
 public class ServiceTracker implements ServiceTrackerCustomizer {
 	/* set this to true to compile in debug messages */
 	static final boolean				DEBUG			= false;
 	/**
-	 * Bundle context against which this <code>ServiceTracker</code> object is
-	 * tracking.
+	 * The Bundle Context used by this <code>ServiceTracker</code>.
 	 */
 	protected final BundleContext		context;
 	/**
-	 * Filter specifying search criteria for the services to track.
+	 * The Filter used by this <code>ServiceTracker</code> which specifies the
+	 * search criteria for the services to track.
 	 * 
 	 * @since 1.1
 	 */
 	protected final Filter				filter;
 	/**
-	 * <code>ServiceTrackerCustomizer</code> object for this tracker.
+	 * The <code>ServiceTrackerCustomizer</code> for this tracker.
 	 */
 	final ServiceTrackerCustomizer		customizer;
 	/**
@@ -84,17 +90,22 @@
 	 */
 	private final ServiceReference		trackReference;
 	/**
-	 * Tracked services: <code>ServiceReference</code> object -> customized
-	 * Object and <code>ServiceListener</code> object
+	 * Tracked services: <code>ServiceReference</code> -> customized Object and
+	 * <code>ServiceListener</code> object
 	 */
 	private volatile Tracked			tracked;
+
 	/**
-	 * Modification count. This field is initialized to zero by open, set to -1
-	 * by close and incremented by modified.
+	 * 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.
 	 * 
-	 * This field is volatile since it is accessed by multiple threads.
+	 * @return The current Tracked object.
 	 */
-	private volatile int				trackingCount	= -1;
+	private Tracked tracked() {
+		return tracked;
+	}
+
 	/**
 	 * Cached ServiceReference for getServiceReference.
 	 * 
@@ -109,126 +120,153 @@
 	private volatile Object				cachedService;
 
 	/**
-	 * Create a <code>ServiceTracker</code> object on the specified
-	 * <code>ServiceReference</code> object.
+	 * org.osgi.framework package version which introduced
+	 * {@link ServiceEvent#MODIFIED_ENDMATCH}
+	 */
+	private static final Version		endMatchVersion	= new Version(1, 5, 0);
+
+	/**
+	 * Create a <code>ServiceTracker</code> on the specified
+	 * <code>ServiceReference</code>.
 	 * 
 	 * <p>
 	 * The service referenced by the specified <code>ServiceReference</code>
-	 * object will be tracked by this <code>ServiceTracker</code> object.
+	 * will be tracked by this <code>ServiceTracker</code>.
 	 * 
-	 * @param context <code>BundleContext</code> object against which the
-	 *        tracking is done.
-	 * @param reference <code>ServiceReference</code> object for the service
-	 *        to be tracked.
+	 * @param context The <code>BundleContext</code> against which the tracking
+	 *        is done.
+	 * @param reference The <code>ServiceReference</code> for the service to be
+	 *        tracked.
 	 * @param customizer The customizer object to call when services are added,
-	 *        modified, or removed in this <code>ServiceTracker</code> object.
-	 *        If customizer is <code>null</code>, then this
-	 *        <code>ServiceTracker</code> object will be used as the
-	 *        <code>ServiceTrackerCustomizer</code> object and the
-	 *        <code>ServiceTracker</code> object will call the
+	 *        modified, or removed in this <code>ServiceTracker</code>. If
+	 *        customizer is <code>null</code>, then this
+	 *        <code>ServiceTracker</code> will be used as the
+	 *        <code>ServiceTrackerCustomizer</code> and this
+	 *        <code>ServiceTracker</code> will call the
 	 *        <code>ServiceTrackerCustomizer</code> methods on itself.
 	 */
-	public ServiceTracker(BundleContext context, ServiceReference reference,
-			ServiceTrackerCustomizer customizer) {
+	public ServiceTracker(final BundleContext context,
+			final ServiceReference reference,
+			final ServiceTrackerCustomizer customizer) {
 		this.context = context;
 		this.trackReference = reference;
 		this.trackClass = null;
 		this.customizer = (customizer == null) ? this : customizer;
-		this.listenerFilter = "(" + Constants.SERVICE_ID + "=" + reference.getProperty(Constants.SERVICE_ID).toString() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		this.listenerFilter = "(" + Constants.SERVICE_ID + "="
+				+ reference.getProperty(Constants.SERVICE_ID).toString() + ")"; 
 		try {
 			this.filter = context.createFilter(listenerFilter);
 		}
-		catch (InvalidSyntaxException e) { // we could only get this exception
-			// if the ServiceReference was
-			// invalid
-			throw new IllegalArgumentException(
-					"unexpected InvalidSyntaxException: " + e.getMessage()); //$NON-NLS-1$
+		catch (InvalidSyntaxException e) {
+			/*
+			 * we could only get this exception if the ServiceReference was
+			 * invalid
+			 */
+			IllegalArgumentException iae = new IllegalArgumentException(
+					"unexpected InvalidSyntaxException: " + e.getMessage());
+			iae.initCause(e);
+			throw iae;
 		}
 	}
 
 	/**
-	 * Create a <code>ServiceTracker</code> object on the specified class
-	 * name.
+	 * Create a <code>ServiceTracker</code> on the specified class name.
 	 * 
 	 * <p>
 	 * Services registered under the specified class name will be tracked by
-	 * this <code>ServiceTracker</code> object.
+	 * this <code>ServiceTracker</code>.
 	 * 
-	 * @param context <code>BundleContext</code> object against which the
-	 *        tracking is done.
-	 * @param clazz Class name of the services to be tracked.
+	 * @param context The <code>BundleContext</code> against which the tracking
+	 *        is done.
+	 * @param clazz The class name of the services to be tracked.
 	 * @param customizer The customizer object to call when services are added,
-	 *        modified, or removed in this <code>ServiceTracker</code> object.
-	 *        If customizer is <code>null</code>, then this
-	 *        <code>ServiceTracker</code> object will be used as the
-	 *        <code>ServiceTrackerCustomizer</code> object and the
-	 *        <code>ServiceTracker</code> object will call the
+	 *        modified, or removed in this <code>ServiceTracker</code>. If
+	 *        customizer is <code>null</code>, then this
+	 *        <code>ServiceTracker</code> will be used as the
+	 *        <code>ServiceTrackerCustomizer</code> and this
+	 *        <code>ServiceTracker</code> will call the
 	 *        <code>ServiceTrackerCustomizer</code> methods on itself.
 	 */
-	public ServiceTracker(BundleContext context, String clazz,
-			ServiceTrackerCustomizer customizer) {
+	public ServiceTracker(final BundleContext context, final String clazz,
+			final ServiceTrackerCustomizer customizer) {
 		this.context = context;
 		this.trackReference = null;
 		this.trackClass = clazz;
 		this.customizer = (customizer == null) ? this : customizer;
-		this.listenerFilter = "(" + Constants.OBJECTCLASS + "=" + clazz.toString() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		// we call clazz.toString to verify clazz is non-null!
+		this.listenerFilter = "(" + Constants.OBJECTCLASS + "="
+				+ clazz.toString() + ")"; 
 		try {
 			this.filter = context.createFilter(listenerFilter);
 		}
-		catch (InvalidSyntaxException e) { // we could only get this exception
-			// if the clazz argument was
-			// malformed
-			throw new IllegalArgumentException(
-					"unexpected InvalidSyntaxException: " + e.getMessage()); //$NON-NLS-1$
+		catch (InvalidSyntaxException e) {
+			/*
+			 * we could only get this exception if the clazz argument was
+			 * malformed
+			 */
+			IllegalArgumentException iae = new IllegalArgumentException(
+					"unexpected InvalidSyntaxException: " + e.getMessage());
+			iae.initCause(e);
+			throw iae;
 		}
 	}
 
 	/**
-	 * Create a <code>ServiceTracker</code> object on the specified
-	 * <code>Filter</code> object.
+	 * Create a <code>ServiceTracker</code> on the specified <code>Filter</code>
+	 * object.
 	 * 
 	 * <p>
 	 * Services which match the specified <code>Filter</code> object will be
-	 * tracked by this <code>ServiceTracker</code> object.
+	 * tracked by this <code>ServiceTracker</code>.
 	 * 
-	 * @param context <code>BundleContext</code> object against which the
-	 *        tracking is done.
-	 * @param filter <code>Filter</code> object to select the services to be
+	 * @param context The <code>BundleContext</code> against which the tracking
+	 *        is done.
+	 * @param filter The <code>Filter</code> to select the services to be
 	 *        tracked.
 	 * @param customizer The customizer object to call when services are added,
-	 *        modified, or removed in this <code>ServiceTracker</code> object.
-	 *        If customizer is null, then this <code>ServiceTracker</code>
-	 *        object will be used as the <code>ServiceTrackerCustomizer</code>
-	 *        object and the <code>ServiceTracker</code> object will call the
+	 *        modified, or removed in this <code>ServiceTracker</code>. If
+	 *        customizer is null, then this <code>ServiceTracker</code> will be
+	 *        used as the <code>ServiceTrackerCustomizer</code> and this
+	 *        <code>ServiceTracker</code> will call the
 	 *        <code>ServiceTrackerCustomizer</code> methods on itself.
 	 * @since 1.1
 	 */
-	public ServiceTracker(BundleContext context, Filter filter,
-			ServiceTrackerCustomizer customizer) {
+	public ServiceTracker(final BundleContext context, final Filter filter,
+			final ServiceTrackerCustomizer customizer) {
 		this.context = context;
 		this.trackReference = null;
 		this.trackClass = null;
-		this.listenerFilter = null;
+		final Version frameworkVersion = (Version) AccessController
+				.doPrivileged(new PrivilegedAction() {
+					public Object run() {
+						String version = context
+								.getProperty(Constants.FRAMEWORK_VERSION);
+						return (version == null) ? Version.emptyVersion
+								: new Version(version);
+					}
+				});
+		final boolean endMatchSupported = (frameworkVersion
+				.compareTo(endMatchVersion) >= 0);
+		this.listenerFilter = endMatchSupported ? filter.toString() : null;
 		this.filter = filter;
 		this.customizer = (customizer == null) ? this : customizer;
-		if ((context == null) || (filter == null)) { // we throw a NPE here
-			// to
-			// be consistent with the
-			// other constructors
+		if ((context == null) || (filter == null)) {
+			/*
+			 * we throw a NPE here to be consistent with the other constructors
+			 */
 			throw new NullPointerException();
 		}
 	}
 
 	/**
-	 * Open this <code>ServiceTracker</code> object and begin tracking
-	 * services.
+	 * Open this <code>ServiceTracker</code> and begin tracking services.
 	 * 
 	 * <p>
-	 * This method calls <code>open(false)</code>.
+	 * This implementation calls <code>open(false)</code>.
 	 * 
-	 * @throws java.lang.IllegalStateException if the <code>BundleContext</code>
-	 *         object with which this <code>ServiceTracker</code> object was
-	 *         created is no longer valid.
+	 * @throws java.lang.IllegalStateException If the <code>BundleContext</code>
+	 *         with which this <code>ServiceTracker</code> was created is no
+	 *         longer valid.
 	 * @see #open(boolean)
 	 */
 	public void open() {
@@ -236,122 +274,140 @@
 	}
 
 	/**
-	 * Open this <code>ServiceTracker</code> object and begin tracking
-	 * services.
+	 * Open this <code>ServiceTracker</code> and begin tracking services.
 	 * 
 	 * <p>
 	 * Services which match the search criteria specified when this
-	 * <code>ServiceTracker</code> object was created are now tracked by this
-	 * <code>ServiceTracker</code> object.
+	 * <code>ServiceTracker</code> was created are now tracked by this
+	 * <code>ServiceTracker</code>.
 	 * 
 	 * @param trackAllServices If <code>true</code>, then this
 	 *        <code>ServiceTracker</code> will track all matching services
 	 *        regardless of class loader accessibility. If <code>false</code>,
 	 *        then this <code>ServiceTracker</code> will only track matching
-	 *        services which are class loader accessibile to the bundle whose
+	 *        services which are class loader accessible to the bundle whose
 	 *        <code>BundleContext</code> is used by this
 	 *        <code>ServiceTracker</code>.
-	 * @throws java.lang.IllegalStateException if the <code>BundleContext</code>
-	 *         object with which this <code>ServiceTracker</code> object was
-	 *         created is no longer valid.
+	 * @throws java.lang.IllegalStateException If the <code>BundleContext</code>
+	 *         with which this <code>ServiceTracker</code> was created is no
+	 *         longer valid.
 	 * @since 1.3
 	 */
-	public synchronized void open(boolean trackAllServices) {
-		if (tracked != null) {
-			return;
-		}
-		if (DEBUG) {
-			System.out.println("ServiceTracker.open: " + filter); //$NON-NLS-1$
-		}
-		tracked = trackAllServices ? new AllTracked() : new Tracked();
-		trackingCount = 0;
-		synchronized (tracked) {
-			try {
-				context.addServiceListener(tracked, listenerFilter);
-				ServiceReference[] references;
-				if (listenerFilter == null) { // user supplied filter
-					references = getInitialReferences(trackAllServices, null,
-							filter.toString());
-				}
-				else { // constructor supplied filter
-					if (trackClass == null) {
-						references = new ServiceReference[] {trackReference};
-					}
-					else {
+	public void open(boolean trackAllServices) {
+		final Tracked t;
+		synchronized (this) {
+			if (tracked != null) {
+				return;
+			}
+			if (DEBUG) {
+				System.out.println("ServiceTracker.open: " + filter); 
+			}
+			t = trackAllServices ? new AllTracked() : new Tracked();
+			synchronized (t) {
+				try {
+					context.addServiceListener(t, listenerFilter);
+					ServiceReference[] references = null;
+					if (trackClass != null) {
 						references = getInitialReferences(trackAllServices,
 								trackClass, null);
 					}
+					else {
+						if (trackReference != null) {
+							if (trackReference.getBundle() != null) {
+								references = new ServiceReference[] {trackReference};
+							}
+						}
+						else { /* user supplied filter */
+							references = getInitialReferences(trackAllServices,
+									null,
+									(listenerFilter != null) ? listenerFilter
+											: filter.toString());
+						}
+					}
+					/* set tracked with the initial references */
+					t.setInitial(references); 
+				}
+				catch (InvalidSyntaxException e) {
+					throw new RuntimeException(
+							"unexpected InvalidSyntaxException: "
+									+ e.getMessage(), e); 
 				}
-
-				tracked.setInitialServices(references); // set tracked with
-				// the initial
-				// references
-			}
-			catch (InvalidSyntaxException e) {
-				throw new RuntimeException(
-						"unexpected InvalidSyntaxException: " + e.getMessage()); //$NON-NLS-1$
 			}
+			tracked = t;
 		}
 		/* Call tracked outside of synchronized region */
-		tracked.trackInitialServices(); // process the initial references
+		t.trackInitial(); /* process the initial references */
 	}
 
 	/**
-	 * Returns the list of initial <code>ServiceReference</code> objects that
-	 * will be tracked by this <code>ServiceTracker</code> object.
+	 * Returns the list of initial <code>ServiceReference</code>s that will be
+	 * tracked by this <code>ServiceTracker</code>.
 	 * 
-	 * @param trackAllServices If true, use getAllServiceReferences.
-	 * @param trackClass the class name with which the service was registered,
-	 *        or null for all services.
-	 * @param filterString the filter criteria or null for all services.
-	 * @return the list of initial <code>ServiceReference</code> objects.
-	 * @throws InvalidSyntaxException if the filter uses an invalid syntax.
+	 * @param trackAllServices If <code>true</code>, use
+	 *        <code>getAllServiceReferences</code>.
+	 * @param className The class name with which the service was registered, or
+	 *        <code>null</code> for all services.
+	 * @param filterString The filter criteria or <code>null</code> for all
+	 *        services.
+	 * @return The list of initial <code>ServiceReference</code>s.
+	 * @throws InvalidSyntaxException If the specified filterString has an
+	 *         invalid syntax.
 	 */
 	private ServiceReference[] getInitialReferences(boolean trackAllServices,
-			String trackClass, String filterString)
+			String className, String filterString)
 			throws InvalidSyntaxException {
 		if (trackAllServices) {
-			return context.getAllServiceReferences(trackClass, filterString);
-		}
-		else {
-			return context.getServiceReferences(trackClass, filterString);
+			return context.getAllServiceReferences(className, filterString);
 		}
+		return context.getServiceReferences(className, filterString);
 	}
 
 	/**
-	 * Close this <code>ServiceTracker</code> object.
+	 * Close this <code>ServiceTracker</code>.
+	 * 
+	 * <p>
+	 * This method should be called when this <code>ServiceTracker</code> should
+	 * end the tracking of services.
 	 * 
 	 * <p>
-	 * This method should be called when this <code>ServiceTracker</code>
-	 * object should end the tracking of services.
+	 * This implementation calls {@link #getServiceReferences()} to get the list
+	 * of tracked services to remove.
 	 */
-	public synchronized void close() {
-		if (tracked == null) {
-			return;
-		}
-		if (DEBUG) {
-			System.out.println("ServiceTracker.close: " + filter); //$NON-NLS-1$
-		}
-		tracked.close();
-		ServiceReference[] references = getServiceReferences();
-		Tracked outgoing = tracked;
-		tracked = null;
-		try {
-			context.removeServiceListener(outgoing);
+	public void close() {
+		final Tracked outgoing;
+		final ServiceReference[] references;
+		synchronized (this) {
+			outgoing = tracked;
+			if (outgoing == null) {
+				return;
+			}
+			if (DEBUG) {
+				System.out.println("ServiceTracker.close: " + filter); 
+			}
+			outgoing.close();
+			references = getServiceReferences();
+			tracked = null;
+			try {
+				context.removeServiceListener(outgoing);
+			}
+			catch (IllegalStateException e) {
+				/* In case the context was stopped. */
+			}
 		}
-		catch (IllegalStateException e) {
-			/* In case the context was stopped. */
+		modified(); /* clear the cache */
+		synchronized (outgoing) {
+			outgoing.notifyAll(); /* wake up any waiters */
 		}
 		if (references != null) {
 			for (int i = 0; i < references.length; i++) {
-				outgoing.untrack(references[i]);
+				outgoing.untrack(references[i], null);
 			}
 		}
-		trackingCount = -1;
 		if (DEBUG) {
 			if ((cachedReference == null) && (cachedService == null)) {
 				System.out
-						.println("ServiceTracker.close[cached cleared]: " + filter); //$NON-NLS-1$
+						.println("ServiceTracker.close[cached cleared]: "
+						+ filter); 
 			}
 		}
 	}
@@ -361,25 +417,26 @@
 	 * <code>ServiceTrackerCustomizer.addingService</code> method.
 	 * 
 	 * <p>
-	 * This method is only called when this <code>ServiceTracker</code> object
-	 * has been constructed with a <code>null ServiceTrackerCustomizer</code>
-	 * argument.
-	 * 
-	 * The default implementation returns the result of calling
-	 * <code>getService</code>, on the <code>BundleContext</code> object
-	 * with which this <code>ServiceTracker</code> object was created, passing
-	 * the specified <code>ServiceReference</code> object.
+	 * This method is only called when this <code>ServiceTracker</code> has been
+	 * constructed with a <code>null ServiceTrackerCustomizer</code> argument.
+	 * 
+	 * <p>
+	 * This implementation returns the result of calling <code>getService</code>
+	 * on the <code>BundleContext</code> with which this
+	 * <code>ServiceTracker</code> was created passing the specified
+	 * <code>ServiceReference</code>.
 	 * <p>
 	 * This method can be overridden in a subclass to customize the service
 	 * object to be tracked for the service being added. In that case, take care
-	 * not to rely on the default implementation of removedService that will
-	 * unget the service.
+	 * not to rely on the default implementation of
+	 * {@link #removedService(ServiceReference, Object) removedService} to unget
+	 * the service.
 	 * 
-	 * @param reference Reference to service being added to this
-	 *        <code>ServiceTracker</code> object.
+	 * @param reference The reference to the service being added to this
+	 *        <code>ServiceTracker</code>.
 	 * @return The service object to be tracked for the service added to this
-	 *         <code>ServiceTracker</code> object.
-	 * @see ServiceTrackerCustomizer
+	 *         <code>ServiceTracker</code>.
+	 * @see ServiceTrackerCustomizer#addingService(ServiceReference)
 	 */
 	public Object addingService(ServiceReference reference) {
 		return context.getService(reference);
@@ -390,17 +447,18 @@
 	 * <code>ServiceTrackerCustomizer.modifiedService</code> method.
 	 * 
 	 * <p>
-	 * This method is only called when this <code>ServiceTracker</code> object
-	 * has been constructed with a <code>null ServiceTrackerCustomizer</code>
-	 * argument.
+	 * This method is only called when this <code>ServiceTracker</code> has been
+	 * constructed with a <code>null ServiceTrackerCustomizer</code> argument.
 	 * 
-	 * The default implementation does nothing.
+	 * <p>
+	 * This implementation does nothing.
 	 * 
-	 * @param reference Reference to modified service.
+	 * @param reference The reference to modified service.
 	 * @param service The service object for the modified service.
-	 * @see ServiceTrackerCustomizer
+	 * @see ServiceTrackerCustomizer#modifiedService(ServiceReference, Object)
 	 */
 	public void modifiedService(ServiceReference reference, Object service) {
+		/* do nothing */
 	}
 
 	/**
@@ -408,22 +466,21 @@
 	 * <code>ServiceTrackerCustomizer.removedService</code> method.
 	 * 
 	 * <p>
-	 * This method is only called when this <code>ServiceTracker</code> object
-	 * has been constructed with a <code>null ServiceTrackerCustomizer</code>
-	 * argument.
-	 * 
-	 * The default implementation calls <code>ungetService</code>, on the
-	 * <code>BundleContext</code> object with which this
-	 * <code>ServiceTracker</code> object was created, passing the specified
-	 * <code>ServiceReference</code> object.
+	 * This method is only called when this <code>ServiceTracker</code> has been
+	 * constructed with a <code>null ServiceTrackerCustomizer</code> argument.
+	 * 
+	 * <p>
+	 * This implementation calls <code>ungetService</code>, on the
+	 * <code>BundleContext</code> with which this <code>ServiceTracker</code>
+	 * was created, passing the specified <code>ServiceReference</code>.
 	 * <p>
 	 * This method can be overridden in a subclass. If the default
-	 * implementation of <code>addingService</code> method was used, this
-	 * method must unget the service.
+	 * implementation of {@link #addingService(ServiceReference) addingService}
+	 * method was used, this method must unget the service.
 	 * 
-	 * @param reference Reference to removed service.
+	 * @param reference The reference to removed service.
 	 * @param service The service object for the removed service.
-	 * @see ServiceTrackerCustomizer
+	 * @see ServiceTrackerCustomizer#removedService(ServiceReference, Object)
 	 */
 	public void removedService(ServiceReference reference, Object service) {
 		context.ungetService(reference);
@@ -431,39 +488,42 @@
 
 	/**
 	 * Wait for at least one service to be tracked by this
-	 * <code>ServiceTracker</code> object.
+	 * <code>ServiceTracker</code>. This method will also return when this
+	 * <code>ServiceTracker</code> is closed.
+	 * 
 	 * <p>
 	 * It is strongly recommended that <code>waitForService</code> is not used
 	 * during the calling of the <code>BundleActivator</code> methods.
-	 * <code>BundleActivator</code> methods are expected to complete in a
-	 * short period of time.
+	 * <code>BundleActivator</code> methods are expected to complete in a short
+	 * period of time.
 	 * 
-	 * @param timeout time interval in milliseconds to wait. If zero, the method
-	 *        will wait indefinately.
-	 * @return Returns the result of <code>getService()</code>.
+	 * <p>
+	 * This implementation calls {@link #getService()} to determine if a service
+	 * is being tracked.
+	 * 
+	 * @param timeout The time interval in milliseconds to wait. If zero, the
+	 *        method will wait indefinitely.
+	 * @return Returns the result of {@link #getService()}.
 	 * @throws InterruptedException If another thread has interrupted the
 	 *         current thread.
 	 * @throws IllegalArgumentException If the value of timeout is negative.
 	 */
 	public Object waitForService(long timeout) throws InterruptedException {
 		if (timeout < 0) {
-			throw new IllegalArgumentException("timeout value is negative"); //$NON-NLS-1$
+			throw new IllegalArgumentException("timeout value is negative"); 
 		}
-		Object object = getService();
+		Object object = getService(); 
 		while (object == null) {
-			Tracked tracked = this.tracked; /*
-											 * use local var since we are not
-											 * synchronized
-											 */
-			if (tracked == null) { /* if ServiceTracker is not open */
+			final Tracked t = tracked();
+			if (t == null) { /* if ServiceTracker is not open */
 				return null;
 			}
-			synchronized (tracked) {
-				if (tracked.size() == 0) {
-					tracked.wait(timeout);
+			synchronized (t) {
+				if (t.size() == 0) {
+					t.wait(timeout);
 				}
 			}
-			object = getService();
+			object = getService(); 
 			if (timeout > 0) {
 				return object;
 			}
@@ -472,53 +532,45 @@
 	}
 
 	/**
-	 * Return an array of <code>ServiceReference</code> objects for all
-	 * services being tracked by this <code>ServiceTracker</code> object.
+	 * Return an array of <code>ServiceReference</code>s for all services being
+	 * tracked by this <code>ServiceTracker</code>.
 	 * 
-	 * @return Array of <code>ServiceReference</code> objects or
-	 *         <code>null</code> if no service are being tracked.
+	 * @return Array of <code>ServiceReference</code>s or <code>null</code> if
+	 *         no services are being tracked.
 	 */
 	public ServiceReference[] getServiceReferences() {
-		Tracked tracked = this.tracked; /*
-										 * use local var since we are not
-										 * synchronized
-										 */
-		if (tracked == null) { /* if ServiceTracker is not open */
+		final Tracked t = tracked();
+		if (t == null) { /* if ServiceTracker is not open */
 			return null;
 		}
-		synchronized (tracked) {
-			int length = tracked.size();
+		synchronized (t) {
+			int length = t.size();
 			if (length == 0) {
 				return null;
 			}
-			ServiceReference[] references = new ServiceReference[length];
-			Enumeration keys = tracked.keys();
-			for (int i = 0; i < length; i++) {
-				references[i] = (ServiceReference) keys.nextElement();
-			}
-			return references;
+			return (ServiceReference[]) t
+					.getTracked(new ServiceReference[length]);
 		}
 	}
 
 	/**
-	 * Returns a <code>ServiceReference</code> object for one of the services
-	 * being tracked by this <code>ServiceTracker</code> object.
+	 * Returns a <code>ServiceReference</code> for one of the services being
+	 * tracked by this <code>ServiceTracker</code>.
 	 * 
 	 * <p>
 	 * If multiple services are being tracked, the service with the highest
 	 * ranking (as specified in its <code>service.ranking</code> property) is
-	 * returned.
+	 * returned. If there is a tie in ranking, the service with the lowest
+	 * service ID (as specified in its <code>service.id</code> property); that
+	 * is, the service that was registered first is returned. This is the same
+	 * algorithm used by <code>BundleContext.getServiceReference</code>.
 	 * 
 	 * <p>
-	 * If there is a tie in ranking, the service with the lowest service ID (as
-	 * specified in its <code>service.id</code> property); that is, the
-	 * service that was registered first is returned.
-	 * <p>
-	 * This is the same algorithm used by
-	 * <code>BundleContext.getServiceReference</code>.
+	 * This implementation calls {@link #getServiceReferences()} to get the list
+	 * of references for the tracked services.
 	 * 
-	 * @return <code>ServiceReference</code> object or <code>null</code> if
-	 *         no service is being tracked.
+	 * @return A <code>ServiceReference</code> or <code>null</code> if no
+	 *         services are being tracked.
 	 * @since 1.1
 	 */
 	public ServiceReference getServiceReference() {
@@ -526,22 +578,21 @@
 		if (reference != null) {
 			if (DEBUG) {
 				System.out
-						.println("ServiceTracker.getServiceReference[cached]: " + filter); //$NON-NLS-1$
+						.println("ServiceTracker.getServiceReference[cached]: "
+								+ filter); 
 			}
 			return reference;
 		}
 		if (DEBUG) {
-			System.out.println("ServiceTracker.getServiceReference: " + filter); //$NON-NLS-1$
+			System.out.println("ServiceTracker.getServiceReference: " + filter); 
 		}
-		ServiceReference[] references = getServiceReferences();
+		ServiceReference[] references = getServiceReferences(); 
 		int length = (references == null) ? 0 : references.length;
-		if (length == 0) /* if no service is being tracked */
-		{
+		if (length == 0) { /* if no service is being tracked */
 			return null;
 		}
 		int index = 0;
-		if (length > 1) /* if more than one service, select highest ranking */
-		{
+		if (length > 1) { /* if more than one service, select highest ranking */
 			int rankings[] = new int[length];
 			int count = 0;
 			int maxRanking = Integer.MIN_VALUE;
@@ -563,8 +614,7 @@
 					}
 				}
 			}
-			if (count > 1) /* if still more than one service, select lowest id */
-			{
+			if (count > 1) { /* if still more than one service, select lowest id */
 				long minId = Long.MAX_VALUE;
 				for (int i = 0; i < length; i++) {
 					if (rankings[i] == maxRanking) {
@@ -584,51 +634,51 @@
 
 	/**
 	 * Returns the service object for the specified
-	 * <code>ServiceReference</code> object if the referenced service is being
-	 * tracked by this <code>ServiceTracker</code> object.
+	 * <code>ServiceReference</code> if the specified referenced service is
+	 * being tracked by this <code>ServiceTracker</code>.
 	 * 
-	 * @param reference Reference to the desired service.
-	 * @return Service object or <code>null</code> if the service referenced
-	 *         by the specified <code>ServiceReference</code> object is not
-	 *         being tracked.
+	 * @param reference The reference to the desired service.
+	 * @return A service object or <code>null</code> if the service referenced
+	 *         by the specified <code>ServiceReference</code> is not being
+	 *         tracked.
 	 */
 	public Object getService(ServiceReference reference) {
-		Tracked tracked = this.tracked; /*
-										 * use local var since we are not
-										 * synchronized
-										 */
-		if (tracked == null) { /* if ServiceTracker is not open */
+		final Tracked t = tracked();
+		if (t == null) { /* if ServiceTracker is not open */
 			return null;
 		}
-		synchronized (tracked) {
-			return tracked.get(reference);
+		synchronized (t) {
+			return t.getCustomizedObject(reference);
 		}
 	}
 
 	/**
 	 * Return an array of service objects for all services being tracked by this
-	 * <code>ServiceTracker</code> object.
+	 * <code>ServiceTracker</code>.
+	 * 
+	 * <p>
+	 * This implementation calls {@link #getServiceReferences()} to get the list
+	 * of references for the tracked services and then calls
+	 * {@link #getService(ServiceReference)} for each reference to get the
+	 * tracked service object.
 	 * 
-	 * @return Array of service objects or <code>null</code> if no service are
-	 *         being tracked.
+	 * @return An array of service objects or <code>null</code> if no services
+	 *         are being tracked.
 	 */
 	public Object[] getServices() {
-		Tracked tracked = this.tracked; /*
-										 * use local var since we are not
-										 * synchronized
-										 */
-		if (tracked == null) { /* if ServiceTracker is not open */
+		final Tracked t = tracked();
+		if (t == null) { /* if ServiceTracker is not open */
 			return null;
 		}
-		synchronized (tracked) {
-			ServiceReference[] references = getServiceReferences();
+		synchronized (t) {
+			ServiceReference[] references = getServiceReferences(); 
 			int length = (references == null) ? 0 : references.length;
 			if (length == 0) {
 				return null;
 			}
 			Object[] objects = new Object[length];
 			for (int i = 0; i < length; i++) {
-				objects[i] = getService(references[i]);
+				objects[i] = getService(references[i]); 
 			}
 			return objects;
 		}
@@ -636,13 +686,13 @@
 
 	/**
 	 * Returns a service object for one of the services being tracked by this
-	 * <code>ServiceTracker</code> object.
+	 * <code>ServiceTracker</code>.
 	 * 
 	 * <p>
-	 * If any services are being tracked, this method returns the result of
-	 * calling <code>getService(getServiceReference())</code>.
+	 * If any services are being tracked, this implementation returns the result
+	 * of calling <code>getService(getServiceReference())</code>.
 	 * 
-	 * @return Service object or <code>null</code> if no service is being
+	 * @return A service object or <code>null</code> if no services are being
 	 *         tracked.
 	 */
 	public Object getService() {
@@ -650,258 +700,114 @@
 		if (service != null) {
 			if (DEBUG) {
 				System.out
-						.println("ServiceTracker.getService[cached]: " + filter); //$NON-NLS-1$
+						.println("ServiceTracker.getService[cached]: "
+						+ filter); 
 			}
 			return service;
 		}
 		if (DEBUG) {
-			System.out.println("ServiceTracker.getService: " + filter); //$NON-NLS-1$
+			System.out.println("ServiceTracker.getService: " + filter); 
 		}
-		ServiceReference reference = getServiceReference();
+		ServiceReference reference = getServiceReference(); 
 		if (reference == null) {
 			return null;
 		}
-		return cachedService = getService(reference);
+		return cachedService = getService(reference); 
 	}
 
 	/**
-	 * Remove a service from this <code>ServiceTracker</code> object.
+	 * Remove a service from this <code>ServiceTracker</code>.
 	 * 
 	 * The specified service will be removed from this
-	 * <code>ServiceTracker</code> object. If the specified service was being
-	 * tracked then the <code>ServiceTrackerCustomizer.removedService</code>
-	 * method will be called for that service.
+	 * <code>ServiceTracker</code>. If the specified service was being tracked
+	 * then the <code>ServiceTrackerCustomizer.removedService</code> method will
+	 * be called for that service.
 	 * 
-	 * @param reference Reference to the service to be removed.
+	 * @param reference The reference to the service to be removed.
 	 */
 	public void remove(ServiceReference reference) {
-		Tracked tracked = this.tracked; /*
-										 * use local var since we are not
-										 * synchronized
-										 */
-		if (tracked == null) { /* if ServiceTracker is not open */
+		final Tracked t = tracked();
+		if (t == null) { /* if ServiceTracker is not open */
 			return;
 		}
-		tracked.untrack(reference);
+		t.untrack(reference, null);
 	}
 
 	/**
 	 * Return the number of services being tracked by this
-	 * <code>ServiceTracker</code> object.
+	 * <code>ServiceTracker</code>.
 	 * 
-	 * @return Number of services being tracked.
+	 * @return The number of services being tracked.
 	 */
 	public int size() {
-		Tracked tracked = this.tracked; /*
-										 * use local var since we are not
-										 * synchronized
-										 */
-		if (tracked == null) { /* if ServiceTracker is not open */
+		final Tracked t = tracked();
+		if (t == null) { /* if ServiceTracker is not open */
 			return 0;
 		}
-		return tracked.size();
+		synchronized (t) {
+			return t.size();
+		}
 	}
 
 	/**
-	 * Returns the tracking count for this <code>ServiceTracker</code> object.
+	 * Returns the tracking count for this <code>ServiceTracker</code>.
 	 * 
 	 * The tracking count is initialized to 0 when this
-	 * <code>ServiceTracker</code> object is opened. Every time a service is
-	 * added, modified or removed from this <code>ServiceTracker</code> object
-	 * the tracking count is incremented.
+	 * <code>ServiceTracker</code> is opened. Every time a service is added,
+	 * modified or removed from this <code>ServiceTracker</code>, the tracking
+	 * count is incremented.
 	 * 
 	 * <p>
 	 * The tracking count can be used to determine if this
-	 * <code>ServiceTracker</code> object has added, modified or removed a
-	 * service by comparing a tracking count value previously collected with the
-	 * current tracking count value. If the value has not changed, then no
-	 * service has been added, modified or removed from this
-	 * <code>ServiceTracker</code> object since the previous tracking count
-	 * was collected.
+	 * <code>ServiceTracker</code> has added, modified or removed a service by
+	 * comparing a tracking count value previously collected with the current
+	 * tracking count value. If the value has not changed, then no service has
+	 * been added, modified or removed from this <code>ServiceTracker</code>
+	 * since the previous tracking count was collected.
 	 * 
 	 * @since 1.2
-	 * @return The tracking count for this <code>ServiceTracker</code> object
-	 *         or -1 if this <code>ServiceTracker</code> object is not open.
+	 * @return The tracking count for this <code>ServiceTracker</code> or -1 if
+	 *         this <code>ServiceTracker</code> is not open.
 	 */
 	public int getTrackingCount() {
-		return trackingCount;
+		final Tracked t = tracked();
+		if (t == null) { /* if ServiceTracker is not open */
+			return -1;
+		}
+		synchronized (t) {
+			return t.getTrackingCount();
+		}
 	}
 
 	/**
 	 * Called by the Tracked object whenever the set of tracked services is
-	 * modified. Increments the tracking count and clears the cache.
-	 * 
-	 * @GuardedBy tracked
+	 * modified. Clears the cache.
 	 */
 	/*
 	 * This method must not be synchronized since it is called by Tracked while
 	 * Tracked is synchronized. We don't want synchronization interactions
-	 * between the ServiceListener thread and the user thread.
+	 * between the listener thread and the user thread.
 	 */
 	void modified() {
-		trackingCount++; /* increment modification count */
 		cachedReference = null; /* clear cached value */
 		cachedService = null; /* clear cached value */
 		if (DEBUG) {
-			System.out.println("ServiceTracker.modified: " + filter); //$NON-NLS-1$
+			System.out.println("ServiceTracker.modified: " + filter); 
 		}
 	}
 
 	/**
-	 * Inner class to track services. If a <code>ServiceTracker</code> object
-	 * is reused (closed then reopened), then a new Tracked object is used. This
-	 * class is a hashtable mapping <code>ServiceReference</code> object ->
-	 * customized Object. This class is the <code>ServiceListener</code>
-	 * object for the tracker. This class is used to synchronize access to the
-	 * tracked services. This is not a public class. It is only for use by the
-	 * implementation of the <code>ServiceTracker</code> class.
+	 * Inner class which subclasses AbstractTracked. This class is the
+	 * <code>ServiceListener</code> object for the tracker.
 	 * 
 	 * @ThreadSafe
 	 */
-	class Tracked extends Hashtable implements ServiceListener {
-		static final long			serialVersionUID	= -7420065199791006079L;
-		/**
-		 * List of ServiceReferences in the process of being added. This is used
-		 * to deal with nesting of ServiceEvents. Since ServiceEvents are
-		 * synchronously delivered, ServiceEvents 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 ArrayList		adding;
-
-		/**
-		 * true if the tracked object is closed.
-		 * 
-		 * This field is volatile because it is set by one thread and read by
-		 * another.
-		 */
-		private volatile boolean	closed;
-
-		/**
-		 * Initial list of ServiceReferences for the tracker. This is used to
-		 * correctly process the initial services which could become
-		 * unregistered before they are tracked. This is necessary since the
-		 * initial set of tracked services are not "announced" by ServiceEvents
-		 * and therefore the ServiceEvent for unregistration could be delivered
-		 * before we track the service.
-		 * 
-		 * A service must not be in both the initial and adding lists at the
-		 * same time. A service 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;
-
+	class Tracked extends AbstractTracked implements ServiceListener {
 		/**
 		 * Tracked constructor.
 		 */
-		protected Tracked() {
+		Tracked() {
 			super();
-			closed = false;
-			adding = new ArrayList(6);
-			initial = new LinkedList();
-		}
-
-		/**
-		 * Set initial list of services into tracker before ServiceEvents begin
-		 * to be received.
-		 * 
-		 * This method must be called from ServiceTracker.open while
-		 * synchronized on this object in the same synchronized block as the
-		 * addServiceListener call.
-		 * 
-		 * @param references The initial list of services to be tracked.
-		 * @GuardedBy this
-		 */
-		protected void setInitialServices(ServiceReference[] references) {
-			if (references == null) {
-				return;
-			}
-			int size = references.length;
-			for (int i = 0; i < size; i++) {
-				if (DEBUG) {
-					System.out
-							.println("ServiceTracker.Tracked.setInitialServices: " + references[i]); //$NON-NLS-1$
-				}
-				initial.add(references[i]);
-			}
-		}
-
-		/**
-		 * Track the initial list of services. This is called after
-		 * ServiceEvents can begin to be received.
-		 * 
-		 * This method must be called from ServiceTracker.open while not
-		 * synchronized on this object after the addServiceListener call.
-		 * 
-		 */
-		protected void trackInitialServices() {
-			while (true) {
-				ServiceReference reference;
-				synchronized (this) {
-					if (initial.size() == 0) {
-						/*
-						 * if there are no more inital services
-						 */
-						return; /* we are done */
-					}
-					/*
-					 * move the first service from the initial list to the
-					 * adding list within this synchronized block.
-					 */
-					reference = (ServiceReference) initial.removeFirst();
-					if (this.get(reference) != null) {
-						/* if we are already tracking this service */
-						if (DEBUG) {
-							System.out
-									.println("ServiceTracker.Tracked.trackInitialServices[already tracked]: " + reference); //$NON-NLS-1$
-						}
-						continue; /* skip this service */
-					}
-					if (adding.contains(reference)) {
-						/*
-						 * if this service is already in the process of being
-						 * added.
-						 */
-						if (DEBUG) {
-							System.out
-									.println("ServiceTracker.Tracked.trackInitialServices[already adding]: " + reference); //$NON-NLS-1$
-						}
-						continue; /* skip this service */
-					}
-					adding.add(reference);
-				}
-				if (DEBUG) {
-					System.out
-							.println("ServiceTracker.Tracked.trackInitialServices: " + reference); //$NON-NLS-1$
-				}
-				trackAdding(reference); /*
-										 * Begin tracking it. We call
-										 * trackAdding since we have already put
-										 * the reference in the adding list.
-										 */
-			}
-		}
-
-		/**
-		 * Called by the owning <code>ServiceTracker</code> object when it is
-		 * closed.
-		 */
-		protected void close() {
-			closed = true;
 		}
 
 		/**
@@ -911,7 +817,7 @@
 		 * 
 		 * @param event <code>ServiceEvent</code> object from the framework.
 		 */
-		public void serviceChanged(ServiceEvent event) {
+		public void serviceChanged(final ServiceEvent event) {
 			/*
 			 * Check if we had a delayed call (which could happen when we
 			 * close).
@@ -919,33 +825,34 @@
 			if (closed) {
 				return;
 			}
-			ServiceReference reference = event.getServiceReference();
+			final ServiceReference reference = event.getServiceReference();
 			if (DEBUG) {
 				System.out
-						.println("ServiceTracker.Tracked.serviceChanged[" + event.getType() + "]: " + reference); //$NON-NLS-1$ //$NON-NLS-2$
+						.println("ServiceTracker.Tracked.serviceChanged["
+						+ event.getType() + "]: " + reference);  
 			}
 
 			switch (event.getType()) {
 				case ServiceEvent.REGISTERED :
 				case ServiceEvent.MODIFIED :
-					if (listenerFilter != null) { // constructor supplied
+					if (listenerFilter != null) { // service listener added with
 						// filter
-						track(reference);
+						track(reference, event);
 						/*
 						 * If the customizer throws an unchecked exception, it
 						 * is safe to let it propagate
 						 */
 					}
-					else { // user supplied filter
+					else { // service listener added without filter
 						if (filter.match(reference)) {
-							track(reference);
+							track(reference, event);
 							/*
 							 * If the customizer throws an unchecked exception,
 							 * it is safe to let it propagate
 							 */
 						}
 						else {
-							untrack(reference);
+							untrack(reference, event);
 							/*
 							 * If the customizer throws an unchecked exception,
 							 * it is safe to let it propagate
@@ -953,8 +860,9 @@
 						}
 					}
 					break;
+				case ServiceEvent.MODIFIED_ENDMATCH :
 				case ServiceEvent.UNREGISTERING :
-					untrack(reference);
+					untrack(reference, event);
 					/*
 					 * If the customizer throws an unchecked exception, it is
 					 * safe to let it propagate
@@ -964,170 +872,54 @@
 		}
 
 		/**
-		 * Begin to track the referenced service.
+		 * Increment the tracking count and tell the tracker there was a
+		 * modification.
 		 * 
-		 * @param reference Reference to a service to be tracked.
+		 * @GuardedBy this
 		 */
-		private void track(ServiceReference reference) {
-			Object object;
-			synchronized (this) {
-				object = this.get(reference);
-			}
-			if (object != null) /* we are already tracking the service */
-			{
-				if (DEBUG) {
-					System.out
-							.println("ServiceTracker.Tracked.track[modified]: " + reference); //$NON-NLS-1$
-				}
-				synchronized (this) {
-					modified(); /* increment modification count */
-				}
-				/* Call customizer outside of synchronized region */
-				customizer.modifiedService(reference, object);
-				/*
-				 * If the customizer throws an unchecked exception, it is safe
-				 * to let it propagate
-				 */
-				return;
-			}
-			synchronized (this) {
-				if (adding.contains(reference)) { /*
-													 * if this service is
-													 * already in the process of
-													 * being added.
-													 */
-					if (DEBUG) {
-						System.out
-								.println("ServiceTracker.Tracked.track[already adding]: " + reference); //$NON-NLS-1$
-					}
-					return;
-				}
-				adding.add(reference); /* mark this service is being added */
-			}
-
-			trackAdding(reference); /*
-									 * call trackAdding now that we have put the
-									 * reference in the adding list
-									 */
+		void modified() {
+			super.modified(); /* increment the modification count */
+			ServiceTracker.this.modified();
 		}
 
 		/**
-		 * Common logic to add a service to the tracker used by track and
-		 * trackInitialServices. The specified reference must have been placed
-		 * in the adding list before calling this method.
+		 * Call the specific customizer adding method. This method must not be
+		 * called while synchronized on this object.
 		 * 
-		 * @param reference Reference to a service to be tracked.
+		 * @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.
 		 */
-		private void trackAdding(ServiceReference reference) {
-			if (DEBUG) {
-				System.out
-						.println("ServiceTracker.Tracked.trackAdding: " + reference); //$NON-NLS-1$
-			}
-			Object object = null;
-			boolean becameUntracked = false;
-			/* Call customizer outside of synchronized region */
-			try {
-				object = customizer.addingService(reference);
-				/*
-				 * If the customizer throws an unchecked exception, it will
-				 * propagate after the finally
-				 */
-			}
-			finally {
-				synchronized (this) {
-					if (adding.remove(reference)) { /*
-													 * if the service was not
-													 * untracked during the
-													 * customizer callback
-													 */
-						if (object != null) {
-							this.put(reference, object);
-							modified(); /* increment modification count */
-							notifyAll(); /*
-											 * notify any waiters in
-											 * waitForService
-											 */
-						}
-					}
-					else {
-						becameUntracked = true;
-					}
-				}
-			}
-			/*
-			 * The service became untracked during the customizer callback.
-			 */
-			if (becameUntracked) {
-				if (DEBUG) {
-					System.out
-							.println("ServiceTracker.Tracked.trackAdding[removed]: " + reference); //$NON-NLS-1$
-				}
-				/* Call customizer outside of synchronized region */
-				customizer.removedService(reference, object);
-				/*
-				 * If the customizer throws an unchecked exception, it is safe
-				 * to let it propagate
-				 */
-			}
+		Object customizerAdding(final Object item,
+				final Object related) {
+			return customizer.addingService((ServiceReference) item);
 		}
 
 		/**
-		 * Discontinue tracking the referenced service.
+		 * Call the specific customizer modified method. This method must not be
+		 * called while synchronized on this object.
 		 * 
-		 * @param reference Reference to the tracked service.
+		 * @param item Tracked item.
+		 * @param related Action related object.
+		 * @param object Customized object for the tracked item.
 		 */
-		protected void untrack(ServiceReference reference) {
-			Object object;
-			synchronized (this) {
-				if (initial.remove(reference)) { /*
-													 * if this service is
-													 * already in the list of
-													 * initial references to
-													 * process
-													 */
-					if (DEBUG) {
-						System.out
-								.println("ServiceTracker.Tracked.untrack[removed from initial]: " + reference); //$NON-NLS-1$
-					}
-					return; /*
-							 * we have removed it from the list and it will not
-							 * be processed
-							 */
-				}
+		void customizerModified(final Object item,
+				final Object related, final Object object) {
+			customizer.modifiedService((ServiceReference) item, object);
+		}
 
-				if (adding.remove(reference)) { /*
-												 * if the service is in the
-												 * process of being added
-												 */
-					if (DEBUG) {
-						System.out
-								.println("ServiceTracker.Tracked.untrack[being added]: " + reference); //$NON-NLS-1$
-					}
-					return; /*
-							 * in case the service is untracked while in the
-							 * process of adding
-							 */
-				}
-				object = this.remove(reference); /*
-													 * must remove from tracker
-													 * before calling customizer
-													 * callback
-													 */
-				if (object == null) { /* are we actually tracking the service */
-					return;
-				}
-				modified(); /* increment modification count */
-			}
-			if (DEBUG) {
-				System.out
-						.println("ServiceTracker.Tracked.untrack[removed]: " + reference); //$NON-NLS-1$
-			}
-			/* Call customizer outside of synchronized region */
-			customizer.removedService(reference, object);
-			/*
-			 * If the customizer throws an unchecked exception, it is safe to
-			 * let it propagate
-			 */
+		/**
+		 * 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.removedService((ServiceReference) item, object);
 		}
 	}
 
@@ -1139,12 +931,10 @@
 	 * @ThreadSafe
 	 */
 	class AllTracked extends Tracked implements AllServiceListener {
-		static final long	serialVersionUID	= 4050764875305137716L;
-
 		/**
 		 * AllTracked constructor.
 		 */
-		protected AllTracked() {
+		AllTracked() {
 			super();
 		}
 	}

Modified: felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTrackerCustomizer.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTrackerCustomizer.java?rev=797561&r1=797560&r2=797561&view=diff
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTrackerCustomizer.java (original)
+++ felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/ServiceTrackerCustomizer.java Fri Jul 24 17:06:37 2009
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.util.tracker/src/org/osgi/util/tracker/ServiceTrackerCustomizer.java,v 1.13 2007/02/19 19:04:33 hargrave Exp $
- * 
- * Copyright (c) OSGi Alliance (2000, 2007). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 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.
@@ -22,76 +20,75 @@
 
 /**
  * The <code>ServiceTrackerCustomizer</code> interface allows a
- * <code>ServiceTracker</code> object to customize the service objects that
- * are tracked. The <code>ServiceTrackerCustomizer</code> object is called
- * when a service is being added to the <code>ServiceTracker</code> object.
- * The <code>ServiceTrackerCustomizer</code> can then return an object for the
- * tracked service. The <code>ServiceTrackerCustomizer</code> object is also
- * called when a tracked service is modified or has been removed from the
- * <code>ServiceTracker</code> object.
+ * <code>ServiceTracker</code> to customize the service objects that are
+ * tracked. A <code>ServiceTrackerCustomizer</code> is called when a service is
+ * being added to a <code>ServiceTracker</code>. The
+ * <code>ServiceTrackerCustomizer</code> can then return an object for the
+ * tracked service. A <code>ServiceTrackerCustomizer</code> is also called when
+ * a tracked service is modified or has been removed from a
+ * <code>ServiceTracker</code>.
  * 
  * <p>
  * The methods in this interface may be called as the result of a
- * <code>ServiceEvent</code> being received by a <code>ServiceTracker</code>
- * object. Since <code>ServiceEvent</code> s are synchronously delivered by
- * the Framework, it is highly recommended that implementations of these methods
- * do not register (<code>BundleContext.registerService</code>), modify (
+ * <code>ServiceEvent</code> being received by a <code>ServiceTracker</code>.
+ * Since <code>ServiceEvent</code>s are synchronously delivered by the
+ * Framework, it is highly recommended that implementations of these methods do
+ * not register (<code>BundleContext.registerService</code>), modify (
  * <code>ServiceRegistration.setProperties</code>) or unregister (
  * <code>ServiceRegistration.unregister</code>) a service while being
  * synchronized on any object.
  * 
  * <p>
  * The <code>ServiceTracker</code> class is thread-safe. It does not call a
- * <code>ServiceTrackerCustomizer</code> object while holding any locks.
+ * <code>ServiceTrackerCustomizer</code> while holding any locks.
  * <code>ServiceTrackerCustomizer</code> implementations must also be
  * thread-safe.
  * 
  * @ThreadSafe
- * @version $Revision: 1.13 $
+ * @version $Revision: 5874 $
  */
 public interface ServiceTrackerCustomizer {
 	/**
-	 * A service is being added to the <code>ServiceTracker</code> object.
+	 * A service is being added to the <code>ServiceTracker</code>.
 	 * 
 	 * <p>
 	 * This method is called before a service which matched the search
-	 * parameters of the <code>ServiceTracker</code> object is added to it.
-	 * This method should return the service object to be tracked for this
-	 * <code>ServiceReference</code> object. The returned service object is
-	 * stored in the <code>ServiceTracker</code> object and is available from
-	 * the <code>getService</code> and <code>getServices</code> methods.
-	 * 
-	 * @param reference Reference to service being added to the
-	 *        <code>ServiceTracker</code> object.
-	 * @return The service object to be tracked for the
-	 *         <code>ServiceReference</code> object or <code>null</code> if
-	 *         the <code>ServiceReference</code> object should not be tracked.
+	 * parameters of the <code>ServiceTracker</code> is added to the
+	 * <code>ServiceTracker</code>. This method should return the service object
+	 * to be tracked for the specified <code>ServiceReference</code>. The
+	 * returned service object is stored in the <code>ServiceTracker</code> and
+	 * is available from the <code>getService</code> and
+	 * <code>getServices</code> methods.
+	 * 
+	 * @param reference The reference to the service being added to the
+	 *        <code>ServiceTracker</code>.
+	 * @return The service object to be tracked for the specified referenced
+	 *         service or <code>null</code> if the specified referenced service
+	 *         should not be tracked.
 	 */
 	public Object addingService(ServiceReference reference);
 
 	/**
-	 * A service tracked by the <code>ServiceTracker</code> object has been
-	 * modified.
+	 * A service tracked by the <code>ServiceTracker</code> has been modified.
 	 * 
 	 * <p>
 	 * This method is called when a service being tracked by the
-	 * <code>ServiceTracker</code> object has had it properties modified.
+	 * <code>ServiceTracker</code> has had it properties modified.
 	 * 
-	 * @param reference Reference to service that has been modified.
-	 * @param service The service object for the modified service.
+	 * @param reference The reference to the service that has been modified.
+	 * @param service The service object for the specified referenced service.
 	 */
 	public void modifiedService(ServiceReference reference, Object service);
 
 	/**
-	 * A service tracked by the <code>ServiceTracker</code> object has been
-	 * removed.
+	 * A service tracked by the <code>ServiceTracker</code> has been removed.
 	 * 
 	 * <p>
 	 * This method is called after a service is no longer being tracked by the
-	 * <code>ServiceTracker</code> object.
+	 * <code>ServiceTracker</code>.
 	 * 
-	 * @param reference Reference to service that has been removed.
-	 * @param service The service object for the removed service.
+	 * @param reference The reference to the service that has been removed.
+	 * @param service The service object for the specified referenced service.
 	 */
 	public void removedService(ServiceReference reference, Object service);
 }

Added: felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/package.html
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/package.html?rev=797561&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/package.html (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/package.html Fri Jul 24 17:06:37 2009
@@ -0,0 +1,10 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>Tracker Package Version 1.4.
+<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.tracker; version=&quot;[1.4,2.0)&quot;
+</pre>
+</BODY>

Added: felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/packageinfo?rev=797561&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/packageinfo (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/tracker/packageinfo Fri Jul 24 17:06:37 2009
@@ -0,0 +1 @@
+version 1.4

Modified: felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/xml/XMLParserActivator.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/xml/XMLParserActivator.java?rev=797561&r1=797560&r2=797561&view=diff
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/xml/XMLParserActivator.java (original)
+++ felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/xml/XMLParserActivator.java Fri Jul 24 17:06:37 2009
@@ -1,7 +1,5 @@
 /*
- * $Header: /cvshome/build/org.osgi.util.xml/src/org/osgi/util/xml/XMLParserActivator.java,v 1.11 2006/10/27 18:17:06 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.
@@ -18,13 +16,28 @@
 
 package org.osgi.util.xml;
 
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.net.URL;
-import java.util.*;
-
-import javax.xml.parsers.*;
-
-import org.osgi.framework.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
 
 /**
  * A BundleActivator class that allows any JAXP compliant XML Parser to register
@@ -50,8 +63,8 @@
  * An XMLParserActivator assumes that it can find the class file names of the
  * factory classes in the following files:
  * <ul>
- * <li><code>/META-INF/services/javax.xml.parsers.SAXParserFactory</code> is
- * a file contained in a jar available to the runtime which contains the
+ * <li><code>/META-INF/services/javax.xml.parsers.SAXParserFactory</code> is a
+ * file contained in a jar available to the runtime which contains the
  * implementation class name(s) of the SAXParserFactory.
  * <li><code>/META-INF/services/javax.xml.parsers.DocumentBuilderFactory</code>
  * is a file contained in a jar available to the runtime which contains the
@@ -63,11 +76,11 @@
  * 
  * <p>
  * <code>XMLParserActivator</code> attempts to instantiate both the
- * <code>SAXParserFactory</code> and the <code>DocumentBuilderFactory</code>.
- * It registers each factory with the framework along with service properties:
+ * <code>SAXParserFactory</code> and the <code>DocumentBuilderFactory</code>. It
+ * registers each factory with the framework along with service properties:
  * <ul>
- * <li>{@link #PARSER_VALIDATING}- indicates if this factory supports
- * validating parsers. It's value is a <code>Boolean</code>.
+ * <li>{@link #PARSER_VALIDATING}- indicates if this factory supports validating
+ * parsers. It's value is a <code>Boolean</code>.
  * <li>{@link #PARSER_NAMESPACEAWARE}- indicates if this factory supports
  * namespace aware parsers It's value is a <code>Boolean</code>.
  * </ul>
@@ -76,48 +89,51 @@
  * or attributes which could be used to select a parser with a filter. These can
  * be added by extending this class and overriding the
  * <code>setSAXProperties</code> and <code>setDOMProperties</code> methods.
+ * 
+ * @ThreadSafe
+ * @version $Revision: 5900 $
  */
 public class XMLParserActivator implements BundleActivator, ServiceFactory {
 	/** Context of this bundle */
-	private BundleContext		context;
+	private volatile BundleContext	context;
 	/**
 	 * Filename containing the SAX Parser Factory Class name. Also used as the
 	 * basis for the <code>SERVICE_PID<code> registration property.
 	 */
-	public static final String	SAXFACTORYNAME			= "javax.xml.parsers.SAXParserFactory";
+	public static final String		SAXFACTORYNAME			= "javax.xml.parsers.SAXParserFactory";
 	/**
 	 * Filename containing the DOM Parser Factory Class name. Also used as the
 	 * basis for the <code>SERVICE_PID</code> registration property.
 	 */
-	public static final String	DOMFACTORYNAME			= "javax.xml.parsers.DocumentBuilderFactory";
+	public static final String		DOMFACTORYNAME			= "javax.xml.parsers.DocumentBuilderFactory";
 	/** Path to the factory class name files */
-	private static final String	PARSERCLASSFILEPATH		= "/META-INF/services/";
+	private static final String		PARSERCLASSFILEPATH		= "/META-INF/services/";
 	/** Fully qualified path name of SAX Parser Factory Class Name file */
-	public static final String	SAXCLASSFILE			= PARSERCLASSFILEPATH
-																+ SAXFACTORYNAME;
+	public static final String		SAXCLASSFILE			= PARSERCLASSFILEPATH
+																	+ SAXFACTORYNAME;
 	/** Fully qualified path name of DOM Parser Factory Class Name file */
-	public static final String	DOMCLASSFILE			= PARSERCLASSFILEPATH
-																+ DOMFACTORYNAME;
+	public static final String		DOMCLASSFILE			= PARSERCLASSFILEPATH
+																	+ DOMFACTORYNAME;
 	/** SAX Factory Service Description */
-	private static final String	SAXFACTORYDESCRIPTION	= "A JAXP Compliant SAX Parser";
+	private static final String		SAXFACTORYDESCRIPTION	= "A JAXP Compliant SAX Parser";
 	/** DOM Factory Service Description */
-	private static final String	DOMFACTORYDESCRIPTION	= "A JAXP Compliant DOM Parser";
+	private static final String		DOMFACTORYDESCRIPTION	= "A JAXP Compliant DOM Parser";
 	/**
 	 * Service property specifying if factory is configured to support
 	 * validating parsers. The value is of type <code>Boolean</code>.
 	 */
-	public static final String	PARSER_VALIDATING		= "parser.validating";
+	public static final String		PARSER_VALIDATING		= "parser.validating";
 	/**
 	 * Service property specifying if factory is configured to support namespace
 	 * aware parsers. The value is of type <code>Boolean</code>.
 	 */
-	public static final String	PARSER_NAMESPACEAWARE	= "parser.namespaceAware";
+	public static final String		PARSER_NAMESPACEAWARE	= "parser.namespaceAware";
 	/**
 	 * Key for parser factory name property - this must be saved in the parsers
 	 * properties hashtable so that the parser factory can be instantiated from
 	 * a ServiceReference
 	 */
-	private static final String	FACTORYNAMEKEY			= "parser.factoryname";
+	private static final String		FACTORYNAMEKEY			= "parser.factoryname";
 
 	/**
 	 * Called when this bundle is started so the Framework can perform the
@@ -141,20 +157,12 @@
 	public void start(BundleContext context) throws Exception {
 		this.context = context;
 		Bundle parserBundle = context.getBundle();
-		try {
-			// check for sax parsers
-			registerSAXParsers(getParserFactoryClassNames(parserBundle
-					.getResource(SAXCLASSFILE)));
-			// check for dom parsers
-			registerDOMParsers(getParserFactoryClassNames(parserBundle
-					.getResource(DOMCLASSFILE)));
-		}
-		catch (IOException ioe) {
-			// if there were any IO errors accessing the resource files
-			// containing the class names
-			ioe.printStackTrace();
-			throw new FactoryConfigurationError(ioe);
-		}
+		// check for sax parsers
+		registerSAXParsers(getParserFactoryClassNames(parserBundle
+				.getResource(SAXCLASSFILE)));
+		// check for dom parsers
+		registerDOMParsers(getParserFactoryClassNames(parserBundle
+				.getResource(DOMCLASSFILE)));
 	}
 
 	/**
@@ -168,6 +176,7 @@
 	 *         bundle, and release all services used by the bundle.
 	 */
 	public void stop(BundleContext context) throws Exception {
+		// framework will automatically unregister the parser services
 	}
 
 	/**
@@ -177,77 +186,70 @@
 	 * 
 	 * @param parserUrl The URL of the service file containing the parser class
 	 *        names
-	 * @return A vector of strings containing the parser class names or null if
-	 *         parserUrl is null
+	 * @return A List of strings containing the parser class names.
 	 * @throws IOException if there is a problem reading the URL input stream
 	 */
-	private Vector getParserFactoryClassNames(URL parserUrl) throws IOException {
-		Vector v = new Vector(1);
-		if (parserUrl != null) {
-			String parserFactoryClassName = null;
-			InputStream is = parserUrl.openStream();
-			BufferedReader br = new BufferedReader(new InputStreamReader(is));
-			while (true) {
-				parserFactoryClassName = br.readLine();
-				if (parserFactoryClassName == null) {
-					break; // end of file reached
-				}
-				String pfcName = parserFactoryClassName.trim();
-				if (pfcName.length() == 0) {
-					continue; // blank line
+	private List getParserFactoryClassNames(URL parserUrl) throws IOException {
+		if (parserUrl == null) {
+			return Collections.EMPTY_LIST;
+		}
+		List v = new ArrayList(1);
+		String parserFactoryClassName = null;
+		InputStream is = parserUrl.openStream();
+		BufferedReader br = new BufferedReader(new InputStreamReader(is));
+		while (true) {
+			parserFactoryClassName = br.readLine();
+			if (parserFactoryClassName == null) {
+				break; // end of file reached
+			}
+			String pfcName = parserFactoryClassName.trim();
+			if (pfcName.length() == 0) {
+				continue; // blank line
+			}
+			int commentIdx = pfcName.indexOf("#");
+			if (commentIdx == 0) { // comment line
+				continue;
+			}
+			else
+				if (commentIdx < 0) { // no comment on this line
+					v.add(pfcName);
 				}
-				int commentIdx = pfcName.indexOf("#");
-				if (commentIdx == 0) { // comment line
-					continue;
+				else {
+					v.add(pfcName.substring(0, commentIdx).trim());
 				}
-				else
-					if (commentIdx < 0) { // no comment on this line
-						v.addElement(pfcName);
-					}
-					else {
-						v.addElement(pfcName.substring(0, commentIdx).trim());
-					}
-			}
-			return v;
-		}
-		else {
-			return null;
 		}
+		return v;
 	}
 
 	/**
 	 * Register SAX Parser Factory Services with the framework.
 	 * 
-	 * @param parserFactoryClassNames - a <code>Vector</code> of
+	 * @param parserFactoryClassNames - a <code>List</code> of
 	 *        <code>String</code> objects containing the names of the parser
 	 *        Factory Classes
 	 * @throws FactoryConfigurationError if thrown from <code>getFactory</code>
 	 */
-	private void registerSAXParsers(Vector parserFactoryClassNames)
+	private void registerSAXParsers(List parserFactoryClassNames)
 			throws FactoryConfigurationError {
-		if (parserFactoryClassNames != null) {
-			Enumeration e = parserFactoryClassNames.elements();
-			int index = 0;
-			while (e.hasMoreElements()) {
-				String parserFactoryClassName = (String) e.nextElement();
-				// create a sax parser factory just to get it's default
-				// properties. It will never be used since
-				// this class will operate as a service factory and give each
-				// service requestor it's own SaxParserFactory
-				SAXParserFactory factory = (SAXParserFactory) getFactory(parserFactoryClassName);
-				Hashtable properties = new Hashtable(7);
-				// figure out the default properties of the parser
-				setDefaultSAXProperties(factory, properties, index);
-				// store the parser factory class name in the properties so that
-				// it can be retrieved when getService is called
-				// to return a parser factory
-				properties.put(FACTORYNAMEKEY, parserFactoryClassName);
-				// release the factory
-				factory = null;
-				// register the factory as a service
-				context.registerService(SAXFACTORYNAME, this, properties);
-				index++;
-			}
+		Iterator e = parserFactoryClassNames.iterator();
+		int index = 0;
+		while (e.hasNext()) {
+			String parserFactoryClassName = (String) e.next();
+			// create a sax parser factory just to get it's default
+			// properties. It will never be used since
+			// this class will operate as a service factory and give each
+			// service requestor it's own SaxParserFactory
+			SAXParserFactory factory = (SAXParserFactory) getFactory(parserFactoryClassName);
+			Hashtable properties = new Hashtable(7);
+			// figure out the default properties of the parser
+			setDefaultSAXProperties(factory, properties, index);
+			// store the parser factory class name in the properties so that
+			// it can be retrieved when getService is called
+			// to return a parser factory
+			properties.put(FACTORYNAMEKEY, parserFactoryClassName);
+			// register the factory as a service
+			context.registerService(SAXFACTORYNAME, this, properties);
+			index++;
 		}
 	}
 
@@ -280,10 +282,9 @@
 	 * Set the customizable SAX Parser Service Properties.
 	 * 
 	 * <p>
-	 * This method attempts to instantiate a validating parser and a
-	 * namespaceaware parser to determine if the parser can support those
-	 * features. The appropriate properties are then set in the specified
-	 * properties object.
+	 * This method attempts to instantiate a validating parser and a namespace
+	 * aware parser to determine if the parser can support those features. The
+	 * appropriate properties are then set in the specified properties object.
 	 * 
 	 * <p>
 	 * This method can be overridden to add additional SAX2 features and
@@ -328,36 +329,32 @@
 	/**
 	 * Register DOM Parser Factory Services with the framework.
 	 * 
-	 * @param parserFactoryClassNames - a <code>Vector</code> of
+	 * @param parserFactoryClassNames - a <code>List</code> of
 	 *        <code>String</code> objects containing the names of the parser
 	 *        Factory Classes
 	 * @throws FactoryConfigurationError if thrown from <code>getFactory</code>
 	 */
-	private void registerDOMParsers(Vector parserFactoryClassNames)
+	private void registerDOMParsers(List parserFactoryClassNames)
 			throws FactoryConfigurationError {
-		if (parserFactoryClassNames != null) {
-			Enumeration e = parserFactoryClassNames.elements();
-			int index = 0;
-			while (e.hasMoreElements()) {
-				String parserFactoryClassName = (String) e.nextElement();
-				// create a dom parser factory just to get it's default
-				// properties. It will never be used since
-				// this class will operate as a service factory and give each
-				// service requestor it's own DocumentBuilderFactory
-				DocumentBuilderFactory factory = (DocumentBuilderFactory) getFactory(parserFactoryClassName);
-				Hashtable properties = new Hashtable(7);
-				// figure out the default properties of the parser
-				setDefaultDOMProperties(factory, properties, index);
-				// store the parser factory class name in the properties so that
-				// it can be retrieved when getService is called
-				// to return a parser factory
-				properties.put(FACTORYNAMEKEY, parserFactoryClassName);
-				// release the factory
-				factory = null;
-				// register the factory as a service
-				context.registerService(DOMFACTORYNAME, this, properties);
-				index++;
-			}
+		Iterator e = parserFactoryClassNames.iterator();
+		int index = 0;
+		while (e.hasNext()) {
+			String parserFactoryClassName = (String) e.next();
+			// create a dom parser factory just to get it's default
+			// properties. It will never be used since
+			// this class will operate as a service factory and give each
+			// service requestor it's own DocumentBuilderFactory
+			DocumentBuilderFactory factory = (DocumentBuilderFactory) getFactory(parserFactoryClassName);
+			Hashtable properties = new Hashtable(7);
+			// figure out the default properties of the parser
+			setDefaultDOMProperties(factory, properties, index);
+			// store the parser factory class name in the properties so that
+			// it can be retrieved when getService is called
+			// to return a parser factory
+			properties.put(FACTORYNAMEKEY, parserFactoryClassName);
+			// register the factory as a service
+			context.registerService(DOMFACTORYNAME, this, properties);
+			index++;
 		}
 	}
 
@@ -388,10 +385,9 @@
 	 * Set the customizable DOM Parser Service Properties.
 	 * 
 	 * <p>
-	 * This method attempts to instantiate a validating parser and a
-	 * namespaceaware parser to determine if the parser can support those
-	 * features. The appropriate properties are then set in the specified props
-	 * object.
+	 * This method attempts to instantiate a validating parser and a namespace
+	 * aware parser to determine if the parser can support those features. The
+	 * appropriate properties are then set in the specified props object.
 	 * 
 	 * <p>
 	 * This method can be overridden to add additional DOM2 features and
@@ -443,20 +439,16 @@
 	 */
 	private Object getFactory(String parserFactoryClassName)
 			throws FactoryConfigurationError {
-		Exception e = null;
 		try {
-			return Class.forName(parserFactoryClassName).newInstance();
-		}
-		catch (ClassNotFoundException cnfe) {
-			e = cnfe;
+			return context.getBundle().loadClass(parserFactoryClassName)
+					.newInstance();
 		}
-		catch (InstantiationException ie) {
-			e = ie;
+		catch (RuntimeException e) {
+			throw e;
 		}
-		catch (IllegalAccessException iae) {
-			e = iae;
+		catch (Exception e) {
+			throw new FactoryConfigurationError(e);
 		}
-		throw new FactoryConfigurationError(e);
 	}
 
 	/**
@@ -484,32 +476,26 @@
 		ServiceReference sref = registration.getReference();
 		String parserFactoryClassName = (String) sref
 				.getProperty(FACTORYNAMEKEY);
-		try {
-			// need to set factory properties
-			Object factory = getFactory(parserFactoryClassName);
-			if (factory instanceof SAXParserFactory) {
-				((SAXParserFactory) factory).setValidating(((Boolean) sref
-						.getProperty(PARSER_VALIDATING)).booleanValue());
-				((SAXParserFactory) factory).setNamespaceAware(((Boolean) sref
-						.getProperty(PARSER_NAMESPACEAWARE)).booleanValue());
-			}
-			else
-				if (factory instanceof DocumentBuilderFactory) {
-					((DocumentBuilderFactory) factory)
-							.setValidating(((Boolean) sref
-									.getProperty(PARSER_VALIDATING))
-									.booleanValue());
-					((DocumentBuilderFactory) factory)
-							.setNamespaceAware(((Boolean) sref
-									.getProperty(PARSER_NAMESPACEAWARE))
-									.booleanValue());
-				}
-			return factory;
+		// need to set factory properties
+		Object factory = getFactory(parserFactoryClassName);
+		if (factory instanceof SAXParserFactory) {
+			((SAXParserFactory) factory).setValidating(((Boolean) sref
+					.getProperty(PARSER_VALIDATING)).booleanValue());
+			((SAXParserFactory) factory).setNamespaceAware(((Boolean) sref
+					.getProperty(PARSER_NAMESPACEAWARE)).booleanValue());
 		}
-		catch (FactoryConfigurationError fce) {
-			fce.printStackTrace();
-			return null;
+		else {
+			if (factory instanceof DocumentBuilderFactory) {
+				((DocumentBuilderFactory) factory)
+						.setValidating(((Boolean) sref
+								.getProperty(PARSER_VALIDATING)).booleanValue());
+				((DocumentBuilderFactory) factory)
+						.setNamespaceAware(((Boolean) sref
+								.getProperty(PARSER_NAMESPACEAWARE))
+								.booleanValue());
+			}
 		}
+		return factory;
 	}
 
 	/**

Added: felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/xml/package.html
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/xml/package.html?rev=797561&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/xml/package.html (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/xml/package.html Fri Jul 24 17:06:37 2009
@@ -0,0 +1,10 @@
+<!-- $Revision: 6204 $ -->
+<BODY>
+<p>XML Parser 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.xml; version=&quot;[1.0,2.0)&quot;
+</pre>
+</BODY>

Added: felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/xml/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/xml/packageinfo?rev=797561&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/xml/packageinfo (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/org/osgi/util/xml/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/xmlns/app/v1.0.0/app.xsd
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/xmlns/app/v1.0.0/app.xsd?rev=797561&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/xmlns/app/v1.0.0/app.xsd (added)
+++ felix/trunk/org.osgi.compendium/xmlns/app/v1.0.0/app.xsd Fri Jul 24 17:06:37 2009
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+ * $Revision: 5673 $
+ * 
+ * Copyright (c) OSGi Alliance (2005, 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.
+ */
+-->		
+<xs:schema
+    xmlns="http://www.osgi.org/xmlns/app/v1.0.0"
+    xmlns:app="http://www.osgi.org/xmlns/app/v1.0.0" 
+    xmlns:xs="http://www.w3.org/2001/XMLSchema"  
+    targetNamespace="http://www.osgi.org/xmlns/app/v1.0.0"
+    elementFormDefault="qualified" 
+    attributeFormDefault="unqualified" 
+    version="1.0.0">
+    
+	<xs:element name="descriptor" type="app:descriptorType">
+		<xs:annotation>
+			<xs:documentation>descriptor element encloses the application descriptors provided in a document</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+
+	<xs:complexType name="descriptorType">
+		<xs:sequence>
+			<xs:element name="application" type="app:applicationType" minOccurs="1" maxOccurs="unbounded"/>
+		</xs:sequence>
+	</xs:complexType>
+
+	<xs:complexType name="applicationType">
+		<xs:annotation>
+			<xs:documentation>describes the service dependencies of an application</xs:documentation>
+		</xs:annotation>
+		<xs:sequence>
+			<xs:element name="reference" minOccurs="0" maxOccurs="unbounded" type="referenceType"/>
+		</xs:sequence>
+		<xs:attribute name="class" type="xs:string"/>
+	</xs:complexType>
+
+	<xs:complexType name="referenceType">
+		<xs:attribute name="name" type="xs:NMTOKEN" use="required"/>
+		<xs:attribute name="interface" type="xs:string" use="required"/>
+		<xs:attribute name="cardinality" default="1..1" use="optional" type="cardinalityType"/>
+		<xs:attribute name="policy" use="optional" default="static" type="policyType"/>
+		<xs:attribute name="target" type="xs:string" use="optional"/>
+	</xs:complexType>
+
+        <xs:simpleType name="cardinalityType">
+               <xs:restriction base="xs:string">
+                       <xs:enumeration value="0..1"/>
+                       <xs:enumeration value="0..n"/>
+                       <xs:enumeration value="1..1"/>
+                       <xs:enumeration value="1..n"/>
+               </xs:restriction>
+	</xs:simpleType>
+
+	<xs:simpleType name="policyType">
+		<xs:restriction base="xs:string">
+			<xs:enumeration value="static"/>
+			<xs:enumeration value="dynamic"/>
+		</xs:restriction>
+	</xs:simpleType>
+
+
+</xs:schema>