sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cziege...@apache.org
Subject svn commit: r1648985 - in /sling/trunk/installer: core/src/main/java/org/apache/sling/installer/core/impl/ factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ it/src/test/java/org/apache/sling/installer/it/
Date Fri, 02 Jan 2015 09:32:41 GMT
Author: cziegeler
Date: Fri Jan  2 09:32:41 2015
New Revision: 1648985

URL: http://svn.apache.org/r1648985
Log:
SLING-4272 : Issues in handling of configurations wrt update handling and write back

Added:
    sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/Coordinator.java
  (with props)
Modified:
    sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/EntityResourceList.java
    sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigInstallTask.java
    sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigRemoveTask.java
    sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigTaskCreator.java
    sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/ConfigInstallTest.java
    sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/OsgiInstallerTestBase.java

Modified: sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/EntityResourceList.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/EntityResourceList.java?rev=1648985&r1=1648984&r2=1648985&view=diff
==============================================================================
--- sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/EntityResourceList.java
(original)
+++ sling/trunk/installer/core/src/main/java/org/apache/sling/installer/core/impl/EntityResourceList.java
Fri Jan  2 09:32:41 2015
@@ -211,7 +211,7 @@ public class EntityResourceList implemen
                 if ( second.getDictionary() != null
                      && second.getDictionary().get(InstallableResource.RESOURCE_IS_TEMPLATE)
!= null ) {
                     // second resource is a template! Do not install
-                    ((RegisteredResourceImpl)second).setState(ResourceState.INSTALLED);
+                    ((RegisteredResourceImpl)second).setState(ResourceState.IGNORED);
                 } else if ( state == ResourceState.UNINSTALLED ) {
                     // first resource got uninstalled, go back to second
                     if (second.getState() == ResourceState.IGNORED || second.getState() ==
ResourceState.INSTALLED) {

Modified: sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigInstallTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigInstallTask.java?rev=1648985&r1=1648984&r2=1648985&view=diff
==============================================================================
--- sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigInstallTask.java
(original)
+++ sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigInstallTask.java
Fri Jan  2 09:32:41 2015
@@ -22,6 +22,7 @@ import org.apache.sling.installer.api.ta
 import org.apache.sling.installer.api.tasks.ResourceState;
 import org.apache.sling.installer.api.tasks.TaskResourceGroup;
 import org.apache.sling.installer.factories.configuration.ConfigurationConstants;
+import org.apache.sling.installer.factories.configuration.impl.Coordinator.Operation;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
 
@@ -44,7 +45,7 @@ public class ConfigInstallTask extends A
     @SuppressWarnings("unchecked")
 	@Override
     public void execute(final InstallationContext ctx) {
-        synchronized ( ConfigTaskCreator.getLock() ) {
+        synchronized ( Coordinator.SHARED ) {
             // Get or create configuration, but do not
             // update if the new one has the same values.
             boolean created = false;
@@ -81,6 +82,8 @@ public class ConfigInstallTask extends A
                     this.getLogger().debug("Configuration " + config.getPid()
                                 + " " + (created ? "created" : "updated")
                                 + " from " + getResource());
+                    final Operation op = new Coordinator.Operation(config.getPid(), config.getFactoryPid(),
false);
+                    Coordinator.SHARED.add(op);
                 } else {
                     this.setFinishedState(ResourceState.IGNORED, this.getCompositeAliasPid());
                 }

Modified: sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigRemoveTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigRemoveTask.java?rev=1648985&r1=1648984&r2=1648985&view=diff
==============================================================================
--- sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigRemoveTask.java
(original)
+++ sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigRemoveTask.java
Fri Jan  2 09:32:41 2015
@@ -45,7 +45,7 @@ public class ConfigRemoveTask extends Ab
     @Override
     @SuppressWarnings("unchecked")
     public void execute(final InstallationContext ctx) {
-        synchronized ( ConfigTaskCreator.getLock() ) {
+        synchronized ( Coordinator.SHARED ) {
             try {
                 final Configuration cfg = getConfiguration();
                 if (cfg == null) {
@@ -54,12 +54,16 @@ public class ConfigRemoveTask extends Ab
                     if ( !ConfigUtil.isSameData(cfg.getProperties(), this.getResource().getDictionary())
) {
                         this.getLogger().debug("Configuration has changed after it has been
installed!");
                     } else {
+                        final Coordinator.Operation op = new Coordinator.Operation(cfg.getPid(),
cfg.getFactoryPid(), true);
+
                         this.getLogger().debug("Deleting config {} ({})", getCompositePid(),
getResource());
                         cfg.delete();
                         ctx.log("Deleted configuration {} from resource {}", getCompositePid(),
getResource());
+
+                        Coordinator.SHARED.add(op);
                     }
                 }
-            } catch (Exception e) {
+            } catch (final Exception e) {
                 this.getLogger().debug("Exception during removal of config " + this.getResource()
+ " : " + e.getMessage() + ". Retrying later.", e);
             }
             // we always set to uninstalled as the resource really has been deleted

Modified: sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigTaskCreator.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigTaskCreator.java?rev=1648985&r1=1648984&r2=1648985&view=diff
==============================================================================
--- sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigTaskCreator.java
(original)
+++ sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigTaskCreator.java
Fri Jan  2 09:32:41 2015
@@ -39,6 +39,8 @@ import org.osgi.service.cm.Configuration
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.cm.ConfigurationEvent;
 import org.osgi.service.cm.ConfigurationListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Task creator for configurations.
@@ -46,6 +48,9 @@ import org.osgi.service.cm.Configuration
 public class ConfigTaskCreator
     implements InstallTaskFactory, ConfigurationListener, ResourceTransformer {
 
+    /** Logger. */
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
     /** Configuration admin. */
     private final ConfigurationAdmin configAdmin;
 
@@ -91,7 +96,7 @@ public class ConfigTaskCreator
      */
     @SuppressWarnings("unchecked")
     public void configurationEvent(final ConfigurationEvent event) {
-        synchronized ( ConfigTaskCreator.getLock() ) {
+        synchronized ( Coordinator.SHARED ) {
             final String id;
             final String pid;
             if (event.getFactoryPid() == null ) {
@@ -103,13 +108,19 @@ public class ConfigTaskCreator
                 id = event.getFactoryPid() + '.' + event.getPid();
             }
             if ( event.getType() == ConfigurationEvent.CM_DELETED ) {
-                this.changeListener.resourceRemoved(InstallableResource.TYPE_CONFIG, id);
+                final Coordinator.Operation op = Coordinator.SHARED.get(event.getPid(), event.getFactoryPid(),
true);
+                if ( op == null ) {
+                    this.changeListener.resourceRemoved(InstallableResource.TYPE_CONFIG,
id);
+                } else {
+                    this.logger.debug("Ignoring configuration event for {}:{}", event.getPid(),
event.getFactoryPid());
+                }
             } else if ( event.getType() == ConfigurationEvent.CM_UPDATED ) {
                 try {
                     final Configuration config = ConfigUtil.getConfiguration(configAdmin,
                             event.getFactoryPid(),
                             event.getPid());
-                    if ( config != null ) {
+                    final Coordinator.Operation op = Coordinator.SHARED.get(event.getPid(),
event.getFactoryPid(), false);
+                    if ( config != null && op == null ) {
                         final boolean persist = ConfigUtil.toBoolean(config.getProperties().get(ConfigurationConstants.PROPERTY_PERSISTENCE),
true);
                         if ( persist ) {
                             final Dictionary<String, Object> dict = ConfigUtil.cleanConfiguration(config.getProperties());
@@ -129,6 +140,8 @@ public class ConfigTaskCreator
                             }
                             this.changeListener.resourceAddedOrUpdated(InstallableResource.TYPE_CONFIG,
id, null, dict, attrs);
                         }
+                    } else {
+                        this.logger.debug("Ignoring configuration event for {}:{}", event.getPid(),
event.getFactoryPid());
                     }
                 } catch ( final Exception ignore) {
                     // ignore for now
@@ -242,10 +255,4 @@ public class ConfigTaskCreator
         }
         return path.replace('\\', '/');
     }
-
-    private static final Object LOCK = new Object();
-
-    public static Object getLock() {
-        return LOCK;
-    }
 }

Added: sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/Coordinator.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/Coordinator.java?rev=1648985&view=auto
==============================================================================
--- sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/Coordinator.java
(added)
+++ sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/Coordinator.java
Fri Jan  2 09:32:41 2015
@@ -0,0 +1,131 @@
+/*
+ * 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.sling.installer.factories.configuration.impl;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Coordinator service.
+ *
+ * All operations should be synced on the {@link #SHARED} instance.
+ */
+public class Coordinator {
+
+    /**
+     * Shared instance for syncing and keeping track of operations.
+     */
+    public static final Coordinator SHARED = new Coordinator();
+
+    /**
+     * Entries expire after this number of milliseconds (defaults to 5 secs)
+     */
+    private static final long EXPIRY = 5000;
+
+    /**
+     * An operation
+     */
+    public static final class Operation {
+        public final String pid;
+        public final String factoryPid;
+        public final boolean isDelete;
+        public final long created;
+
+        public Operation(final String pid, final String factoryPid, final boolean isDelete)
{
+            created = System.currentTimeMillis();
+            this.pid = pid;
+            this.factoryPid = factoryPid;
+            this.isDelete = isDelete;
+        }
+
+        @Override
+        public String toString() {
+            return "Operation [pid=" + pid + ", factoryPid=" + factoryPid
+                    + ", isDelete=" + isDelete + ", created=" + created + "]";
+        }
+    }
+
+    /**
+     * Logger
+     */
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    /**
+     * The list of operations.
+     */
+    private final List<Operation> operations = new ArrayList<Coordinator.Operation>();
+
+    /**
+     * Private constructor
+     */
+    private Coordinator() {
+        // private constructor
+    }
+
+    public void add(final Operation op) {
+        this.cleanup();
+        this.operations.add(op);
+        logger.debug("Adding {}", op);
+    }
+
+    public Operation get(final String pid, final String factoryPid, final boolean isDelete)
{
+        this.cleanup();
+        logger.debug("Searching {} : {} - {}", new Object[] {pid, factoryPid, isDelete});
+        Operation result = null;
+        final Iterator<Operation> i = this.operations.iterator();
+        while ( i.hasNext() ) {
+            final Operation op = i.next();
+            if ( op.isDelete == isDelete ) {
+                if ( op.pid.equals(pid) ) {
+                    if ( (op.factoryPid == null && factoryPid == null)
+                      || (op.factoryPid != null && op.factoryPid.equals(factoryPid))
) {
+                        result = op;
+                        i.remove();
+                        break;
+                    }
+                }
+            }
+        }
+        logger.debug("Result ({} : {} - {}) : {}", new Object[] {pid, factoryPid, isDelete,
result});
+        return result;
+    }
+
+    /**
+     * Clean up the list of operations.
+     * Remove all entries which are older then the {@link #EXPIRY}
+     */
+    private void cleanup() {
+        final long time = System.currentTimeMillis() - EXPIRY;
+        final Iterator<Operation> i = this.operations.iterator();
+        while ( i.hasNext() ) {
+            final Operation op = i.next();
+            if ( op.created <= time ) {
+                logger.debug("Deleting expired {}", op);
+                i.remove();
+            } else {
+                break;
+            }
+        }
+    }
+}

Propchange: sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/Coordinator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/installer/factories/configuration/src/main/java/org/apache/sling/installer/factories/configuration/impl/Coordinator.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Modified: sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/ConfigInstallTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/ConfigInstallTest.java?rev=1648985&r1=1648984&r2=1648985&view=diff
==============================================================================
--- sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/ConfigInstallTest.java
(original)
+++ sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/ConfigInstallTest.java
Fri Jan  2 09:32:41 2015
@@ -151,7 +151,7 @@ public class ConfigInstallTest extends O
     }
 
     @Test
-    public void testInstallUpdateRemoveConfig() throws Exception {
+    public void testInstallUpdateRemoveConfigResource() throws Exception {
         final Dictionary<String, Object> cfgData = new Hashtable<String, Object>();
         cfgData.put("foo", "bar");
         final String cfgPid = getClass().getSimpleName() + "." + uniqueID();
@@ -189,7 +189,7 @@ public class ConfigInstallTest extends O
     }
 
     @Test
-    public void testInstallUpdateRemoveTemplateConfig() throws Exception {
+    public void testInstallUpdateRemoveTemplateConfigResource() throws Exception {
         final Dictionary<String, Object> cfgData = new Hashtable<String, Object>();
         cfgData.put("foo", "bar");
         cfgData.put(InstallableResource.RESOURCE_IS_TEMPLATE, "true");
@@ -228,6 +228,85 @@ public class ConfigInstallTest extends O
     }
 
     @Test
+    public void testInstallUpdateRemoveConfigFactoryResource() throws Exception {
+        final Dictionary<String, Object> cfgData = new Hashtable<String, Object>();
+        cfgData.put("foo", "bar");
+        final String cfgFactoryPid = getClass().getSimpleName() + "." + uniqueID();
+        final String alias = "alias" + uniqueID();
+        assertNull("Factory config " + cfgFactoryPid + " must not be found before test",
findFactoryConfiguration(cfgFactoryPid));
+
+        // install factory config
+        final InstallableResource rsrc = new InstallableResource("/configA/" + cfgFactoryPid
+ "-" + alias,
+                null, cfgData, null, InstallableResource.TYPE_PROPERTIES, 10);
+        installer.updateResources(URL_SCHEME, new InstallableResource[] {rsrc}, null);
+
+        // get factory config
+        final Configuration cfg = waitForFactoryConfiguration("After installing", cfgFactoryPid,
TIMEOUT, true);
+        assertEquals("Config value must match", "bar", cfg.getProperties().get("foo"));
+
+        // create second factory configuration with same alias
+        final Dictionary<String, Object> secondData = new Hashtable<String, Object>();
+        secondData.put("foo", "bla");
+        final InstallableResource rsrc2 = new InstallableResource("/configB/" + cfgFactoryPid
+ "-" + alias,
+                null, secondData, null, InstallableResource.TYPE_PROPERTIES, 20);
+        installer.updateResources(URL_SCHEME, new InstallableResource[] {rsrc2}, null);
+
+        sleep(200);
+
+        // get updated factory config
+        final Configuration secondCfg = waitForFactoryConfiguration("After updating", cfgFactoryPid,
TIMEOUT, true);
+        assertEquals("Config value must match", "bla", secondCfg.getProperties().get("foo"));
+
+        // remove factory config
+        installer.updateResources(URL_SCHEME, null, new String[] {"/configB/" + cfgFactoryPid
+ "-" + alias});
+
+        sleep(200);
+
+        final Configuration origCfg = waitForFactoryConfiguration("After deleting", cfgFactoryPid,
TIMEOUT, true);
+        assertEquals("Config value must match", "bar", origCfg.getProperties().get("foo"));
+    }
+
+    @Test
+    public void testInstallUpdateRemoveTemplateConfigFactoryResource() throws Exception {
+        final Dictionary<String, Object> cfgData = new Hashtable<String, Object>();
+        cfgData.put("foo", "bar");
+        cfgData.put(InstallableResource.RESOURCE_IS_TEMPLATE, "true");
+        final String cfgFactoryPid = getClass().getSimpleName() + "." + uniqueID();
+        final String alias = "alias" + uniqueID();
+        assertNull("Factory config " + cfgFactoryPid + " must not be found before test",
findFactoryConfiguration(cfgFactoryPid));
+
+        // install factory config
+        final InstallableResource rsrc = new InstallableResource("/configA/" + cfgFactoryPid
+ "-" + alias,
+                null, cfgData, null, InstallableResource.TYPE_PROPERTIES, 10);
+        installer.updateResources(URL_SCHEME, new InstallableResource[] {rsrc}, null);
+
+        // get factory config
+        final Configuration cfg = waitForFactoryConfiguration("After installing", cfgFactoryPid,
TIMEOUT, true);
+        assertEquals("Config value must match", "bar", cfg.getProperties().get("foo"));
+
+        // create second factory configuration
+        final Dictionary<String, Object> secondData = new Hashtable<String, Object>();
+        secondData.put("foo", "bla");
+        final InstallableResource rsrc2 = new InstallableResource("/configB/" + cfgFactoryPid
+ "-" + alias,
+                null, secondData, null, InstallableResource.TYPE_PROPERTIES, 20);
+        installer.updateResources(URL_SCHEME, new InstallableResource[] {rsrc2}, null);
+
+        sleep(200);
+
+        // get updated factory config
+        final Configuration secondCfg = waitForFactoryConfiguration("After updating", cfgFactoryPid,
TIMEOUT, true);
+        assertEquals("Config value must match", "bla", secondCfg.getProperties().get("foo"));
+
+        // remove config
+        installer.updateResources(URL_SCHEME, null, new String[] {"/configB/" + cfgFactoryPid
+ "-" + alias});
+
+        sleep(200);
+
+        final Configuration noCfg = waitForFactoryConfiguration("After deleting", cfgFactoryPid,
TIMEOUT, false);
+        assertNull("Factory configuration should be removed", noCfg);
+    }
+
+    @Test
     public void testDeferredConfigInstall() throws Exception {
         // get config admin bundle and wait for service
     	final Bundle configAdmin = this.getConfigAdminBundle();

Modified: sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/OsgiInstallerTestBase.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/OsgiInstallerTestBase.java?rev=1648985&r1=1648984&r2=1648985&view=diff
==============================================================================
--- sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/OsgiInstallerTestBase.java
(original)
+++ sling/trunk/installer/it/src/test/java/org/apache/sling/installer/it/OsgiInstallerTestBase.java
Fri Jan  2 09:32:41 2015
@@ -187,23 +187,51 @@ public class OsgiInstallerTestBase imple
         }
     }
 
-    protected Configuration findConfiguration(String pid) throws Exception {
+    /**
+     * Encode the value for the ldap filter: \, *, (, and ) should be escaped.
+     */
+    private static String encode(final String value) {
+        return value.replace("\\", "\\\\")
+                .replace("*", "\\*")
+                .replace("(", "\\(")
+                .replace(")", "\\)");
+    }
+
+    /**
+     * Find the configuration with the given pid.
+     */
+    protected Configuration findConfiguration(final String pid) throws Exception {
     	final ConfigurationAdmin ca = this.waitForConfigAdmin(true);
     	if (ca != null) {
-	    	final Configuration[] cfgs = ca.listConfigurations(null);
-	    	if (cfgs != null) {
-		    	for(Configuration cfg : cfgs) {
-		    	    try {
-    		    		if(cfg.getPid().equals(pid)) {
-    		    			return cfg;
-    		    		}
-		    	    } catch (IllegalStateException e) {}
-		    	}
+	    	final Configuration[] cfgs = ca.listConfigurations("(" + Constants.SERVICE_PID + "="
+ encode(pid) + ")");
+	    	if (cfgs != null && cfgs.length > 0 ) {
+                if ( cfgs.length == 1 ) {
+                    return cfgs[0];
+                }
+                throw new IllegalStateException("More than one configuration for " + pid);
 	    	}
     	}
     	return null;
     }
 
+    /**
+     * Find the configuration with the given factory pid.
+     */
+    protected Configuration findFactoryConfiguration(final String factoryPid) throws Exception
{
+        final ConfigurationAdmin ca = this.waitForConfigAdmin(true);
+        if (ca != null) {
+            final Configuration[] cfgs = ca.listConfigurations("("
+                    + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + encode(factoryPid) +
")");
+            if (cfgs != null && cfgs.length > 0 ) {
+                if ( cfgs.length == 1 ) {
+                    return cfgs[0];
+                }
+                throw new IllegalStateException("More than one factory configuration for
" + factoryPid);
+            }
+        }
+        return null;
+    }
+
     protected void waitForCondition(String info, long timeoutMsec, Condition c) throws Exception
{
         final long end = System.currentTimeMillis() + timeoutMsec;
         do {
@@ -261,6 +289,40 @@ public class OsgiInstallerTestBase imple
         }
         return result;
     }
+
+    protected Configuration waitForFactoryConfiguration(final String info,
+            final String factoryPid,
+            final long timeoutMsec,
+            final boolean shouldBePresent)
+    throws Exception {
+        String msg;
+        if (info == null) {
+            msg = "";
+        } else {
+            msg = info + ": ";
+        }
+
+        Configuration result = null;
+        final long start = System.currentTimeMillis();
+        final long end = start + timeoutMsec;
+        log(LogService.LOG_DEBUG, "Starting factory config check at " + start + "; ending
by " + end);
+        do {
+            result = findFactoryConfiguration(factoryPid);
+            if ((shouldBePresent && result != null) ||
+                    (!shouldBePresent && result == null)) {
+                break;
+            }
+            log(LogService.LOG_DEBUG, "Config check failed at " + System.currentTimeMillis()
+ "; sleeping");
+            sleep(25);
+        } while(System.currentTimeMillis() < end);
+
+        if (shouldBePresent && result == null) {
+            fail(msg + "Factory Configuration not found (" + factoryPid + ")");
+        } else if (!shouldBePresent && result != null) {
+            fail(msg + "Factory Configuration is still present (" + factoryPid + ")");
+        }
+        return result;
+    }
 
     protected Bundle findBundle(String symbolicName) {
     	for(Bundle b : bundleContext.getBundles()) {



Mime
View raw message