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 2014/02/17 15:37:34 UTC

svn commit: r1569011 [3/3] - in /ace/trunk: cnf/localrepo/ cnf/localrepo/org.apache.felix.useradmin.filestore/ cnf/localrepo/org.apache.felix.useradmin/ org.apache.ace.authentication.itest/ org.apache.ace.client.automation/src/org/apache/ace/client/aut...

Added: ace/trunk/cnf/localrepo/org.apache.felix.useradmin.filestore/org.apache.felix.useradmin.filestore-1.0.2.jar
URL: http://svn.apache.org/viewvc/ace/trunk/cnf/localrepo/org.apache.felix.useradmin.filestore/org.apache.felix.useradmin.filestore-1.0.2.jar?rev=1569011&view=auto
==============================================================================
Binary file - no diff available.

Propchange: ace/trunk/cnf/localrepo/org.apache.felix.useradmin.filestore/org.apache.felix.useradmin.filestore-1.0.2.jar
------------------------------------------------------------------------------
    svn:mime-type = application/jar

Added: ace/trunk/cnf/localrepo/org.apache.felix.useradmin/org.apache.felix.useradmin-1.0.3.jar
URL: http://svn.apache.org/viewvc/ace/trunk/cnf/localrepo/org.apache.felix.useradmin/org.apache.felix.useradmin-1.0.3.jar?rev=1569011&view=auto
==============================================================================
Binary file - no diff available.

Propchange: ace/trunk/cnf/localrepo/org.apache.felix.useradmin/org.apache.felix.useradmin-1.0.3.jar
------------------------------------------------------------------------------
    svn:mime-type = application/jar

Modified: ace/trunk/org.apache.ace.authentication.itest/bnd.bnd
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.authentication.itest/bnd.bnd?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.authentication.itest/bnd.bnd (original)
+++ ace/trunk/org.apache.ace.authentication.itest/bnd.bnd Mon Feb 17 14:37:33 2014
@@ -41,7 +41,6 @@ Test-Cases: ${classes;CONCRETE;EXTENDS;o
 	org.apache.ace.client.repository.helper.bundle;version=latest,\
 	org.apache.ace.client.repository.helper.configuration;version=latest,\
 	org.apache.ace.client.repository.impl;version=latest,\
-	org.apache.ace.configurator.serveruseradmin;version=latest,\
 	org.apache.ace.configurator.useradmin.task;version=latest,\
 	org.apache.ace.connectionfactory;version=latest,\
 	org.apache.ace.deployment.provider.api;version=latest,\

Modified: ace/trunk/org.apache.ace.client.automation/src/org/apache/ace/client/automation/AutoTargetOperator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.automation/src/org/apache/ace/client/automation/AutoTargetOperator.java?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.automation/src/org/apache/ace/client/automation/AutoTargetOperator.java (original)
+++ ace/trunk/org.apache.ace.client.automation/src/org/apache/ace/client/automation/AutoTargetOperator.java Mon Feb 17 14:37:33 2014
@@ -40,8 +40,8 @@ import org.osgi.service.useradmin.User;
 import org.osgi.service.useradmin.UserAdmin;
 
 /**
- * Automatic target operator, when configured will automatically register, approve, auto-approve
- * and commit targets to the repository. An LDAP filter can be used to filter for the correct targets.
+ * Automatic target operator, when configured will automatically register, approve, auto-approve and commit targets to
+ * the repository. An LDAP filter can be used to filter for the correct targets.
  */
 public class AutoTargetOperator implements ManagedService {
 
@@ -55,20 +55,18 @@ public class AutoTargetOperator implemen
     private volatile LogService m_log;
     private volatile Dictionary m_settings;
 
-    private static String username = "serverUser";
-
     // used for processing the auditlog (tell the repository about that)
     private final AuditLogProcessTask m_task = new AuditLogProcessTask();
     private Object m_serviceReg = null;
 
     public void start() {
         // get user
-        User user = m_userAdmin.getUser("username",username);
+        User user = m_userAdmin.getUser("username", getConfigValue(ConfigItem.USERNAME));
 
         // login at Repository admin
         try {
-            URL url =  new URL(getConfigValue( ConfigItem.HOSTNAME) + getConfigValue( ConfigItem.ENDPOINT));
-            String customerName = getConfigValue( ConfigItem.CUSTOMER_NAME);
+            URL url = new URL(getConfigValue(ConfigItem.HOSTNAME) + getConfigValue(ConfigItem.ENDPOINT));
+            String customerName = getConfigValue(ConfigItem.CUSTOMER_NAME);
 
             RepositoryAdminLoginContext loginContext = m_reposAdmin.createLoginContext(user);
             loginContext
@@ -99,7 +97,7 @@ public class AutoTargetOperator implemen
 
         m_serviceReg = null;
 
-        //logout
+        // logout
         try {
             m_reposAdmin.logout(true);
         }
@@ -110,7 +108,8 @@ public class AutoTargetOperator implemen
     }
 
     /**
-     * Runnable that will synchronize audit log data with the server and tell the repository about the changes if applicable.
+     * Runnable that will synchronize audit log data with the server and tell the repository about the changes if
+     * applicable.
      */
     private final class AuditLogProcessTask implements Runnable {
 
@@ -118,7 +117,7 @@ public class AutoTargetOperator implemen
 
         public void process() {
             // perform synchronous model actions
-            synchronized(m_lock) {
+            synchronized (m_lock) {
                 m_statefulTargetRepos.refresh();
                 boolean changed = false;
                 try {
@@ -147,22 +146,22 @@ public class AutoTargetOperator implemen
         }
 
         public void run() {
-                process();
+            process();
         }
     }
 
     private void checkoutModel() throws IOException {
         // Do a checkout
         if (!m_reposAdmin.isCurrent()) {
-               m_reposAdmin.checkout();
+            m_reposAdmin.checkout();
         }
     }
 
     private boolean registerTargets() throws InvalidSyntaxException {
         boolean changed = false;
-        String filter = "(&" + getConfigValue( ConfigItem.REGISTER_TARGET_FILTER) +
-        "(" + StatefulTargetObject.KEY_REGISTRATION_STATE + "=" + StatefulTargetObject.RegistrationState.Unregistered + "))";
-        List<StatefulTargetObject> stos =  m_statefulTargetRepos.get(m_bundleContext.createFilter(filter));
+        String filter = "(&" + getConfigValue(ConfigItem.REGISTER_TARGET_FILTER) +
+            "(" + StatefulTargetObject.KEY_REGISTRATION_STATE + "=" + StatefulTargetObject.RegistrationState.Unregistered + "))";
+        List<StatefulTargetObject> stos = m_statefulTargetRepos.get(m_bundleContext.createFilter(filter));
         for (StatefulTargetObject sto : stos) {
             sto.register();
             changed = true;
@@ -172,28 +171,28 @@ public class AutoTargetOperator implemen
 
     private boolean setAutoApprove() throws InvalidSyntaxException {
         boolean changed = false;
-        String filter = "(&" + getConfigValue( ConfigItem.AUTO_APPROVE_TARGET_FILTER) +
-        "(" + StatefulTargetObject.KEY_REGISTRATION_STATE + "=" + StatefulTargetObject.RegistrationState.Registered + ")" +
-        "(!(" + TargetObject.KEY_AUTO_APPROVE + "=true)))";
+        String filter = "(&" + getConfigValue(ConfigItem.AUTO_APPROVE_TARGET_FILTER) +
+            "(" + StatefulTargetObject.KEY_REGISTRATION_STATE + "=" + StatefulTargetObject.RegistrationState.Registered + ")" +
+            "(!(" + TargetObject.KEY_AUTO_APPROVE + "=true)))";
 
-        List<StatefulTargetObject> stos =  m_statefulTargetRepos.get(m_bundleContext.createFilter(filter));
+        List<StatefulTargetObject> stos = m_statefulTargetRepos.get(m_bundleContext.createFilter(filter));
         for (StatefulTargetObject sto : stos) {
-                sto.setAutoApprove(true);
-                changed = true;
-            }
+            sto.setAutoApprove(true);
+            changed = true;
+        }
         return changed;
     }
 
     private boolean approveTargets() throws InvalidSyntaxException {
         boolean changed = false;
-        String filter = "(&" + getConfigValue( ConfigItem.APPROVE_TARGET_FILTER) +
-        "(" + StatefulTargetObject.KEY_STORE_STATE + "=" + StatefulTargetObject.StoreState.Unapproved + "))";
+        String filter = "(&" + getConfigValue(ConfigItem.APPROVE_TARGET_FILTER) +
+            "(" + StatefulTargetObject.KEY_STORE_STATE + "=" + StatefulTargetObject.StoreState.Unapproved + "))";
 
-        List<StatefulTargetObject> stos =  m_statefulTargetRepos.get(m_bundleContext.createFilter(filter));
-            for (StatefulTargetObject sto : stos) {
-                sto.approve();
-                changed = true;
-            }
+        List<StatefulTargetObject> stos = m_statefulTargetRepos.get(m_bundleContext.createFilter(filter));
+        for (StatefulTargetObject sto : stos) {
+            sto.approve();
+            changed = true;
+        }
         return changed;
     }
 
@@ -201,7 +200,7 @@ public class AutoTargetOperator implemen
         if (settings != null) {
             for (ConfigItem item : ConfigItem.values()) {
                 String value = (String) settings.get(item.toString());
-                if ((value == null) || value.equals("")) {
+                if ((value == null) || "".equals(value.trim())) {
                     throw new ConfigurationException(item.toString(), item.getErrorText());
                 }
             }
@@ -211,7 +210,8 @@ public class AutoTargetOperator implemen
     }
 
     /**
-     * @param item The configuration item (enum)
+     * @param item
+     *            The configuration item (enum)
      * @return The value stored in the configuration dictionary.
      */
     private String getConfigValue(ConfigItem item) {
@@ -219,21 +219,21 @@ public class AutoTargetOperator implemen
     }
 
     /**
-     *  Helper class used for target automation client configuration.
-     *  ENUM (itemname, errormessage, filter true/false)
+     * Helper class used for target automation client configuration. ENUM (itemname, errormessage, filter true/false)
      *
      */
     private enum ConfigItem {
-        REGISTER_TARGET_FILTER ("registerTargetFilter", "Register target filter missing", true),
-        APPROVE_TARGET_FILTER ("approveTargetFilter", "Approve target filter missing", true),
-        AUTO_APPROVE_TARGET_FILTER ("autoApproveTargetFilter", "Auto approve config value missing", true),
-        COMMIT_REPO ("commitRepositories", "Commit value missing.", false),
-        TARGET_REPOSITORY ("targetRepository", "TargetRepository id missing.", false),
-        DEPLOYMENT_REPOSITORY ("deploymentRepository", "DeploymentRepository id missing.", false),
-        STORE_REPOSITORY ("storeRepository", "Store Repository id missing.", false),
-        CUSTOMER_NAME ("customerName", "Customer name missing", false),
-        HOSTNAME ("hostName", "Hostname missing.", false),
-        ENDPOINT ("endpoint", "Endpoint missing in config.", false);
+        REGISTER_TARGET_FILTER("registerTargetFilter", "Register target filter missing", true),
+        APPROVE_TARGET_FILTER("approveTargetFilter", "Approve target filter missing", true),
+        AUTO_APPROVE_TARGET_FILTER("autoApproveTargetFilter", "Auto approve config value missing", true),
+        COMMIT_REPO("commitRepositories", "Commit value missing.", false),
+        TARGET_REPOSITORY("targetRepository", "TargetRepository id missing.", false),
+        DEPLOYMENT_REPOSITORY("deploymentRepository", "DeploymentRepository id missing.", false),
+        STORE_REPOSITORY("storeRepository", "Store Repository id missing.", false),
+        CUSTOMER_NAME("customerName", "Customer name missing", false),
+        HOSTNAME("hostName", "Hostname missing.", false),
+        ENDPOINT("endpoint", "Endpoint missing in config.", false),
+        USERNAME("userName", "UserName missing.", false);
 
         private final String m_name;
         private final String m_errorText;
@@ -259,4 +259,4 @@ public class AutoTargetOperator implemen
             return m_isFilter;
         }
     }
-}
\ No newline at end of file
+}

Modified: ace/trunk/org.apache.ace.client.repository.itest/bnd.bnd
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository.itest/bnd.bnd?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.repository.itest/bnd.bnd (original)
+++ ace/trunk/org.apache.ace.client.repository.itest/bnd.bnd Mon Feb 17 14:37:33 2014
@@ -5,6 +5,7 @@ Test-Cases: ${classes;CONCRETE;EXTENDS;o
 	org.apache.felix.dependencymanager,\
 	org.apache.ace.test;version=latest,\
 	org.apache.ace.http.listener;version=latest,\
+	org.apache.ace.configurator.useradmin.task;version=latest,\
 	org.apache.ace.discovery.api;version=latest,\
 	org.apache.ace.discovery.property;version=latest,\
 	org.apache.ace.identification.api;version=latest,\
@@ -59,7 +60,6 @@ Test-Cases: ${classes;CONCRETE;EXTENDS;o
 	org.apache.ace.repository.api;version=latest,\
 	org.apache.ace.repository.impl;version=latest,\
 	org.apache.ace.repository.servlet;version=latest,\
-	org.apache.ace.configurator.serveruseradmin;version=latest,\
 	org.apache.ace.obr.metadata;version=latest,\
 	org.apache.ace.obr.servlet;version=latest,\
 	org.apache.ace.obr.storage;version=latest,\

Modified: ace/trunk/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/BaseRepositoryAdminTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/BaseRepositoryAdminTest.java?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/BaseRepositoryAdminTest.java (original)
+++ ace/trunk/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/BaseRepositoryAdminTest.java Mon Feb 17 14:37:33 2014
@@ -70,11 +70,15 @@ import org.osgi.service.event.Event;
 import org.osgi.service.event.EventConstants;
 import org.osgi.service.event.EventHandler;
 import org.osgi.service.http.HttpService;
+import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
 import org.osgi.util.tracker.ServiceTracker;
 
 public abstract class BaseRepositoryAdminTest extends IntegrationTestBase {
 
+    protected static final String TEST_USER_NAME = "testUser";
+
     final class MockUser implements User {
         private final String m_name;
 
@@ -271,6 +275,30 @@ public abstract class BaseRepositoryAdmi
         return m_targetRepository.create(attr, tags);
     }
 
+    /**
+     * @return a {@link User} with {@link #TEST_USER_NAME} as user name, can be <code>null</code>.
+     */
+    protected final User createTestUser() {
+        return createUser(TEST_USER_NAME);
+    }
+
+    /**
+     * @param name
+     *            the name of the user to create, cannot be <code>null</code>;
+     * @return a {@link User} with the given name, or <code>null</code> in case no such user could be created.
+     */
+    protected final User createUser(String name) {
+        UserAdmin useradmin = getService(UserAdmin.class);
+        User user = (User) useradmin.createRole(name, Role.USER);
+        if (user == null) {
+            user = useradmin.getUser("username", name);
+        }
+        else {
+            user.getProperties().put("username", name);
+        }
+        return user;
+    }
+
     protected void deleteObr(String endpoint) throws IOException, InvalidSyntaxException, InterruptedException {
         // This is a little ugly: we cannot just delete the configuration, since that will result in a
         // sharing violation between this bundle and the servlet bundle. In stead, we make the servlet

Modified: ace/trunk/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/ClientAutomationTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/ClientAutomationTest.java?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/ClientAutomationTest.java (original)
+++ ace/trunk/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/ClientAutomationTest.java Mon Feb 17 14:37:33 2014
@@ -44,6 +44,8 @@ public class ClientAutomationTest extend
      */
     public void testAutoTargetOperator() throws Exception {
         startRepositoryService();
+        
+        createTestUser();
 
         addRepository("storeInstance", "apache", "store", true);
         addRepository("targetInstance", "apache", "target", true);
@@ -60,6 +62,7 @@ public class ClientAutomationTest extend
         props.put("storeRepository", "store");
         props.put("customerName", "apache");
         props.put("hostName", HOST);
+        props.put("userName", TEST_USER_NAME);
         props.put("endpoint", ENDPOINT_NAME);
 
         final Configuration config = m_configAdmin.getConfiguration("org.apache.ace.client.automation", null);

Modified: ace/trunk/org.apache.ace.client.rest.itest/bnd.bnd
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.rest.itest/bnd.bnd?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.rest.itest/bnd.bnd (original)
+++ ace/trunk/org.apache.ace.client.rest.itest/bnd.bnd Mon Feb 17 14:37:33 2014
@@ -68,7 +68,6 @@ Test-Cases: ${classes;CONCRETE;EXTENDS;o
 	org.apache.ace.repository.api;version=latest,\
 	org.apache.ace.repository.impl;version=latest,\
 	org.apache.ace.repository.servlet;version=latest,\
-	org.apache.ace.configurator.serveruseradmin;version=latest,\
 	org.apache.ace.obr.metadata;version=latest,\
 	org.apache.ace.obr.servlet;version=latest,\
 	org.apache.ace.obr.storage;version=latest,\

Modified: ace/trunk/org.apache.ace.configurator/src/org/apache/ace/configurator/useradmin/task/UpdateUserAdminTask.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.configurator/src/org/apache/ace/configurator/useradmin/task/UpdateUserAdminTask.java?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.configurator/src/org/apache/ace/configurator/useradmin/task/UpdateUserAdminTask.java (original)
+++ ace/trunk/org.apache.ace.configurator/src/org/apache/ace/configurator/useradmin/task/UpdateUserAdminTask.java Mon Feb 17 14:37:33 2014
@@ -98,9 +98,13 @@ public class UpdateUserAdminTask impleme
     public void run() {
         try {
             if (!m_repo.isCurrent()) {
+                m_log.log(LogService.LOG_DEBUG, "UpdateUserAdminTask updating to latest version...");
+
                 m_configurator.setUsers(m_repo.checkout(true));
-                m_log.log(LogService.LOG_DEBUG, "UpdateUserAdminTask updates to a new version: " + m_repo.getMostRecentVersion());
+
                 saveVersion(m_properties, m_repo.getMostRecentVersion());
+
+                m_log.log(LogService.LOG_DEBUG, "UpdateUserAdminTask updated to latest version: " + m_repo.getMostRecentVersion());
             }
         }
         catch (ConnectException e) {
@@ -111,25 +115,7 @@ public class UpdateUserAdminTask impleme
             // If anything went wrong, this means the remote repository is not available;
             // this also means the UserAdmin is left undisturbed.
             m_log.log(LogService.LOG_WARNING, "Failed to update UserAdmin repository.", e);
-        }
-    }
 
-    /**
-     * Called by Dependency Manager upon starting of this component.
-     * 
-     * @param comp
-     *            this component, cannot be <code>null</code>.
-     */
-    public void start(Component comp) {
-        try {
-            // Try to read the server data
-            m_configurator.setUsers(m_repo.checkout(true));
-        }
-        catch (ConnectException e) {
-            // ACE-199: log only a single line, instead of a complete stack trace...
-            m_log.log(LogService.LOG_WARNING, "Failed to update UserAdmin repository. Connection refused (is the server down?!)");
-        }
-        catch (IOException e) {
             try {
                 m_log.log(LogService.LOG_DEBUG, "UpdateUserAdminTask failed to load remote data; falling back to local data.");
                 // If reading remote fails, try to set whatever we have locally
@@ -142,6 +128,17 @@ public class UpdateUserAdminTask impleme
         }
     }
 
+    /**
+     * Called by Dependency Manager upon starting of this component.
+     * 
+     * @param comp
+     *            this component, cannot be <code>null</code>.
+     */
+    public void start(Component comp) {
+        // ACE-452: run at least once at start-up...
+        run();
+    }
+
     public void updated(Dictionary dict) throws ConfigurationException {
         if (dict != null) {
             String customer = (String) dict.get(KEY_REPOSITORY_CUSTOMER);
@@ -182,6 +179,9 @@ public class UpdateUserAdminTask impleme
      *            the remote repository to remove, cannot be <code>null</code>.
      */
     final void removeRepo(Repository remoteRepo) {
+        // Ensure the latest version is properly stored...
+        saveVersion(m_properties, m_repo.getMostRecentVersion());
+
         m_repo = null;
     }
 

Modified: ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/UserAdminConfigurator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/UserAdminConfigurator.java?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/UserAdminConfigurator.java (original)
+++ ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/UserAdminConfigurator.java Mon Feb 17 14:37:33 2014
@@ -21,13 +21,12 @@ package org.apache.ace.resourceprocessor
 import java.io.IOException;
 import java.io.InputStream;
 
-import org.w3c.dom.Document;
-
 /**
- * The UserAdminConfigurator can be used to install, remove or explicitly set the users that
- * should be present in the system's UserAdmin.<br>
+ * The UserAdminConfigurator can be used to install, remove or explicitly set the users that should be present in the
+ * system's UserAdmin.<br>
  * <br>
  * The document should have the following shape,
+ * 
  * <pre>
  * &lt;roles&gt;
  *     &lt;group name="group1"/&gt;
@@ -46,48 +45,21 @@ import org.w3c.dom.Document;
  *     &lt;/user&gt;
  * &lt;/roles&gt;
  * </pre>
- * Note that when 'type' is missing in the values for properties or credentials, "String" will be assumed.
- * <br>
- * When no UserAdmin is available at time of installation, the UserAdminStore will keep the
- * data around until one is, and update it with all data it has received up to then.
- * Note that UserAdminStore is intended to work with one UserAdmin at a time.
+ * 
+ * Note that when 'type' is missing in the values for properties or credentials, "String" will be assumed. <br>
+ * When no UserAdmin is available at time of installation, the UserAdminStore will keep the data around until one is,
+ * and update it with all data it has received up to then. Note that UserAdminStore is intended to work with one
+ * UserAdmin at a time.
  */
 public interface UserAdminConfigurator
 {
     /**
-     * Installs all roles found in a document.
-     * @param doc The document.
-     */
-    public void install(Document doc);
-    /**
-     * Installs all roles found in a document.
-     * @param input A stream containing the document.
-     * @throws java.io.IOException When there is a problem retrieving the document from the stream.
-     */
-    public void install(InputStream input) throws IOException;
-    /**
-     * Removes all roles found in a document.
-     * @param doc The document.
-     */
-    public void uninstall(Document doc);
-    /**
-     * Uninstalls all roles found in a document.
-     * @param input A stream containing the document.
-     * @throws java.io.IOException When there is a problem retrieving the document from the stream.
-     */
-    public void uninstall(InputStream input) throws IOException;
-
-    /**
-     * Sets the users found in a document as the only users to be present
-     * in the UserAdmin.
-     * @param doc The document.
-     */
-    public void setUsers(Document doc);
-    /**
-     * Sets the users found in a document as the only users to be present
-     * in the UserAdmin.
-     * @param input A stream containing the document.
-     * @throws java.io.IOException When there is a problem retrieving the document from the stream.
+     * Sets the users found in a document as the only users to be present in the UserAdmin.
+     * 
+     * @param input
+     *            A stream containing the document.
+     * @throws java.io.IOException
+     *             When there is a problem retrieving the document from the stream.
      */
     public void setUsers(InputStream input) throws IOException;
-}
\ No newline at end of file
+}

Modified: ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/Activator.java?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/Activator.java (original)
+++ ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/Activator.java Mon Feb 17 14:37:33 2014
@@ -30,9 +30,8 @@ import org.osgi.service.log.LogService;
 import org.osgi.service.useradmin.UserAdmin;
 
 /**
- * Activator for the UserAdmin resource processor. The services of this bundle
- * will be published as a UserAdminConfigurator, and a ResourceProcessor for use
- * by the Deployment Admin.
+ * Activator for the UserAdmin resource processor. The services of this bundle will be published as a
+ * UserAdminConfigurator, and a ResourceProcessor for use by the Deployment Admin.
  */
 public class Activator extends DependencyActivatorBase {
     private static final String PID = "org.apache.ace.resourceprocessor.useradmin";
@@ -45,15 +44,14 @@ public class Activator extends Dependenc
         Properties props = new Properties();
         props.put(Constants.SERVICE_PID, PID);
         manager.add(createComponent().setInterface(ResourceProcessor.class.getName(), props)
-                .setImplementation(processor)
-                .add(createServiceDependency()
-                    .setService(UserAdminConfigurator.class)
-                    .setRequired(true)) // This UserAdminConfigurator is the same as below,
-                                        // and we don't want to add UserAdmins twice.
-                .add(createServiceDependency()
-                    .setService(LogService.class)
-                    .setRequired(false)));
-
+            .setImplementation(processor)
+            .add(createServiceDependency()
+                .setService(UserAdminConfigurator.class)
+                .setRequired(true)) // This UserAdminConfigurator is the same as below,
+                                    // and we don't want to add UserAdmins twice.
+            .add(createServiceDependency()
+                .setService(LogService.class)
+                .setRequired(false)));
 
         manager.add(createComponent().setInterface(UserAdminConfigurator.class.getName(), null)
             .setImplementation(userAdminStore)
@@ -70,4 +68,4 @@ public class Activator extends Dependenc
     public void destroy(BundleContext context, DependencyManager manager) throws Exception {
         // do nothing
     }
-}
\ No newline at end of file
+}

Modified: ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/Processor.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/Processor.java?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/Processor.java (original)
+++ ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/Processor.java Mon Feb 17 14:37:33 2014
@@ -29,11 +29,10 @@ import org.osgi.service.deploymentadmin.
 import org.osgi.service.log.LogService;
 
 /**
- * Implementation of the ResourceProcessor. This base class takes care of
- * the interaction with the DeploymentAdmin, while delegating the 'actual' work
- * to a store.
+ * Implementation of the ResourceProcessor. This base class takes care of the interaction with the DeploymentAdmin,
+ * while delegating the 'actual' work to a store.
  */
-public class Processor implements ResourceProcessor{
+public class Processor implements ResourceProcessor {
     private volatile LogService m_log; /* Injected by dependency manager */
 
     private volatile DeploymentSession m_session;
@@ -41,9 +40,9 @@ public class Processor implements Resour
     private List<String> m_toInstall;
     private List<String> m_toRemove;
 
-    private final ResourceStore m_resourceStore;
+    private final UserAdminStore m_resourceStore;
 
-    Processor(ResourceStore store) {
+    Processor(UserAdminStore store) {
         m_resourceStore = store;
     }
 
@@ -78,7 +77,7 @@ public class Processor implements Resour
         m_toRemove = null;
     }
 
-    private void ensureSession()  {
+    private void ensureSession() {
         if (m_session == null) {
             throw new IllegalStateException("This resource processor is currently not part of a deployment session.");
         }
@@ -155,4 +154,4 @@ public class Processor implements Resour
         // Nothing to do: we have no long-running operation, we only read the stream.
     }
 
-}
\ No newline at end of file
+}

Modified: ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/ResourceStore.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/ResourceStore.java?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/ResourceStore.java (original)
+++ ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/ResourceStore.java Mon Feb 17 14:37:33 2014
@@ -32,10 +32,9 @@ import org.osgi.framework.BundleContext;
 import org.osgi.service.deploymentadmin.spi.ResourceProcessorException;
 
 /**
- * The ResourceStore keeps track of resources, keeps them around in a separate storage
- * for installing and removing, and keeps track of which resource belongs to which deployment package.
- * The information stored by the ResourceStore will be persisted as often as possible, to allow
- * crash recovery.
+ * The ResourceStore keeps track of resources, keeps them around in a separate storage for installing and removing, and
+ * keeps track of which resource belongs to which deployment package. The information stored by the ResourceStore will
+ * be persisted as often as possible, to allow crash recovery.
  */
 abstract class ResourceStore
 {
@@ -72,9 +71,12 @@ abstract class ResourceStore
     /**
      * Adds a resource to persistent storage and handles the administration.
      *
-     * @param deploymentPackageName the name of a deployment package
-     * @param name the name of the resource
-     * @param stream a stream from which the resource with <code>name</code> can be read
+     * @param deploymentPackageName
+     *            the name of a deployment package
+     * @param name
+     *            the name of the resource
+     * @param stream
+     *            a stream from which the resource with <code>name</code> can be read
      */
     public void addResource(String deploymentPackageName, String name, InputStream stream) throws IOException, ResourceProcessorException {
         synchronized (m_resources) {
@@ -124,11 +126,13 @@ abstract class ResourceStore
     /**
      * Checks the validity of a resource.
      *
-     * @param resource a stream containing the resource
-     * @throws Exception when something is wrong with the resource
+     * @param resource
+     *            a stream containing the resource
+     * @throws Exception
+     *             when something is wrong with the resource
      */
     public abstract void validate(InputStream resource) throws Exception;
-    
+
     /**
      * Marks the start of a deployment process.
      */
@@ -142,21 +146,24 @@ abstract class ResourceStore
     /**
      * Installs a given resource.
      *
-     * @param resourceName the name of the resource
+     * @param resourceName
+     *            the name of the resource
      */
     public abstract void install(String resourceName) throws IOException;
 
     /**
      * Uninstalls a given resource.
      *
-     * @param resourceName the name of the resource
+     * @param resourceName
+     *            the name of the resource
      */
     public abstract void uninstall(String resourceName) throws IOException;
 
     /**
      * Gets the names of all driver bundles that belong to a given deployment package.
      *
-     * @param deploymentPackageName the name of a deployment package
+     * @param deploymentPackageName
+     *            the name of a deployment package
      * @return a list of the names of all driver bundles that belong to <code>deploymentPackageName</code>
      */
     public List<String> getResources(String deploymentPackageName) {
@@ -174,9 +181,10 @@ abstract class ResourceStore
     /**
      * Gets the name of the deployment package to which a given resource belongs.
      *
-     * @param resourceName the name of a resource
-     * @return the name of the deployment package to which <code>resourceName</code>
-     *     belongs, or <code>null</code> if this resource is unknown
+     * @param resourceName
+     *            the name of a resource
+     * @return the name of the deployment package to which <code>resourceName</code> belongs, or <code>null</code> if
+     *         this resource is unknown
      */
     public String getDeploymentPackage(String resourceName) {
         return m_resources.get(resourceName);
@@ -185,10 +193,11 @@ abstract class ResourceStore
     /**
      * Gets the stream belonging to a given resource.
      *
-     * @param name the name of a the resource
-     * @return an InputStream providing access to the named resource. It is the caller's
-     * task to close it.
-     * @throws java.io.IOException when an exception occurs accessing the resource
+     * @param name
+     *            the name of a the resource
+     * @return an InputStream providing access to the named resource. It is the caller's task to close it.
+     * @throws java.io.IOException
+     *             when an exception occurs accessing the resource
      */
     protected InputStream getResource(String name) throws IOException {
         File resource = new File(new File(m_context.getDataFile(TEMP_DIR), m_resources.get(name)), name);

Modified: ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/UserAdminStore.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/UserAdminStore.java?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/UserAdminStore.java (original)
+++ ace/trunk/org.apache.ace.resourceprocessor.useradmin/src/org/apache/ace/resourceprocessor/useradmin/impl/UserAdminStore.java Mon Feb 17 14:37:33 2014
@@ -46,183 +46,126 @@ import org.xml.sax.SAXException;
 
 public class UserAdminStore extends ResourceStore implements UserAdminConfigurator {
 
-    private UserAdmin m_userAdmin;
-    private Object m_userAdminLock = new Object();
+    /**
+     * Value object for relaying user information between XML-processing methods and UserAdmin users. This indirection
+     * is necessary because we want to separate the parsing of the XML, and the actual installation.
+     */
+    private class ProcessRole {
+        private final int m_type;
+        private final String m_name;
+        private final Map<String, Object> m_properties = new HashMap<String, Object>();
+        private final Map<String, Object> m_credentials = new HashMap<String, Object>();
+        private final List<String> m_memberOf = new ArrayList<String>();
+
+        ProcessRole(String name, int type) {
+            m_name = name;
+            m_type = type;
+        }
+
+        public Map<String, Object> getCredentials() {
+            return m_credentials;
+        }
+
+        public List<String> getMemberOf() {
+            return m_memberOf;
+        }
+
+        public String getName() {
+            return m_name;
+        }
+
+        public Map<String, Object> getProperties() {
+            return m_properties;
+        }
+
+        public int getType() {
+            return m_type;
+        }
+    }
+    
+    private final Object m_installListLock = new Object();
+    private final Object m_userAdminLock = new Object();
+
+    private volatile UserAdmin m_userAdmin;
     private volatile LogService m_log;
+    private volatile List<String> m_installedUsers;
 
     private List<ProcessRole> m_toInstall = new ArrayList<ProcessRole>();
     private List<ProcessRole> m_toRemove = new ArrayList<ProcessRole>();
-    private Object m_installListLock = new Object();
     private boolean m_clear;
 
-    private List<String> m_installedUsers;
-    
+
     UserAdminStore(BundleContext context) {
         super(context);
     }
 
-    
-    
     @Override
     public void begin() {
-    	m_installedUsers = new ArrayList<String>();
+        m_installedUsers = new ArrayList<String>();
     }
-    
+
     @Override
     public void end() {
-    	m_installedUsers = new ArrayList<String>();
+        checkTransactionInProgress();
+        m_installedUsers = null;
     }
-    
+
     @Override
     public void install(String resourceName) throws IOException {
-        InputStream input = getResource(resourceName);
-        install(input);
-    }
-
-    public void install(Document doc) {
-        installRoles(doc);
+        begin();
+        installRoles(getDocument(getResource(resourceName)));
         updateUserAdmin();
+        end();
     }
 
-    public void install(InputStream input) throws IOException {
-        install(getDocument(input));
+    public void setUsers(InputStream input) throws IOException {
+        setUsers(getDocument(input), true /* clearExistingUsers */);
     }
 
     @Override
     public void uninstall(String resourceName) throws IOException {
-        InputStream input = getResource(resourceName);
-        uninstall(getDocument(input));
-    }
-
-    public void uninstall(Document doc) {
-        removeRoles(doc);
-        updateUserAdmin();
-    }
-
-    public void uninstall(InputStream input) throws IOException {
-        uninstall(getDocument(input));
-    }
-
-    public void setUsers(Document doc) {
-        m_toInstall.clear();
-        m_toRemove.clear();
-        installRoles(doc);
-        m_clear = true;
         begin();
+        removeRoles(getDocument(getResource(resourceName)));
         updateUserAdmin();
         end();
     }
 
-    public void setUsers(InputStream input) throws IOException {
-        setUsers(getDocument(input));
-    }
-
-    @Override
-    public void validate(InputStream resource) throws Exception {
-        Document doc = getDocument(resource);
-        getRoles(doc);
-    }
-
     /**
-     * Installs the users and groups found in a document.
-     */
-    private void installRoles(Document doc) {
-        synchronized (m_installListLock) {
-            m_toInstall.addAll(getRoles(doc));
-        }
-    }
-
-    /**
-     * Removes the users and groups found in a document.
+     * Called by the dependency manager when a user admin becomes available.
      */
-    private void removeRoles(Document doc) {
-        synchronized (m_installListLock) {
-            m_toRemove.addAll(getRoles(doc));
+    public void userAdminAdded(UserAdmin admin) {
+        synchronized (m_userAdminLock) {
+            if (m_userAdmin != null) {
+                throw new IllegalStateException("UserAdminStore is intended to work with a single user admin.");
+            }
+            m_userAdmin = admin;
+            begin();
+            updateUserAdmin();
+            end();
         }
     }
 
     /**
-     * Updates the currently present UserAdmin with the data in m_toInstall and m_toRemove.
+     * Called by the dependency manager when a user admin goes away.
      */
-    private void updateUserAdmin() {
-        synchronized(m_installListLock) {
-            synchronized (m_userAdminLock) {
-                if (m_userAdmin == null) {
-                    return;
-                }
-
-                // install or update all roles we have to update
-                while (!m_toInstall.isEmpty()) {
-                    ProcessRole role = m_toInstall.remove(0);
-                    updateRole(role);
-                }
-
-                // remove all roles that have not been updated if this install
-                // is a full install
-                if (m_clear) {
-                    Role[] roles = null;
-                    try {
-                        roles = m_userAdmin.getRoles(null);
-                    }
-                    catch (InvalidSyntaxException e) {
-                        // Will not happen, since we pass in a null filter.
-                    }
-                    for (Role r : roles) {
-                        if (!m_installedUsers.contains(r.getName())) {
-                            m_userAdmin.removeRole(r.getName());
-                        }
-                    }
-                }
-
-                // if this is not a full install, remove any roles that should be
-                // removed
-                if (!m_clear) {
-                    while (!m_toRemove.isEmpty()) {
-                    	//do it tail to head
-                        ProcessRole role = m_toRemove.remove( m_toRemove.size() - 1 );
-                        
-                        if (!m_installedUsers.contains(role.getName())) {
-                        	m_userAdmin.removeRole(role.getName());
-                        }
-                    }
-                }
-
-                m_clear = false;
+    public void userAdminRemoved(UserAdmin admin) {
+        synchronized (m_userAdminLock) {
+            if (m_userAdmin != admin) {
+                throw new IllegalStateException("UserAdminStore is intended to work with a single user admin.");
             }
+            m_userAdmin = null;
         }
     }
 
-    /**
-     * Updates a role with new parameter, but reuses the UserAdmin's role object
-     * for this (if available).
-     */
-    private void updateRole(ProcessRole role) {
-        m_installedUsers.add(role.getName());
-        
-        Role r = m_userAdmin.getRole(role.getName());
-        if (r == null) {
-            r = m_userAdmin.createRole(role.getName(), role.getType());
-        }
-        clearDictionary(r.getProperties());
-        for (Entry<String, Object> entry : role.getProperties().entrySet()) {
-            r.getProperties().put(entry.getKey(), entry.getValue());
-        }
-        clearDictionary(((User) r).getCredentials());
-        if (role.getType() == Role.USER) {
-            for (Entry<String, Object> entry : role.getCredentials().entrySet()) {
-                ((User) r).getCredentials().put(entry.getKey(), entry.getValue());
-            }
-        }
-        for (Group g : memberOf(r)) {
-            g.removeMember(r);
-        }
-        for (String groupName : role.getMemberOf()) {
-            Group g = (Group) m_userAdmin.getRole(groupName);
-            if (g == null) {
-                m_log.log(LogService.LOG_WARNING, "Cannot add user " + role.getName() + " to group " + groupName + ", because the group does not exist.");
-                continue;
-            }
-            g.addMember(r);
+    @Override
+    public void validate(InputStream resource) throws Exception {
+        Document doc = getDocument(resource);
+        getRoles(doc);
+    }
+    
+    private void checkTransactionInProgress() {
+        if (m_installedUsers == null) {
+            throw new IllegalStateException("No transaction in progress!");
         }
     }
 
@@ -234,37 +177,8 @@ public class UserAdminStore extends Reso
     }
 
     /**
-     * Helper that finds all groups this role is a member of.
-     */
-    private Group[] memberOf(Role r) {
-        List<Group> result = new ArrayList<Group>();
-        Role[] roles = null;
-        try {
-            roles = m_userAdmin.getRoles(null);
-        }
-        catch (InvalidSyntaxException e) {
-            // Will not happen, since we pass in a null filter.
-        }
-        if (roles == null) {
-            return new Group[0];
-        }
-        for (Role group : roles) {
-            if (group instanceof Group) {
-                Role[] members = ((Group) group).getMembers();
-                if (members != null) {
-                    if (contains(r, members)) {
-                        result.add((Group) group);
-                    }
-                }
-            }
-        }
-
-        return result.toArray(new Group[result.size()]);
-    }
-
-    /**
-     * Helper method that checks the presence of an object in an array. Returns
-     * <code>true</code> if <code>t</code> is in <code>ts</code>, <code>false</code> otherwise.
+     * Helper method that checks the presence of an object in an array. Returns <code>true</code> if <code>t</code> is
+     * in <code>ts</code>, <code>false</code> otherwise.
      */
     private <T> boolean contains(T t, T[] ts) {
         for (T current : ts) {
@@ -276,33 +190,6 @@ public class UserAdminStore extends Reso
     }
 
     /**
-     * Called by the dependency manager when a user admin becomes available.
-     */
-    public void userAdminAdded(UserAdmin admin) {
-        synchronized (m_userAdminLock) {
-            if (m_userAdmin != null) {
-                throw new IllegalStateException("UserAdminStore is intended to work with a single user admin.");
-            }
-            m_userAdmin = admin;
-            begin();
-            updateUserAdmin();
-            end();
-        }
-    }
-
-    /**
-     * Called by the dependency manager when a user admin goes away.
-     */
-    public void userAdminRemoved(UserAdmin admin) {
-        synchronized (m_userAdminLock) {
-            if (m_userAdmin != admin) {
-                throw new IllegalStateException("UserAdminStore is intended to work with a single user admin.");
-            }
-            m_userAdmin = null;
-        }
-    }
-
-    /**
      * Gets the DOM document contained in a stream.
      */
     private Document getDocument(InputStream input) throws IOException {
@@ -321,23 +208,7 @@ public class UserAdminStore extends Reso
     }
 
     /**
-     * Gets all roles that are present in a document.
-     * @param doc The document to use.
-     * @return A list of ProcessRoles.
-     */
-    private List<ProcessRole> getRoles(Document doc) {
-        List<ProcessRole> result = new ArrayList<ProcessRole>();
-        for (Node node = doc.getFirstChild().getFirstChild(); node != null; node = node.getNextSibling()) {
-            if (!node.getNodeName().equals("#text")) {
-                result.add(getRole(node));
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Helper method that takes a single XML node containing a 'user' or 'group', and return a
-     * ProcessRole for it.
+     * Helper method that takes a single XML node containing a 'user' or 'group', and return a ProcessRole for it.
      */
     private ProcessRole getRole(Node node) {
         ProcessRole result = new ProcessRole(node.getAttributes().getNamedItem("name").getTextContent(), (node.getNodeName().equals("group") ? Role.GROUP : Role.USER));
@@ -379,42 +250,161 @@ public class UserAdminStore extends Reso
     }
 
     /**
-     * Value object for relaying user information between XML-processing methods and
-     * UserAdmin users.
-     * This indirection is necessary because we want to separate the parsing of the
-     * XML, and the actual installation.
+     * Gets all roles that are present in a document.
+     * 
+     * @param doc
+     *            The document to use.
+     * @return A list of ProcessRoles.
      */
-    private class ProcessRole {
-        private final int m_type;
-        private final String m_name;
-        private final Map<String, Object> m_properties = new HashMap<String, Object>();
-        private final Map<String, Object> m_credentials = new HashMap<String, Object>();
-        private final List<String> m_memberOf = new ArrayList<String>();
-
-        ProcessRole(String name, int type) {
-            m_name = name;
-            m_type = type;
+    private List<ProcessRole> getRoles(Document doc) {
+        List<ProcessRole> result = new ArrayList<ProcessRole>();
+        for (Node node = doc.getFirstChild().getFirstChild(); node != null; node = node.getNextSibling()) {
+            if (!node.getNodeName().equals("#text")) {
+                result.add(getRole(node));
+            }
         }
+        return result;
+    }
 
-        public int getType() {
-            return m_type;
+    /**
+     * Installs the users and groups found in a document.
+     */
+    private void installRoles(Document doc) {
+        synchronized (m_installListLock) {
+            m_toInstall.addAll(getRoles(doc));
         }
+    }
 
-        public String getName() {
-            return m_name;
+    /**
+     * Helper that finds all groups this role is a member of.
+     */
+    private Group[] memberOf(Role r) {
+        List<Group> result = new ArrayList<Group>();
+        Role[] roles = null;
+        try {
+            roles = m_userAdmin.getRoles(null);
+        }
+        catch (InvalidSyntaxException e) {
+            // Will not happen, since we pass in a null filter.
+        }
+        if (roles == null) {
+            return new Group[0];
+        }
+        for (Role group : roles) {
+            if (group instanceof Group) {
+                Role[] members = ((Group) group).getMembers();
+                if (members != null) {
+                    if (contains(r, members)) {
+                        result.add((Group) group);
+                    }
+                }
+            }
         }
 
-        public Map<String, Object> getProperties() {
-            return m_properties;
+        return result.toArray(new Group[result.size()]);
+    }
+
+    /**
+     * Removes the users and groups found in a document.
+     */
+    private void removeRoles(Document doc) {
+        synchronized (m_installListLock) {
+            m_toRemove.addAll(getRoles(doc));
         }
+    }
 
-        public Map<String, Object> getCredentials() {
-            return m_credentials;
+    private void setUsers(Document doc, boolean clearExistingUsers) {
+        m_toInstall.clear();
+        m_toRemove.clear();
+        installRoles(doc);
+        m_clear = clearExistingUsers;
+        begin();
+        updateUserAdmin();
+        end();        
+    }
+
+    /**
+     * Updates a role with new parameter, but reuses the UserAdmin's role object for this (if available).
+     */
+    private void updateRole(ProcessRole role) {
+        m_installedUsers.add(role.getName());
+
+        Role r = m_userAdmin.getRole(role.getName());
+        if (r == null) {
+            r = m_userAdmin.createRole(role.getName(), role.getType());
+        }
+        clearDictionary(r.getProperties());
+        for (Entry<String, Object> entry : role.getProperties().entrySet()) {
+            r.getProperties().put(entry.getKey(), entry.getValue());
+        }
+        clearDictionary(((User) r).getCredentials());
+        if (role.getType() == Role.USER) {
+            for (Entry<String, Object> entry : role.getCredentials().entrySet()) {
+                ((User) r).getCredentials().put(entry.getKey(), entry.getValue());
+            }
+        }
+        for (Group g : memberOf(r)) {
+            g.removeMember(r);
+        }
+        for (String groupName : role.getMemberOf()) {
+            Group g = (Group) m_userAdmin.getRole(groupName);
+            if (g == null) {
+                m_log.log(LogService.LOG_WARNING, "Cannot add user " + role.getName() + " to group " + groupName + ", because the group does not exist.");
+                continue;
+            }
+            g.addMember(r);
         }
+    }
 
-        public List<String> getMemberOf() {
-            return m_memberOf;
+    /**
+     * Updates the currently present UserAdmin with the data in m_toInstall and m_toRemove.
+     */
+    private void updateUserAdmin() {
+        synchronized (m_installListLock) {
+            synchronized (m_userAdminLock) {
+                if (m_userAdmin == null) {
+                    return;
+                }
+
+                // install or update all roles we have to update
+                while (!m_toInstall.isEmpty()) {
+                    ProcessRole role = m_toInstall.remove(0);
+                    updateRole(role);
+                }
+
+                // remove all roles that have not been updated if this install
+                // is a full install
+                if (m_clear) {
+                    Role[] roles = null;
+                    try {
+                        roles = m_userAdmin.getRoles(null);
+                    }
+                    catch (InvalidSyntaxException e) {
+                        // Will not happen, since we pass in a null filter.
+                    }
+                    for (Role r : roles) {
+                        if (!m_installedUsers.contains(r.getName())) {
+                            m_userAdmin.removeRole(r.getName());
+                        }
+                    }
+                }
+
+                // if this is not a full install, remove any roles that should be
+                // removed
+                if (!m_clear) {
+                    while (!m_toRemove.isEmpty()) {
+                        // do it tail to head
+                        ProcessRole role = m_toRemove.remove(m_toRemove.size() - 1);
+
+                        if (!m_installedUsers.contains(role.getName())) {
+                            m_userAdmin.removeRole(role.getName());
+                        }
+                    }
+                }
+
+                m_clear = false;
+            }
         }
     }
 
-}
\ No newline at end of file
+}

Modified: ace/trunk/org.apache.ace.test/src/org/apache/ace/it/IntegrationTestBase.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.test/src/org/apache/ace/it/IntegrationTestBase.java?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.test/src/org/apache/ace/it/IntegrationTestBase.java (original)
+++ ace/trunk/org.apache.ace.test/src/org/apache/ace/it/IntegrationTestBase.java Mon Feb 17 14:37:33 2014
@@ -175,6 +175,28 @@ public class IntegrationTestBase extends
     }
 
     /**
+     * The 'after' callback will be called after all components from {@link #getDependencies} have been started.<br>
+     * <br>
+     * The {@link #after} callback is most useful for configuring additional services after all mandatory services are
+     * resolved.
+     */
+    protected void configureAdditionalServices() throws Exception {
+    }
+
+    /**
+     * Creates a factory configuration with the given properties, just like {@link #configure}.
+     * 
+     * @return The PID of newly created configuration.
+     */
+    protected String configureFactory(String factoryPid, String... configuration) throws IOException {
+        Properties props = properties(configuration);
+        Configuration config = createFactoryConfiguration(factoryPid);
+        config.update(props);
+        m_trackedConfigurations.add(config);
+        return config.getPid();
+    }
+
+    /**
      * Configures the "org.apache.felix.http" and waits until the service is actually ready to process requests.
      * <p>
      * The reason that this method exists is that configuring the Felix HTTP bundle causes it to actually stop and
@@ -229,47 +251,6 @@ public class IntegrationTestBase extends
     }
 
     /**
-     * The 'after' callback will be called after all components from {@link #getDependencies} have been started.<br>
-     * <br>
-     * The {@link #after} callback is most useful for configuring additional services after all mandatory services are
-     * resolved.
-     */
-    protected void configureAdditionalServices() throws Exception {
-    }
-
-    /**
-     * @param filter
-     * @return an array of configurations, can be <code>null</code>.
-     */
-    protected Configuration[] listConfigurations(String filter) throws IOException, InvalidSyntaxException {
-        ConfigurationAdmin admin = getService(ConfigurationAdmin.class);
-        return admin.listConfigurations(filter);
-    }
-
-    /**
-     * Sets whether or not any of the tracked configurations should be automatically be deleted when ending a test.
-     * 
-     * @param aClean
-     *            <code>true</code> (the default) to clean configurations, <code>false</code> to disable this behaviour.
-     */
-    protected void setAutoDeleteTrackedConfigurations(boolean aClean) {
-        m_cleanConfigurations = aClean;
-    }
-
-    /**
-     * Creates a factory configuration with the given properties, just like {@link #configure}.
-     * 
-     * @return The PID of newly created configuration.
-     */
-    protected String configureFactory(String factoryPid, String... configuration) throws IOException {
-        Properties props = properties(configuration);
-        Configuration config = createFactoryConfiguration(factoryPid);
-        config.update(props);
-        m_trackedConfigurations.add(config);
-        return config.getPid();
-    }
-
-    /**
      * The 'before' callback will be called after the components from {@link #getDependencies} have been added, but you
      * cannot necessarily rely on injected members here. You can use the {@link #configure} and
      * {@link #configureFactory} methods, as well as the {@link #getService} methods.<br>
@@ -549,6 +530,45 @@ public class IntegrationTestBase extends
     }
 
     /**
+     * Utility method to determine the number of test cases in the implementing class.
+     * <p>
+     * Test cases are considered <em>public</em> methods starting their name with "test".
+     * </p>
+     * 
+     * @return a test count, >= 0.
+     */
+    protected final int getTestCount() {
+        int count = 0;
+
+        for (Method m : getClass().getMethods()) {
+            if (m.getName().startsWith("test")) {
+                count++;
+            }
+        }
+
+        return count;
+    }
+
+    /**
+     * @param filter
+     * @return an array of configurations, can be <code>null</code>.
+     */
+    protected Configuration[] listConfigurations(String filter) throws IOException, InvalidSyntaxException {
+        ConfigurationAdmin admin = getService(ConfigurationAdmin.class);
+        return admin.listConfigurations(filter);
+    }
+
+    /**
+     * Sets whether or not any of the tracked configurations should be automatically be deleted when ending a test.
+     * 
+     * @param aClean
+     *            <code>true</code> (the default) to clean configurations, <code>false</code> to disable this behaviour.
+     */
+    protected void setAutoDeleteTrackedConfigurations(boolean aClean) {
+        m_cleanConfigurations = aClean;
+    }
+
+    /**
      * Set up of this test case.
      */
     protected final void setUp() throws Exception {
@@ -592,26 +612,6 @@ public class IntegrationTestBase extends
         }
     }
 
-    /**
-     * Utility method to determine the number of test cases in the implementing class.
-     * <p>
-     * Test cases are considered <em>public</em> methods starting their name with "test".
-     * </p>
-     * 
-     * @return a test count, >= 0.
-     */
-    protected final int getTestCount() {
-        int count = 0;
-
-        for (Method m : getClass().getMethods()) {
-            if (m.getName().startsWith("test")) {
-                count++;
-            }
-        }
-
-        return count;
-    }
-
     @Override
     protected final void tearDown() throws Exception {
         try {

Modified: ace/trunk/run-client/client.bndrun
URL: http://svn.apache.org/viewvc/ace/trunk/run-client/client.bndrun?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/run-client/client.bndrun (original)
+++ ace/trunk/run-client/client.bndrun Mon Feb 17 14:37:33 2014
@@ -24,7 +24,6 @@
 	org.apache.ace.client.repository.helper.configuration;version=latest,\
 	org.apache.ace.client.repository.impl;version=latest,\
 	org.apache.ace.client.rest;version=latest,\
-	org.apache.ace.configurator.serveruseradmin;version=latest,\
 	org.apache.ace.configurator.useradmin.task;version=latest,\
 	org.apache.ace.configurator.impl;version=latest,\
 	org.apache.ace.connectionfactory;version=latest,\

Modified: ace/trunk/run-server-allinone/conf/org.apache.ace.client.automation.cfg
URL: http://svn.apache.org/viewvc/ace/trunk/run-server-allinone/conf/org.apache.ace.client.automation.cfg?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/run-server-allinone/conf/org.apache.ace.client.automation.cfg (original)
+++ ace/trunk/run-server-allinone/conf/org.apache.ace.client.automation.cfg Mon Feb 17 14:37:33 2014
@@ -6,5 +6,6 @@ targetRepository           = target
 deploymentRepository       = deployment
 storeRepository            = shop
 customerName               = apache
+userName				   = d
 hostName                   = http://${org.apache.ace.server}
 endpoint                   = /repository
\ No newline at end of file

Modified: ace/trunk/run-server-allinone/server-allinone.bndrun
URL: http://svn.apache.org/viewvc/ace/trunk/run-server-allinone/server-allinone.bndrun?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/run-server-allinone/server-allinone.bndrun (original)
+++ ace/trunk/run-server-allinone/server-allinone.bndrun Mon Feb 17 14:37:33 2014
@@ -24,7 +24,6 @@
 	org.apache.ace.client.repository.helper.configuration;version=latest,\
 	org.apache.ace.client.repository.impl;version=latest,\
 	org.apache.ace.client.rest;version=latest,\
-	org.apache.ace.configurator.serveruseradmin;version=latest,\
 	org.apache.ace.configurator.useradmin.task;version=latest,\
 	org.apache.ace.configurator.impl;version=latest,\
 	org.apache.ace.connectionfactory;version=latest,\

Modified: ace/trunk/run-server/server.bndrun
URL: http://svn.apache.org/viewvc/ace/trunk/run-server/server.bndrun?rev=1569011&r1=1569010&r2=1569011&view=diff
==============================================================================
--- ace/trunk/run-server/server.bndrun (original)
+++ ace/trunk/run-server/server.bndrun Mon Feb 17 14:37:33 2014
@@ -17,7 +17,6 @@
 	org.apache.ace.authentication.impl;version=latest,\
 	org.apache.ace.authentication.processor.basicauth;version=latest,\
 	org.apache.ace.authentication.processor.password;version=latest,\
-	org.apache.ace.configurator.serveruseradmin;version=latest,\
 	org.apache.ace.configurator.useradmin.task;version=latest,\
 	org.apache.ace.configurator.impl;version=latest,\
 	org.apache.ace.connectionfactory;version=latest,\