You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ja...@apache.org on 2012/07/11 12:44:07 UTC

svn commit: r1360115 [2/3] - in /ace/sandbox/marrs: org.apache.ace.client.repository.itest/ org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/RepositoryAdminTest.java org.apache.ace.deployment.itest/

Modified: ace/sandbox/marrs/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/RepositoryAdminTest.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/RepositoryAdminTest.java?rev=1360115&r1=1360114&r2=1360115&view=diff
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/RepositoryAdminTest.java (original)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/RepositoryAdminTest.java Wed Jul 11 10:44:07 2012
@@ -114,79 +114,37 @@ import org.osgi.util.tracker.ServiceTrac
 
 public class RepositoryAdminTest extends IntegrationTestBase implements EventHandler {
 
-//    @org.ops4j.pax.exam.junit.Configuration
-//    public Option[] configuration() {
-//        return options(
-//            systemProperty("org.osgi.service.http.port").value("" + TestConstants.PORT),
-//            new VMOption("-ea"),
-//            new CleanCachesOption(),
-//            junitBundles(),
-//            provision(
-//                Osgi.compendium(),
-//                Felix.dependencyManager(),
-//                jetty(),
-//                Felix.configAdmin(),
-//                Felix.preferences(),
-//                Felix.eventAdmin(),
-//                Knopflerfish.useradmin(),
-//                Knopflerfish.log(),
-//                Ace.util(),
-//                Ace.authenticationApi(),
-//                Ace.connectionFactory(),
-//                Ace.rangeApi(),
-//                Ace.log(),
-//                Ace.serverLogStore(),
-//                Ace.httplistener(),
-//                Ace.repositoryApi(),
-//                Ace.repositoryImpl(),
-//                Ace.repositoryServlet(),
-//                Ace.configuratorServeruseradmin(),
-//                Ace.obrMetadata(),
-//                Ace.obrServlet(),
-//                Ace.obrStorage(),
-//                Ace.clientRepositoryApi(),
-//                Ace.clientRepositoryImpl(),
-//                Ace.clientRepositoryHelperBase(),
-//                Ace.clientRepositoryHelperBundle(),
-//                Ace.clientRepositoryHelperConfiguration(),
-//                Ace.clientAutomation()
-//            ));
-//    }
+	private class MockUser implements User {
+        private final String m_name;
 
-	@Override
-	protected void before() throws Exception {
-        getService(SessionFactory.class).createSession("test-session-ID");
-        configureFactory("org.apache.ace.server.log.store.factory",
-            "name", "auditlog", "authentication.enabled", "false");
-    }
+        public MockUser(String name) {
+            m_name = name;
+        }
 
-    protected Component[] getDependencies() {
-        Dictionary<String, Object> topics = new Hashtable<String, Object>();
-        topics.put(EventConstants.EVENT_TOPIC, new String[] { PUBLIC_TOPIC_ROOT + "*",
-            PRIVATE_TOPIC_ROOT + "*",
-            RepositoryAdmin.PUBLIC_TOPIC_ROOT + "*",
-            RepositoryAdmin.PRIVATE_TOPIC_ROOT + "*",
-            TOPIC_ALL });
-        return new Component[] {
-            createComponent()
-                .setInterface(EventHandler.class.getName(), topics)
-                .setImplementation(this)
-                .add(createServiceDependency().setService(HttpService.class).setRequired(true))
-                .add(createServiceDependency().setService(RepositoryAdmin.class).setRequired(true))
-                .add(createServiceDependency().setService(ArtifactRepository.class).setRequired(true))
-                .add(createServiceDependency().setService(Artifact2FeatureAssociationRepository.class).setRequired(true))
-                .add(createServiceDependency().setService(FeatureRepository.class).setRequired(true))
-                .add(createServiceDependency().setService(Feature2DistributionAssociationRepository.class).setRequired(true))
-                .add(createServiceDependency().setService(DistributionRepository.class).setRequired(true))
-                .add(createServiceDependency().setService(Distribution2TargetAssociationRepository.class).setRequired(true))
-                .add(createServiceDependency().setService(TargetRepository.class).setRequired(true))
-                .add(createServiceDependency().setService(DeploymentVersionRepository.class).setRequired(true))
-                .add(createServiceDependency().setService(StatefulTargetRepository.class).setRequired(true))
-                .add(createServiceDependency().setService(LogStore.class, "(&(" + Constants.OBJECTCLASS + "=" + LogStore.class.getName() + ")(name=auditlog))").setRequired(true))
-                .add(createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true))
-        };
+        public Dictionary getCredentials() {
+            return new Properties();
+        }
+
+        public String getName() {
+            return m_name;
+        }
+
+        public Dictionary getProperties() {
+            return new Properties();
+        }
+
+        public int getType() {
+            return 0;
+        }
+
+        public boolean hasCredential(String arg0, Object arg1) {
+            return false;
+        }
     }
 
+    private static final String ENDPOINT_NAME = "/AdminRepTest";
+    private static final String HOST = "http://localhost:" + TestConstants.PORT;
+
     private volatile ConfigurationAdmin m_configAdmin; /* Injected by dependency manager */
     private volatile RepositoryAdmin m_repositoryAdmin; /* Injected by dependency manager */
     private volatile ArtifactRepository m_artifactRepository; /* Injected by dependency manager */
@@ -199,8 +157,13 @@ public class RepositoryAdminTest extends
     private volatile DeploymentVersionRepository m_deploymentVersionRepository; /* Injected by dependency manager */
     private volatile StatefulTargetRepository m_statefulTargetRepository; /* Injected by dependency manager */
     private volatile LogStore m_auditLogStore; /* Injected by dependency manager */
+    private volatile List<String> m_waitingForTopic = Collections.synchronizedList(new ArrayList<String>());
+    private volatile Semaphore m_semaphore;
+    private volatile boolean m_runAndWaitDebug = false;
+    
+    private URL m_endpoint;
 
-    public void cleanUp() throws IOException, InvalidSyntaxException, InterruptedException {
+    public void cleanUp() throws InvalidSyntaxException, InterruptedException {
         // Simply remove all objects in the repository.
         clearRepository(m_artifactRepository);
         clearRepository(m_artifact2featureRepository);
@@ -216,72 +179,36 @@ public class RepositoryAdminTest extends
             m_repositoryAdmin.logout(true);
         }
         catch (Exception ioe) {
-            // ioe.printStackTrace(System.out);
+//            ioe.printStackTrace(System.out);
         }
     }
-
+    
     public <T extends RepositoryObject> void clearRepository(ObjectRepository<T> rep) {
         for (T entity : rep.get()) {
             rep.remove(entity);
         }
-        assert rep.get().size() == 0 : "Something went wrong clearing the repository.";
+        assertEquals("Something went wrong clearing the repository.", 0, rep.get().size());
     }
 
-    /**
-     * Add a bundle, feature and distribution, associate all, remove the feature, No associations should be left.
-     * 
-     * @throws Exception
-     */
-    public void testRemoveBundleFeature() throws Exception {
-        final ArtifactObject b1 = createBasicBundleObject("thebundle", "1", null);
-        final FeatureObject g1 = createBasicFeatureObject("thefeature");
-
-        final Artifact2FeatureAssociation bg = runAndWaitForEvent(new Callable<Artifact2FeatureAssociation>() {
-            public Artifact2FeatureAssociation call() throws Exception {
-                return m_artifact2featureRepository.create("(&(" + BundleHelper.KEY_SYMBOLICNAME + "=thebundle)(|("
-                    + BundleHelper.KEY_VERSION + ">=1)(" + BundleHelper.KEY_VERSION + "=<3))(!("
-                    + BundleHelper.KEY_VERSION + "=3)))", "(name=thefeature)");
-            }
-        }, false, Artifact2FeatureAssociation.TOPIC_ADDED);
-
-        final DistributionObject l1 = createBasicDistributionObject("thedistribution");
-
-        final Feature2DistributionAssociation gtl = runAndWaitForEvent(new Callable<Feature2DistributionAssociation>() {
-            public Feature2DistributionAssociation call() throws Exception {
-                return m_feature2distributionRepository.create("(name=thefeature)", "(name=thedistribution)");
+    public void handleEvent(Event event) {
+        if (m_runAndWaitDebug) {
+            System.err.println("Received event: " + event.getTopic());
+        }
+        if (m_waitingForTopic.remove(event.getTopic())) {
+            if (m_runAndWaitDebug) {
+                System.err.println("Event was expected.");
             }
-        }, false, Feature2DistributionAssociation.TOPIC_ADDED);
-
-        assert (bg.getLeft().size() == 1) && bg.getLeft().contains(b1) : "The left side of the BG-association should be b1.";
-        assert (bg.getRight().size() == 1) && bg.getRight().contains(g1) : "The right side of the BG-association should be g1.";
-        assert (gtl.getLeft().size() == 1) && gtl.getLeft().contains(g1) : "The left side of the GtL-association should be g1.";
-        assert (gtl.getRight().size() == 1) && gtl.getRight().contains(l1) : "The right side of the GtL-association should be l1.";
-        assert bg.isSatisfied() : "The bundlefeature association should be satisfied.";
-        assert gtl.isSatisfied() : "The feature2distribution association should be satisfied.";
-        assert b1.getFeatures().size() == 1 : "Bundle b1 should be associated to one feature.";
-        assert l1.getFeatures().size() == 1 : "Distribution l1 should be associated to one feature.";
-
-        // remove the feature
-        runAndWaitForEvent(new Callable<Object>() {
-            public Object call() throws Exception {
-                m_featureRepository.remove(g1);
-                return null;
+            if ((m_semaphore != null) && m_waitingForTopic.isEmpty()) {
+                m_semaphore.release();
+                m_runAndWaitDebug = false;
             }
-        }, false, Artifact2FeatureAssociation.TOPIC_CHANGED, Feature2DistributionAssociation.TOPIC_CHANGED);
-
-        assert !gtl.isSatisfied() : "The bundlefeature association shouldn not be satisfied.";
-        assert !bg.isSatisfied() : "The feature2distribution assocation should not be satisfied.";
-
-        assert b1.getFeatures().size() == 0 : "Bundle b1 shouldn't be associated to any feature, but is associated to "
-            + b1.getFeatures();
-        assert l1.getFeatures().size() == 0 : "Distribution l1 shouldn't be associated to any feature.";
-
-        cleanUp();
+        }
     }
 
     public void testAssociationsWithMovingEndpoints() throws Exception {
         final ArtifactObject b1 = createBasicBundleObject("thebundle", "1", null);
         final FeatureObject g1 = createBasicFeatureObject("thefeature");
+        
         final Artifact2FeatureAssociation bg = runAndWaitForEvent(new Callable<Artifact2FeatureAssociation>() {
             public Artifact2FeatureAssociation call() throws Exception {
                 Map<String, String> properties = new HashMap<String, String>();
@@ -290,11 +217,11 @@ public class RepositoryAdminTest extends
             }
         }, false, Artifact2FeatureAssociation.TOPIC_ADDED);
 
-        assert (bg.getLeft().size() == 1) && bg.getLeft().contains(b1) : "The left side of the association should now be b1; we find "
-            + bg.getLeft().size() + " bundles on the left side of the association.";
-        assert (bg.getRight().size() == 1) && bg.getRight().contains(g1) : "The right side of the association should now be g1.";
-        assert b1.getFeatures().get(0) == g1 : "b1 should be assocated with g1";
-        assert g1.getArtifacts().get(0) == b1 : "g1 should be assocated with b1";
+        assertTrue("The left side of the association should now be b1; we find "
+            + bg.getLeft().size() + " bundles on the left side of the association.", (bg.getLeft().size() == 1) && bg.getLeft().contains(b1));
+        assertTrue("The right side of the association should now be g1.", (bg.getRight().size() == 1) && bg.getRight().contains(g1));
+        assertEquals("b1 should be assocated with g1", g1, b1.getFeatures().get(0));
+        assertEquals("g1 should be assocated with b1", b1, g1.getArtifacts().get(0));
 
         final ArtifactObject b2 = runAndWaitForEvent(new Callable<ArtifactObject>() {
             public ArtifactObject call() throws Exception {
@@ -302,40 +229,40 @@ public class RepositoryAdminTest extends
             }
         }, false, Artifact2FeatureAssociation.TOPIC_CHANGED);
 
-        assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b1) : "The left side of the association should no longer be b1; we find "
-            + bg.getLeft().size() + " bundles.";
-        assert (bg.getLeft().size() == 1) && bg.getLeft().contains(b2) : "The left side of the association should now be b2.";
-        assert (bg.getRight().size() == 1) && bg.getRight().contains(g1) : "The right side of the association should now be g1.";
-        assert b1.getFeatures().size() == 0 : "b1 should not be associated with any feature.";
-        assert b2.getFeatures().get(0) == g1 : "b2 should now be assocation with g1";
-        assert g1.getArtifacts().get(0) == b2 : "g1 should be assocation with b2";
-        assert g1.getArtifacts().size() == 1 : "g1 should be associated with one bundle";
+        assertTrue("The left side of the association should no longer be b1; we find "
+            + bg.getLeft().size() + " bundles.", (bg.getLeft().size() == 1) && !bg.getLeft().contains(b1));
+        assertTrue("The left side of the association should now be b2.", (bg.getLeft().size() == 1) && bg.getLeft().contains(b2));
+        assertTrue("The right side of the association should now be g1.", (bg.getRight().size() == 1) && bg.getRight().contains(g1));
+        assertEquals("b1 should not be associated with any feature.", 0, b1.getFeatures().size());
+        assertEquals("b2 should now be assocation with g1", g1, b2.getFeatures().get(0));
+        assertEquals("g1 should be assocation with b2", b2, g1.getArtifacts().get(0));
+        assertEquals("g1 should be associated with one bundle", 1, g1.getArtifacts().size());
 
         ArtifactObject b3 = createBasicBundleObject("thebundle", "3", null);
 
-        assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b1) : "The left side of the association should no longer be b1.";
-        assert (bg.getLeft().size() == 1) && bg.getLeft().contains(b2) : "The left side of the association should now be b2.";
-        assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b3) : "The left side of the association should not be b3.";
-        assert (bg.getRight().size() == 1) && bg.getRight().contains(g1) : "The right side of the association should now be g1.";
-        assert b1.getFeatures().size() == 0 : "b1 should not be associated with any feature.";
-        assert b2.getFeatures().get(0) == g1 : "b2 should now be assocation with g1";
-        assert b3.getFeatures().size() == 0 : "b3 should not be associated with any feature.";
-        assert g1.getArtifacts().get(0) == b2 : "g1 should be assocation with b2";
-        assert g1.getArtifacts().size() == 1 : "g1 should be associated with one bundle";
+        assertTrue("The left side of the association should no longer be b1.", (bg.getLeft().size() == 1) && !bg.getLeft().contains(b1));
+        assertTrue("The left side of the association should now be b2.", (bg.getLeft().size() == 1) && bg.getLeft().contains(b2));
+        assertTrue("The left side of the association should not be b3.", (bg.getLeft().size() == 1) && !bg.getLeft().contains(b3));
+        assertTrue("The right side of the association should now be g1.", (bg.getRight().size() == 1) && bg.getRight().contains(g1));
+        assertEquals("b1 should not be associated with any feature.", 0, b1.getFeatures().size());
+        assertEquals("b2 should now be assocation with g1", g1, b2.getFeatures().get(0));
+        assertEquals("b3 should not be associated with any feature.", 0, b3.getFeatures().size());
+        assertEquals("g1 should be assocation with b2", b2, g1.getArtifacts().get(0));
+        assertEquals("g1 should be associated with one bundle", 1, g1.getArtifacts().size());
 
         ArtifactObject b15 = createBasicBundleObject("thebundle", "1.5", null);
 
-        assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b1) : "The left side of the association should no longer be b1.";
-        assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b15) : "The left side of the association should not be b15.";
-        assert (bg.getLeft().size() == 1) && bg.getLeft().contains(b2) : "The left side of the association should now be b2.";
-        assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b3) : "The left side of the association should not be b3.";
-        assert (bg.getRight().size() == 1) && bg.getRight().contains(g1) : "The right side of the association should now be g1.";
-        assert b1.getFeatures().size() == 0 : "b1 should not be associated with any feature.";
-        assert b15.getFeatures().size() == 0 : "b15 should not be associated with any feature.";
-        assert b2.getFeatures().get(0) == g1 : "b2 should now be assocation with g1";
-        assert b3.getFeatures().size() == 0 : "b3 should not be associated with any feature.";
-        assert g1.getArtifacts().get(0) == b2 : "g1 should be assocation with b2";
-        assert g1.getArtifacts().size() == 1 : "g1 should be associated with one bundle";
+        assertTrue("The left side of the association should no longer be b1.", (bg.getLeft().size() == 1) && !bg.getLeft().contains(b1));
+        assertTrue("The left side of the association should not be b15.", (bg.getLeft().size() == 1) && !bg.getLeft().contains(b15));
+        assertTrue("The left side of the association should now be b2.", (bg.getLeft().size() == 1) && bg.getLeft().contains(b2));
+        assertTrue("The left side of the association should not be b3.", (bg.getLeft().size() == 1) && !bg.getLeft().contains(b3));
+        assertTrue("The right side of the association should now be g1.", (bg.getRight().size() == 1) && bg.getRight().contains(g1));
+        assertEquals("b1 should not be associated with any feature.", 0, b1.getFeatures().size());
+        assertEquals("b15 should not be associated with any feature.", 0, b15.getFeatures().size());
+        assertEquals("b2 should now be assocation with g1", g1, b2.getFeatures().get(0));
+        assertEquals("b3 should not be associated with any feature.", 0, b3.getFeatures().size());
+        assertEquals("g1 should be assocation with b2", b2, g1.getArtifacts().get(0));
+        assertEquals("g1 should be associated with one bundle", 1, g1.getArtifacts().size());
 
         runAndWaitForEvent(new Callable<Object>() {
             public Object call() throws Exception {
@@ -346,942 +273,640 @@ public class RepositoryAdminTest extends
 
         // note that we cannot test anything for b2: this has been removed, and now has no
         // defined state.
-        assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b1) : "The left side of the association should no longer be b1.";
-        assert (bg.getLeft().size() == 1) && bg.getLeft().contains(b15) : "The left side of the association should now be b15.";
-        assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b3) : "The left side of the association should not be b3.";
-        assert (bg.getRight().size() == 1) && bg.getRight().contains(g1) : "The right side of the association should now be g1.";
-        assert b1.getFeatures().size() == 0 : "b1 should not be associated with any feature.";
-        assert b15.getFeatures().get(0) == g1 : "b15 should now be assocation with g1";
-        assert b3.getFeatures().size() == 0 : "b3 should not be associated with any feature.";
-        assert g1.getArtifacts().get(0) == b15 : "g1 should be assocation with b15";
-        assert g1.getArtifacts().size() == 1 : "g1 should be associated with one bundle";
+        assertTrue("The left side of the association should no longer be b1.", (bg.getLeft().size() == 1) && !bg.getLeft().contains(b1));
+        assertTrue("The left side of the association should now be b15.", (bg.getLeft().size() == 1) && bg.getLeft().contains(b15));
+        assertTrue("The left side of the association should not be b3.", (bg.getLeft().size() == 1) && !bg.getLeft().contains(b3));
+        assertTrue("The right side of the association should now be g1.", (bg.getRight().size() == 1) && bg.getRight().contains(g1));
+        assertEquals("b1 should not be associated with any feature.", 0, b1.getFeatures().size());
+        assertEquals("b15 should now be assocation with g1", g1, b15.getFeatures().get(0));
+        assertEquals("b3 should not be associated with any feature.", 0, b3.getFeatures().size());
+        assertEquals("g1 should be assocation with b15", b15, g1.getArtifacts().get(0));
+        assertEquals("g1 should be associated with one bundle", 1, g1.getArtifacts().size());
 
         cleanUp();
     }
 
-    private static final String ENDPOINT = "/AdminRepTest";
-    private static final String HOST = "http://localhost:" + TestConstants.PORT;
-
-    /**
-     * Tests the behavior with logging in and out (with multiple users), and communication
-     * with the server.
-     * 
-     * @throws Exception
-     */
-    public void testRepositoryAdmin() throws Exception {
-        final User user1 = new MockUser("user1");
-        final User user2 = new MockUser("user2");
+    public void testAutoApprove() throws Exception {
+        User user = new MockUser("user");
 
         startRepositoryService();
 
         addRepository("storeInstance", "apache", "store", true);
         addRepository("targetInstance", "apache", "target", true);
+        addRepository("deploymentInstance", "apache", "deployment", true);
 
-        try {
-            m_repositoryAdmin.checkout();
-            assert false : "Without being logged in, it should not be possible to do checkout.";
-        }
-        catch (IllegalStateException ise) {
-            // expected
-        }
-
-        final RepositoryAdminLoginContext loginContext1 = m_repositoryAdmin.createLoginContext(user1);
-        loginContext1
-            .add(loginContext1.createShopRepositoryContext()
-                .setLocation(new URL(HOST + ENDPOINT)).setCustomer("apache").setName("store").setWriteable())
-            .add(loginContext1.createTargetRepositoryContext()
-                .setLocation(new URL(HOST + ENDPOINT)).setCustomer("apache").setName("target").setWriteable());
-        m_repositoryAdmin.login(loginContext1);
-
-        assert !m_repositoryAdmin.isCurrent() : "When first logging in without checking out, the repository cannot be current.";
-        assert !m_repositoryAdmin.isModified() : "Immediately after login, the repository not is modified.";
+        RepositoryAdminLoginContext loginContext = m_repositoryAdmin.createLoginContext(user);
+        loginContext
+            .add(loginContext.createShopRepositoryContext()
+                .setLocation(m_endpoint).setCustomer("apache").setName("store").setWriteable())
+            .add(loginContext.createTargetRepositoryContext()
+                .setLocation(m_endpoint).setCustomer("apache").setName("target").setWriteable())
+            .add(loginContext.createDeploymentRepositoryContext()
+                .setLocation(m_endpoint).setCustomer("apache").setName("deployment").setWriteable());
 
-        try {
-            m_repositoryAdmin.commit();
-            assert false : "We should not be able to commit before we check something out.";
-        }
-        catch (IllegalStateException e) {
-            // expected
-        }
+        m_repositoryAdmin.login(loginContext);
 
         runAndWaitForEvent(new Callable<Object>() {
             public Object call() throws Exception {
-                m_repositoryAdmin.checkout();
+                createBasicTargetObject("testAutoApproveTarget");
                 return null;
             }
-        }, false, RepositoryAdmin.TOPIC_REFRESH);
+        }, false, TargetObject.TOPIC_ADDED, TOPIC_ADDED);
 
-        assert m_repositoryAdmin.isCurrent() : "After initial checkout, the repository is current.";
-        assert !m_repositoryAdmin.isModified() : "Immediately after login, the repository cannot be modified.";
+        final StatefulTargetObject sgo =
+            m_statefulTargetRepository.get(
+                m_bundleContext.createFilter("(" + TargetObject.KEY_ID + "=" + "testAutoApproveTarget)")).get(0);
 
-        ArtifactObject b1 = runAndWaitForEvent(new Callable<ArtifactObject>() {
-            public ArtifactObject call() throws Exception {
-                return createBasicBundleObject("bundle1");
+        // Set up some deployment information for the target.
+        final FeatureObject g = runAndWaitForEvent(new Callable<FeatureObject>() {
+            public FeatureObject call() throws Exception {
+                ArtifactObject b = createBasicBundleObject("myBundle", "1.0", null);
+                FeatureObject g = createBasicFeatureObject("myFeature");
+                DistributionObject l = createBasicDistributionObject("myDistribution");
+                m_artifact2featureRepository.create(b, g);
+                m_feature2distributionRepository.create(g, l);
+                m_distribution2targetRepository.create(l, sgo.getTargetObject());
+                return g;
             }
-        }, false, ArtifactObject.TOPIC_ADDED, RepositoryAdmin.TOPIC_STATUSCHANGED);
-
-        assert m_repositoryAdmin.isCurrent() : "After initial checkout, the repository is current.";
-        assert m_repositoryAdmin.isModified() : "We have added a bundle, so the repository is modified.";
-        assert m_artifactRepository.get().size() == 1;
-        assert m_repositoryAdmin.getWorkingState(b1).equals(WorkingState.New) : "We expect the working state of our bundle to be New, but it is "
-            + m_repositoryAdmin.getWorkingState(b1);
-        assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New) == 1 : "We expect one bundle object in working state New, but we find "
-            + m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New);
-        assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed) == 0 : "We expect 0 bundle object in working state Changed, but we find "
-            + m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed);
-        assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Unchanged) == 0 : "We expect 0 bundle object in working state New, but we find "
-            + m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed);
+        }, false, ArtifactObject.TOPIC_ADDED, FeatureObject.TOPIC_ADDED, DistributionObject.TOPIC_ADDED,
+            Artifact2FeatureAssociation.TOPIC_ADDED, Feature2DistributionAssociation.TOPIC_ADDED,
+            Distribution2TargetAssociation.TOPIC_ADDED, TOPIC_STATUS_CHANGED);
 
-        runAndWaitForEvent(new Callable<Object>() {
-            public Object call() throws Exception {
-                m_repositoryAdmin.logout(false);
-                return null;
-            }
-        }, false, RepositoryAdmin.TOPIC_LOGOUT);
+        assertTrue("We added some deployment information, so the target should need approval.", sgo.needsApprove());
 
-        cleanUp();
+        sgo.setAutoApprove(true);
 
-        assert m_artifactRepository.get().size() == 0;
+        assertTrue("Turning on the autoapprove should not automatically approve whatever was waiting.", sgo.needsApprove());
 
         runAndWaitForEvent(new Callable<Object>() {
             public Object call() throws Exception {
-                m_repositoryAdmin.login(loginContext1);
+                sgo.approve();
                 return null;
             }
-        }, false, RepositoryAdmin.TOPIC_LOGIN);
-
-        assert m_repositoryAdmin.isCurrent() : "There has not been another commit in between, so we are still current.";
-        assert m_repositoryAdmin.isModified() : "We have made changes since the last commit, so the repository must be modified.";
-        assert m_artifactRepository.get().size() == 1;
-        assert m_repositoryAdmin.getWorkingState(b1).equals(WorkingState.New) : "We expect the working state of our bundle to be New, but it is "
-            + m_repositoryAdmin.getWorkingState(b1);
-        assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New) == 1 : "We expect one bundle object in working state New, but we find "
-            + m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New);
-        assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed) == 0 : "We expect 0 bundle object in working state Changed, but we find "
-            + m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed);
-        assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Unchanged) == 0 : "We expect 0 bundle object in working state New, but we find "
-            + m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed);
-
-        m_repositoryAdmin.commit();
+        }, false, TOPIC_STATUS_CHANGED);
 
-        assert m_repositoryAdmin.isCurrent() : "After a commit, the repository must be current.";
-        assert !m_repositoryAdmin.isModified() : "After a commit, the repository cannot be modified.";
+        assertFalse("We approved the new version by hand, so we should not need approval.", sgo.needsApprove());
 
         runAndWaitForEvent(new Callable<Object>() {
             public Object call() throws Exception {
-                m_repositoryAdmin.logout(false);
+                ArtifactObject b = createBasicBundleObject("myBundle2", "1.0", null);
+                m_artifact2featureRepository.create(b, g);
                 return null;
             }
-        }, false, RepositoryAdmin.TOPIC_LOGOUT);
-
-        cleanUp();
+        }, false, ArtifactObject.TOPIC_ADDED, Artifact2FeatureAssociation.TOPIC_ADDED, TOPIC_STATUS_CHANGED,
+            TOPIC_STATUS_CHANGED);
 
-        final RepositoryAdminLoginContext loginContext2 = m_repositoryAdmin.createLoginContext(user2);
-        loginContext2
-            .add(loginContext2.createShopRepositoryContext()
-                .setLocation(new URL(HOST + ENDPOINT)).setCustomer("apache").setName("store").setWriteable())
-            .add(loginContext2.createTargetRepositoryContext()
-                .setLocation(new URL(HOST + ENDPOINT)).setCustomer("apache").setName("target").setWriteable());
+        assertFalse("With autoapprove on, adding new deployment information should still not need approval (at least, after the two CHANGED events).", sgo.needsApprove());
 
         runAndWaitForEvent(new Callable<Object>() {
             public Object call() throws Exception {
-                m_repositoryAdmin.login(loginContext2);
+                m_statefulTargetRepository.unregister(sgo.getID());
                 return null;
             }
-        }, false, RepositoryAdmin.TOPIC_LOGIN);
+        }, false, TOPIC_STATUS_CHANGED, TOPIC_REMOVED);
 
-        assert m_artifactRepository.get().size() == 0;
+        try {
+            removeAllRepositories();
+        }
+        catch (Exception e) {
+            // Not much we can do...
+            e.printStackTrace(System.err);
+        }
+        cleanUp();
+    }
 
-        runAndWaitForEvent(new Callable<Object>() {
-            public Object call() throws Exception {
-                m_repositoryAdmin.checkout();
-                return null;
-            }
-        }, false, RepositoryAdmin.TOPIC_REFRESH);
+    /*
+     * The auto target operator is not yet session-aware; therefore, this test will fail. We should decide what
+     * to do with this operator.
+     */
+    public void testAutoTargetOperator() throws Exception {
+        startRepositoryService();
 
-        assert m_artifactRepository.get().size() == 1 : "We expect to find 1 bundle after checkout, but we find "
-            + m_artifactRepository.get().size();
-        assert m_repositoryAdmin.isCurrent() : "After a checkout, without changing anything, the repository must be current.";
-        assert !m_repositoryAdmin.isModified() : "After a checkout, without changing anything, the repository cannot be modified.";
+        addRepository("storeInstance", "apache", "store", true);
+        addRepository("targetInstance", "apache", "target", true);
+        addRepository("deploymentInstance", "apache", "deployment", true);
 
-        ArtifactObject b2 = runAndWaitForEvent(new Callable<ArtifactObject>() {
-            public ArtifactObject call() throws Exception {
-                return createBasicBundleObject("bundle2");
-            }
-        }, false, ArtifactObject.TOPIC_ADDED, RepositoryAdmin.TOPIC_STATUSCHANGED);
+        // configure automation bundle; new configuration properties; bundle will start
+        final Properties props = new Properties();
+        props.put("registerTargetFilter", "(id=anotherGate*)");
+        props.put("approveTargetFilter", "(id=DO_NOTHING)");
+        props.put("autoApproveTargetFilter", "(id=anotherGate*)");
+        props.put("commitRepositories", "true");
+        props.put("targetRepository", "target");
+        props.put("deploymentRepository", "deployment");
+        props.put("storeRepository", "store");
+        props.put("customerName", "apache");
+        props.put("hostName", HOST);
+        props.put("endpoint", ENDPOINT_NAME);
 
-        assert m_artifactRepository.get().size() == 2;
-        assert m_repositoryAdmin.isCurrent() : "After changing something in memory without flushing it, the repository still is current.";
-        assert m_repositoryAdmin.isModified() : "We have added something, so the repository is modified.";
-        assert m_repositoryAdmin.getWorkingState(b1).equals(WorkingState.Unchanged) : "We expect the working state of our bundle1 to be Unchanged, but it is "
-            + m_repositoryAdmin.getWorkingState(b1);
-        assert m_repositoryAdmin.getWorkingState(b2).equals(WorkingState.New) : "We expect the working state of our bundle2 to be New, but it is "
-            + m_repositoryAdmin.getWorkingState(b1);
-        assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New) == 1 : "We expect one bundle object in working state New, but we find "
-            + m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New);
-        assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed) == 0 : "We expect 0 bundle object in working state Changed, but we find "
-            + m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed);
-        assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Unchanged) == 1 : "We expect 1 bundle object in working state New, but we find "
-            + m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed);
+        final Configuration config = m_configAdmin.getConfiguration("org.apache.ace.client.automation", null);
 
+        /*
+         * First test the basic scenario where we create some auditlog data, this target should be auto-registered after max 1 sec.
+         */
         runAndWaitForEvent(new Callable<Object>() {
             public Object call() throws Exception {
-                m_repositoryAdmin.logout(false);
+                config.update(props);
                 return null;
             }
-        }, false, RepositoryAdmin.TOPIC_LOGOUT);
+        }, true, RepositoryAdmin.TOPIC_LOGIN);
+
+        doAutoTargetReg();
 
         runAndWaitForEvent(new Callable<Object>() {
             public Object call() throws Exception {
-                m_repositoryAdmin.login(loginContext1);
+                config.delete();
                 return null;
             }
-        }, false, RepositoryAdmin.TOPIC_LOGIN);
-
-        assert m_artifactRepository.get().size() == 1 : "We expect 1 item in the bundle repository, in stead of "
-            + m_artifactRepository.get().size();
-
-        runAndWaitForEvent(new Callable<Object>() {
-            public Object call() throws Exception {
-                m_repositoryAdmin.logout(false);
-                return null;
-            }
-        }, false, RepositoryAdmin.TOPIC_LOGOUT);
-
-        runAndWaitForEvent(new Callable<Object>() {
-            public Object call() throws Exception {
-                m_repositoryAdmin.login(loginContext2);
-                return null;
-            }
-        }, false, RepositoryAdmin.TOPIC_LOGIN);
-
-        assert m_artifactRepository.get().size() == 2 : "We expect 2 items in the bundle repository, in stead of "
-            + m_artifactRepository.get().size();
-
-        runAndWaitForEvent(new Callable<Object>() {
-            public Object call() throws Exception {
-                m_repositoryAdmin.revert();
-                return null;
-            }
-        }, false, RepositoryAdmin.TOPIC_REFRESH, RepositoryAdmin.TOPIC_STATUSCHANGED);
-
-        assert m_artifactRepository.get().size() == 1 : "We expect 1 item in the bundle repository, in stead of "
-            + m_artifactRepository.get().size();
+        }, false, RepositoryAdmin.TOPIC_LOGOUT);
 
+        // Remove all repositories
         try {
             removeAllRepositories();
         }
         catch (Exception e) {
             // Not much we can do...
-            e.printStackTrace(System.err);
         }
 
         cleanUp();
     }
 
-    public void testAutoApprove() throws Exception {
-        User user = new MockUser("user");
+    public void testImportArtifactGeneralBundle() throws Exception {
+        // Use a valid JAR file, without a Bundle-SymbolicName header.
+        Manifest manifest = new Manifest();
+        Attributes attributes = manifest.getMainAttributes();
+        attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1");
+        attributes.putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
 
-        startRepositoryService();
+        File temp = File.createTempFile("org.apache.ace.test1", ".jar");
+        temp.deleteOnExit();
+        JarOutputStream jos = new JarOutputStream(new FileOutputStream(temp), manifest);
+        jos.close();
 
-        addRepository("storeInstance", "apache", "store", true);
-        addRepository("targetInstance", "apache", "target", true);
-        addRepository("deploymentInstance", "apache", "deployment", true);
+        try {
+            m_artifactRepository.importArtifact(temp.toURI().toURL(), true);
+            fail("Without a Bundle-SymbolicName header, the BundleHelper cannot recognize this bundle.");
+        }
+        catch (IllegalArgumentException re) {
+            // expected
+        }
 
-        RepositoryAdminLoginContext loginContext = m_repositoryAdmin.createLoginContext(user);
-        loginContext
-            .add(loginContext.createShopRepositoryContext()
-                .setLocation(new URL(HOST + ENDPOINT)).setCustomer("apache").setName("store").setWriteable())
-            .add(loginContext.createTargetRepositoryContext()
-                .setLocation(new URL(HOST + ENDPOINT)).setCustomer("apache").setName("target").setWriteable())
-            .add(loginContext.createDeploymentRepositoryContext()
-                .setLocation(new URL(HOST + ENDPOINT)).setCustomer("apache").setName("deployment").setWriteable());
+        try {
+            m_artifactRepository.importArtifact(temp.toURI().toURL(), "notTheBundleMime", true);
+            fail("We have given an illegal mimetype, so no recognizer or helper can be found.");
+        }
+        catch (IllegalArgumentException re) {
+            // expected
+        }
 
-        m_repositoryAdmin.login(loginContext);
+        // Use a valid JAR file, with a Bundle-SymbolicName header, but do not supply an OBR.
+        attributes.putValue(BundleHelper.KEY_SYMBOLICNAME, "org.apache.ace.test" + System.currentTimeMillis());
 
-        runAndWaitForEvent(new Callable<Object>() {
-            public Object call() throws Exception {
-                createBasicTargetObject("testAutoApproveTarget");
-                return null;
-            }
-        }, false, TargetObject.TOPIC_ADDED, TOPIC_ADDED);
+        temp = File.createTempFile("org.apache.ace.test2", ".jar");
+        temp.deleteOnExit();
+        jos = new JarOutputStream(new FileOutputStream(temp), manifest);
+        jos.close();
 
-        final StatefulTargetObject sgo =
-            m_statefulTargetRepository.get(
-                m_bundleContext.createFilter("(" + TargetObject.KEY_ID + "=" + "testAutoApproveTarget)")).get(0);
+        try {
+            m_artifactRepository.importArtifact(temp.toURI().toURL(), true);
+            fail("No OBR has been started, so the artifact repository should complain that there is no storage available.");
+        }
+        catch (IOException ise) {
+            // expected
+        }
 
-        // Set up some deployment information for the target.
-        final FeatureObject g = runAndWaitForEvent(new Callable<FeatureObject>() {
-            public FeatureObject call() throws Exception {
-                ArtifactObject b = createBasicBundleObject("myBundle", "1.0", null);
-                FeatureObject g = createBasicFeatureObject("myFeature");
-                DistributionObject l = createBasicDistributionObject("myDistribution");
-                m_artifact2featureRepository.create(b, g);
-                m_feature2distributionRepository.create(g, l);
-                m_distribution2targetRepository.create(l, sgo.getTargetObject());
-                return g;
-            }
-        }, false, ArtifactObject.TOPIC_ADDED, FeatureObject.TOPIC_ADDED, DistributionObject.TOPIC_ADDED,
-            Artifact2FeatureAssociation.TOPIC_ADDED, Feature2DistributionAssociation.TOPIC_ADDED,
-            Distribution2TargetAssociation.TOPIC_ADDED, TOPIC_STATUS_CHANGED);
+        // Supply the OBR.
+        addObr("/obr", "store");
+        m_artifactRepository.setObrBase(new URL(HOST + "/obr/"));
 
-        assert sgo.needsApprove() : "We added some deployment information, so the target should need approval.";
+        m_artifactRepository.importArtifact(temp.toURI().toURL(), true);
 
-        sgo.setAutoApprove(true);
+        assertTrue(m_artifactRepository.get().size() == 1);
+        assertTrue(m_artifactRepository.getResourceProcessors().size() == 0);
 
-        assert sgo.needsApprove() : "Turning on the autoapprove should not automatically approve whatever was waiting.";
+        // Create a JAR file which looks like a resource processor supplying bundle.
+        attributes.putValue(BundleHelper.KEY_RESOURCE_PROCESSOR_PID, "someProcessor");
+        attributes.putValue(BundleHelper.KEY_VERSION, "1.0.0.processor");
 
-        runAndWaitForEvent(new Callable<Object>() {
-            public Object call() throws Exception {
-                sgo.approve();
-                return null;
-            }
-        }, false, TOPIC_STATUS_CHANGED);
+        temp = File.createTempFile("org.apache.ace.test3", ".jar");
+        temp.deleteOnExit();
+        jos = new JarOutputStream(new FileOutputStream(temp), manifest);
+        jos.close();
 
-        assert !sgo.needsApprove() : "We approved the new version by hand, so we should not need approval.";
+        m_artifactRepository.importArtifact(temp.toURI().toURL(), true);
 
-        runAndWaitForEvent(new Callable<Object>() {
-            public Object call() throws Exception {
-                ArtifactObject b = createBasicBundleObject("myBundle2", "1.0", null);
-                m_artifact2featureRepository.create(b, g);
-                return null;
-            }
-        }, false, ArtifactObject.TOPIC_ADDED, Artifact2FeatureAssociation.TOPIC_ADDED, TOPIC_STATUS_CHANGED,
-            TOPIC_STATUS_CHANGED);
+        assertTrue(m_artifactRepository.get().size() == 1);
+        assertTrue(m_artifactRepository.getResourceProcessors().size() == 1);
 
-        assert !sgo.needsApprove() : "With autoapprove on, adding new deployment information should still not need approval (at least, after the two CHANGED events).";
+        deleteObr("/obr");
+    }
 
-        runAndWaitForEvent(new Callable<Object>() {
-            public Object call() throws Exception {
-                m_statefulTargetRepository.unregister(sgo.getID());
-                return null;
-            }
-        }, false, TOPIC_STATUS_CHANGED, TOPIC_REMOVED);
+    public void testImportArtifactInvalidURL() throws Exception {
+        try {
+            m_artifactRepository.importArtifact(null, true);
+            fail("A null URL cannot be imported into an artifact repository.");
+        }
+        catch (IllegalArgumentException iae) {
+            // expected
+        }
+
+        URL invalidfile = new URL("file:/thisfilecannotexist");
 
         try {
-            removeAllRepositories();
+            m_artifactRepository.importArtifact(invalidfile, true);
+            fail("An illegal URL should result in an error.");
         }
-        catch (Exception e) {
-            // Not much we can do...
-            e.printStackTrace(System.err);
+        catch (IllegalArgumentException iae) {
+            // expected
         }
+
         cleanUp();
     }
 
-    public void testStateful() throws Exception {
-        User user = new MockUser("user");
+    public void testLoginLogoutAndLoginOnceAgainWhileCreatingAnAssociation() throws IOException, InterruptedException,
+        InvalidSyntaxException {
+        User user1 = new MockUser("user1");
 
         startRepositoryService();
 
         addRepository("storeInstance", "apache", "store", true);
         addRepository("targetInstance", "apache", "target", true);
-        addRepository("deploymentInstance", "apache", "deployment", true);
 
-        RepositoryAdminLoginContext loginContext = m_repositoryAdmin.createLoginContext(user);
-        loginContext
-            .add(loginContext.createShopRepositoryContext()
-                .setLocation(new URL(HOST + ENDPOINT)).setCustomer("apache").setName("store").setWriteable())
-            .add(loginContext.createTargetRepositoryContext()
-                .setLocation(new URL(HOST + ENDPOINT)).setCustomer("apache").setName("target").setWriteable())
-            .add(loginContext.createDeploymentRepositoryContext()
-                .setLocation(new URL(HOST + ENDPOINT)).setCustomer("apache").setName("deployment").setWriteable());
+        final RepositoryAdminLoginContext loginContext1 = m_repositoryAdmin.createLoginContext(user1);
+        loginContext1
+            .add(loginContext1.createShopRepositoryContext()
+                .setLocation(m_endpoint).setCustomer("apache").setName("store").setWriteable())
+            .add(loginContext1.createTargetRepositoryContext()
+                .setLocation(m_endpoint).setCustomer("apache").setName("target").setWriteable());
 
-        m_repositoryAdmin.login(loginContext);
+        m_repositoryAdmin.login(loginContext1);
 
-        /*
-         * First, test some functionality without auditlog data.
-         * I would prefer to test without an auditlog present at all, but that
-         * is not so easily done.
-         */
-        doStatefulCreateRemove();
-        doStatefulSetAutoApprove();
-        doStatefulApprove();
+        FeatureObject g1 = createBasicFeatureObject("feature1");
+        DistributionObject l1 = createBasicDistributionObject("distribution1");
 
-        doStatefulAuditlog();
-        doStatefulAuditAndRegister();
-        doStatefulAuditAndRemove();
-        doStrangeNamesInTargets();
+        m_feature2distributionRepository.create(g1, l1);
+
+        m_repositoryAdmin.logout(false);
+
+        m_repositoryAdmin.login(loginContext1);
 
         try {
             removeAllRepositories();
         }
-        catch (Exception e) {
-            // Not much we can do...
-            e.printStackTrace(System.err);
+        catch (IOException ioe) {
+            // too bad.
         }
-
-        cleanUp();
     }
 
-    private void doStatefulSetAutoApprove() throws Exception {
+    /**
+     * Tests read only repository access: marking a repository as readonly for a login should
+     * mean that it does not get committed, but local changes will stay around between logins.
+     */
+    public void testReadOnlyRepositoryAccess() throws Exception {
+        User user1 = new MockUser("user3");
 
-        // register target with
-        final Map<String, String> attr = new HashMap<String, String>();
-        attr.put(TargetObject.KEY_ID, "a_target");
-        attr.put(TargetObject.KEY_AUTO_APPROVE, String.valueOf(true));
-        final Map<String, String> tags = new HashMap<String, String>();
+        startRepositoryService();
 
-        final StatefulTargetObject sgo = runAndWaitForEvent(new Callable<StatefulTargetObject>() {
-            public StatefulTargetObject call() throws Exception {
-                return m_statefulTargetRepository.preregister(attr, tags);
-            }
-        }, false, TargetObject.TOPIC_ADDED, TOPIC_ADDED);
+        addRepository("storeInstance", "apache", "store", true);
+        addRepository("targetInstance", "apache", "target", true);
 
-        assert m_targetRepository.get().size() == 1 : "We expect to find exactly one target in the repository, but we find "
-            + m_targetRepository.get().size();
-        assert m_statefulTargetRepository.get().size() == 1 : "We expect to find exactly one stateful target in the repository, but we find "
-            + m_statefulTargetRepository.get().size();
+        final RepositoryAdminLoginContext loginContext1 = m_repositoryAdmin.createLoginContext(user1);
+        loginContext1
+            .add(loginContext1.createShopRepositoryContext()
+                .setLocation(m_endpoint).setCustomer("apache").setName("store").setWriteable())
+            .add(loginContext1.createTargetRepositoryContext()
+                .setLocation(m_endpoint).setCustomer("apache").setName("target"));
 
-        assert sgo.getAutoApprove() : "The target should have auto approved value: true but got: false.";
+        m_repositoryAdmin.login(loginContext1);
 
-        sgo.setAutoApprove(false);
+        m_repositoryAdmin.checkout();
 
-        assert !sgo.getAutoApprove() : "The target should have auto approved value: false but got: true.";
+        createBasicFeatureObject("feature1");
+        createBasicTargetObject("target1");
 
-        // clean up
-        runAndWaitForEvent(new Callable<Object>() {
-            public Object call() throws Exception {
-                m_statefulTargetRepository.unregister(sgo.getID());
-                return null;
-            }
-        }, false, TargetObject.TOPIC_REMOVED, TOPIC_REMOVED);
-    }
+        m_repositoryAdmin.logout(false);
 
-    private void doStatefulCreateRemove() throws Exception {
-        final Map<String, String> attr = new HashMap<String, String>();
-        attr.put(TargetObject.KEY_ID, "myNewTarget1");
-        final Map<String, String> tags = new HashMap<String, String>();
+        m_repositoryAdmin.login(loginContext1);
 
-        try {
-            m_statefulTargetRepository.create(attr, tags);
-            assert false : "Creating a stateful target repository should not be allowed.";
-        }
-        catch (UnsupportedOperationException uoe) {
-            // expected
-        }
+        assertEquals("We expect our own feature object in the repository;", 1, m_featureRepository.get().size());
+        assertEquals("We expect our own target object in the repository;", 1, m_targetRepository.get().size());
 
-        final StatefulTargetObject sgo = runAndWaitForEvent(new Callable<StatefulTargetObject>() {
-            public StatefulTargetObject call() throws Exception {
-                return m_statefulTargetRepository.preregister(attr, tags);
-            }
-        }, false, TargetObject.TOPIC_ADDED, TOPIC_ADDED);
+        m_repositoryAdmin.commit();
+
+        m_repositoryAdmin.logout(false);
 
-        assert m_targetRepository.get().size() == 1 : "We expect to find exactly one target in the repository, but we find " + m_targetRepository.get().size();
-        assert m_statefulTargetRepository.get().size() == 1 : "We expect to find exactly one stateful target in the repository, but we find " + m_statefulTargetRepository.get().size();
+        m_repositoryAdmin.login(loginContext1);
 
-        // Removing stateful objects is now (partially) supported; see ACE-167 & ACE-230...
-        m_statefulTargetRepository.remove(sgo);
+        m_repositoryAdmin.checkout();
+
+        assertEquals("We expect our own feature object in the repository;", 1, m_featureRepository.get().size());
+        assertEquals("Since the target repository will not be committed, we expect no target objects in the repository;", 0, m_targetRepository.get().size());
 
-        assert m_targetRepository.get().isEmpty() : "We expect to find no target in the repository, but we find " + m_targetRepository.get().size();
-        assert m_statefulTargetRepository.get().isEmpty() : "We expect to find exactly no target in the repository, but we find " + m_statefulTargetRepository.get().size();
-        
         cleanUp();
+        try {
+            removeAllRepositories();
+        }
+        catch (IOException ioe) {
+            // too bad.
+        }
     }
 
-    private void doStatefulAuditAndRemove() throws Exception {
-        // preregister gateway
-        final Map<String, String> attr = new HashMap<String, String>();
-        attr.put(TargetObject.KEY_ID, "myNewGatewayA");
-        final Map<String, String> tags = new HashMap<String, String>();
+    /**
+     * Add a bundle, feature and distribution, associate all, remove the feature, No associations should be left.
+     * 
+     * @throws Exception
+     */
+    public void testRemoveBundleFeature() throws Exception {
+        final ArtifactObject b1 = createBasicBundleObject("thebundle", "1", null);
+        final FeatureObject g1 = createBasicFeatureObject("thefeature");
 
-        final StatefulTargetObject sgo1 = runAndWaitForEvent(new Callable<StatefulTargetObject>() {
-            public StatefulTargetObject call() throws Exception {
-                return m_statefulTargetRepository.preregister(attr, tags);
+        final Artifact2FeatureAssociation bg = runAndWaitForEvent(new Callable<Artifact2FeatureAssociation>() {
+            public Artifact2FeatureAssociation call() throws Exception {
+                return m_artifact2featureRepository.create("(&(" + BundleHelper.KEY_SYMBOLICNAME + "=thebundle)(|("
+                    + BundleHelper.KEY_VERSION + ">=1)(" + BundleHelper.KEY_VERSION + "=<3))(!("
+                    + BundleHelper.KEY_VERSION + "=3)))", "(name=thefeature)");
             }
-        }, false, TargetObject.TOPIC_ADDED, TOPIC_ADDED);
-
-        // do checks
-        assert sgo1.isRegistered() : "We just preregistered a gateway, so it should be registered.";
+        }, false, Artifact2FeatureAssociation.TOPIC_ADDED);
 
-        // add auditlog data
-        List<LogEvent> events = new ArrayList<LogEvent>();
-        Properties props = new Properties();
-        events.add(new LogEvent("myNewGatewayA", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
-        m_auditLogStore.put(events);
-        m_statefulTargetRepository.refresh();
+        final DistributionObject l1 = createBasicDistributionObject("thedistribution");
 
-        // do checks
-        assert sgo1.isRegistered() : "Adding auditlog data for a gateway does not influence its isRegistered().";
-        try {
-            sgo1.getTargetObject();
-        }
-        catch (IllegalStateException ise) {
-            assert false : "We should be able to get sgo1's gatewayObject.";
-        }
-        // add auditlog data for other gateway
-        events = new ArrayList<LogEvent>();
-        props = new Properties();
-        events.add(new LogEvent("myNewGatewayB", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
-        m_auditLogStore.put(events);
-        runAndWaitForEvent(new Callable<Object>() {
-            public Object call() throws Exception {
-                m_statefulTargetRepository.refresh();
-                return false;
+        final Feature2DistributionAssociation gtl = runAndWaitForEvent(new Callable<Feature2DistributionAssociation>() {
+            public Feature2DistributionAssociation call() throws Exception {
+                return m_feature2distributionRepository.create("(name=thefeature)", "(name=thedistribution)");
             }
-        }, false, TOPIC_ADDED);
-        final StatefulTargetObject sgo2 = findStatefulTarget("myNewGatewayB");
+        }, false, Feature2DistributionAssociation.TOPIC_ADDED);
 
-        // do checks
-        assert sgo1.isRegistered() : "Adding auditlog data for a gateway does not influence its isRegistered().";
-        try {
-            sgo1.getTargetObject();
-        }
-        catch (IllegalStateException ise) {
-            assert false : "We should be able to get sgo1's gatewayObject.";
-        }
-        assert !sgo2.isRegistered() : "sgo2 is only found in the auditlog, so it cannot be in registered.";
-        try {
-            sgo2.getTargetObject();
-            assert false : "We should not be able to get sgo2's gatewayObject.";
-        }
-        catch (IllegalStateException ise) {
-            // expected
-        }
-        // remove original gateway
+        assertTrue("The left side of the BG-association should be b1.", (bg.getLeft().size() == 1) && bg.getLeft().contains(b1));
+        assertTrue("The right side of the BG-association should be g1.", (bg.getRight().size() == 1) && bg.getRight().contains(g1));
+        assertTrue("The left side of the GtL-association should be g1.", (gtl.getLeft().size() == 1) && gtl.getLeft().contains(g1));
+        assertTrue("The right side of the GtL-association should be l1.", (gtl.getRight().size() == 1) && gtl.getRight().contains(l1));
+        assertTrue("The bundlefeature association should be satisfied.", bg.isSatisfied());
+        assertTrue("The feature2distribution association should be satisfied.", gtl.isSatisfied());
+        assertEquals("Bundle b1 should be associated to one feature.", 1, b1.getFeatures().size());
+        assertEquals("Distribution l1 should be associated to one feature.", 1, l1.getFeatures().size());
+
+        // remove the feature
         runAndWaitForEvent(new Callable<Object>() {
             public Object call() throws Exception {
-                m_statefulTargetRepository.remove(sgo1);
+                m_featureRepository.remove(g1);
                 return null;
             }
-        }, true, TargetObject.TOPIC_REMOVED, TOPIC_REMOVED);
+        }, false, Artifact2FeatureAssociation.TOPIC_CHANGED, Feature2DistributionAssociation.TOPIC_CHANGED);
+
+        assertFalse("The bundlefeature association shouldn not be satisfied.", gtl.isSatisfied());
+        assertFalse("The feature2distribution assocation should not be satisfied.", bg.isSatisfied());
+
+        assertEquals("Bundle b1 shouldn't be associated to any feature, but is associated to " + b1.getFeatures(), 0, b1.getFeatures().size());
+        assertEquals("Distribution l1 shouldn't be associated to any feature.", 0, l1.getFeatures().size());
+
+        cleanUp();
+    }
+
+    /**
+     * Tests the behavior with logging in and out (with multiple users), and communication
+     * with the server.
+     * 
+     * @throws Exception
+     */
+    public void testRepositoryAdmin() throws Exception {
+        final User user1 = new MockUser("user1");
+        final User user2 = new MockUser("user2");
+
+        startRepositoryService();
+
+        addRepository("storeInstance", "apache", "store", true);
+        addRepository("targetInstance", "apache", "target", true);
 
-        // do checks
-        assert !sgo1.isRegistered() : "sgo1 is now only found in the auditlog, so it cannot be registered.";
         try {
-            sgo1.getTargetObject();
-            assert false : "We should not be able to get sgo1's gatewayObject.";
+            m_repositoryAdmin.checkout();
+            fail("Without being logged in, it should not be possible to do checkout.");
         }
         catch (IllegalStateException ise) {
             // expected
         }
 
-        assert !sgo2.isRegistered() : "sgo2 is only found in the auditlog, so it cannot be in registered.";
+        final RepositoryAdminLoginContext loginContext1 = m_repositoryAdmin.createLoginContext(user1);
+        loginContext1
+            .add(loginContext1.createShopRepositoryContext()
+                .setLocation(m_endpoint).setCustomer("apache").setName("store").setWriteable())
+            .add(loginContext1.createTargetRepositoryContext()
+                .setLocation(m_endpoint).setCustomer("apache").setName("target").setWriteable());
+        m_repositoryAdmin.login(loginContext1);
+
+        assertFalse("When first logging in without checking out, the repository cannot be current.", m_repositoryAdmin.isCurrent());
+        assertFalse("Immediately after login, the repository not is modified.", m_repositoryAdmin.isModified());
+
         try {
-            sgo2.getTargetObject();
-            assert false : "We should not be able to get sgo2's gatewayObject.";
+            m_repositoryAdmin.commit();
+            fail("We should not be able to commit before we check something out.");
         }
-        catch (IllegalStateException ise) {
+        catch (IllegalStateException e) {
             // expected
         }
 
-        // register second gateway
         runAndWaitForEvent(new Callable<Object>() {
             public Object call() throws Exception {
-                sgo2.register();
+                m_repositoryAdmin.checkout();
                 return null;
             }
-        }, false, TargetObject.TOPIC_ADDED, TOPIC_STATUS_CHANGED);
+        }, false, RepositoryAdmin.TOPIC_REFRESH);
 
-        // do checks
-        assert !sgo1.isRegistered() : "sgo1 is now only found in the auditlog, so it cannot be in registered.";
-        try {
-            sgo1.getTargetObject();
-            assert false : "We should not be able to get sgo1's gatewayObject.";
-        }
-        catch (IllegalStateException ise) {
-            // expected
-        }
-        assert sgo2.isRegistered() : "sgo2 has been registered.";
-        try {
-            sgo2.getTargetObject();
-        }
-        catch (IllegalStateException ise) {
-            assert false : "We should be able to get sgo2's gatewayObject.";
-        }
+        assertTrue("After initial checkout, the repository is current.", m_repositoryAdmin.isCurrent());
+        assertFalse("Immediately after login, the repository cannot be modified.", m_repositoryAdmin.isModified());
 
-        int nrRegistered = m_statefulTargetRepository.get(m_bundleContext.createFilter("(" + KEY_REGISTRATION_STATE + "=" + RegistrationState.Registered + ")")).size();
-        assert nrRegistered == 1 : "We expect to filter out one registered gateway, but we find " + nrRegistered;
+        ArtifactObject b1 = runAndWaitForEvent(new Callable<ArtifactObject>() {
+            public ArtifactObject call() throws Exception {
+                return createBasicBundleObject("bundle1");
+            }
+        }, false, ArtifactObject.TOPIC_ADDED, RepositoryAdmin.TOPIC_STATUSCHANGED);
 
-        // Finally, refresh the repository; it should cause sgo1 to be re-created (due to its audit log)...
-        // ACE-167 does not cover this scenario, but at a later time this should be fixed as well (see ACE-230).
-        m_statefulTargetRepository.refresh();
+        assertTrue("After initial checkout, the repository is current.", m_repositoryAdmin.isCurrent());
+        assertTrue("We have added a bundle, so the repository is modified.", m_repositoryAdmin.isModified());
+        assertEquals(1, m_artifactRepository.get().size());
+        assertEquals("We expect the working state of our bundle to be New;", WorkingState.New, m_repositoryAdmin.getWorkingState(b1));
+        assertEquals("We expect one bundle object in working state New;", 1, m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New));
+        assertEquals("We expect 0 bundle objects in working state Changed;", 0, m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed));
+        assertEquals("We expect 0 bundle objects in working state Unchanged;", 0, m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Unchanged));
 
-        int count = m_statefulTargetRepository.get(m_bundleContext.createFilter("(" + KEY_ID + "=myNewGatewayA)")).size();
-        assert count == 1 : "We expected sgo1 to be re-created!";
+        runAndWaitForEvent(new Callable<Object>() {
+            public Object call() throws Exception {
+                m_repositoryAdmin.logout(false);
+                return null;
+            }
+        }, false, RepositoryAdmin.TOPIC_LOGOUT);
 
         cleanUp();
-    }
 
-    private void doStatefulApprove() throws Exception {
-        final Map<String, String> attr = new HashMap<String, String>();
-        attr.put(TargetObject.KEY_ID, "myNewTarget2");
-        final Map<String, String> tags = new HashMap<String, String>();
-        final StatefulTargetObject sgo = runAndWaitForEvent(new Callable<StatefulTargetObject>() {
-            public StatefulTargetObject call() throws Exception {
-                return m_statefulTargetRepository.preregister(attr, tags);
+        assertEquals(0, m_artifactRepository.get().size());
+
+        runAndWaitForEvent(new Callable<Object>() {
+            public Object call() throws Exception {
+                m_repositoryAdmin.login(loginContext1);
+                return null;
             }
-        }, false, TargetObject.TOPIC_ADDED, TOPIC_ADDED);
+        }, false, RepositoryAdmin.TOPIC_LOGIN);
 
-        assert !sgo.needsApprove() : "Without any deployment versions, and no information in the shop, we should not need to approve.";
-        assert sgo.getRegistrationState().equals(RegistrationState.Registered) : "We expect the registration state to be Registered, but it is "
-            + sgo.getRegistrationState();
-        assert sgo.getStoreState().equals(StoreState.New) : "We expect the registration state to be New, but it is "
-            + sgo.getStoreState();
-        assert sgo.getCurrentVersion().equals(UNKNOWN_VERSION);
+        assertTrue("There has not been another commit in between, so we are still current.", m_repositoryAdmin.isCurrent());
+        assertTrue("We have made changes since the last commit, so the repository must be modified.", m_repositoryAdmin.isModified());
+        assertEquals(1, m_artifactRepository.get().size());
+        assertEquals("We expect the working state of our bundle to be New;", WorkingState.New, m_repositoryAdmin.getWorkingState(b1));
+        assertEquals("We expect one bundle object in working state New;", 1, m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New));
+        assertEquals("We expect 0 bundle objects in working state Changed;", 0, m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed));
+        assertEquals("We expect 0 bundle objects in working state Unchanged;", 0, m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Unchanged));
 
-        final ArtifactObject b11 = createBasicBundleObject("bundle1", "1", null);
+        m_repositoryAdmin.commit();
 
-        FeatureObject g1 = createBasicFeatureObject("feature1");
-        FeatureObject g2 = createBasicFeatureObject("feature2"); // note that this feature is not associated to a bundle.
+        assertTrue("After a commit, the repository must be current.", m_repositoryAdmin.isCurrent());
+        assertFalse("After a commit, the repository cannot be modified.", m_repositoryAdmin.isModified());
 
-        createDynamicBundle2FeatureAssociation(b11, g1);
+        runAndWaitForEvent(new Callable<Object>() {
+            public Object call() throws Exception {
+                m_repositoryAdmin.logout(false);
+                return null;
+            }
+        }, false, RepositoryAdmin.TOPIC_LOGOUT);
 
-        final DistributionObject l1 = createBasicDistributionObject("distribution1");
+        cleanUp();
 
-        m_feature2distributionRepository.create(g1, l1);
-        m_feature2distributionRepository.create(g2, l1);
+        final RepositoryAdminLoginContext loginContext2 = m_repositoryAdmin.createLoginContext(user2);
+        loginContext2
+            .add(loginContext2.createShopRepositoryContext()
+                .setLocation(m_endpoint).setCustomer("apache").setName("store").setWriteable())
+            .add(loginContext2.createTargetRepositoryContext()
+                .setLocation(m_endpoint).setCustomer("apache").setName("target").setWriteable());
 
-        runAndWaitForEvent(new Callable<Distribution2TargetAssociation>() {
-            public Distribution2TargetAssociation call() throws Exception {
-                return m_distribution2targetRepository.create(l1, sgo.getTargetObject());
+        runAndWaitForEvent(new Callable<Object>() {
+            public Object call() throws Exception {
+                m_repositoryAdmin.login(loginContext2);
+                return null;
             }
-        }, false, Distribution2TargetAssociation.TOPIC_ADDED, TOPIC_STATUS_CHANGED);
+        }, false, RepositoryAdmin.TOPIC_LOGIN);
 
-        assert sgo.needsApprove() : "We added information that influences our target, so we should need to approve it.";
-        assert sgo.getRegistrationState().equals(RegistrationState.Registered) : "We expect the registration state to be Registered, but it is "
-            + sgo.getRegistrationState();
-        assert sgo.getStoreState().equals(StoreState.Unapproved) : "We expect the registration state to be Unapproved, but it is "
-            + sgo.getStoreState();
-        assert sgo.getArtifactsFromShop().length == 1 : "According to the shop, this target needs 1 bundle, but it states we need "
-            + sgo.getArtifactsFromShop().length;
-        assert sgo.getArtifactsFromDeployment().length == 0 : "According to the deployment, this target needs 0 bundles, but it states we need "
-            + sgo.getArtifactsFromDeployment().length;
-        assert sgo.getCurrentVersion().equals(UNKNOWN_VERSION);
+        assertEquals(0, m_artifactRepository.get().size());
 
         runAndWaitForEvent(new Callable<Object>() {
             public Object call() throws Exception {
-                createBasicDeploymentVersionObject("myNewTarget2", "1", b11);
+                m_repositoryAdmin.checkout();
                 return null;
             }
-        }, false, DeploymentVersionObject.TOPIC_ADDED, TOPIC_STATUS_CHANGED);
+        }, false, RepositoryAdmin.TOPIC_REFRESH);
 
-        assert !sgo.needsApprove() : "We manually created a deployment version that reflects the shop, so no approval should be necessary.";
-        assert sgo.getRegistrationState().equals(RegistrationState.Registered) : "We expect the registration state to be Registered, but it is "
-            + sgo.getRegistrationState();
-        assert sgo.getStoreState().equals(StoreState.Approved) : "We expect the registration state to be Approved, but it is "
-            + sgo.getStoreState();
-        assert sgo.getArtifactsFromShop().length == 1 : "According to the shop, this target needs 1 bundle, but it states we need "
-            + sgo.getArtifactsFromShop().length;
-        assert sgo.getArtifactsFromDeployment().length == 1 : "According to the deployment, this target needs 1 bundles, but it states we need "
-            + sgo.getArtifactsFromDeployment().length;
+        assertEquals("We expect to find 1 bundle after checkout;", 1, m_artifactRepository.get().size());
+        assertTrue("After a checkout, without changing anything, the repository must be current.", m_repositoryAdmin.isCurrent());
+        assertFalse("After a checkout, without changing anything, the repository cannot be modified.", m_repositoryAdmin.isModified());
 
-        runAndWaitForEvent(new Callable<ArtifactObject>() {
+        ArtifactObject b2 = runAndWaitForEvent(new Callable<ArtifactObject>() {
             public ArtifactObject call() throws Exception {
-                return createBasicBundleObject("bundle1", "2", null);
+                return createBasicBundleObject("bundle2");
             }
-        }, false, ArtifactObject.TOPIC_ADDED, Artifact2FeatureAssociation.TOPIC_CHANGED, TOPIC_STATUS_CHANGED);
+        }, false, ArtifactObject.TOPIC_ADDED, RepositoryAdmin.TOPIC_STATUSCHANGED);
 
-        assert sgo.needsApprove() : "We added a new version of a bundle that is used by the target, so approval should be necessary.";
-        assert sgo.getRegistrationState().equals(RegistrationState.Registered) : "We expect the registration state to be Registered, but it is "
-            + sgo.getRegistrationState();
-        assert sgo.getStoreState().equals(StoreState.Unapproved) : "We expect the registration state to be Unapproved, but it is "
-            + sgo.getStoreState();
-        assert sgo.getArtifactsFromShop().length == 1 : "According to the shop, this target needs 1 bundle, but it states we need "
-            + sgo.getArtifactsFromShop().length;
-        assert sgo.getArtifactsFromShop()[0].getURL().equals("http://bundle1-2") : "The shop should tell use we need bundle URL 'bundle1-2', but it tells us we need "
-            + sgo.getArtifactsFromShop()[0].getURL();
-        assert sgo.getArtifactsFromDeployment().length == 1 : "According to the deployment, this target needs 1 bundles, but it states we need "
-            + sgo.getArtifactsFromDeployment().length;
-        assert sgo.getArtifactsFromDeployment()[0].getUrl().equals("http://bundle1-1") : "The deployment should tell use we need bundle URL 'bundle1-1', but it tells us we need "
-            + sgo.getArtifactsFromDeployment()[0].getUrl();
-        assert sgo.getCurrentVersion().equals("1");
+        assertTrue(m_artifactRepository.get().size() == 2);
+        assertTrue("After changing something in memory without flushing it, the repository still is current.", m_repositoryAdmin.isCurrent());
+        assertTrue("We have added something, so the repository is modified.", m_repositoryAdmin.isModified());
+        assertEquals("We expect the working state of our bundle1 to be Unchanged;", WorkingState.Unchanged, m_repositoryAdmin.getWorkingState(b1));
+        assertEquals("We expect the working state of our bundle2 to be New;", WorkingState.New, m_repositoryAdmin.getWorkingState(b2));
+        assertEquals("We expect one bundle object in working state New;", 1, m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New));
+        assertEquals("We expect 0 bundle objects in working state Changed;", 0, m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed));
+        assertEquals("We expect one bundle object in working state Unchanged;", 1, m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Unchanged));
 
-        final String newVersion = runAndWaitForEvent(new Callable<String>() {
-            public String call() throws Exception {
-                return sgo.approve();
+        runAndWaitForEvent(new Callable<Object>() {
+            public Object call() throws Exception {
+                m_repositoryAdmin.logout(false);
+                return null;
             }
-        }, false, DeploymentVersionObject.TOPIC_ADDED, TOPIC_STATUS_CHANGED);
+        }, false, RepositoryAdmin.TOPIC_LOGOUT);
+
+        runAndWaitForEvent(new Callable<Object>() {
+            public Object call() throws Exception {
+                m_repositoryAdmin.login(loginContext1);
+                return null;
+            }
+        }, false, RepositoryAdmin.TOPIC_LOGIN);
 
-        assert !sgo.needsApprove() : "Immediately after approval, no approval is necessary.";
-        assert sgo.getRegistrationState().equals(RegistrationState.Registered) : "We expect the registration state to be Registered, but it is "
-            + sgo.getRegistrationState();
-        assert sgo.getStoreState().equals(StoreState.Approved) : "We expect the registration state to be Approved, but it is "
-            + sgo.getStoreState();
-        assert sgo.getArtifactsFromShop().length == 1 : "According to the shop, this target needs 1 bundle, but it states we need "
-            + sgo.getArtifactsFromShop().length;
-        assert sgo.getArtifactsFromShop()[0].getURL().equals("http://bundle1-2") : "The shop should tell use we need bundle URL 'bundle1-2', but it tells us we need "
-            + sgo.getArtifactsFromShop()[0].getURL();
-        assert sgo.getArtifactsFromDeployment().length == 1 : "According to the deployment, this target needs 1 bundles, but it states we need "
-            + sgo.getArtifactsFromDeployment().length;
-        assert sgo.getArtifactsFromShop()[0].getURL().equals("http://bundle1-2") : "Deployment should tell use we need bundle URL 'bundle1-2', but it tells us we need "
-            + sgo.getArtifactsFromShop()[0].getURL();
-        assert m_deploymentVersionRepository.get().size() == 2 : "We expect two deployment versions, but we find "
-            + m_deploymentVersionRepository.get().size();
-        assert sgo.getCurrentVersion().equals(newVersion);
+        assertEquals("We expect 1 item in the bundle repository;", 1, m_artifactRepository.get().size());
 
-        // clean up this object ourselves; we cannot rely on cleanUp() in this case.
         runAndWaitForEvent(new Callable<Object>() {
             public Object call() throws Exception {
-                m_statefulTargetRepository.unregister(sgo.getID());
+                m_repositoryAdmin.logout(false);
                 return null;
             }
-        }, false, TargetObject.TOPIC_REMOVED, TOPIC_REMOVED);
+        }, false, RepositoryAdmin.TOPIC_LOGOUT);
 
-        assert m_statefulTargetRepository.get().size() == 0;
-    }
+        runAndWaitForEvent(new Callable<Object>() {
+            public Object call() throws Exception {
+                m_repositoryAdmin.login(loginContext2);
+                return null;
+            }
+        }, false, RepositoryAdmin.TOPIC_LOGIN);
 
-    private void doStrangeNamesInTargets() throws InvalidSyntaxException, IOException {
-        List<LogEvent> events = new ArrayList<LogEvent>();
-        Properties props = new Properties();
+        assertEquals("We expect 2 items in the bundle repository;", 2, m_artifactRepository.get().size());
 
-        // add a target with a weird name.
-        events.add(new LogEvent(":)", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
-        // fill auditlog; no install data
-        m_auditLogStore.put(events);
+        runAndWaitForEvent(new Callable<Object>() {
+            public Object call() throws Exception {
+                m_repositoryAdmin.revert();
+                return null;
+            }
+        }, false, RepositoryAdmin.TOPIC_REFRESH, RepositoryAdmin.TOPIC_STATUSCHANGED);
 
-        // see presence of sgo
-        int sgrSizeBefore = m_statefulTargetRepository.get().size();
-        m_statefulTargetRepository.refresh();
-        assert m_statefulTargetRepository.get().size() == sgrSizeBefore + 1 : "After refresh, we expect "
-            + (sgrSizeBefore + 1) + " target based on auditlogdata, but we find "
-            + m_statefulTargetRepository.get().size();
-        StatefulTargetObject sgo = findStatefulTarget(":)");
-        sgo.register();
-        assert sgo.getRegistrationState().equals(RegistrationState.Registered) : "After registring our target, we assume it to be registered.";
-        assert sgo.getProvisioningState().equals(ProvisioningState.Idle) : "We expect our object's provisioning state to be Idle, but it is "
-            + m_statefulTargetRepository.get().get(0).getProvisioningState();
+        assertEquals("We expect 1 item in the bundle repository;", 1, m_artifactRepository.get().size());
+
+        try {
+            removeAllRepositories();
+        }
+        catch (Exception e) {
+            // Not much we can do...
+            e.printStackTrace(System.err);
+        }
 
+        cleanUp();
     }
 
-    private void doStatefulAuditlog() throws IOException, InvalidSyntaxException {
-        List<LogEvent> events = new ArrayList<LogEvent>();
-        Properties props = new Properties();
-        events.add(new LogEvent("myTarget", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
-        // fill auditlog; no install data
-        m_auditLogStore.put(events);
-
-        // see presence of sgo
-        assert m_statefulTargetRepository.get().size() == 0 : "Before audit log refresh, we expect nothing in the stateful repository, but we find "
-            + m_statefulTargetRepository.get().size();
-        m_statefulTargetRepository.refresh();
-        assert m_statefulTargetRepository.get().size() == 1 : "After refresh, we expect 1 target based on auditlogdata, but we find "
-            + m_statefulTargetRepository.get().size();
-        StatefulTargetObject sgo = m_statefulTargetRepository.get().get(0);
-        assert sgo.getProvisioningState().equals(ProvisioningState.Idle) : "We expect our object's provisioning state to be Idle, but it is "
-            + m_statefulTargetRepository.get().get(0).getProvisioningState();
-
-        // fill auditlog with complete-data
-        events = new ArrayList<LogEvent>();
-        props = new Properties();
-        props.put(AuditEvent.KEY_NAME, "mypackage");
-        props.put(AuditEvent.KEY_VERSION, "123");
-        events.add(new LogEvent("myTarget", 1, 2, 2, AuditEvent.DEPLOYMENTCONTROL_INSTALL, props));
-        m_auditLogStore.put(events);
-        m_statefulTargetRepository.refresh();
-
-        assert sgo.getLastInstallVersion().equals("123") : "Our last install version should be 123, but it is "
-            + sgo.getLastInstallVersion();
-        assert sgo.getProvisioningState().equals(ProvisioningState.InProgress) : "We expect our object's provisioning state to be InProgress, but it is "
-            + sgo.getProvisioningState();
-
-        // fill auditlog with install data
-        events = new ArrayList<LogEvent>();
-        props = new Properties();
-        props.put(AuditEvent.KEY_NAME, "mypackage");
-        props.put(AuditEvent.KEY_VERSION, "123");
-        props.put(AuditEvent.KEY_SUCCESS, "false");
-        events.add(new LogEvent("myTarget", 1, 3, 3, AuditEvent.DEPLOYMENTADMIN_COMPLETE, props));
-        m_auditLogStore.put(events);
-        m_statefulTargetRepository.refresh();
-
-        assert sgo.getLastInstallVersion().equals("123") : "Our last install version should be 123, but it is "
-            + sgo.getLastInstallVersion();
-        assert sgo.getProvisioningState().equals(ProvisioningState.Failed) : "We expect our object's provisioning state to be Failed, but it is "
-            + sgo.getProvisioningState();
-        assert !sgo.getLastInstallSuccess() : "Our last install was not successful, but according to the sgo it was.";
-
-        sgo.acknowledgeInstallVersion("123");
-        assert sgo.getProvisioningState().equals(ProvisioningState.Idle) : "We expect our object's provisioning state to be Idle, but it is "
-            + sgo.getProvisioningState();
-
-        // add another install event.
-        events = new ArrayList<LogEvent>();
-        props = new Properties();
-        props.put(AuditEvent.KEY_NAME, "mypackage");
-        props.put(AuditEvent.KEY_VERSION, "124");
-        events.add(new LogEvent("myTarget", 1, 4, 4, AuditEvent.DEPLOYMENTCONTROL_INSTALL, props));
-        m_auditLogStore.put(events);
-        m_statefulTargetRepository.refresh();
-
-        assert sgo.getLastInstallVersion().equals("124") : "Our last install version should be 124, but it is "
-            + sgo.getLastInstallVersion();
-        assert sgo.getProvisioningState().equals(ProvisioningState.InProgress) : "We expect our object's provisioning state to be InProgress, but it is "
-            + sgo.getProvisioningState();
-
-        // fill auditlog with install data
-        events = new ArrayList<LogEvent>();
-        props = new Properties();
-        props.put(AuditEvent.KEY_NAME, "mypackage");
-        props.put(AuditEvent.KEY_VERSION, "124");
-        props.put(AuditEvent.KEY_SUCCESS, "true");
-        events.add(new LogEvent("myTarget", 1, 5, 5, AuditEvent.DEPLOYMENTADMIN_COMPLETE, props));
-        m_auditLogStore.put(events);
-        m_statefulTargetRepository.refresh();
-
-        assert sgo.getLastInstallVersion().equals("124") : "Our last install version should be 124, but it is "
-            + sgo.getLastInstallVersion();
-        assert sgo.getProvisioningState().equals(ProvisioningState.OK) : "We expect our object's provisioning state to be OK, but it is "
-            + sgo.getProvisioningState();
-        assert sgo.getLastInstallSuccess() : "Our last install was successful, but according to the sgo it was not.";
-
-        sgo.acknowledgeInstallVersion("124");
-        assert sgo.getProvisioningState().equals(ProvisioningState.Idle) : "We expect our object's provisioning state to be Idle, but it is "
-            + sgo.getProvisioningState();
-    }
-
-    private void doStatefulAuditAndRegister() throws Exception {
-        // preregister target
-        final Map<String, String> attr = new HashMap<String, String>();
-        attr.put(TargetObject.KEY_ID, "myNewTarget3");
-        final Map<String, String> tags = new HashMap<String, String>();
-
-        final StatefulTargetObject sgo1 = runAndWaitForEvent(new Callable<StatefulTargetObject>() {
-            public StatefulTargetObject call() throws Exception {
-                return m_statefulTargetRepository.preregister(attr, tags);
-            }
-        }, false, TargetObject.TOPIC_ADDED, TOPIC_ADDED);
-
-        // do checks
-        assert sgo1.isRegistered() : "We just preregistered a target, so it should be registered.";
-
-        // add auditlog data
-        List<LogEvent> events = new ArrayList<LogEvent>();
-        Properties props = new Properties();
-        events.add(new LogEvent("myNewTarget3", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
-        m_auditLogStore.put(events);
-        m_statefulTargetRepository.refresh();
+    public void testStateful() throws Exception {
+        User user = new MockUser("user4");
 
-        // do checks
-        assert sgo1.isRegistered() : "Adding auditlog data for a target does not influence its isRegistered().";
-        try {
-            sgo1.getTargetObject();
-        }
-        catch (IllegalStateException ise) {
-            assert false : "We should be able to get sgo1's targetObject.";
-        }
+        startRepositoryService();
 
-        // add auditlog data for other target
-        events = new ArrayList<LogEvent>();
-        props = new Properties();
-        events.add(new LogEvent("myNewTarget4", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
-        m_auditLogStore.put(events);
-        runAndWaitForEvent(new Callable<Object>() {
-            public Object call() throws Exception {
-                m_statefulTargetRepository.refresh();
-                return false;
-            }
-        }, false, TOPIC_ADDED);
-        final StatefulTargetObject sgo2 = findStatefulTarget("myNewTarget4");
+        addRepository("storeInstance", "apache", "store", true);
+        addRepository("targetInstance", "apache", "target", true);
+        addRepository("deploymentInstance", "apache", "deployment", true);
 
-        // do checks
-        assert sgo1.isRegistered() : "Adding auditlog data for a target does not influence its isRegistered().";
-        try {
-            sgo1.getTargetObject();
-        }
-        catch (IllegalStateException ise) {
-            assert false : "We should be able to get sgo1's targetObject.";
-        }
-        assert !sgo2.isRegistered() : "sgo2 is only found in the auditlog, so it cannot be in registered.";
-        try {
-            sgo2.getTargetObject();
-            assert false : "We should not be able to get sgo2's targetObject.";
-        }
-        catch (IllegalStateException ise) {
-            // expected
-        }
+        RepositoryAdminLoginContext loginContext = m_repositoryAdmin.createLoginContext(user);
+        loginContext
+            .add(loginContext.createShopRepositoryContext()
+                .setLocation(m_endpoint).setCustomer("apache").setName("store").setWriteable())
+            .add(loginContext.createTargetRepositoryContext()

[... 1814 lines stripped ...]