You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ma...@apache.org on 2012/07/05 14:10:06 UTC

svn commit: r1357570 [20/34] - in /ace/sandbox/marrs: cnf/ cnf/ext/ cnf/lib/ cnf/releaserepo/ cnf/repo/ cnf/repo/.obrcache/ cnf/repo/.obrcache/http%3A%2F%2Fbundles.bndtools.org.s3.amazonaws.com%2Fcom.jcraft.jsch/ cnf/repo/.obrcache/http%3A%2F%2Fbundles...

Added: ace/sandbox/marrs/org.apache.ace.client.repository.impl/test/org/apache/ace/client/repository/impl/ModelTest.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.impl/test/org/apache/ace/client/repository/impl/ModelTest.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.impl/test/org/apache/ace/client/repository/impl/ModelTest.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.impl/test/org/apache/ace/client/repository/impl/ModelTest.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,698 @@
+/*
+ * 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.ace.client.repository.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ace.client.repository.Association;
+import org.apache.ace.client.repository.ObjectRepository;
+import org.apache.ace.client.repository.RepositoryUtil;
+import org.apache.ace.client.repository.helper.bundle.BundleHelper;
+import org.apache.ace.client.repository.helper.bundle.impl.BundleHelperImpl;
+import org.apache.ace.client.repository.object.Artifact2FeatureAssociation;
+import org.apache.ace.client.repository.object.ArtifactObject;
+import org.apache.ace.client.repository.object.DeploymentArtifact;
+import org.apache.ace.client.repository.object.DeploymentVersionObject;
+import org.apache.ace.client.repository.object.TargetObject;
+import org.apache.ace.client.repository.object.Feature2DistributionAssociation;
+import org.apache.ace.client.repository.object.FeatureObject;
+import org.apache.ace.client.repository.object.DistributionObject;
+import org.apache.ace.client.repository.repository.Artifact2FeatureAssociationRepository;
+import org.apache.ace.client.repository.repository.ArtifactRepository;
+import org.apache.ace.client.repository.repository.DeploymentVersionRepository;
+import org.apache.ace.client.repository.repository.TargetRepository;
+import org.apache.ace.client.repository.repository.Feature2DistributionAssociationRepository;
+import org.apache.ace.client.repository.repository.FeatureRepository;
+import org.apache.ace.client.repository.repository.Distribution2TargetAssociationRepository;
+import org.apache.ace.client.repository.repository.DistributionRepository;
+import org.apache.ace.test.utils.TestUtils;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.log.LogService;
+import org.osgi.service.prefs.Preferences;
+import org.osgi.service.prefs.PreferencesService;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+
+/**
+ * Test class for the object model used </code>org.apache.ace.client.repository<code>.
+ */
+public class ModelTest {
+
+    private ArtifactRepositoryImpl m_artifactRepository;
+    private FeatureRepositoryImpl m_featureRepository;
+    private Artifact2FeatureAssociationRepositoryImpl m_artifact2FeatureRepository;
+    private DistributionRepositoryImpl m_distributionRepository;
+    private Feature2DistributionAssociationRepositoryImpl m_feature2DistributionRepository;
+    private TargetRepositoryImpl m_targetRepository;
+    private Distribution2TargetAssociationRepositoryImpl m_distribution2TargetRepository;
+    private DeploymentVersionRepositoryImpl m_deploymentVersionRepository;
+    private RepositoryAdminImpl m_repositoryAdmin;
+
+    private BundleHelperImpl m_bundleHelper = new BundleHelperImpl();
+
+
+    @BeforeMethod(alwaysRun = true)
+    private void initializeRepositoryAdmin() {
+        BundleContext bc = TestUtils.createMockObjectAdapter(BundleContext.class, new Object() {
+            @SuppressWarnings("unused")
+            public Filter createFilter(String filter) throws InvalidSyntaxException {
+                return createLocalFilter(filter);
+            }
+        });
+
+        ChangeNotifier notifier = TestUtils.createNullObject(ChangeNotifier.class);
+
+        m_artifactRepository = new ArtifactRepositoryImpl(notifier);
+        TestUtils.configureObject(m_artifactRepository, LogService.class);
+        TestUtils.configureObject(m_artifactRepository, BundleContext.class, bc);
+        m_artifactRepository.addHelper(BundleHelper.MIMETYPE, m_bundleHelper);
+        m_featureRepository = new FeatureRepositoryImpl(notifier);
+        TestUtils.configureObject(m_featureRepository, BundleContext.class, bc);
+        m_artifact2FeatureRepository = new Artifact2FeatureAssociationRepositoryImpl(m_artifactRepository, m_featureRepository, notifier);
+        TestUtils.configureObject(m_artifact2FeatureRepository, BundleContext.class, bc);
+        m_distributionRepository = new DistributionRepositoryImpl(notifier);
+        TestUtils.configureObject(m_distributionRepository, BundleContext.class, bc);
+        m_feature2DistributionRepository = new Feature2DistributionAssociationRepositoryImpl(m_featureRepository, m_distributionRepository, notifier);
+        TestUtils.configureObject(m_feature2DistributionRepository, BundleContext.class, bc);
+        m_targetRepository = new TargetRepositoryImpl(notifier);
+        TestUtils.configureObject(m_targetRepository, BundleContext.class, bc);
+        m_distribution2TargetRepository = new Distribution2TargetAssociationRepositoryImpl(m_distributionRepository, m_targetRepository, notifier);
+        TestUtils.configureObject(m_distribution2TargetRepository, BundleContext.class, bc);
+        m_deploymentVersionRepository = new DeploymentVersionRepositoryImpl(notifier);
+        TestUtils.configureObject(m_deploymentVersionRepository, BundleContext.class, bc);
+
+        m_repositoryAdmin = new RepositoryAdminImpl("testSessionID");
+
+        Map<Class<? extends ObjectRepository>, ObjectRepositoryImpl> repos = new HashMap<Class<? extends ObjectRepository>, ObjectRepositoryImpl>();
+        repos.put(ArtifactRepository.class, m_artifactRepository);
+        repos.put(Artifact2FeatureAssociationRepository.class, m_artifact2FeatureRepository);
+        repos.put(FeatureRepository.class, m_featureRepository);
+        repos.put(Feature2DistributionAssociationRepository.class, m_feature2DistributionRepository);
+        repos.put(DistributionRepository.class, m_distributionRepository);
+        repos.put(Distribution2TargetAssociationRepository.class, m_distribution2TargetRepository);
+        repos.put(TargetRepository.class, m_targetRepository);
+        repos.put(DeploymentVersionRepository.class, m_deploymentVersionRepository);
+
+        m_repositoryAdmin.initialize(repos);
+        TestUtils.configureObject(m_repositoryAdmin, Preferences.class);
+        TestUtils.configureObject(m_repositoryAdmin, PreferencesService.class);
+    }
+
+    /**
+     * The artifact object can test functionality coming from
+     * RepositoryObjectImpl, and ArtifactRepository checks much of
+     * ObjectRepositoryImpl.
+     * @throws InvalidSyntaxException
+     */
+    @Test( groups = { TestUtils.UNIT } )
+    public void testArtifactObjectAndRepository() throws InvalidSyntaxException {
+        // Create a very simple artifact.
+        ArtifactObject a = createBasicArtifactObject("myartifact", "1.0.0");
+
+        // Try to create an illegal one
+        try {
+            createBasicArtifactObject("");
+            assert false : "Creating an artifact with an empty name is not allowed.";
+        }
+        catch (IllegalArgumentException iae) {
+            // expected
+        }
+
+        // Even though the artifact is not yet associated to a feature, try to get its features.
+        List<FeatureObject> features = a.getFeatures();
+
+        assert features.size() == 0 : "The artifact is not associated, so it should not return any features.";
+
+        assert a.getAttribute(BundleHelper.KEY_SYMBOLICNAME).equals("myartifact") : "We should be able to read an attribute we just put in ourselves.";
+
+        a.addTag("mytag", "myvalue");
+
+        assert a.getTag("mytag").equals("myvalue")  : "We should be able to read an attribute we just put in ourselves.";
+        assert a.getTag(BundleHelper.KEY_SYMBOLICNAME) == null : "We should not find an attribute value when asking for a tag.";
+
+        a.addTag(BundleHelper.KEY_SYMBOLICNAME, "mytagname");
+
+        assert a.getTag(BundleHelper.KEY_SYMBOLICNAME).equals("mytagname") : "We can adds tags that have the same name as a artifact, but still return another value.";
+
+        Dictionary<String, Object> dict = a.getDictionary();
+
+        assert dict.get("mytag") == "myvalue" : "The dictionary of the object should contain all tags.";
+        assert dict.get(BundleHelper.KEY_VERSION).equals("1.0.0") : "The dictionary of the object should contain all attributes; we found " + dict.get(BundleHelper.KEY_VERSION);
+        String[] foundNames = (String[]) dict.get(BundleHelper.KEY_SYMBOLICNAME);
+        assert foundNames.length == 2 : "For keys which are used both as a value and as a tag, we should get back both from the dictionary in an array.";
+        assert (foundNames[0].equals("myartifact") && foundNames[1].equals("mytagname")) ||
+        (foundNames[1].equals("myartifact") && foundNames[0].equals("mytagname")) : "The order is undefined, but we should find both the items we put in for '"+BundleHelper.KEY_SYMBOLICNAME+"'.";
+
+        assert m_artifactRepository.get().size() == 1 : "The repository should contain exactly one artifact.";
+        assert m_artifactRepository.get().get(0).equals(a) : "The repository should contain exactly our artifact.";
+
+        ArtifactObject b2 = createBasicArtifactObject("myotherartifact", "1");
+
+        assert m_artifactRepository.get(createLocalFilter("(" + BundleHelper.KEY_SYMBOLICNAME + "=myartifact)")).size() == 1 : "When filtering for our artifact, we should find only that.";
+        assert m_artifactRepository.get(createLocalFilter("(" + BundleHelper.KEY_VERSION + "=1.0.0)")).size() == 2 : "When filtering for a version, we should find two artifacts.";
+
+        try {
+            createBasicArtifactObject("myartifact", "1.0.0");
+            assert false : "Adding a artifact which is identical to one already in the repository should be illegal.";
+        }
+        catch (IllegalArgumentException iae) {
+            //expected
+        }
+
+        try {
+            b2.addAttribute("thenewattribute", "withsomevalue");
+        }
+        catch (UnsupportedOperationException uoe) {
+            assert false : "Adding arbitrary attributes to a artifact object should be allowed.";
+        }
+
+        try {
+            b2.addAttribute(BundleHelper.KEY_SYMBOLICNAME, "artifact.42");
+            assert false : "Changing key attributes in a artifact should not be allowed.";
+        }
+        catch (UnsupportedOperationException uoe) {
+            //expected
+        }
+
+
+        try {
+            Map<String, String> attr = new HashMap<String, String>();
+            attr.put(BundleHelper.KEY_NAME, "mynewartifact");
+            Map<String, String> tags = new HashMap<String, String>();
+            m_artifactRepository.create(attr, tags);
+            assert false : "Creating a artifact without specifying all mandatory atttributes should be illegal.";
+        }
+        catch (IllegalArgumentException iae) {
+            //expected
+        }
+
+
+        m_artifactRepository.remove(a);
+
+        try {
+            a.addTag("mytag", "myvalue");
+            assert false : "Deleted objects are not allowed to be changed.";
+        }
+        catch (IllegalStateException ise) {
+            // expected
+        }
+
+        assert m_artifactRepository.get().size() == 1 : "After removing our first artifact, the repository should contain one artifact.";
+        assert m_artifactRepository.get().get(0).equals(b2) : "After removing our first artifact, the repository should contain only our second artifact.";
+    }
+
+    @Test( groups = { TestUtils.UNIT } )
+    public void testRepositorySerialization() {
+        createBasicArtifactObject("myartifact", "1");
+        createBasicArtifactObject("myartifact", "2");
+
+        // Write the store to a stream, reset the repository, and re-read it.
+        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        RepositorySet store = new RepositorySet(null, null, null, null, new ObjectRepositoryImpl[] {m_artifactRepository, m_artifact2FeatureRepository, m_featureRepository}, null, "", true);
+        new RepositorySerializer(store).toXML(buffer);
+        initializeRepositoryAdmin();
+        store = new RepositorySet(null, null, null, null, new ObjectRepositoryImpl[] {m_artifactRepository, m_artifact2FeatureRepository, m_featureRepository}, null, "", true);
+        new RepositorySerializer(store).fromXML(new ByteArrayInputStream(buffer.toByteArray()));
+
+        assert m_artifactRepository.get().size() == 2 : "We expect to find 2 artifacts, but we find " + m_artifactRepository.get().size();
+    }
+
+    @Test( groups = { TestUtils.UNIT } )
+    public void testSerialization() {
+        ArtifactObject b1 = createBasicArtifactObject("artifact1");
+        ArtifactObject b2 = createBasicArtifactObject("artifact2");
+        ArtifactObject b3 = createBasicArtifactObject("artifact3");
+
+        FeatureObject g1 = createBasicFeatureObject("feature1");
+        FeatureObject g2 = createBasicFeatureObject("feature2");
+
+        m_artifact2FeatureRepository.create(b1, g1);
+        m_artifact2FeatureRepository.create(b2, g2);
+        m_artifact2FeatureRepository.create(b3, g2);
+
+        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        RepositorySet store = new RepositorySet(null, null, null, null, new ObjectRepositoryImpl[] {m_artifactRepository, m_featureRepository, m_artifact2FeatureRepository}, null, "", true);
+        new RepositorySerializer(store).toXML(buffer);
+        initializeRepositoryAdmin();
+        store = new RepositorySet(null, null, null, null, new ObjectRepositoryImpl[] {m_artifactRepository, m_featureRepository, m_artifact2FeatureRepository}, null, "", true);
+        new RepositorySerializer(store).fromXML(new ByteArrayInputStream(buffer.toByteArray()));
+
+        assert m_artifactRepository.get().size() == 3 : "We expect to find 3 artifacts, but we find " + m_artifactRepository.get().size();
+        assert m_featureRepository.get().size() == 2 : "We expect to find 2 features, but we find " + m_featureRepository.get().size();
+        assert m_artifact2FeatureRepository.get().size() == 3 : "We expect to find 3 associations, but we find " + m_artifact2FeatureRepository.get().size();
+        assert b1.isAssociated(g1, FeatureObject.class) : "After serialization, b1 should still be associated with g1.";
+        assert !b1.isAssociated(g2, FeatureObject.class) : "After serialization, b1 should not be associated with g1.";
+        assert !b2.isAssociated(g1, FeatureObject.class) : "After serialization, b2 should not be associated with g2.";
+        assert b2.isAssociated(g2, FeatureObject.class) : "After serialization, b2 should still be associated with g2.";
+        assert !b3.isAssociated(g1, FeatureObject.class) : "After serialization, b3 should not be associated with g2.";
+        assert b3.isAssociated(g2, FeatureObject.class) : "After serialization, b3 should still be associated with g2.";
+    }
+
+    @Test( groups = { TestUtils.UNIT } )
+    public void testModelFiltering() throws InvalidSyntaxException {
+        initializeRepositoryAdmin();
+        // Create an empty artifact repository.
+        Map<String, String> attributes = new HashMap<String, String>();
+        attributes.put("myattribute", "theattribute");
+        attributes.put("name", "attname");
+        Map<String, String> tags = new HashMap<String, String>();
+
+        assert m_featureRepository != null : "Something has gone wrong injecting the feature repository.";
+        FeatureObject g1 = m_featureRepository.create(attributes, tags);
+        g1.addTag("mytag", "thetag");
+        g1.addTag("name", "tagname");
+        g1.addTag("difficult", ")diffi)c*ul\\t");
+
+
+        assert m_featureRepository.get(createLocalFilter("(myattribute=*)")).size() == 1 : "There should be a myattribute in b1.";
+        assert m_featureRepository.get(createLocalFilter("(myattribute=theattribute)")).size() == 1 : "There should be myattribute=theattribute in b1.";
+        assert m_featureRepository.get(createLocalFilter("(myattribute=thetag)")).size() == 0 : "There should not be myattribute=thetag in b1.";
+        assert m_featureRepository.get(createLocalFilter("(mytag=*)")).size() == 1 : "There should be a mytag in b1.";
+        assert m_featureRepository.get(createLocalFilter("(mytag=thetag)")).size() == 1 : "There should be mytag=thetag in b1.";
+        assert m_featureRepository.get(createLocalFilter("(mytag=theattribute)")).size() == 0 : "There should not be mytag=theattribute in b1.";
+
+        assert m_featureRepository.get(createLocalFilter("(name=*)")).size() == 1 : "There should be a name parameter in b1.";
+        assert m_featureRepository.get(createLocalFilter("(name=attname)")).size() == 1 : "There should be a name=attname in b1.";
+        assert m_featureRepository.get(createLocalFilter("(name=tagname)")).size() == 1 : "There should be a name=tagname in b1.";
+        assert m_featureRepository.get(createLocalFilter("(name=thetag)")).size() == 0 : "There should not be name=thetag in b1.";
+
+        try {
+            m_featureRepository.get(createLocalFilter("(difficult=)diffi)c*ul\\t"));
+            assert false : "The non-escaped difficult string should raise an error.";
+        }
+        catch (InvalidSyntaxException ex) {
+            //expected
+        }
+        assert m_featureRepository.get(createLocalFilter("(difficult=" + RepositoryUtil.escapeFilterValue(")diffi)c*ul\\t") + ")")).size() == 1 : "The 'difficult' string should be correctly escaped, and thus return exactly one match.";
+    }
+
+    /**
+     * Tests the behavior when associating stuff, and removing associations.
+     */
+    @Test( groups = { TestUtils.UNIT } )
+    public void testAssociations() {
+        initializeRepositoryAdmin();
+        // Create two, rather boring, artifacts.
+        ArtifactObject b1 = createBasicArtifactObject("artifact1");
+        ArtifactObject b2 = createBasicArtifactObject("artifact2");
+
+        // Create three features.
+        FeatureObject g1 = createBasicFeatureObject("feature1");
+        FeatureObject g2 = createBasicFeatureObject("feature2");
+        FeatureObject g3 = createBasicFeatureObject("feature3");
+
+        // Create some associations.
+        Artifact2FeatureAssociation b2g1 = m_artifact2FeatureRepository.create(b1, g2);
+        assert b2g1 != null;
+        Artifact2FeatureAssociation b2g2 = m_artifact2FeatureRepository.create(b2, g1);
+        assert b2g2 != null;
+        Artifact2FeatureAssociation b2g3 = m_artifact2FeatureRepository.create(b1, g3);
+        assert b2g3 != null;
+        Artifact2FeatureAssociation b2g4 = m_artifact2FeatureRepository.create(b2, g3);
+        assert b2g4 != null;
+
+        // Do some basic checks on the repositories.
+        assert m_artifactRepository.get().size() == 2 : "We should have two artifacts in our repository; we found " + m_artifactRepository.get().size() + ".";
+        assert m_featureRepository.get().size() == 3 : "We should have three features in our repository; we found " + m_featureRepository.get().size() + ".";
+        assert m_artifact2FeatureRepository.get().size() == 4 : "We should have four associations in our repository; we found " + m_artifact2FeatureRepository.get().size() + ".";
+
+        assert (b2g4.getLeft().size() == 1) && b2g4.getLeft().contains(b2) : "The left side of the fourth association should be artifact 2.";
+        assert (b2g4.getRight().size() == 1) && b2g4.getRight().contains(g3) : "The right side of the fourth association should be feature 3.";
+
+        // Check the wiring: what is wired to what?
+        List<FeatureObject> b1features = b1.getFeatures();
+        List<FeatureObject> b2features = b2.getFeatures();
+
+        List<ArtifactObject> g1artifacts = g1.getArtifacts();
+        List<ArtifactObject> g2artifacts = g2.getArtifacts();
+        List<ArtifactObject> g3artifacts = g3.getArtifacts();
+        List<DistributionObject> g1distributions = g1.getDistributions();
+        List<DistributionObject> g2distributions = g2.getDistributions();
+        List<DistributionObject> g3distributions = g3.getDistributions();
+
+        assert g1distributions.size() == 0 : "Feature one should not have any associations to distributions; we found " + g1distributions.size() + ".";
+        assert g2distributions.size() == 0 : "Feature two should not have any associations to distributions; we found " + g2distributions.size() + ".";
+        assert g3distributions.size() == 0 : "Feature three should not have any associations to distributions; we found " + g3distributions.size() + ".";
+
+        List<FeatureObject> b1expectedFeatures = new ArrayList<FeatureObject>();
+        b1expectedFeatures.add(g2);
+        b1expectedFeatures.add(g3);
+        List<FeatureObject> b2expectedFeatures = new ArrayList<FeatureObject>();
+        b2expectedFeatures.add(g1);
+        b2expectedFeatures.add(g3);
+
+        List<ArtifactObject> g1expectedArtifacts = new ArrayList<ArtifactObject>();
+        g1expectedArtifacts.add(b2);
+        List<ArtifactObject> g2expectedArtifacts = new ArrayList<ArtifactObject>();
+        g2expectedArtifacts.add(b1);
+        List<ArtifactObject> g3expectedArtifacts = new ArrayList<ArtifactObject>();
+        g3expectedArtifacts.add(b1);
+        g3expectedArtifacts.add(b2);
+
+        assert b1features.containsAll(b1expectedFeatures) && b1expectedFeatures.containsAll(b1features) : "b1 should be associated to exactly features 2 and 3.";
+        assert b2features.containsAll(b2expectedFeatures) && b2expectedFeatures.containsAll(b2features) : "b2 should be associated to exactly features 1 and 3.";
+
+        assert g1artifacts.containsAll(g1expectedArtifacts) && g1expectedArtifacts.containsAll(g1artifacts) : "g1 should be associated to exactly artifact 2.";
+        assert g2artifacts.containsAll(g2expectedArtifacts) && g2expectedArtifacts.containsAll(g2artifacts) : "g2 should be associated to exactly artifact 1.";
+        assert g3artifacts.containsAll(g3expectedArtifacts) && g3expectedArtifacts.containsAll(g3artifacts) : "g3 should be associated to exactly artifacts 1 and 2.";
+
+        m_artifact2FeatureRepository.remove(b2g4);
+
+        b1features = b1.getFeatures();
+        b2features = b2.getFeatures();
+        g1artifacts = g1.getArtifacts();
+        g2artifacts = g2.getArtifacts();
+        g3artifacts = g3.getArtifacts();
+
+        b2expectedFeatures.remove(g3);
+        g3expectedArtifacts.remove(b2);
+
+        assert b1features.containsAll(b1expectedFeatures) && b1expectedFeatures.containsAll(b1features) : "b1 should be associated to exactly features 2 and 3.";
+        assert b2features.containsAll(b2expectedFeatures) && b2expectedFeatures.containsAll(b2features) : "b2 should be associated to exactly feature 1.";
+
+        assert g1artifacts.containsAll(g1expectedArtifacts) && g1expectedArtifacts.containsAll(g1artifacts) : "g1 should be associated to exactly artifact 2.";
+        assert g2artifacts.containsAll(g2expectedArtifacts) && g2expectedArtifacts.containsAll(g2artifacts) : "g2 should be associated to exactly artifact 1.";
+        assert g3artifacts.containsAll(g3expectedArtifacts) && g3expectedArtifacts.containsAll(g3artifacts) : "g3 should be associated to exactly artifact 1.";
+    }
+
+
+    /**
+     * Not a full-fledged testcase, but a quick test of the correctness of the
+     * specified classes for features, distributions and their associations. In essence,
+     * this test 'touches' all code which uses generic code which has been tested
+     * by TestAssociations.
+     */
+    @Test( groups = { TestUtils.UNIT } )
+    public void TestFeature2DistributionAssociations() {
+        initializeRepositoryAdmin();
+        FeatureObject f1 = createBasicFeatureObject("feature1");
+        DistributionObject d1 = createBasicDistributionObject("distribution1");
+        Feature2DistributionAssociation f2d1 = m_feature2DistributionRepository.create(f1, d1);
+
+        assert (f2d1.getLeft().size() == 1) && f2d1.getLeft().contains(f1) : "Left side of the association should be our feature.";
+        assert (f2d1.getRight().size() == 1) &&  f2d1.getRight().contains(d1) : "Right side of the association should be our distribution.";
+
+        assert f1.getArtifacts().size() == 0 : "Feature 1 should not be associated with any artifacts; it is associated with " + f1.getArtifacts().size() + ".";
+        assert f1.getDistributions().size() == 1 : "Feature 1 should be associated with exactly one distribution; it is associated with " + f1.getDistributions().size() + ".";
+
+        assert d1.getFeatures().size() == 1 : "Distribution 1 should be associated with exactly one feature; it is associated with " + d1.getFeatures().size() + ".";
+        assert d1.getTargets().size() == 0 : "Distribution 1 should not be associated with any targets; it is associated with " + d1.getTargets().size() + ".";
+    }
+
+    /**
+     * Not a full-fledged testcase, but a quick test of the correctness of the
+     * specified classes for distributions, targets and their associations. In essence,
+     * this test 'touches' all code which uses generic code which has been tested
+     * by TestAssociations.
+     */
+    @Test( groups = { TestUtils.UNIT } )
+    public void testDistribution2TargetAssociations() {
+        initializeRepositoryAdmin();
+        DistributionObject d1 = createBasicDistributionObject("distribution1");
+        TargetObject t1 = createBasicTargetObject("target1");
+        m_distribution2TargetRepository.create(d1, t1);
+
+        assert d1.getFeatures().size() == 0 : "Distribution 1 should not be associated with any features; it is associated with " + d1.getFeatures().size() + ".";
+        assert d1.getTargets().size() == 1 : "Distribution 1 should be associated with exactly one target; it is associated with " + d1.getTargets().size() + ".";
+
+        assert t1.getDistributions().size() == 1 : "Target 1 should be associated with exactly one distribution; it is associated with " + t1.getDistributions().size() + ".";
+    }
+
+    @Test( groups = { TestUtils.UNIT } )
+    public void testGetAssociationsWith() {
+        initializeRepositoryAdmin();
+        ArtifactObject a1 = createBasicArtifactObject("artifact1");
+        FeatureObject f1 = createBasicFeatureObject("feature1");
+        Artifact2FeatureAssociation a2f1 = m_artifact2FeatureRepository.create(a1, f1);
+
+        List<Artifact2FeatureAssociation> b1Associations = a1.getAssociationsWith(f1);
+        List<Artifact2FeatureAssociation> g1Associations = f1.getAssociationsWith(a1);
+
+        assert b1Associations.size() == 1 : "The artifact has exactly one association to the feature, but it shows " + b1Associations.size() + ".";
+        assert b1Associations.get(0) == a2f1 : "The artifact's association should be the one we created.";
+
+        assert g1Associations.size() == 1 : "The feature has exactly one association to the artifact.";
+        assert g1Associations.get(0) == a2f1 : "The feature's association should be the one we created.";
+    }
+
+    /**
+     * Tests the correctness of the equals() in RepositoryObject.
+     */
+    @Test( groups = { TestUtils.UNIT } )
+    public void testEquals() {
+        List<ArtifactObject> artifacts = new ArrayList<ArtifactObject>();
+        artifacts.add(createBasicArtifactObject("artifact1"));
+        artifacts.add(createBasicArtifactObject("artifact2"));
+        artifacts.get(1).addTag("thetag", "thevalue");
+        artifacts.add(createBasicArtifactObject("artifact3"));
+
+        List<ArtifactObject> backupArtifacts = new ArrayList<ArtifactObject>();
+        backupArtifacts.addAll(artifacts);
+
+        for (ArtifactObject b : backupArtifacts) {
+            artifacts.remove(b);
+        }
+
+        assert artifacts.size() == 0 : "The artifacts list should be empty; if not, the ArtifactObject's equals() could be broken.";
+    }
+
+    @Test( groups = { TestUtils.UNIT } )
+    public void testDeploymentVersion() {
+        DeploymentVersionObject version = createBasicDeploymentVersionObject("target1", "1", new String[] {"artifact1", "artifact2"});
+
+        assert version.getDeploymentArtifacts().length == 2 : "We expect to find two artifacts, but we find " + version.getDeploymentArtifacts().length;
+        assert version.getDeploymentArtifacts()[0].getUrl().equals("artifact1");
+        assert version.getDeploymentArtifacts()[1].getUrl().equals("artifact2");
+
+        ((DeploymentArtifactImpl) version.getDeploymentArtifacts()[0]).addDirective("myDirective", "myValue");
+
+        try {
+            createBasicDeploymentVersionObject("target1", "1", new String[] {"artifact1", "artifact2"});
+            assert false : "Creating a deployment version with a target and version that already exists should not be allowed.";
+        }
+        catch (IllegalArgumentException iae) {
+            // expected
+        }
+
+        assert m_deploymentVersionRepository.get().size() == 1 : "The disallowed version should not be in the repository; we find " + m_deploymentVersionRepository.get().size();
+        assert m_deploymentVersionRepository.get().get(0) == version : "Only our newly created version object should be in the repository.";
+
+        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        RepositorySet deployment = new RepositorySet(null, null, null, null, new ObjectRepositoryImpl[] {m_deploymentVersionRepository}, null, "", true);
+        new RepositorySerializer(deployment).toXML(buffer);
+        initializeRepositoryAdmin();
+
+        assert m_deploymentVersionRepository.get().size() == 0;
+
+        deployment = new RepositorySet(null, null, null, null, new ObjectRepositoryImpl[] {m_deploymentVersionRepository}, null, "", true);
+        new RepositorySerializer(deployment).fromXML(new ByteArrayInputStream(buffer.toByteArray()));
+
+
+        assert m_deploymentVersionRepository.get().size() == 1 : "The disallowed version should not be in the repository.";
+        assert m_deploymentVersionRepository.get().get(0).equals(version) : "Only our newly created version object should be in the repository.";
+
+        assert m_deploymentVersionRepository.get().get(0).getDeploymentArtifacts().length == 2 : "We expect to find two artifacts, but we find " + m_deploymentVersionRepository.get().get(0).getDeploymentArtifacts().length;
+        assert m_deploymentVersionRepository.get().get(0).getDeploymentArtifacts()[0].getUrl().equals("artifact1");
+        assert m_deploymentVersionRepository.get().get(0).getDeploymentArtifacts()[0].getKeys().length == 1 : "We expect to find one directive in the first artifact.";
+        assert m_deploymentVersionRepository.get().get(0).getDeploymentArtifacts()[0].getDirective("myDirective").equals("myValue") : "The directive should be 'myValue'.";
+        assert m_deploymentVersionRepository.get().get(0).getDeploymentArtifacts()[1].getUrl().equals("artifact2");
+    }
+
+    @Test( groups = { TestUtils.UNIT } )
+    public void testDeploymentRepository() {
+        DeploymentVersionObject version11 = createBasicDeploymentVersionObject("target1", "1", new String[] {"artifact1", "artifact2"});
+        DeploymentVersionObject version12 = createBasicDeploymentVersionObject("target1", "2", new String[] {"artifact3", "artifact4"});
+        // Note the different order in adding the versions for target2.
+        DeploymentVersionObject version22 = createBasicDeploymentVersionObject("target2", "2", new String[] {"artifactC", "artifactD"});
+        DeploymentVersionObject version21 = createBasicDeploymentVersionObject("target2", "1", new String[] {"artifactA", "artifactB"});
+
+        assert m_deploymentVersionRepository.getDeploymentVersions("NotMyTarget").size() == 0 : "The deployment repository should not return" +
+        		"any versions when we ask for a target that does not exist, but it returns " + m_deploymentVersionRepository.getDeploymentVersions("NotMyTarget").size();
+
+        List<DeploymentVersionObject> for1 = m_deploymentVersionRepository.getDeploymentVersions("target1");
+        assert for1.size() == 2 : "We expect two versions for target1, but we find " + for1.size();
+        assert for1.get(0) == version11 : "The first version for target1 should be version11";
+        assert for1.get(1) == version12 : "The second version for target1 should be version12";
+
+        List<DeploymentVersionObject> for2 = m_deploymentVersionRepository.getDeploymentVersions("target2");
+        assert for2.size() == 2 : "We expect two versions for target2, but we find " + for2.size();
+        assert for2.get(0) == version21 : "The first version for target2 should be version21";
+        assert for2.get(1) == version22 : "The second version for target2 should be version22";
+
+        assert m_deploymentVersionRepository.getMostRecentDeploymentVersion("NotMyTarget") == null : "The most recent version for a non-existent target should not exist.";
+        assert m_deploymentVersionRepository.getMostRecentDeploymentVersion("target1") == version12 : "The most recent version for target1 should be version12";
+        assert m_deploymentVersionRepository.getMostRecentDeploymentVersion("target2") == version22 : "The most recent version for target2 should be version22";
+    }
+
+    @Test( groups = { TestUtils.UNIT } )
+    public void testDeploymentRepositoryFilter() {
+
+        String gwId = "\\ ( * ) target1)";
+        DeploymentVersionObject version1 = createBasicDeploymentVersionObject(gwId, "1", new String[] {"artifact1", "artifact2"});
+
+        List<DeploymentVersionObject> for1 = m_deploymentVersionRepository.getDeploymentVersions( gwId );
+        assert for1.size() == 1 : "We expect one version for" + gwId + ", but we find " + for1.size();
+        assert for1.get(0) == version1 : "The only version for" + gwId +  "should be version1";
+    }
+
+    @Test( groups = { TestUtils.UNIT } )
+    public void testAssociationsWithLists() {
+        ArtifactObject b1 = createBasicArtifactObject("b1");
+        ArtifactObject b2 = createBasicArtifactObject("b2");
+        ArtifactObject b3 = createBasicArtifactObject("b3");
+        FeatureObject g1 = createBasicFeatureObject("g1");
+        FeatureObject g2 = createBasicFeatureObject("g2");
+        FeatureObject g3 = createBasicFeatureObject("g3");
+
+        List<ArtifactObject> artifacts = new ArrayList<ArtifactObject>();
+        artifacts.add(b1);
+        artifacts.add(b2);
+        List<FeatureObject> features = new ArrayList<FeatureObject>();
+        features.add(g1);
+        features.add(g3);
+
+        Artifact2FeatureAssociation bg = m_artifact2FeatureRepository.create(artifacts, features);
+
+        assert bg.getLeft().size() == 2 : "We expect two artifacts on the left side of the association.";
+        assert bg.getRight().size() == 2 : "We expect two features on the right side of the association.";
+
+        assert bg.getLeft().contains(b1) : "b1 should be on the left side of the association.";
+        assert bg.getLeft().contains(b2) : "b2 should be on the left side of the association.";
+        assert !bg.getLeft().contains(b3) : "b3 should not be on the left side of the association.";
+        assert bg.getRight().contains(g1) : "g1 should be on the right side of the association.";
+        assert !bg.getRight().contains(g2) : "g2 should not be on the right side of the association.";
+        assert bg.getRight().contains(g3) : "g3 should be on the right side of the association.";
+
+        List<FeatureObject> foundFeatures = b1.getFeatures();
+        assert foundFeatures.size() == 2 : "b1 should be associated with two features.";
+        assert foundFeatures.contains(g1) : "b1 should be associated with g1";
+        assert !foundFeatures.contains(g2) : "b1 not should be associated with g2";
+        assert foundFeatures.contains(g3) : "b1 should be associated with g3";
+
+        foundFeatures = b3.getFeatures();
+        assert foundFeatures.size() == 0 : "b3 should not be associated with any features.";
+
+        List<ArtifactObject> foundArtifacts = g3.getArtifacts();
+        assert foundArtifacts.size() == 2 : "g1 should be associated with two features.";
+        assert foundArtifacts.contains(b1) : "g1 should be associated with b1";
+        assert foundArtifacts.contains(b2) : "g1 should be associated with b2";
+        assert !foundArtifacts.contains(b3) : "g1 should not be associated with b3";
+    }
+
+    @Test( groups = { TestUtils.UNIT } )
+    public void testAssociationsWithCardinality() {
+        ArtifactObject a1 = createBasicArtifactObject("a1");
+        FeatureObject f1 = createBasicFeatureObject("f1");
+        FeatureObject f2 = createBasicFeatureObject("f2");
+        FeatureObject f3 = createBasicFeatureObject("f3");
+
+        Map<String, String> props = new HashMap<String, String>();
+        props.put(Association.LEFT_ENDPOINT, "(" + BundleHelper.KEY_SYMBOLICNAME + "=a1)");
+        props.put(Association.LEFT_CARDINALITY, "1");
+        props.put(Association.RIGHT_ENDPOINT, "(" + FeatureObject.KEY_NAME + "=f*)");
+        props.put(Association.RIGHT_CARDINALITY, "2");
+        Map<String, String> tags = new HashMap<String, String>();
+
+        try {
+            m_artifact2FeatureRepository.create(props, tags);
+            assert false : "There are three matches for the feature, but we have a cardinality of 2; we should expect a NPE because no comparator is provided.";
+        }
+        catch (NullPointerException npe) {
+            //expected
+        }
+
+        props.put(Association.RIGHT_CARDINALITY, "3");
+
+        Artifact2FeatureAssociation bg = m_artifact2FeatureRepository.create(props, tags);
+        assert bg != null : "Assocating artifact to feature failed?!";
+        
+        assert a1.getFeatures().size() == 3 : "The artifact should be associated to three features.";
+        assert (f1.getArtifacts().size() == 1) && f1.getArtifacts().contains(a1) : "g1 should be associated to only b1.";
+        assert (f2.getArtifacts().size() == 1) && f2.getArtifacts().contains(a1) : "g1 should be associated to only b1.";
+        assert (f3.getArtifacts().size() == 1) && f3.getArtifacts().contains(a1) : "g1 should be associated to only b1.";
+    }
+
+    private Filter createLocalFilter(String filter) throws InvalidSyntaxException {
+        return FrameworkUtil.createFilter(filter);
+    }
+
+    private ArtifactObject createBasicArtifactObject(String symbolicName) {
+        return createBasicArtifactObject(symbolicName, null);
+    }
+
+    private ArtifactObject createBasicArtifactObject(String symbolicName, String version) {
+        Map<String, String> attr = new HashMap<String, String>();
+        attr.put(BundleHelper.KEY_SYMBOLICNAME, symbolicName);
+        attr.put(ArtifactObject.KEY_MIMETYPE, BundleHelper.MIMETYPE);
+        attr.put(ArtifactObject.KEY_URL, "http://" + symbolicName + "-v" + ((version == null) ? "null" : version));
+        Map<String, String> tags = new HashMap<String, String>();
+
+        if (version != null) {
+            attr.put(BundleHelper.KEY_VERSION, version);
+        }
+        return m_artifactRepository.create(attr, tags);
+    }
+
+    private FeatureObject createBasicFeatureObject(String name) {
+        Map<String, String> attr = new HashMap<String, String>();
+        attr.put(FeatureObject.KEY_NAME, name);
+        Map<String, String> tags = new HashMap<String, String>();
+
+        return m_featureRepository.create(attr, tags);
+    }
+
+    private DistributionObject createBasicDistributionObject(String name) {
+        Map<String, String> attr = new HashMap<String, String>();
+        attr.put(DistributionObject.KEY_NAME, name);
+        Map<String, String> tags = new HashMap<String, String>();
+
+        return m_distributionRepository.create(attr, tags);
+    }
+
+    private TargetObject createBasicTargetObject(String id) {
+        Map<String, String> attr = new HashMap<String, String>();
+        attr.put(TargetObject.KEY_ID, id);
+        Map<String, String> tags = new HashMap<String, String>();
+
+        return m_targetRepository.create(attr, tags);
+    }
+
+    private DeploymentVersionObject createBasicDeploymentVersionObject(String targetID, String version, String[] artifacts) {
+        Map<String, String> attr = new HashMap<String, String>();
+        attr.put(DeploymentVersionObject.KEY_TARGETID, targetID);
+        attr.put(DeploymentVersionObject.KEY_VERSION, version);
+        Map<String, String> tags = new HashMap<String, String>();
+
+        List<DeploymentArtifactImpl> deploymentArtifacts = new ArrayList<DeploymentArtifactImpl>();
+        for (String s : artifacts) {
+            deploymentArtifacts.add(new DeploymentArtifactImpl(s));
+        }
+        return m_deploymentVersionRepository.create(attr, tags, deploymentArtifacts.toArray(new DeploymentArtifact[0]));
+    }
+}

Added: ace/sandbox/marrs/org.apache.ace.client.repository.impl/test/org/apache/ace/client/repository/impl/RepositoryAdminLoginContextImplTest.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.impl/test/org/apache/ace/client/repository/impl/RepositoryAdminLoginContextImplTest.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.impl/test/org/apache/ace/client/repository/impl/RepositoryAdminLoginContextImplTest.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.impl/test/org/apache/ace/client/repository/impl/RepositoryAdminLoginContextImplTest.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ace.client.repository.impl;
+
+import java.net.URL;
+
+import org.apache.ace.client.repository.impl.RepositoryAdminLoginContextImpl.RepositorySetDescriptor;
+import org.apache.ace.client.repository.repository.ArtifactRepository;
+import org.apache.ace.client.repository.repository.FeatureRepository;
+import org.apache.ace.test.constants.TestConstants;
+import org.apache.ace.test.utils.TestUtils;
+import org.mockito.Mockito;
+import org.osgi.service.useradmin.User;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * Test cases for {@link RepositoryAdminLoginContextImpl}.
+ */
+public class RepositoryAdminLoginContextImplTest {
+
+    private static final String CUSTOMER = "apache";
+    
+    private static final String NAME_SHOP = "shop";
+    private static final String NAME_DEPLOYMENT = "deployment";
+    
+    private URL m_location;
+    
+    @BeforeMethod
+	public void setUp() throws Exception {
+        m_location = new URL("http://localhost:" + TestConstants.PORT);
+    }
+    
+    /**
+     * Test method for {@link RepositoryAdminLoginContextImpl#addDescriptor(RepositorySetDescriptor)}.
+     */
+    @Test( groups = { TestUtils.UNIT }, expectedExceptions = { IllegalArgumentException.class } )
+    public void testAddDuplicateObjectRepositoryFail() throws Exception {
+        RepositoryAdminLoginContextImpl context = new RepositoryAdminLoginContextImpl(Mockito.mock(User.class), "12345");
+
+        context.addDescriptor(new RepositorySetDescriptor(m_location, CUSTOMER, NAME_SHOP, true, FeatureRepository.class));
+        context.addDescriptor(new RepositorySetDescriptor(m_location, CUSTOMER, NAME_DEPLOYMENT, true, FeatureRepository.class));
+    }
+
+    /**
+     * Test method for {@link RepositoryAdminLoginContextImpl#addDescriptor(RepositorySetDescriptor)}.
+     */
+    @Test( groups = { TestUtils.UNIT } )
+    public void testAddDisjointObjectRepositoriesOk() throws Exception {
+        RepositoryAdminLoginContextImpl context = new RepositoryAdminLoginContextImpl(Mockito.mock(User.class), "12345");
+
+        context.addDescriptor(new RepositorySetDescriptor(m_location, CUSTOMER, NAME_SHOP, true, ArtifactRepository.class));
+        context.addDescriptor(new RepositorySetDescriptor(m_location, CUSTOMER, NAME_DEPLOYMENT, true, FeatureRepository.class));
+    }
+
+    /**
+     * Test method for {@link RepositoryAdminLoginContextImpl#addDescriptor(RepositorySetDescriptor)}.
+     */
+    @Test( groups = { TestUtils.UNIT }, expectedExceptions = { IllegalArgumentException.class } )
+    public void testDuplicateRepositoryNameFail() throws Exception {
+        RepositoryAdminLoginContextImpl context = new RepositoryAdminLoginContextImpl(Mockito.mock(User.class), "12345");
+        
+        context.addDescriptor(new RepositorySetDescriptor(m_location, CUSTOMER, NAME_SHOP, true, ArtifactRepository.class));
+        context.addDescriptor(new RepositorySetDescriptor(m_location, CUSTOMER, NAME_SHOP, true, FeatureRepository.class));
+    }
+}

Added: ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/.classpath
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/.classpath?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/.classpath (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/.classpath Thu Jul  5 12:09:30 2012
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="src" output="bin_test" path="test"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
+	<classpathentry kind="con" path="aQute.bnd.classpath.container"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

Added: ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/.project
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/.project?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/.project (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/.project Thu Jul  5 12:09:30 2012
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.apache.ace.client.repository.useradmin</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>bndtools.core.bndbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>bndtools.core.bndnature</nature>
+	</natures>
+</projectDescription>

Added: ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/bnd.bnd
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/bnd.bnd?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/bnd.bnd (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/bnd.bnd Thu Jul  5 12:09:30 2012
@@ -0,0 +1,12 @@
+-buildpath: osgi.core,\
+	osgi.cmpn,\
+	org.apache.felix.dependencymanager,\
+	org.apache.ace.client.repository.api;version=latest,\
+	org.apache.ace.repository.api;version=latest,\
+	org.apache.ace.range.api;version=latest,\
+	org.apache.ace.util;version=latest,\
+	../cnf/lib/xpp3-1.1.4c.jar;version=file,\
+	../cnf/lib/xstream-1.2.2.jar;version=file,\
+	org.apache.ace.client.repository.helper.base;version=latest,\
+	org.apache.ace.repository.ext;version=latest,\
+	org.apache.ace.server.log.store;version=latest

Added: ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/build.xml
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/build.xml?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/build.xml (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/build.xml Thu Jul  5 12:09:30 2012
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="project" default="build"> 
+	<import file="../cnf/build.xml"/>
+</project>

Added: ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/old/main/appended-resources/META-INF/LICENSE.vm
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/old/main/appended-resources/META-INF/LICENSE.vm?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/old/main/appended-resources/META-INF/LICENSE.vm (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/old/main/appended-resources/META-INF/LICENSE.vm Thu Jul  5 12:09:30 2012
@@ -0,0 +1,90 @@
+##
+## 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.
+##
+XStream License
+---------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of
+conditions and the following disclaimer. Redistributions in binary form must reproduce
+the above copyright notice, this list of conditions and the following disclaimer in
+the documentation and/or other materials provided with the distribution.
+
+Neither the name of XStream nor the names of its contributors may be used to endorse
+or promote products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+XPP3 License
+------------
+* The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.

Added: ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/old/main/appended-resources/META-INF/NOTICE.vm
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/old/main/appended-resources/META-INF/NOTICE.vm?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/old/main/appended-resources/META-INF/NOTICE.vm (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/old/main/appended-resources/META-INF/NOTICE.vm Thu Jul  5 12:09:30 2012
@@ -0,0 +1,30 @@
+##
+## 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.
+##
+This product includes software developed at
+'XStream' (http://xstream.codehaus.org)
+Copyright (c) 2003-2006, Joe Walnes
+Copyright (c) 2006-2007, XStream Committers
+Licensed under BSD style  
+
+This product includes software developed at
+'Extreme! Lab, Indiana University' (http://www.extreme.indiana.edu/)
+Copyright (c) all rights reserved
+Licensed under Apache Software License, version 1.1  
+
+

Added: ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/pom.xml
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/pom.xml?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/pom.xml (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/pom.xml Thu Jul  5 12:09:30 2012
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ace</groupId>
+        <artifactId>ace-pom</artifactId>
+        <version>0.8.1-SNAPSHOT</version>
+        <relativePath>../pom/pom.xml</relativePath>
+    </parent>
+
+    <version>0.8.1-SNAPSHOT</version>
+    <artifactId>org.apache.ace.client.repository.useradmin</artifactId>
+    <packaging>bundle</packaging>
+
+    <name>Apache ACE :: Client :: Repository :: UserAdmin</name>
+    <description />
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/ace/trunk/ace-client-repository-useradmin</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/ace/trunk/ace-client-repository-useradmin</developerConnection>
+        <url>http://svn.apache.org/repos/asf/ace/trunk/ace-client-repository-useradmin</url>
+    </scm>
+
+    <properties>
+        <export.package>
+            org.apache.ace.client.repositoryuseradmin;version=${project.version}
+        </export.package>
+        <import.package>
+            !org.apache.ace.client.repositoryuseradmin,
+            !javax.security.auth,
+	        !javax.swing.plaf,
+	        !javax.xml.parsers,
+	        !javax.xml.stream,
+	        !javax.xml.transform.sax,
+	        !net.sf.cglib.proxy,
+	        !nu.xom,
+	        !org.codehaus.jettison.mapped,
+	        !org.dom4j,
+	        !org.dom4j.io,
+	        !org.dom4j.tree,
+	        !org.jdom,
+	        !org.jdom.input,
+	        !org.joda.time,
+	        !org.joda.time.format,
+	        !org.w3c.dom,
+	        !org.xml.sax,
+	        !org.xml.sax.helpers,
+	        !sun.misc,
+	        !sun.reflect,
+	        *
+        </import.package>
+        <private.package>
+            org.apache.ace.client.repositoryuseradmin.impl,
+            org.apache.ace.repository.ext,
+            org.apache.ace.repository.ext.impl
+        </private.package>
+        <bundle.activator>org.apache.ace.client.repositoryuseradmin.impl.Activator</bundle.activator>
+        <embed.dependency>xstream, xpp3</embed.dependency>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.client.repository.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.client.repository.helper.base</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.range.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.repository.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.repository.ext</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.server.log.store</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.thoughtworks.xstream</groupId>
+            <artifactId>xstream</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>xpp3</groupId>
+            <artifactId>xpp3</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

Added: ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/src/org/apache/ace/client/repositoryuseradmin/RepositoryUserAdmin.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/src/org/apache/ace/client/repositoryuseradmin/RepositoryUserAdmin.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/src/org/apache/ace/client/repositoryuseradmin/RepositoryUserAdmin.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/src/org/apache/ace/client/repositoryuseradmin/RepositoryUserAdmin.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,79 @@
+/*
+ * 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.ace.client.repositoryuseradmin;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * RepositoryUserAdmin is used for managing a User Admin repository
+ * that is present on a server. It uses the UserAdmin interface to
+ * allow alterations. Any non-supported functions from UserAdmin
+ * (or its related classes) will result in a {@link UnsupportedOperationException}.<br>
+ * <br>
+ * This service uses the same checkout/commit/revert scheme that
+ * RepositoryAdmin does; when making changes, they will always be stored locally,
+ * but they will only be updated on the server once commit is called.<br>
+ * <br>
+ * Note that this implementation will <b>not</b> send any events.
+ */
+public interface RepositoryUserAdmin extends UserAdmin {
+
+    /**
+     * Logs in to a specific repository location.
+     * @param user A user object to use in the connection
+     * @param repositoryLocation A URL representing the base URL of the repository service
+     * @param repositoryCustomer The 'customer' for which the repository is registered
+     * @param repositoryName The 'name' for which the repository is registered
+     * @param writeAccess <code>true</code> if write-access is required, <code>false</code> otherwise.
+     * @throws java.io.IOException Thrown when there is a problem handling the backup files.
+     */
+    public void login(User user, URL repositoryLocation, String repositoryCustomer, String repositoryName) throws IOException;
+
+    /**
+     * Logs out the user.
+     * @param force Even when something goes wrong, force a logout.
+     * @throws java.io.IOException When there is a problem writing the current status to local storage.
+     */
+    public void logout(boolean force) throws IOException;
+
+    /**
+     * Checks out the latest version from the server. If any changes exist, they will
+     * be reflected in this service's user admin.
+     * @throws java.io.IOException If there is a problem communicating with the server.
+     */
+    public void checkout() throws IOException;
+
+    /**
+     * Writes all changes made to this service's user admin to the server.
+     * @throws java.io.IOException If there is a problem communicating with the server.
+     */
+    public void commit() throws IOException;
+
+    /**
+     * Undoes all changes to this service's user admin, and restores the previously
+     * checked out or committed version.
+     * @throws java.io.IOException If there is a problem retrieving the data from the
+     * local backup.
+     */
+    public void revert() throws IOException;
+}
\ No newline at end of file

Added: ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/src/org/apache/ace/client/repositoryuseradmin/impl/Activator.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/src/org/apache/ace/client/repositoryuseradmin/impl/Activator.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/src/org/apache/ace/client/repositoryuseradmin/impl/Activator.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.useradmin/src/org/apache/ace/client/repositoryuseradmin/impl/Activator.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,56 @@
+/*
+ * 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.ace.client.repositoryuseradmin.impl;
+
+import org.apache.ace.client.repositoryuseradmin.RepositoryUserAdmin;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+import org.osgi.service.prefs.PreferencesService;
+
+/**
+ * Activator for the Repository UserAdmin. Note that this UserAdmin is not intended
+ * to be a full implementation of the UserAdmin specification, but rather a
+ * value-object model that uses the UserAdmin interface for convenience.
+ */
+public class Activator extends DependencyActivatorBase {
+
+    RepositoryUserAdminImpl m_impl;
+
+    @Override
+    public void init(BundleContext context, DependencyManager manager) {
+        m_impl = new RepositoryUserAdminImpl();
+        manager.add(createComponent()
+            .setInterface(RepositoryUserAdmin.class.getName(), null)
+            .setImplementation(m_impl)
+            .add(createServiceDependency()
+                 .setService(PreferencesService.class)
+                 .setRequired(true))
+            .add(createServiceDependency()
+                 .setService(LogService.class)
+                 .setRequired(false)));
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+        // At least, save our progress.
+        m_impl.logout(true);
+    }
+}
\ No newline at end of file