package org.osgi.test.cases.upnp.tbc.device.discovery;

import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.upnp.UPnPDevice;
import org.osgi.test.support.compatibility.DefaultTestBundleControl;
import org.osgi.test.support.compatibility.Semaphore;
import org.osgi.util.tracker.ServiceTracker;

/**
 * Seems to track the latest registration/modification/unregistration of a
 * device. It was using a service listener with all dangers associated. It also
 * did not discriminate between the looked for devices and the existing or found
 * devices on the network.
 * 
 */
public class ServicesListener extends ServiceTracker {
	private final Semaphore	waiter;
	private final int		desiredCount;
	private UPnPDevice	last;

	public ServicesListener(BundleContext bc, int count)
			throws InvalidSyntaxException {
		super(
				bc,
				bc
						.createFilter("(&(objectclass=org.osgi.service.upnp.UPnPDevice)(UPnP.device.manufacturer=ProSyst))"),
				null);
		waiter = new Semaphore();
		desiredCount = count;
	}

	public Object addingService(ServiceReference ref) {
		UPnPDevice device = (UPnPDevice) super.addingService(ref);

		DefaultTestBundleControl.log("adding UPnP Device " + device);
		synchronized (this) {
			last = device;
		}
		if (size() + 1 == desiredCount) {
			DefaultTestBundleControl.log(desiredCount
					+ " UPnP Devices arrived, signaling waiter");
			waiter.signal();
		}
		return device;
	}

	public void removedService(ServiceReference reference, Object service) {
		DefaultTestBundleControl.log("removing UPnP Device " + service);
		super.removedService(reference, service);
	}

	public synchronized UPnPDevice getUPnPDevice() {
		return last;
	}

	public void waitFor(long timeout) throws InterruptedException {
		DefaultTestBundleControl.log("waiting for UPnP Devices " + timeout);
		waiter.waitForSignal(timeout);
	}
}

@@ -816,16 +816,38 @@
 ce%09last;
+%0A%09private int%09%09%09%09size;
 %0A%0A%09publi
@@ -1124,16 +1124,405 @@
  count;%0A
+%09%09size = 0;%0A%09%7D%0A%0A%09public void open() %7B%0A%09%09super.open();%0A%09%09synchronized (this) %7B%0A%09%09%09size = super.size();%0A%09%09%7D%0A%09%7D%0A%0A%09public void open(boolean trackAllServices) %7B%0A%09%09super.open(trackAllServices);%0A%09%09synchronized (this) %7B%0A%09%09%09size = super.size();%0A%09%09%7D%0A%09%7D%0A%0A%09public void close() %7B%0A%09%09super.close();%0A%09%09synchronized (this) %7B%0A%09%09%09size = super.size();%0A%09%09%7D%0A%09%7D%0A%0A%09public synchronized int size() %7B%0A%09%09return size;%0A
 %09%7D%0A%0A%09pub
@@ -1720,16 +1720,27 @@
 this) %7B%0A
+%09%09%09size++;%0A
 %09%09%09last 
@@ -1750,19 +1750,16 @@
 evice;%0A%09
-%09%7D%0A
 %09%09if (si
@@ -1764,16 +1764,10 @@
 size
-() + 1 =
+ !
 = de
@@ -1781,16 +1781,43 @@
 unt) %7B%0A%09
+%09%09%09return device;%0A%09%09%09%7D%0A%09%09%7D%0A
 %09%09Defaul
@@ -1852,17 +1852,16 @@
 edCount%0A
-%09
 %09%09%09%09+ %22 
@@ -1904,17 +1904,16 @@
 er%22);%0A%09%09
-%09
 waiter.s
@@ -1921,20 +1921,16 @@
 gnal();%0A
-%09%09%7D%0A
 %09%09return
@@ -2127,16 +2127,55 @@
 rvice);%0A
+%09%09synchronized (this) %7B%0A%09%09%09size--;%0A%09%09%7D%0A
 %09%7D%0A%0A%09pub

Remove race condition in UPnP test case.