You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ti...@apache.org on 2010/08/12 17:06:31 UTC

svn commit: r984819 - in /incubator/aries/trunk/quiesce: quiesce-manager-itest/ quiesce-manager-itest/src/ quiesce-manager-itest/src/test/ quiesce-manager-itest/src/test/java/ quiesce-manager-itest/src/test/java/org/ quiesce-manager-itest/src/test/java...

Author: timothyjward
Date: Thu Aug 12 15:06:30 2010
New Revision: 984819

URL: http://svn.apache.org/viewvc?rev=984819&view=rev
Log:
ARIES-371 - Quiesce Manager implementation (from Hannah Ramlee)

Added:
    incubator/aries/trunk/quiesce/quiesce-manager/   (with props)
    incubator/aries/trunk/quiesce/quiesce-manager-itest/   (with props)
    incubator/aries/trunk/quiesce/quiesce-manager-itest/pom.xml
    incubator/aries/trunk/quiesce/quiesce-manager-itest/src/
    incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/
    incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/
    incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/
    incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/
    incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/
    incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/quiesce/
    incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/quiesce/manager/
    incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/quiesce/manager/itest/
    incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/quiesce/manager/itest/MockQuiesceParticipant.java
    incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/quiesce/manager/itest/QuiesceManagerTest.java
    incubator/aries/trunk/quiesce/quiesce-manager/pom.xml
    incubator/aries/trunk/quiesce/quiesce-manager/src/
    incubator/aries/trunk/quiesce/quiesce-manager/src/main/
    incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/
    incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/
    incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/
    incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/
    incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/quiesce/
    incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/quiesce/manager/
    incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/quiesce/manager/impl/
    incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/quiesce/manager/impl/Activator.java
    incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/quiesce/manager/impl/QuiesceManagerImpl.java

Propchange: incubator/aries/trunk/quiesce/quiesce-manager/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Thu Aug 12 15:06:30 2010
@@ -0,0 +1 @@
+target

Propchange: incubator/aries/trunk/quiesce/quiesce-manager-itest/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Thu Aug 12 15:06:30 2010
@@ -0,0 +1 @@
+target

Added: incubator/aries/trunk/quiesce/quiesce-manager-itest/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/quiesce/quiesce-manager-itest/pom.xml?rev=984819&view=auto
==============================================================================
--- incubator/aries/trunk/quiesce/quiesce-manager-itest/pom.xml (added)
+++ incubator/aries/trunk/quiesce/quiesce-manager-itest/pom.xml Thu Aug 12 15:06:30 2010
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>quiesce</artifactId>
+        <groupId>org.apache.aries.quiesce</groupId>
+        <version>0.2-incubating-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>org.apache.aries.quiesce.manager.itest</artifactId>
+    <name>Aries Quiesce Manager iTests</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.aries.quiesce</groupId>
+            <artifactId>org.apache.aries.quiesce.api</artifactId>
+            <scope>provided</scope>
+		    <version>${version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.aries.quiesce</groupId>
+            <artifactId>org.apache.aries.quiesce.manager</artifactId>
+            <scope>provided</scope>
+		    <version>${version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.logging</groupId>
+            <artifactId>pax-logging-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.logging</groupId>
+            <artifactId>pax-logging-service</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-container-default</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.url</groupId>
+            <artifactId>pax-url-mvn</artifactId>
+            <scope>test</scope>
+        </dependency> 
+                <dependency>
+            <groupId>org.apache.aries</groupId>
+            <artifactId>org.apache.aries.util</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.configadmin</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-pool</groupId>
+            <artifactId>commons-pool</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.serp</artifactId>
+        </dependency>
+   </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.servicemix.tooling</groupId>
+                <artifactId>depends-maven-plugin</artifactId>
+                <version>1.2</version>
+                <executions>
+                    <execution>
+                        <id>generate-depends-file</id>
+                        <goals>
+                            <goal>generate-depends-file</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>ci-build-profile</id>
+            <activation>
+                <property>
+                    <name>maven.repo.local</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <!--
+                              when the local repo location has been specified, we need
+                              to pass on this information to PAX mvn url
+                            -->
+                            <argLine>-Dorg.ops4j.pax.url.mvn.localRepository=${maven.repo.local}
+                            </argLine>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>

Added: incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/quiesce/manager/itest/MockQuiesceParticipant.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/quiesce/manager/itest/MockQuiesceParticipant.java?rev=984819&view=auto
==============================================================================
--- incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/quiesce/manager/itest/MockQuiesceParticipant.java (added)
+++ incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/quiesce/manager/itest/MockQuiesceParticipant.java Thu Aug 12 15:06:30 2010
@@ -0,0 +1,77 @@
+package org.apache.aries.quiesce.manager.itest;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.apache.aries.quiesce.manager.QuiesceCallback;
+import org.apache.aries.quiesce.participant.QuiesceParticipant;
+import org.osgi.framework.Bundle;
+
+public class MockQuiesceParticipant implements QuiesceParticipant {
+
+	public static final int RETURNIMMEDIATELY = 0;
+	public static final int NEVERRETURN = 1;
+	public static final int WAIT = 2;
+	private int behaviour;
+	private List<QuiesceCallback> callbacks = new ArrayList<QuiesceCallback>();
+	private ExecutorService executor = Executors.newCachedThreadPool();
+	private int started = 0;
+	private int finished = 0;
+	
+	public MockQuiesceParticipant( int i ) {
+		behaviour = i;
+	}
+
+	public void quiesce(final QuiesceCallback callback, final List<Bundle> bundlesToQuiesce) {
+		Runnable command = new Runnable() {
+			public void run() {
+				started += 1;
+				callbacks.add(callback);
+				switch (behaviour) {
+				case 0:
+					//return immediately
+					System.out.println("MockParticipant: return immediately");
+					callback.bundleQuiesced(bundlesToQuiesce.toArray(new Bundle[bundlesToQuiesce.size()]));
+					callbacks.remove(callback);
+					finished += 1;
+					break;
+				case 1:
+					//just don't do anything
+					System.out.println("MockParticipant: just don't do anything");
+					break;
+				case 2:
+					//Wait for 5s then quiesce
+					System.out.println("MockParticipant: Wait for 5s then quiesce");
+					try {
+						Thread.sleep(5000);
+					} catch (InterruptedException e) {
+					}
+					callback.bundleQuiesced(bundlesToQuiesce.toArray(new Bundle[bundlesToQuiesce.size()]));
+					callbacks.remove(callback);
+					finished += 1;
+					break;
+				default: 
+					//Unknown behaviour, don't do anything
+				}
+			}
+		};
+		executor.execute(command);
+	}
+
+	public int getStartedCount() {
+		return started;
+	}
+	
+	public int getFinishedCount() {
+		return finished;
+	}
+	
+	public synchronized void reset() {
+		started = 0;
+		finished = 0;
+	}
+	
+	
+}

Added: incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/quiesce/manager/itest/QuiesceManagerTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/quiesce/manager/itest/QuiesceManagerTest.java?rev=984819&view=auto
==============================================================================
--- incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/quiesce/manager/itest/QuiesceManagerTest.java (added)
+++ incubator/aries/trunk/quiesce/quiesce-manager-itest/src/test/java/org/apache/aries/quiesce/manager/itest/QuiesceManagerTest.java Thu Aug 12 15:06:30 2010
@@ -0,0 +1,384 @@
+/*  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.apache.aries.quiesce.manager.itest;
+
+import static org.junit.Assert.assertTrue;
+import static org.ops4j.pax.exam.CoreOptions.equinox;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
+import static org.ops4j.pax.exam.OptionUtils.combine;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.aries.quiesce.manager.QuiesceManager;
+import org.apache.aries.quiesce.participant.QuiesceParticipant;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Inject;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.ops4j.pax.exam.options.BootDelegationOption;
+import org.ops4j.pax.exam.options.MavenArtifactProvisionOption;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.Version;
+import org.osgi.util.tracker.ServiceTracker;
+
+@RunWith(JUnit4TestRunner.class)
+public class QuiesceManagerTest {
+  public static final long DEFAULT_TIMEOUT = 30000;
+  private QuiesceManager manager;
+  private Bundle b1;
+  private Bundle b2;
+  private Bundle b3;
+  private long timeoutTime;
+  private List<Bundle> bundleList;
+  private MockQuiesceParticipant participant1;
+  private MockQuiesceParticipant participant2;
+  private MockQuiesceParticipant participant3;
+
+
+  @Inject
+  protected BundleContext bundleContext;
+  
+  @Before
+  public void setup() {
+	  manager = getOsgiService(QuiesceManager.class);
+	  b1 = bundleContext.getBundle(5);
+	  b2 = bundleContext.getBundle(6);
+	  b3 = bundleContext.getBundle(10);
+	  participant1 = new MockQuiesceParticipant(MockQuiesceParticipant.RETURNIMMEDIATELY);
+	  participant2 = new MockQuiesceParticipant(MockQuiesceParticipant.NEVERRETURN);
+	  participant3 = new MockQuiesceParticipant(MockQuiesceParticipant.WAIT);
+
+  }
+  
+  @Test
+  public void testNullSafe() throws Exception {
+	  //Check we're null safe
+	  manager.quiesce(null);  
+  }
+  
+  @Test
+  public void testNoParticipants() throws Exception {
+	  bundleList = new ArrayList<Bundle>();
+	  bundleList.add(b1);
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should be in active state", b1.getState() == Bundle.ACTIVE);
+	  //Try quiescing one bundle with no participants
+	  manager.quiesce(bundleList);
+	  //quiesce is non-blocking so what do we do? 
+	  //verify bundle is no longer active
+	  timeoutTime = System.currentTimeMillis()+5000;
+	  while (System.currentTimeMillis() < timeoutTime && b1.getState() == Bundle.ACTIVE){
+		  Thread.sleep(500);
+	  }
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE);
+	  b1.start();
+  }
+  
+  @Test
+  public void testImmediateReturn() throws Exception {
+	  bundleList = new ArrayList<Bundle>();
+	  bundleList.add(b1);
+	  //Register a mock participant which will report back quiesced immediately
+	  ServiceRegistration sr = bundleContext.registerService(QuiesceParticipant.class.getName(), participant1, null);
+	  //Try quiescing the bundle with immediate return
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should be in active state", b1.getState() == Bundle.ACTIVE);
+	  manager.quiesce(1000,bundleList);
+	  timeoutTime = System.currentTimeMillis()+5000;
+	  while (System.currentTimeMillis() < timeoutTime && b1.getState() == Bundle.ACTIVE){
+		  Thread.sleep(500);
+	  }
+	  assertTrue("Participant should have finished once", participant1.getFinishedCount() == 1);
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE);
+	  b1.start();
+	  sr.unregister();
+	  participant1.reset();
+  }
+    
+  @Test
+  public void testNoReturn() throws Exception {
+	  //Register a mock participant which won't respond
+	  ServiceRegistration sr = bundleContext.registerService(QuiesceParticipant.class.getName(), participant2, null);
+	  //recreate the list as it may have been emptied?
+	  bundleList = new ArrayList<Bundle>();
+	  bundleList.add(b1);
+	  
+	  //Try quiescing the bundle with no return
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should be in active state", b1.getState() == Bundle.ACTIVE);
+	  manager.quiesce(1000,bundleList);
+	  timeoutTime = System.currentTimeMillis()+5000;
+	  while (System.currentTimeMillis() < timeoutTime && b1.getState() == Bundle.ACTIVE){
+		  Thread.sleep(500);
+	  }
+	  assertTrue("Participant should have started once", participant2.getStartedCount() == 1);
+	  assertTrue("Participant should not have finished", participant2.getFinishedCount() == 0);
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE);
+	  b1.start();
+	  sr.unregister();
+	  participant2.reset();
+  }
+	  
+	@Test
+	public void testWaitAShortTime() throws Exception {
+	  //Try quiescing where participant takes 5s to do the work. We should get InterruptedException
+	  ServiceRegistration sr = bundleContext.registerService(QuiesceParticipant.class.getName(), participant3, null);
+	  //recreate the list as it may have been emptied?
+	  bundleList = new ArrayList<Bundle>();
+	  bundleList.add(b1);
+	  
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should be in active state", b1.getState() == Bundle.ACTIVE);
+	  manager.quiesce(10000,bundleList);
+	  //timeout is > how long participant takes, and < the quiesce timeout
+	  timeoutTime = System.currentTimeMillis()+7000;
+	  while (System.currentTimeMillis() < timeoutTime && b1.getState() == Bundle.ACTIVE){
+		  Thread.sleep(500);
+	  }
+	  assertTrue("Participant should have started once", participant3.getStartedCount() == 1);
+	  assertTrue("Participant should finished once", participant3.getFinishedCount() == 1);
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE);
+	  b1.start();
+	  participant3.reset();
+	}
+
+	@Test
+	public void testThreeParticipants() throws Exception {
+	  //Register three participants. One returns immediately, one waits 5s then returns, one never returns
+	  bundleContext.registerService(QuiesceParticipant.class.getName(), participant1, null);
+	  bundleContext.registerService(QuiesceParticipant.class.getName(), participant2, null);
+	  bundleContext.registerService(QuiesceParticipant.class.getName(), participant3, null);
+	  //recreate the list as it may have been emptied
+	  bundleList = new ArrayList<Bundle>();
+	  bundleList.add(b1);
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should be in active state", b1.getState() == Bundle.ACTIVE);
+	  manager.quiesce(10000,bundleList);
+	  timeoutTime = System.currentTimeMillis()+15000;
+	  while (System.currentTimeMillis() < timeoutTime && b1.getState() == Bundle.ACTIVE){
+		  Thread.sleep(500);
+	  }
+	  assertTrue("Participant 1 should have started once", participant1.getStartedCount() == 1);
+	  assertTrue("Participant 1 should finished once", participant1.getFinishedCount() == 1);
+	  assertTrue("Participant 2 should have started once", participant2.getStartedCount() == 1);
+	  assertTrue("Participant 2 should not have finished", participant2.getFinishedCount() == 0);
+	  assertTrue("Participant 3 should have started once", participant3.getStartedCount() == 1);
+	  assertTrue("Participant 3 should finished once", participant3.getFinishedCount() == 1);
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE);
+	  
+	  b1.start();
+	  participant1.reset();
+	  participant2.reset();
+	  participant3.reset();
+	}
+	
+	@Test
+	public void testTwoBundles() throws Exception {
+		//Register three participants. One returns immediately, one waits 5s then returns, one never returns
+		  bundleContext.registerService(QuiesceParticipant.class.getName(), participant1, null);
+		  bundleContext.registerService(QuiesceParticipant.class.getName(), participant2, null);
+		  bundleContext.registerService(QuiesceParticipant.class.getName(), participant3, null);
+	  //recreate the list as it may have been emptied
+	  bundleList = new ArrayList<Bundle>();
+	  bundleList.add(b1);
+	  bundleList.add(b2);
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should be in active state", b1.getState() == Bundle.ACTIVE);
+	  assertTrue("Bundle "+b2.getSymbolicName()+" should be in active state", b2.getState() == Bundle.ACTIVE);
+	  manager.quiesce(10000,bundleList);
+	  timeoutTime = System.currentTimeMillis()+15000;
+	  while (System.currentTimeMillis() < timeoutTime && b1.getState() == Bundle.ACTIVE){
+		  Thread.sleep(500);
+	  }
+	  assertTrue("Participant 1 should have started once", participant1.getStartedCount() == 1);
+	  assertTrue("Participant 1 should finished once", participant1.getFinishedCount() == 1);
+	  assertTrue("Participant 2 should have started once", participant2.getStartedCount() == 1);
+	  assertTrue("Participant 2 should not have finished", participant2.getFinishedCount() == 0);
+	  assertTrue("Participant 3 should have started once", participant3.getStartedCount() == 1);
+	  assertTrue("Participant 3 should finished once", participant3.getFinishedCount() == 1);
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE);
+	  assertTrue("Bundle "+b2.getSymbolicName()+" should not be in active state", b2.getState() != Bundle.ACTIVE);
+	  b1.start();
+	  b2.start();	
+	  participant1.reset();
+	  participant2.reset();
+	  participant3.reset();
+	}
+	
+	@Test
+	public void testOverlappedQuiesces() throws Exception {
+	  
+      //Register three participants. One returns immediately, one waits 5s then returns, one never returns
+	  bundleContext.registerService(QuiesceParticipant.class.getName(), participant1, null);
+	  bundleContext.registerService(QuiesceParticipant.class.getName(), participant2, null);
+	  bundleContext.registerService(QuiesceParticipant.class.getName(), participant3, null);
+	  //recreate the list as it may have been emptied
+	  bundleList = new ArrayList<Bundle>();
+	  bundleList.add(b1);
+	  bundleList.add(b2);
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should be in active state", b1.getState() == Bundle.ACTIVE);
+	  assertTrue("Bundle "+b2.getSymbolicName()+" should be in active state", b2.getState() == Bundle.ACTIVE);
+	  assertTrue("Bundle "+b3.getSymbolicName()+" should be in active state", b3.getState() == Bundle.ACTIVE);
+	  manager.quiesce(10000,bundleList);
+	  bundleList = new ArrayList<Bundle>();
+	  bundleList.add(b2);
+	  bundleList.add(b3);
+	  manager.quiesce(bundleList);
+	  timeoutTime = System.currentTimeMillis()+15000;
+	  while (System.currentTimeMillis() < timeoutTime && b1.getState() == Bundle.ACTIVE){
+		  Thread.sleep(500);
+	  }
+	  assertTrue("Participant 1 should have started twice", participant1.getStartedCount() == 2);
+	  assertTrue("Participant 1 should finished twice", participant1.getFinishedCount() == 2);
+	  assertTrue("Participant 2 should have started twice", participant2.getStartedCount() == 2);
+	  assertTrue("Participant 2 should not have finished", participant2.getFinishedCount() == 0);
+	  assertTrue("Participant 3 should have started twice", participant3.getStartedCount() == 2);
+	  assertTrue("Participant 3 should finished twice", participant3.getFinishedCount() == 2);
+	  assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE);
+	  assertTrue("Bundle "+b2.getSymbolicName()+" should not be in active state", b2.getState() != Bundle.ACTIVE);
+	  assertTrue("Bundle "+b3.getSymbolicName()+" should not be in active state", b3.getState() != Bundle.ACTIVE);
+	  participant1.reset();
+	  participant2.reset();
+	  participant3.reset();
+	  
+	}
+ 
+  @org.ops4j.pax.exam.junit.Configuration
+  public static Option[] configuration() {
+    Option[] options = options(
+        bootDelegation(),
+        
+        // Log
+        mavenBundle("org.ops4j.pax.logging", "pax-logging-api"),
+        mavenBundle("org.ops4j.pax.logging", "pax-logging-service"),
+        // Felix Config Admin
+        mavenBundle("org.apache.felix", "org.apache.felix.configadmin"),
+        // Felix mvn url handler
+        mavenBundle("org.ops4j.pax.url", "pax-url-mvn"),
+
+        // this is how you set the default log level when using pax
+        // logging (logProfile)
+        systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("DEBUG"),
+
+        // Bundles
+        mavenBundle("org.osgi", "org.osgi.compendium"),
+        mavenBundle("org.apache.aries", "org.apache.aries.util"),
+        mavenBundle("commons-lang", "commons-lang"),
+        mavenBundle("commons-collections", "commons-collections"),
+        mavenBundle("commons-pool", "commons-pool"),
+        mavenBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.serp"),
+        mavenBundle("org.apache.aries.quiesce", "org.apache.aries.quiesce.api"),
+        mavenBundle("org.apache.aries.quiesce", "org.apache.aries.quiesce.manager"),
+        
+        equinox().version("3.5.0"));
+    options = updateOptions(options);
+    return options;
+  }
+  
+  
+  protected Bundle getBundle(String symbolicName) {
+    return getBundle(symbolicName, null);
+  }
+
+  protected Bundle getBundle(String bundleSymbolicName, String version) {
+    Bundle result = null;
+    for (Bundle b : bundleContext.getBundles()) {
+      if (b.getSymbolicName().equals(bundleSymbolicName)) {
+        if (version == null
+            || b.getVersion().equals(Version.parseVersion(version))) {
+          result = b;
+          break;
+        }
+      }
+    }
+    return result;
+  }
+
+  public static BootDelegationOption bootDelegation() {
+    return new BootDelegationOption("org.apache.aries.unittest.fixture");
+  }
+  
+  public static MavenArtifactProvisionOption mavenBundle(String groupId,
+      String artifactId) {
+    return CoreOptions.mavenBundle().groupId(groupId).artifactId(artifactId)
+        .versionAsInProject();
+  }
+
+  protected static Option[] updateOptions(Option[] options) {
+    // We need to add pax-exam-junit here when running with the ibm
+    // jdk to avoid the following exception during the test run:
+    // ClassNotFoundException: org.ops4j.pax.exam.junit.Configuration
+    if ("IBM Corporation".equals(System.getProperty("java.vendor"))) {
+      Option[] ibmOptions = options(wrappedBundle(mavenBundle(
+          "org.ops4j.pax.exam", "pax-exam-junit")));
+      options = combine(ibmOptions, options);
+    }
+
+    return options;
+  }
+
+  protected <T> T getOsgiService(Class<T> type, long timeout) {
+    return getOsgiService(type, null, timeout);
+  }
+
+  protected <T> T getOsgiService(Class<T> type) {
+    return getOsgiService(type, null, DEFAULT_TIMEOUT);
+  }
+  
+  protected <T> T getOsgiService(Class<T> type, String filter, long timeout) {
+    return getOsgiService(null, type, filter, timeout);
+  }
+
+  protected <T> T getOsgiService(BundleContext bc, Class<T> type,
+      String filter, long timeout) {
+    ServiceTracker tracker = null;
+    try {
+      String flt;
+      if (filter != null) {
+        if (filter.startsWith("(")) {
+          flt = "(&(" + Constants.OBJECTCLASS + "=" + type.getName() + ")"
+              + filter + ")";
+        } else {
+          flt = "(&(" + Constants.OBJECTCLASS + "=" + type.getName() + ")("
+              + filter + "))";
+        }
+      } else {
+        flt = "(" + Constants.OBJECTCLASS + "=" + type.getName() + ")";
+      }
+      Filter osgiFilter = FrameworkUtil.createFilter(flt);
+      tracker = new ServiceTracker(bc == null ? bundleContext : bc, osgiFilter,
+          null);
+      tracker.open();
+      // Note that the tracker is not closed to keep the reference
+      // This is buggy, has the service reference may change i think
+      Object svc = type.cast(tracker.waitForService(timeout));
+      if (svc == null) {
+        throw new RuntimeException("Gave up waiting for service " + flt);
+      }
+      return type.cast(svc);
+    } catch (InvalidSyntaxException e) {
+      throw new IllegalArgumentException("Invalid filter", e);
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    }
+  }
+}

Added: incubator/aries/trunk/quiesce/quiesce-manager/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/quiesce/quiesce-manager/pom.xml?rev=984819&view=auto
==============================================================================
--- incubator/aries/trunk/quiesce/quiesce-manager/pom.xml (added)
+++ incubator/aries/trunk/quiesce/quiesce-manager/pom.xml Thu Aug 12 15:06:30 2010
@@ -0,0 +1,83 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.aries.quiesce</groupId>
+        <artifactId>quiesce</artifactId>
+        <version>0.2-incubating-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>org.apache.aries.quiesce.manager</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Aries Quiesce Manager</name>
+    <description>
+      Quiesce Manager.
+    </description>
+
+    <properties>
+        <aries.osgi.export.pkg>
+        </aries.osgi.export.pkg>
+        <aries.osgi.private.pkg>
+            org.apache.aries.quiesce.manager.impl
+        </aries.osgi.private.pkg>
+        <aries.osgi.activator>
+            org.apache.aries.quiesce.manager.impl.Activator
+        </aries.osgi.activator>
+        <aries.osgi.export.service>
+            org.apache.aries.quiesce.manager.QuiesceManager
+        </aries.osgi.export.service>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.aries.quiesce</groupId>
+            <artifactId>org.apache.aries.quiesce.api</artifactId>
+            <scope>provided</scope>
+		<version>${version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+        
+
+</project>

Added: incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/quiesce/manager/impl/Activator.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/quiesce/manager/impl/Activator.java?rev=984819&view=auto
==============================================================================
--- incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/quiesce/manager/impl/Activator.java (added)
+++ incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/quiesce/manager/impl/Activator.java Thu Aug 12 15:06:30 2010
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.aries.quiesce.manager.impl;
+
+import org.apache.aries.quiesce.manager.QuiesceManager;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class Activator implements BundleActivator {
+
+    private ServiceRegistration serviceReg;
+
+    public void start(BundleContext bundleContext) throws Exception {
+        QuiesceManager manager = new QuiesceManagerImpl(bundleContext);
+        serviceReg = bundleContext.registerService(QuiesceManager.class.getName(), manager, null);
+    }
+
+
+    public void stop(BundleContext bundleContext) throws Exception {
+    	if (serviceReg != null)
+    		serviceReg.unregister();
+    }
+
+}
\ No newline at end of file

Added: incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/quiesce/manager/impl/QuiesceManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/quiesce/manager/impl/QuiesceManagerImpl.java?rev=984819&view=auto
==============================================================================
--- incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/quiesce/manager/impl/QuiesceManagerImpl.java (added)
+++ incubator/aries/trunk/quiesce/quiesce-manager/src/main/java/org/apache/aries/quiesce/manager/impl/QuiesceManagerImpl.java Thu Aug 12 15:06:30 2010
@@ -0,0 +1,268 @@
+/*
+ * 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.apache.aries.quiesce.manager.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.aries.quiesce.manager.QuiesceCallback;
+import org.apache.aries.quiesce.manager.QuiesceManager;
+import org.apache.aries.quiesce.participant.QuiesceParticipant;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class QuiesceManagerImpl implements QuiesceManager {
+	
+	/** Logger */
+    private static final Logger LOGGER = LoggerFactory.getLogger(QuiesceManagerImpl.class.getName());
+    /** The default timeout to use */
+    private static int defaultTimeout = 60000; 
+    /** The container's {@link BundleContext} */
+    private BundleContext bundleContext = null;
+    /** The thread pool to execute timeout commands */
+    private ScheduledExecutorService timeoutExecutor = Executors.newScheduledThreadPool(10);
+    /** The thread pool to execute quiesce commands */
+    private ExecutorService executor = new ThreadPoolExecutor(0, 10, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),new ThreadFactory() {
+		
+		public Thread newThread(Runnable arg0) {
+			Thread t = new Thread(arg0, "Quiesce Manager Thread");
+			t.setDaemon(true);
+			return t;
+		}
+	});
+    /** The map of bundles that are currently being quiesced */
+    private static ConcurrentHashMap<Long, Bundle> bundleMap = new ConcurrentHashMap<Long, Bundle>();
+
+
+    public QuiesceManagerImpl(BundleContext bc) {
+    	bundleContext = bc;
+    }
+    
+    /**
+     * Attempts to quiesce all bundles in the list. After the timeout has elapsed, 
+     * or if successfully quiesced before that, the bundles are stopped. This method 
+     * is non-blocking. Calling objects wishing to track the state of the bundles 
+     * need to listen for the resulting stop events. 
+     */
+    public void quiesce(long timeout, List<Bundle> bundles) {
+    	if (bundles != null && !!!bundles.isEmpty()) {
+			//check that bundle b is not already quiescing
+			Iterator<Bundle> it = bundles.iterator();
+			Set<Bundle> bundlesToQuiesce = new HashSet<Bundle>();
+			while(it.hasNext()) {
+				Bundle b = it.next();
+				Bundle priorBundle = bundleMap.putIfAbsent(b.getBundleId(), b);
+				if (priorBundle == null) {
+					bundlesToQuiesce.add(b);
+				}else{
+					LOGGER.warn("Already quiescing bundle "+ b.getSymbolicName());
+				}
+	  	  	}
+			Runnable command = new BundleQuiescer(bundlesToQuiesce, timeout, bundleMap);
+			executor.execute(command);
+    	}
+    }
+
+    /**
+     * Attempts to quiesce all bundles in the list, using the default timeout. 
+     * After the timeout has elapsed, or if successfully quiesced before that, 
+     * the bundles are stopped. This method is non-blocking. Calling objects 
+     * wishing to track the state of the bundles need to listen for the 
+     * resulting stop events. 
+     */
+    public void quiesce(List<Bundle> bundlesToQuiesce) {
+    	quiesce(defaultTimeout, bundlesToQuiesce);
+    }
+  
+    private static boolean stopBundle(Bundle bundleToStop) {
+    	try {
+    		bundleToStop.stop();
+    		bundleMap.remove(bundleToStop.getBundleId());
+    	}catch (BundleException be) {
+    		return false;
+    	}
+    	return true;
+    }
+
+    /**
+     * BundleQuiescer is used for each bundle to quiesce. It creates a callback object for each 
+     * participant. Well-behaved participants will be non-blocking on their quiesce method.
+     * When all callbacks for the participants have completed, this thread will get an 
+     * interrupt, so it sleeps until it hits the timeout. When complete it stops the bundle
+     * and removes the bundles from the list of those that are being quiesced.
+     */
+    private class BundleQuiescer implements Runnable {
+	  
+    	private Set<Bundle> bundlesToQuiesce;
+    	private long timeout;
+    	
+    	public BundleQuiescer(Set<Bundle> bundlesToQuiesce, long timeout, ConcurrentHashMap<Long, Bundle> bundleMap) {
+    		this.bundlesToQuiesce = new HashSet<Bundle>(bundlesToQuiesce);
+    		this.timeout = timeout;
+    	}
+
+    	public void run() {
+    		try {
+				if (bundleContext != null) {
+					ServiceReference[] serviceRefs = bundleContext.getServiceReferences(QuiesceParticipant.class.getName(), null);
+					if (serviceRefs != null) {
+						List<QuiesceParticipant> participants = new ArrayList<QuiesceParticipant>();
+						final List<QuiesceCallbackImpl> callbacks = new ArrayList<QuiesceCallbackImpl>();
+						Set<Bundle> copyOfBundles = new HashSet<Bundle>(bundlesToQuiesce);
+						Timer timer = new Timer();
+						
+						//Create callback objects for all participants
+						for( ServiceReference sr : serviceRefs ) {
+							QuiesceParticipant participant = (QuiesceParticipant) bundleContext.getService(sr);
+							participants.add(participant);
+							callbacks.add(new QuiesceCallbackImpl(copyOfBundles, callbacks, timer));
+						}
+						
+						//Quiesce each participant and wait for an interrupt from a callback 
+						//object when all are quiesced, or the timeout to be reached
+						for( int i=0; i<participants.size(); i++ ) {
+							QuiesceParticipant participant = participants.get(i);
+							QuiesceCallbackImpl callback = callbacks.get(i);
+							List<Bundle> participantBundles = new ArrayList<Bundle>();
+							//deep copy
+							for (Bundle b : copyOfBundles) {
+								participantBundles.add(b);
+							}
+							participant.quiesce(callback, participantBundles);
+						}
+						timer.schedule(new TimerTask() {
+
+							@Override
+							public void run() {
+								//stop bundles
+								//go through callbacks and cancel all bundles
+								for ( Enumeration<Bundle> remainingBundles = bundleMap.elements(); remainingBundles.hasMoreElements(); ) {
+									Bundle b = remainingBundles.nextElement();
+									LOGGER.warn("Could not quiesce, so stopping bundle "+ b.getSymbolicName());
+									stopBundle(b);
+								}
+								/*
+								for ( QuiesceCallbackImpl cb : callbacks ) {
+									System.out.println("Clearing callback");
+									cb.clear();
+									}
+									*/
+							}
+							
+						}, timeout);
+					}else{
+						LOGGER.warn("No participants, so stopping bundles");
+						for ( Enumeration<Bundle> remainingBundles = bundleMap.elements(); remainingBundles.hasMoreElements(); ) {
+							Bundle b = remainingBundles.nextElement();
+							stopBundle(b);
+						}
+					}
+				}
+			} catch (InvalidSyntaxException e) {
+				LOGGER.warn("Exception trying to get service references for quiesce participants "+ e.getMessage());
+			}
+		}
+	}
+ 
+    /**
+     * Callback object provided for each participant for each quiesce call 
+     * from the quiesce manager. 
+     */
+    private static class QuiesceCallbackImpl implements QuiesceCallback {
+    	//Must be a copy
+    	private final Set<Bundle> toQuiesce;
+    	//Must not be a copy
+    	private final List<QuiesceCallbackImpl> allCallbacks;
+    	//Timer so we can cancel the alarm if all done
+    	private final Timer timer;
+    	
+    	public QuiesceCallbackImpl(Collection<Bundle> toQuiesce, List<QuiesceCallbackImpl> allCallbacks, Timer timer) 
+    	{
+    		this.toQuiesce = new HashSet<Bundle>(toQuiesce);
+    		this.allCallbacks = allCallbacks;
+    		this.timer = timer;
+    	}
+
+    	public void clear() {
+			// TODO Auto-generated method stub
+			
+		}
+
+		/** 
+    	 * Removes the bundles from the list of those to quiesce. 
+    	 * If the list is now empty, this callback object is finished (i.e. 
+    	 * the participant linked to this object has quiesced all the bundles
+    	 * requested).  
+    	 * 
+    	 * If all other participants have also completed, then the 
+    	 * calling BundleQuieser thread is interrupted.
+    	 */
+    	public void bundleQuiesced(Bundle... bundlesQuiesced) {
+    		
+    		synchronized (allCallbacks) {
+			  for(Bundle b : bundlesQuiesced) {
+				  if(toQuiesce.remove(b)) {
+					  if(checkOthers(b)){
+						 QuiesceManagerImpl.stopBundle(b);
+						 if(allCallbacksComplete()){
+							 timer.cancel();
+						 }
+					  }
+				  }
+			  }
+			}
+    	}
+
+		private boolean checkOthers(Bundle b) {
+			boolean allDone = true;
+			Iterator<QuiesceCallbackImpl> it = allCallbacks.iterator();
+			while (allDone && it.hasNext()) {
+				allDone = !!!it.next().toQuiesce.contains(b);
+			}
+			return allDone;
+		}
+		
+		private boolean allCallbacksComplete() {
+			boolean allDone = true;
+			Iterator<QuiesceCallbackImpl> it = allCallbacks.iterator();
+			while (allDone && it.hasNext()) {
+				allDone = !!!it.next().toQuiesce.isEmpty();
+			}
+			return allDone;
+		}		
+    }
+}
\ No newline at end of file