Author: jawi
Date: Fri Feb 19 08:36:10 2016
New Revision: 1731198

URL: http://svn.apache.org/viewvc?rev=1731198&view=rev
Log:
ACE-452 / ACE-531:

- applied patch from @brampouwelse;
- this closes #5.


Added:
    ace/trunk/org.apache.ace.useradmin/
    ace/trunk/org.apache.ace.useradmin.itest/
    ace/trunk/org.apache.ace.useradmin.itest/.classpath   (with props)
    ace/trunk/org.apache.ace.useradmin.itest/.project   (with props)
    ace/trunk/org.apache.ace.useradmin.itest/bnd.bnd
    ace/trunk/org.apache.ace.useradmin.itest/src/
    ace/trunk/org.apache.ace.useradmin.itest/src/org/
    ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/
    ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/
    ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/
    ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/useradmin/
    
ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/useradmin/RepositoryBasedRoleRepositoryStoreTest.java
   (with props)
    
ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/useradmin/Utils.java
   (with props)
    ace/trunk/org.apache.ace.useradmin/.classpath   (with props)
    ace/trunk/org.apache.ace.useradmin/.project   (with props)
    ace/trunk/org.apache.ace.useradmin/bnd.bnd
    ace/trunk/org.apache.ace.useradmin/repository.bnd
    ace/trunk/org.apache.ace.useradmin/src/
    ace/trunk/org.apache.ace.useradmin/src/org/
    ace/trunk/org.apache.ace.useradmin/src/org/apache/
    ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/
    ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/
    ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/
    
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/Activator.java
   (with props)
    
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/RepositoryBasedRoleRepositoryStore.java
   (with props)
    
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/RepositoryGroup.java
   (with props)
    
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/RepositoryUser.java
   (with props)
    
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/xstream/
    
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/xstream/GroupDTO.java
   (with props)
    
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/xstream/PropertiesConverter.java
   (with props)
    
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/xstream/RoleDTO.java
   (with props)
    
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/xstream/UserDTO.java
   (with props)
    
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/xstream/XStreamFactory.java
   (with props)
    ace/trunk/org.apache.ace.useradmin/test/
    ace/trunk/org.apache.ace.useradmin/test/aceDefault.xml   (with props)
    ace/trunk/org.apache.ace.useradmin/test/current.xml   (with props)
    ace/trunk/org.apache.ace.useradmin/test/org/
    ace/trunk/org.apache.ace.useradmin/test/org/apache/
    ace/trunk/org.apache.ace.useradmin/test/org/apache/ace/
    ace/trunk/org.apache.ace.useradmin/test/org/apache/ace/useradmin/
    ace/trunk/org.apache.ace.useradmin/test/org/apache/ace/useradmin/repository/
    
ace/trunk/org.apache.ace.useradmin/test/org/apache/ace/useradmin/repository/xstream/
    
ace/trunk/org.apache.ace.useradmin/test/org/apache/ace/useradmin/repository/xstream/XStreamTest.java
   (with props)
    ace/trunk/org.apache.ace.useradmin/test/valid.xml   (with props)
    ace/trunk/run-client/conf/org.apache.ace.useradmin.repository.cfg
    ace/trunk/run-obr/conf/org.apache.ace.connectionfactory/
    ace/trunk/run-obr/conf/org.apache.ace.connectionfactory/repository.cfg
    ace/trunk/run-obr/conf/org.apache.ace.useradmin.repository.cfg
    ace/trunk/run-relay/conf/org.apache.ace.useradmin.repository.cfg
    ace/trunk/run-server-allinone/conf/org.apache.ace.useradmin.repository.cfg
    ace/trunk/run-server/conf/org.apache.ace.useradmin.repository.cfg
Removed:
    ace/trunk/org.apache.ace.configurator.useradmin.itest/
    
ace/trunk/org.apache.ace.configurator/src/org/apache/ace/configurator/useradmin/
    ace/trunk/org.apache.ace.configurator/useradmin.task.bnd
    
ace/trunk/run-client/conf/org.apache.ace.configurator.useradmin.task.UpdateUserAdminTask.cfg
    ace/trunk/run-client/conf/org.apache.ace.server.repository.factory/
    
ace/trunk/run-server/conf/org.apache.ace.configurator.useradmin.task.UpdateUserAdminTask.cfg
Modified:
    ace/trunk/build/bnd.bnd
    ace/trunk/org.apache.ace.authentication.itest/bnd.bnd
    
ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/AuthenticationTestBase.java
    
ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/LogAuthenticationTest.java
    
ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/ObrAuthenticationTest.java
    ace/trunk/org.apache.ace.client.repository.itest/bnd.bnd
    ace/trunk/org.apache.ace.client.repository/impl.bnd
    
ace/trunk/org.apache.ace.client.rest.itest/src/org/apache/ace/client/rest/itest/RESTClientTest.java
    ace/trunk/org.apache.ace.client.rest/bnd.bnd
    
ace/trunk/org.apache.ace.deployment.itest/src/org/apache/ace/it/deployment/Ace330Test.java
    ace/trunk/org.apache.ace.deployment/provider.repositorybased.bnd
    
ace/trunk/org.apache.ace.repository.itest/src/org/apache/ace/it/repository/RepositoryTest.java
    ace/trunk/org.apache.ace.repository/ext.bnd
    ace/trunk/org.apache.ace.repository/servlets.bnd
    
ace/trunk/org.apache.ace.repository/src/org/apache/ace/repository/ext/impl/RemoteRepository.java
    
ace/trunk/org.apache.ace.repository/src/org/apache/ace/repository/servlet/RepositoryServletBase.java
    ace/trunk/org.apache.ace.useradmin.ui.itest/bnd.bnd
    
ace/trunk/org.apache.ace.useradmin.ui.itest/src/org/apache/ace/useradmin/ui/test/UserEditorTest.java
    ace/trunk/org.apache.ace.useradmin.ui/bnd.bnd
    
ace/trunk/org.apache.ace.useradmin.ui/src/org/apache/ace/useradmin/ui/editor/UserDTO.java
    ace/trunk/run-client/client.bndrun
    ace/trunk/run-client/conf/org.apache.ace.scheduler.cfg
    ace/trunk/run-obr/obr.bndrun
    ace/trunk/run-relay/relay.bndrun
    ace/trunk/run-server-allinone/conf/org.apache.ace.scheduler.cfg
    ace/trunk/run-server-allinone/server-allinone.bndrun
    ace/trunk/run-server/conf/org.apache.ace.scheduler.cfg
    ace/trunk/run-server/server.bndrun

Modified: ace/trunk/build/bnd.bnd
URL: 
http://svn.apache.org/viewvc/ace/trunk/build/bnd.bnd?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- ace/trunk/build/bnd.bnd (original)
+++ ace/trunk/build/bnd.bnd Fri Feb 19 08:36:10 2016
@@ -1,46 +1,48 @@
 # Licensed to the Apache Software Foundation (ASF) under the terms of ASLv2 
(http://www.apache.org/licenses/LICENSE-2.0).
 -nobundles: true
 -dependson: \
-    org.apache.ace.agent,\
-    org.apache.ace.agent.controller.itest,\
-    org.apache.ace.agent.itest,\
-    org.apache.ace.agent.launcher,\
-    org.apache.ace.agent.update.itest,\
-    org.apache.ace.authentication,\
-    org.apache.ace.authentication.itest,\
-    org.apache.ace.bnd,\
-    org.apache.ace.builder,\
-    org.apache.ace.client.automation,\
-    org.apache.ace.client.repository,\
-    org.apache.ace.client.repository.itest,\
-    org.apache.ace.client.rest,\
-    org.apache.ace.client.rest.itest,\
-    org.apache.ace.client.workspace,\
-    org.apache.ace.configurator,\
-    org.apache.ace.configurator.useradmin.itest,\
-    org.apache.ace.connectionfactory,\
-    org.apache.ace.consolelogger,\
-    org.apache.ace.deployment,\
-    org.apache.ace.deployment.itest,\
-    org.apache.ace.discovery,\
+       org.apache.ace.agent,\
+       org.apache.ace.agent.controller.itest,\
+       org.apache.ace.agent.itest,\
+       org.apache.ace.agent.launcher,\
+       org.apache.ace.agent.update.itest,\
+       org.apache.ace.authentication,\
+       org.apache.ace.authentication.itest,\
+       org.apache.ace.bnd,\
+       org.apache.ace.builder,\
+       org.apache.ace.client.automation,\
+       org.apache.ace.client.repository,\
+       org.apache.ace.client.repository.itest,\
+       org.apache.ace.client.rest,\
+       org.apache.ace.client.rest.itest,\
+       org.apache.ace.client.workspace,\
+       org.apache.ace.configurator,\
+       org.apache.ace.connectionfactory,\
+       org.apache.ace.consolelogger,\
+       org.apache.ace.deployment,\
+       org.apache.ace.deployment.itest,\
+       org.apache.ace.discovery,\
        org.apache.ace.feedback.common,\
-    org.apache.ace.gogo,\
-    org.apache.ace.http,\
-    org.apache.ace.http.itest,\
-    org.apache.ace.identification,\
-    org.apache.ace.log,\
-    org.apache.ace.log.itest,\
-    org.apache.ace.log.server.ui,\
-    org.apache.ace.obr,\
-    org.apache.ace.range.api,\
-    org.apache.ace.repository,\
-    org.apache.ace.repository.itest,\
-    org.apache.ace.resourceprocessor.useradmin,\
-    org.apache.ace.scheduler,\
-    org.apache.ace.tageditor,\
-    org.apache.ace.target.mgmt.ui,\
-    org.apache.ace.test,\
-    org.apache.ace.useradmin.ui,\
-    org.apache.ace.useradmin.ui.itest,\
-    org.apache.ace.verifier,\
-    org.apache.ace.webui.vaadin
+       org.apache.ace.gogo,\
+       org.apache.ace.gogo.servlet,\
+       org.apache.ace.http,\
+       org.apache.ace.http.itest,\
+       org.apache.ace.identification,\
+       org.apache.ace.log,\
+       org.apache.ace.log.itest,\
+       org.apache.ace.log.server.ui,\
+       org.apache.ace.obr,\
+       org.apache.ace.range.api,\
+       org.apache.ace.repository,\
+       org.apache.ace.repository.itest,\
+       org.apache.ace.resourceprocessor.useradmin,\
+       org.apache.ace.scheduler,\
+       org.apache.ace.tageditor,\
+       org.apache.ace.target.mgmt.ui,\
+       org.apache.ace.test,\
+       org.apache.ace.useradmin,\
+       org.apache.ace.useradmin.itest,\
+       org.apache.ace.useradmin.ui,\
+       org.apache.ace.useradmin.ui.itest,\
+       org.apache.ace.verifier,\
+       org.apache.ace.webui.vaadin

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=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.authentication.itest/bnd.bnd (original)
+++ ace/trunk/org.apache.ace.authentication.itest/bnd.bnd Fri Feb 19 08:36:10 
2016
@@ -22,7 +22,8 @@ Test-Cases: ${classes;CONCRETE;NAMED;*Te
        org.apache.ace.feedback.common;version=latest
 -runfw: org.apache.felix.framework;version='[5.2.0,6)'
 -runvm: -ea
--runbundles: osgi.cmpn,\
+-runbundles: \
+       osgi.cmpn,\
        org.apache.felix.log,\
        org.apache.felix.dependencymanager,\
        org.apache.felix.configadmin,\
@@ -31,7 +32,6 @@ Test-Cases: ${classes;CONCRETE;NAMED;*Te
        org.apache.felix.http.servlet-api,\
        org.apache.felix.http.jetty,\
        org.apache.felix.useradmin,\
-       org.apache.felix.useradmin.filestore,\
        org.apache.ace.authentication.api;version=latest,\
        org.apache.ace.authentication.impl;version=latest,\
        org.apache.ace.authentication.processor.basicauth;version=latest,\
@@ -40,7 +40,6 @@ Test-Cases: ${classes;CONCRETE;NAMED;*Te
        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.useradmin.task;version=latest,\
        org.apache.ace.connectionfactory;version=latest,\
        org.apache.ace.deployment.provider.api;version=latest,\
        org.apache.ace.discovery.api;version=latest,\
@@ -66,10 +65,14 @@ Test-Cases: ${classes;CONCRETE;NAMED;*Te
        org.apache.ace.scheduler.impl;version=latest,\
        org.apache.ace.test;version=latest,\
        org.apache.ace.log.api;version=latest,\
-       org.apache.ace.feedback.common;version=latest
+       org.apache.ace.feedback.common;version=latest,\
+       org.apache.ace.useradmin.repository
+       
 Private-Package: org.apache.ace.it.authentication
 Bundle-Version: 1.0.0
 Bundle-Name: Apache ACE Authentication itest
 Bundle-Category: itest
 Bundle-Description: Integration tests for Apache ACE Authentication
 -baseline:
+
+-dependson: org.apache.ace.useradmin

Modified: 
ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/AuthenticationTestBase.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/AuthenticationTestBase.java?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- 
ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/AuthenticationTestBase.java
 (original)
+++ 
ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/AuthenticationTestBase.java
 Fri Feb 19 08:36:10 2016
@@ -66,8 +66,7 @@ public class AuthenticationTestBase exte
         ByteArrayInputStream bis = new ByteArrayInputStream((
             "<roles>" +
                 "<user name=\"" + userName + "\">" +
-                "<properties><username>" + userName + 
"</username></properties>" +
-                "<credentials><password type=\"String\">" + password + 
"</password></credentials>" +
+                "<credentials><password>" + password + 
"</password></credentials>" +
                 "</user>" +
             "</roles>").getBytes());
 
@@ -131,7 +130,7 @@ public class AuthenticationTestBase exte
      */
     protected final void waitForUser(UserAdmin userAdmin, String userName) 
throws Exception {
         int count = 0;
-        while ((userAdmin.getRole(userName) == null) && (count++ < 60)) {
+        while ((userAdmin.getRole(userName) == null) && (++count < 60)) {
             Thread.sleep(100);
         }
         Assert.assertTrue("Failed to obtain user from userAdmin!", count != 
60);

Modified: 
ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/LogAuthenticationTest.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/LogAuthenticationTest.java?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- 
ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/LogAuthenticationTest.java
 (original)
+++ 
ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/LogAuthenticationTest.java
 Fri Feb 19 08:36:10 2016
@@ -122,12 +122,13 @@ public class LogAuthenticationTest exten
             RepositoryConstants.REPOSITORY_CUSTOMER, "apache",
             RepositoryConstants.REPOSITORY_MASTER, "true");
 
-        
configure("org.apache.ace.configurator.useradmin.task.UpdateUserAdminTask",
-            "repositoryName", "users",
-            "repositoryCustomer", "apache");
+        configure("org.apache.ace.repository.servlet.RepositoryServlet",
+            HttpConstants.ENDPOINT, "/repository", "authentication.enabled", 
"false");
 
-        configure("org.apache.ace.scheduler",
-            "org.apache.ace.configurator.useradmin.task.UpdateUserAdminTask", 
"100");
+        configure("org.apache.ace.useradmin.repository",
+            "repositoryLocation", "http://localhost:"; + TestConstants.PORT + 
"/repository",
+            "repositoryCustomer", "apache",
+            "repositoryName", "users");
 
         configure("org.apache.ace.log.server.store.filebased", "MaxEvents", 
"0");
 

Modified: 
ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/ObrAuthenticationTest.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/ObrAuthenticationTest.java?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- 
ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/ObrAuthenticationTest.java
 (original)
+++ 
ace/trunk/org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/ObrAuthenticationTest.java
 Fri Feb 19 08:36:10 2016
@@ -32,6 +32,7 @@ import org.apache.ace.client.repository.
 import org.apache.ace.client.repository.helper.bundle.BundleHelper;
 import org.apache.ace.client.repository.repository.ArtifactRepository;
 import org.apache.ace.connectionfactory.ConnectionFactory;
+import org.apache.ace.http.listener.constants.HttpConstants;
 import org.apache.ace.obr.storage.OBRFileStoreConstants;
 import org.apache.ace.repository.Repository;
 import org.apache.ace.repository.RepositoryConstants;
@@ -96,15 +97,17 @@ public class ObrAuthenticationTest exten
             RepositoryConstants.REPOSITORY_NAME, "users",
             RepositoryConstants.REPOSITORY_CUSTOMER, "apache",
             RepositoryConstants.REPOSITORY_MASTER, "true");
-
+        
+        configure("org.apache.ace.repository.servlet.RepositoryServlet",
+            HttpConstants.ENDPOINT, "/repository", "authentication.enabled", 
"false");
+
+        configure("org.apache.ace.useradmin.repository",
+            "repositoryLocation", "http://localhost:"; + TestConstants.PORT + 
"/repository",
+            "repositoryCustomer", "apache",
+            "repositoryName", "users");
+        
         configure("org.apache.ace.log.server.store.filebased", "MaxEvents", 
"0");
-
-        
configure("org.apache.ace.configurator.useradmin.task.UpdateUserAdminTask",
-            "repositoryName", "users",
-            "repositoryCustomer", "apache");
-
-        configure("org.apache.ace.scheduler",
-            "org.apache.ace.configurator.useradmin.task.UpdateUserAdminTask", 
"100");
+        
 
         configure("org.apache.ace.obr.servlet",
             "OBRInstance", "singleOBRServlet",
@@ -127,9 +130,9 @@ public class ObrAuthenticationTest exten
             String password = "f";
             importSingleUser(m_userRepository, userName, password);
             waitForUser(m_userAdmin, userName);
-
-            URL testURL = new URL(m_obrURL, "index.xml");
-
+            
+            URL testURL = new URL(m_obrURL, "index.xml");            
+            
             assertTrue("Failed to access OBR in time!", 
waitForURL(m_connectionFactory, testURL, 401, 15000));
 
             m_authConfigPID = 
configureFactory("org.apache.ace.connectionfactory",
@@ -138,7 +141,7 @@ public class ObrAuthenticationTest exten
                 "authentication.user.name", userName,
                 "authentication.user.password", password);
 
-            assertTrue("Failed to access auditlog in time!", 
waitForURL(m_connectionFactory, testURL, 200, 15000));
+            assertTrue("Failed to access OBR in time!", 
waitForURL(m_connectionFactory, testURL, 200, 15000));
         }
         catch (Exception e) {
             printLog(m_logReader);

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=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.repository.itest/bnd.bnd (original)
+++ ace/trunk/org.apache.ace.client.repository.itest/bnd.bnd Fri Feb 19 
08:36:10 2016
@@ -9,7 +9,6 @@ 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,\

Modified: ace/trunk/org.apache.ace.client.repository/impl.bnd
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/impl.bnd?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/impl.bnd (original)
+++ ace/trunk/org.apache.ace.client.repository/impl.bnd Fri Feb 19 08:36:10 2016
@@ -60,6 +60,6 @@ Import-Package: !javax.security.auth,\
     !sun.reflect,\
     *
 Bundle-Activator: org.apache.ace.client.repository.impl.Activator
-Bundle-Version: 1.0.2
+Bundle-Version: 1.0.3
 Bundle-Name: Apache Ace Client Repository factory
 Bundle-Description: Registers the Apache ACE Client Repository SessionFactory
\ No newline at end of file

Modified: 
ace/trunk/org.apache.ace.client.rest.itest/src/org/apache/ace/client/rest/itest/RESTClientTest.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.rest.itest/src/org/apache/ace/client/rest/itest/RESTClientTest.java?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- 
ace/trunk/org.apache.ace.client.rest.itest/src/org/apache/ace/client/rest/itest/RESTClientTest.java
 (original)
+++ 
ace/trunk/org.apache.ace.client.rest.itest/src/org/apache/ace/client/rest/itest/RESTClientTest.java
 Fri Feb 19 08:36:10 2016
@@ -440,10 +440,6 @@ public class RESTClientTest extends Inte
             "customer", "apache",
             "master", "true");
 
-        
configure("org.apache.ace.configurator.useradmin.task.UpdateUserAdminTask",
-            "repositoryLocation", HOST.concat("/repository"),
-            "repositoryCustomer", "apache",
-            "repositoryName", "user");
     }
 
     /** Create a user so we can log in to the server. */

Modified: ace/trunk/org.apache.ace.client.rest/bnd.bnd
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.rest/bnd.bnd?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.rest/bnd.bnd (original)
+++ ace/trunk/org.apache.ace.client.rest/bnd.bnd Fri Feb 19 08:36:10 2016
@@ -21,6 +21,6 @@ Private-Package: \
        org.apache.ace.client.rest,\
        com.google.gson*
 Bundle-Activator: org.apache.ace.client.rest.Activator
-Bundle-Version: 1.0.2
+Bundle-Version: 1.0.3
 Bundle-Name: Apache ACE Client REST
 Bundle-Description: Provides a REST binding for the Apache ACE Client

Modified: 
ace/trunk/org.apache.ace.deployment.itest/src/org/apache/ace/it/deployment/Ace330Test.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment.itest/src/org/apache/ace/it/deployment/Ace330Test.java?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- 
ace/trunk/org.apache.ace.deployment.itest/src/org/apache/ace/it/deployment/Ace330Test.java
 (original)
+++ 
ace/trunk/org.apache.ace.deployment.itest/src/org/apache/ace/it/deployment/Ace330Test.java
 Fri Feb 19 08:36:10 2016
@@ -78,8 +78,6 @@ public class Ace330Test extends Integrat
             "customer.name", TEST_CUSTOMER, "store.repository.name", "shop",
             "distribution.repository.name", "target", 
"deployment.repository.name", "deployment");
 
-        
configure("org.apache.ace.configurator.useradmin.task.UpdateUserAdminTask", 
"repositoryLocation", repoLocation, "repositoryCustomer", TEST_CUSTOMER, 
"repositoryName", "user");
-
         configure("org.apache.ace.deployment.provider.repositorybased", "url", 
repoLocation, "name", "deployment", "customer", TEST_CUSTOMER);
         configure("org.apache.ace.deployment.servlet", 
"org.apache.ace.server.servlet.endpoint", "/deployment", 
"authentication.enabled", "false");
         configure("org.apache.ace.deployment.servlet.agent", 
"org.apache.ace.server.servlet.endpoint", "/agent", "obr.url", obrLocation, 
"authentication.enabled", "false");
@@ -92,8 +90,6 @@ public class Ace330Test extends Integrat
 
         
configure("org.apache.ace.repository.servlet.RepositoryReplicationServlet", 
"org.apache.ace.server.servlet.endpoint", "/replication", 
"authentication.enabled", "false");
         configure("org.apache.ace.repository.servlet.RepositoryServlet", 
"org.apache.ace.server.servlet.endpoint", "/repository", 
"authentication.enabled", "false");
-
-        configure("org.apache.ace.scheduler", "auditlog", "2000", 
"org.apache.ace.configurator.useradmin.task.UpdateUserAdminTask", "2000");
     }
 
     @Override

Modified: ace/trunk/org.apache.ace.deployment/provider.repositorybased.bnd
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/provider.repositorybased.bnd?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/provider.repositorybased.bnd (original)
+++ ace/trunk/org.apache.ace.deployment/provider.repositorybased.bnd Fri Feb 19 
08:36:10 2016
@@ -5,6 +5,6 @@ Private-Package: org.apache.ace.deployme
        org.apache.ace.repository.ext,\
        org.apache.ace.repository.ext.impl
 Bundle-Activator: org.apache.ace.deployment.provider.repositorybased.Activator
-Bundle-Version: 1.0.2
+Bundle-Version: 1.0.3
 Bundle-Name: Apache ACE Deployment Provider Repository
 Bundle-Description: Registers a repository based Deployemnt Provider service
\ No newline at end of file

Modified: 
ace/trunk/org.apache.ace.repository.itest/src/org/apache/ace/it/repository/RepositoryTest.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.repository.itest/src/org/apache/ace/it/repository/RepositoryTest.java?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- 
ace/trunk/org.apache.ace.repository.itest/src/org/apache/ace/it/repository/RepositoryTest.java
 (original)
+++ 
ace/trunk/org.apache.ace.repository.itest/src/org/apache/ace/it/repository/RepositoryTest.java
 Fri Feb 19 08:36:10 2016
@@ -238,10 +238,62 @@ public class RepositoryTest extends Inte
         byteArrayInputStream.reset();
 
         responseCode = put(m_host, "repository/commit", "apache", "test", "0", 
byteArrayInputStream);
+        assertResponseCode(HttpURLConnection.HTTP_NOT_ACCEPTABLE, 
responseCode);
+
+        removeRepository("testInstance");
+    }
+    
+    public void testCommitUnchangedContents() throws Exception {
+        addRepository("testInstance", "apache", "test", true);
+
+        ByteArrayInputStream byteArrayInputStream = new 
ByteArrayInputStream("test".getBytes());
+
+        int responseCode = put(m_host, "repository/commit", "apache", "test", 
"0", byteArrayInputStream);
+        assertResponseCode(HttpURLConnection.HTTP_OK, responseCode);
+        
+        byteArrayInputStream.reset();
+        responseCode = put(m_host, "repository/commit", "apache", "test", "1", 
byteArrayInputStream);
+        assertResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED, responseCode);
+
+        removeRepository("testInstance");
+    }
+    
+    public void testCommitExistingVersion() throws Exception {
+        addRepository("testInstance", "apache", "test", true);
+
+        ByteArrayInputStream byteArrayInputStream = new 
ByteArrayInputStream("test".getBytes());
+
+        int responseCode = put(m_host, "repository/commit", "apache", "test", 
"0", byteArrayInputStream);
+        assertResponseCode(HttpURLConnection.HTTP_OK, responseCode);
+        
+        byteArrayInputStream = new ByteArrayInputStream("testje".getBytes());
+        responseCode = put(m_host, "repository/commit", "apache", "test", "0", 
byteArrayInputStream);
         assertResponseCode(HttpURLConnection.HTTP_INTERNAL_ERROR, 
responseCode);
 
         removeRepository("testInstance");
     }
+    
+    public void testCommitIllegalVersion() throws Exception {
+        addRepository("testInstance", "apache", "test", true);
+
+        ByteArrayInputStream byteArrayInputStream = new 
ByteArrayInputStream("test".getBytes());
+
+        int responseCode = put(m_host, "repository/commit", "apache", "test", 
"-1", byteArrayInputStream);
+        assertResponseCode(HttpURLConnection.HTTP_BAD_REQUEST, responseCode);
+        
+        removeRepository("testInstance");
+    }
+    
+    public void testCommitToSlave() throws Exception {
+        addRepository("testInstance", "apache", "test", false);
+
+        ByteArrayInputStream byteArrayInputStream = new 
ByteArrayInputStream("test".getBytes());
+
+        int responseCode = put(m_host, "repository/commit", "apache", "test", 
"-1", byteArrayInputStream);
+        assertResponseCode(HttpURLConnection.HTTP_NOT_ACCEPTABLE, 
responseCode);
+        
+        removeRepository("testInstance");
+    }
 
     protected void configureProvisionedServices() throws IOException {
         m_host = new URL("http://localhost:"; + TestConstants.PORT);

Modified: ace/trunk/org.apache.ace.repository/ext.bnd
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.repository/ext.bnd?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.repository/ext.bnd (original)
+++ ace/trunk/org.apache.ace.repository/ext.bnd Fri Feb 19 08:36:10 2016
@@ -2,6 +2,6 @@
 
 Export-Package: org.apache.ace.repository.ext,\
        org.apache.ace.repository.ext.impl
-Bundle-Version: 1.0.2
+Bundle-Version: 1.0.3
 Bundle-Name: Apache ACE Repository EXT
 Bundle-Description: Provides the Apache ACE Repository EXT packages
\ No newline at end of file

Modified: ace/trunk/org.apache.ace.repository/servlets.bnd
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.repository/servlets.bnd?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.repository/servlets.bnd (original)
+++ ace/trunk/org.apache.ace.repository/servlets.bnd Fri Feb 19 08:36:10 2016
@@ -2,6 +2,6 @@
 
 Private-Package: org.apache.ace.repository.servlet
 Bundle-Activator: org.apache.ace.repository.servlet.Activator
-Bundle-Version: 1.0.0
+Bundle-Version: 1.0.1
 Bundle-Name: Apache ACE Repository Servlet
 Bundle-Description: Registers a repository and replication servlet
\ No newline at end of file

Modified: 
ace/trunk/org.apache.ace.repository/src/org/apache/ace/repository/ext/impl/RemoteRepository.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.repository/src/org/apache/ace/repository/ext/impl/RemoteRepository.java?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- 
ace/trunk/org.apache.ace.repository/src/org/apache/ace/repository/ext/impl/RemoteRepository.java
 (original)
+++ 
ace/trunk/org.apache.ace.repository/src/org/apache/ace/repository/ext/impl/RemoteRepository.java
 Fri Feb 19 08:36:10 2016
@@ -117,7 +117,19 @@ public class RemoteRepository implements
         }
         try {
             // causes the stream the be flushed and the server response to be 
obtained...
-            return connection.getResponseCode() == HttpServletResponse.SC_OK;
+            switch (connection.getResponseCode()) {
+                case HttpServletResponse.SC_OK:
+                    return true;
+                case HttpServletResponse.SC_NOT_MODIFIED:
+                    return false;
+                case HttpServletResponse.SC_BAD_REQUEST: 
+                    throw new 
IllegalArgumentException(connection.getResponseMessage());
+                case HttpServletResponse.SC_NOT_ACCEPTABLE:
+                    throw new 
IllegalStateException(connection.getResponseMessage());
+                case HttpServletResponse.SC_INTERNAL_SERVER_ERROR:
+                default:
+                    throw new IOException(connection.getResponseMessage());
+            }
         }
         finally {
             closeQuietly(connection);

Modified: 
ace/trunk/org.apache.ace.repository/src/org/apache/ace/repository/servlet/RepositoryServletBase.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.repository/src/org/apache/ace/repository/servlet/RepositoryServletBase.java?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- 
ace/trunk/org.apache.ace.repository/src/org/apache/ace/repository/servlet/RepositoryServletBase.java
 (original)
+++ 
ace/trunk/org.apache.ace.repository/src/org/apache/ace/repository/servlet/RepositoryServletBase.java
 Fri Feb 19 08:36:10 2016
@@ -360,17 +360,17 @@ public abstract class RepositoryServletB
 
             try {
                 if (!doCommit(repo, version, data)) {
-                    
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Could not 
commit");
+                    response.sendError(HttpServletResponse.SC_NOT_MODIFIED, 
"Could not commit");
                 }
                 else {
                     response.sendError(HttpServletResponse.SC_OK);
                 }
             }
             catch (IllegalArgumentException e) {
-                
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Invalid 
version");
+                response.sendError(HttpServletResponse.SC_BAD_REQUEST, 
"Invalid version");
             }
             catch (IllegalStateException e) {
-                
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Cannot 
commit, not the master repository");
+                response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE, 
"Cannot commit, not the master repository");
             }
             finally {
                 m_context.ungetService(ref);

Added: ace/trunk/org.apache.ace.useradmin.itest/.classpath
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin.itest/.classpath?rev=1731198&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.useradmin.itest/.classpath (added)
+++ ace/trunk/org.apache.ace.useradmin.itest/.classpath Fri Feb 19 08:36:10 2016
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" output="bin" path="src"/>
+       <classpathentry kind="con" 
path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+       <classpathentry kind="con" path="aQute.bnd.classpath.container"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>

Propchange: ace/trunk/org.apache.ace.useradmin.itest/.classpath
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/org.apache.ace.useradmin.itest/.project
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin.itest/.project?rev=1731198&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.useradmin.itest/.project (added)
+++ ace/trunk/org.apache.ace.useradmin.itest/.project Fri Feb 19 08:36:10 2016
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.apache.ace.useradmin.itest</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>

Propchange: ace/trunk/org.apache.ace.useradmin.itest/.project
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/org.apache.ace.useradmin.itest/bnd.bnd
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin.itest/bnd.bnd?rev=1731198&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.useradmin.itest/bnd.bnd (added)
+++ ace/trunk/org.apache.ace.useradmin.itest/bnd.bnd Fri Feb 19 08:36:10 2016
@@ -0,0 +1,39 @@
+# Licensed to the Apache Software Foundation (ASF) under the terms of ASLv2 
(http://www.apache.org/licenses/LICENSE-2.0).
+
+Test-Cases: ${classes;CONCRETE;EXTENDS;org.apache.ace.it.IntegrationTestBase}
+-buildpath: \
+       junit.osgi,\
+       osgi.core;version=6.0.0,\
+       osgi.cmpn,\
+       org.mockito.mockito-all,\
+       org.apache.ace.test;version=latest,\
+       org.apache.ace.http.listener;version=latest,\
+       org.apache.ace.range.api;version=latest,\
+       org.apache.ace.repository.api;version=latest,\
+       org.apache.felix.dependencymanager
+-runfw: org.apache.felix.framework;version='[5.2.0,6)'
+-runvm: -ea
+-runbundles: osgi.cmpn,\
+       org.apache.felix.log,\
+       org.apache.felix.dependencymanager,\
+       org.apache.felix.configadmin,\
+       org.apache.felix.prefs,\
+       org.apache.felix.http.servlet-api,\
+       org.apache.felix.http.jetty,\
+       org.apache.felix.useradmin,\
+       org.apache.ace.deployment.provider.api;version=latest,\
+       org.apache.ace.authentication.api;version=latest,\
+       org.apache.ace.connectionfactory;version=latest,\
+       org.apache.ace.http.listener;version=latest,\
+       org.apache.ace.test;version=latest,\
+       org.apache.ace.range.api;version=latest,\
+       org.apache.ace.repository.api;version=latest,\
+       org.apache.ace.repository.impl;version=latest,\
+       org.apache.ace.repository.servlets;version=latest,\
+       org.apache.ace.useradmin.repository
+       
+Private-Package: org.apache.ace.it.useradmin
+Bundle-Version: 1.0.0
+Bundle-Name: Apache ACE Repository itest
+Bundle-Description: Integration test bundle for Apache ACE Repository backed 
UserAdmin
+Bundle-Category: itest
\ No newline at end of file

Added: 
ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/useradmin/RepositoryBasedRoleRepositoryStoreTest.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/useradmin/RepositoryBasedRoleRepositoryStoreTest.java?rev=1731198&view=auto
==============================================================================
--- 
ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/useradmin/RepositoryBasedRoleRepositoryStoreTest.java
 (added)
+++ 
ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/useradmin/RepositoryBasedRoleRepositoryStoreTest.java
 Fri Feb 19 08:36:10 2016
@@ -0,0 +1,206 @@
+/*
+ * 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.it.useradmin;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.ace.http.listener.constants.HttpConstants;
+import org.apache.ace.it.IntegrationTestBase;
+import org.apache.ace.range.SortedRangeSet;
+import org.apache.ace.repository.Repository;
+import org.apache.ace.test.constants.TestConstants;
+import org.apache.felix.dm.Component;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.UserAdmin;
+
+public class RepositoryBasedRoleRepositoryStoreTest extends 
IntegrationTestBase {
+
+    private URL m_host;
+
+    private volatile UserAdmin m_userAdmin;
+    private volatile Repository m_repository;
+
+    @Override
+    protected Component[] getDependencies() {
+        return new Component[] {
+            createComponent()
+                .setImplementation(this)
+                
.add(createServiceDependency().setService(UserAdmin.class).setRequired(true))
+                .add(createServiceDependency().setService(Repository.class, 
"(&(customer=apache)(name=user))").setRequired(true))
+        };
+    }
+    
+    public void testAddUser() throws Exception {
+        long high = m_repository.getRange().getHigh();
+        m_userAdmin.createRole("Piet", Role.USER);
+        waitForRepoChange(high);
+        
+        String repoContentsAsString = getRepoContentsAsString();
+        assertTrue(repoContentsAsString.contains("<user name=\"Piet\">"));
+    }
+    
+    public void testDuplicateAddUser() throws Exception {
+        Role role = m_userAdmin.createRole("Piet", Role.USER);
+        assertEquals("Piet", role.getName());
+        Role dup = m_userAdmin.createRole("Piet", Role.USER);
+        assertNull(dup);
+    }
+    
+    public void testRemoveUser() throws Exception {
+        // Write a new version directly to the repository
+        SortedRangeSet range = m_repository.getRange();
+        try (InputStream is = new ByteArrayInputStream("<roles><user 
name=\"Piet\"><properties><test>changed</test></properties></user></roles>".getBytes())){
+            m_repository.commit(is, range.getHigh());
+        }
+        
+        Role role = m_userAdmin.getRole("Piet");
+        assertEquals("Piet", role.getName());
+        
+        boolean removeRole = m_userAdmin.removeRole("Piet");
+        assertTrue(removeRole);
+        
+        Role afterRemove = m_userAdmin.getRole("Piet");
+        assertNull(afterRemove);
+        
+        boolean removeRoleAgain = m_userAdmin.removeRole("Piet");
+        assertFalse(removeRoleAgain);
+    }
+    
+    public void testUpdateUser() throws Exception {
+        long high = m_repository.getRange().getHigh();
+        Role piet = m_userAdmin.createRole("Piet", Role.USER);
+
+        high = waitForRepoChange(high);
+        
+        piet.getProperties().put("test", "property");
+        waitForRepoChange(high);
+        
+        String repoContentsAsString = getRepoContentsAsString();
+        assertTrue(repoContentsAsString.contains("<test>property</test>"));
+    }
+    
+    public void testUpdateUserRepoOutOfSync() throws Exception {
+        long high = m_repository.getRange().getHigh();
+        Role piet = m_userAdmin.createRole("Piet", Role.USER);
+        high = waitForRepoChange(high);
+        piet.getProperties().put("test", "property");
+        waitForRepoChange(high);
+        
+        // Write a new version directly to the repository
+        SortedRangeSet range = m_repository.getRange();
+        try (InputStream is = new ByteArrayInputStream("<roles><user 
name=\"Piet\"><properties><test>changed</test></properties></user></roles>".getBytes())){
+            m_repository.commit(is, range.getHigh());
+        }
+        
+        try {
+            // Expect that updating properties fails as the user object is out 
of date
+            piet.getProperties().put("this", "fails");
+            fail("Expected IllegalStateException");
+        } catch (IllegalStateException e) {
+            //expected
+        }
+        
+        Role role = m_userAdmin.getRole("Piet");
+        assertEquals("changed", role.getProperties().get("test"));
+    }
+    
+    public void testUpdateUserFetchedBeforeRepoSync() throws Exception {
+        long high = m_repository.getRange().getHigh();
+        Role piet = m_userAdmin.createRole("Piet", Role.USER);
+        high = waitForRepoChange(high);
+        piet.getProperties().put("test", "property");
+        high = waitForRepoChange(high);
+        
+        // Write a new version directly to the repository
+        SortedRangeSet range = m_repository.getRange();
+        try (InputStream is = new ByteArrayInputStream("<roles><user 
name=\"Piet\"><properties><test>changed</test></properties></user></roles>".getBytes())){
+            m_repository.commit(is, range.getHigh());
+        }
+        
+        // try to get a Role just to trigger the 
RepositoryBasedRoleRepositoryStore to refresh from the repository 
+        m_userAdmin.getRole("JustATrigger"); 
+        
+        try {
+            // Expect that updating properties fails as the user was fetched 
before the repository was refreshed
+            piet.getProperties().put("this", "fails");
+            fail("Expected IllegalStateException");
+        } catch (IllegalStateException e) {
+//            expected
+        }
+        
+        Role role = m_userAdmin.getRole("Piet");
+        assertEquals("changed", role.getProperties().get("test"));
+    }
+
+    private String getRepoContentsAsString() throws IOException {
+        String repoContentsAsString;
+        try(InputStream repoInputStream = 
m_repository.checkout(m_repository.getRange().getHigh());
+                ByteArrayOutputStream out = new ByteArrayOutputStream()){
+            byte[] buf = new byte[4096];
+            int bytesRead = -1;
+            while ((bytesRead = repoInputStream.read(buf)) >= 0) {
+                out.write(buf, 0, bytesRead);
+            }
+            repoContentsAsString = out.toString();
+        }
+        return repoContentsAsString;
+    }
+
+    private long waitForRepoChange(long high) throws IOException, 
InterruptedException {
+        int i = 0;
+        while (m_repository.getRange().getHigh() <= high) {
+            Thread.sleep(10l);
+            i++;
+            if (i > 250){
+                fail("Repo didn't update in time");
+            }
+        } 
+        return m_repository.getRange().getHigh();
+    }
+   
+    protected void configureProvisionedServices() throws Exception {
+        m_host = new URL("http://localhost:"; + TestConstants.PORT);
+
+        configure("org.apache.ace.repository.servlet.RepositoryServlet",
+            HttpConstants.ENDPOINT, "/repository", "authentication.enabled", 
"false");
+        
+        configureFactory("org.apache.ace.server.repository.factory", 
+            "customer", "apache",
+            "name", "user", 
+            "master", "true",
+            "initial", "<roles></roles>"
+            );
+        
+        configure("org.apache.ace.useradmin.repository",
+            "repositoryLocation", "http://localhost:"; + TestConstants.PORT + 
"/repository",
+            "repositoryCustomer", "apache",
+            "repositoryName", "user");
+
+        Utils.waitForWebserver(m_host);
+    }
+
+    @Override
+    protected void doTearDown() throws Exception {
+    }
+
+}

Propchange: 
ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/useradmin/RepositoryBasedRoleRepositoryStoreTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/useradmin/Utils.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/useradmin/Utils.java?rev=1731198&view=auto
==============================================================================
--- 
ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/useradmin/Utils.java
 (added)
+++ 
ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/useradmin/Utils.java
 Fri Feb 19 08:36:10 2016
@@ -0,0 +1,219 @@
+/*
+ * 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.it.useradmin;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ConnectException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+final class Utils {
+
+    private static final int COPY_BUFFER_SIZE = 4096;
+    private static final String MIME_APPLICATION_OCTET_STREAM = 
"application/octet-stream";
+
+    static void closeSilently(Closeable resource) {
+        if (resource != null) {
+            try {
+                resource.close();
+            }
+            catch (IOException exception) {
+                // Ignore...
+            }
+        }
+    }
+
+    static void closeSilently(HttpURLConnection resource) {
+        if (resource != null) {
+            resource.disconnect();
+        }
+    }
+
+    /* copy in to out */
+    static void copy(InputStream in, OutputStream out) throws IOException {
+        byte[] buffer = new byte[COPY_BUFFER_SIZE];
+        int bytes = in.read(buffer);
+        while (bytes != -1) {
+            out.write(buffer, 0, bytes);
+            bytes = in.read(buffer);
+        }
+    }
+
+    static void flushStream(InputStream is) {
+        byte[] buf = new byte[COPY_BUFFER_SIZE];
+        try {
+            while (is.read(buf) > 0) {
+                // Ignore...
+            }
+        }
+        catch (IOException ex) {
+            // deal with the exception
+        }
+        finally {
+            closeSilently(is);
+        }
+    }
+
+    static int get(URL host, String endpoint, String customer, String name, 
String version, OutputStream out) throws IOException {
+        int responseCode;
+
+        URL url = new URL(host, endpoint + "?customer=" + customer + "&name=" 
+ name + "&version=" + version);
+
+        InputStream input = null;
+        HttpURLConnection connection = (HttpURLConnection) 
url.openConnection();
+        try {
+            responseCode = connection.getResponseCode();
+            input = connection.getInputStream();
+
+            copy(input, out);
+            out.flush();
+        }
+        catch (IOException e) {
+            responseCode = handleIOException(connection);
+        }
+        finally {
+            closeSilently(input);
+            closeSilently(connection);
+        }
+
+        return responseCode;
+    }
+
+    /**
+     * @see 
http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html
+     */
+    static int handleIOException(HttpURLConnection conn) {
+        int respCode = -1;
+        try {
+            respCode = conn.getResponseCode();
+            flushStream(conn.getErrorStream());
+        }
+        catch (IOException ex) {
+            // deal with the exception
+        }
+        return respCode;
+    }
+
+    static int put(URL host, String endpoint, String customer, String name, 
String version, InputStream in) throws IOException {
+        URL url = new URL(host, endpoint + "?customer=" + customer + "&name=" 
+ name + "&version=" + version);
+
+        int responseCode;
+        HttpURLConnection connection = null;
+        OutputStream out = null;
+
+        try {
+            connection = (HttpURLConnection) url.openConnection();
+            connection.setDoOutput(true);
+            // ACE-294: enable streaming mode causing only small amounts of 
memory to be
+            // used for this commit. Otherwise, the entire input stream is 
cached into
+            // memory prior to sending it to the server...
+            connection.setChunkedStreamingMode(8192);
+            connection.setRequestProperty("Content-Type", 
MIME_APPLICATION_OCTET_STREAM);
+            out = connection.getOutputStream();
+
+            copy(in, out);
+            out.flush();
+
+            responseCode = connection.getResponseCode();
+            flushStream(connection.getInputStream());
+        }
+        catch (IOException e) {
+            responseCode = handleIOException(connection);
+        }
+        finally {
+            closeSilently(in);
+            closeSilently(out);
+            closeSilently(connection);
+        }
+
+        return responseCode;
+    }
+
+    static int query(URL host, String endpoint, String customer, String name, 
OutputStream out) throws IOException {
+        String f1 = (customer == null) ? null : "customer=" + customer;
+        String f2 = (name == null) ? null : "name=" + name;
+        String filter = ((f1 == null) ? "?" : "?" + f1 + "&") + ((f2 == null) 
? "" : f2);
+        URL url = new URL(host, endpoint + filter);
+
+        int responseCode;
+        HttpURLConnection connection = null;
+        InputStream input = null;
+
+        try {
+            connection = (HttpURLConnection) url.openConnection();
+            responseCode = connection.getResponseCode();
+            input = connection.getInputStream();
+
+            copy(input, out);
+            out.flush();
+        }
+        catch (IOException e) {
+            responseCode = handleIOException(connection);
+        }
+        finally {
+            closeSilently(input);
+            closeSilently(out);
+            closeSilently(connection);
+        }
+
+        return responseCode;
+    }
+
+    static void waitForWebserver(URL host) throws IOException {
+        int retries = 1, rc = -1;
+        IOException ioe = null;
+        HttpURLConnection conn = null;
+        while (retries++ < 10) {
+            try {
+                conn = (HttpURLConnection) host.openConnection();
+
+                rc = conn.getResponseCode();
+                if (rc >= 0) {
+                    return;
+                }
+            }
+            catch (ConnectException e) {
+                ioe = e;
+                try {
+                    Thread.sleep(retries * 50);
+                }
+                catch (InterruptedException ie) {
+                    // We're asked to stop...
+                    return;
+                }
+            }
+            catch (IOException e) {
+                rc = handleIOException(conn);
+            }
+            finally {
+                if (conn != null) {
+                    conn.disconnect();
+                }
+                conn = null;
+            }
+        }
+        if (ioe != null) {
+            throw ioe;
+        }
+    }
+}

Propchange: 
ace/trunk/org.apache.ace.useradmin.itest/src/org/apache/ace/it/useradmin/Utils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: ace/trunk/org.apache.ace.useradmin.ui.itest/bnd.bnd
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin.ui.itest/bnd.bnd?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.useradmin.ui.itest/bnd.bnd (original)
+++ ace/trunk/org.apache.ace.useradmin.ui.itest/bnd.bnd Fri Feb 19 08:36:10 2016
@@ -35,7 +35,6 @@ Private-Package: org.apache.ace.useradmi
        org.apache.ace.test;version=latest,\
        org.apache.ace.useradmin.ui;version=latest,\
        org.apache.ace.webui.vaadin;version=latest,\
-       org.apache.ace.configurator.useradmin.task;version=latest,\
        org.apache.ace.authentication.api;version=latest,\
        org.apache.ace.log.server.store.api;version=latest,\
        org.apache.ace.feedback.common;version=latest

Modified: 
ace/trunk/org.apache.ace.useradmin.ui.itest/src/org/apache/ace/useradmin/ui/test/UserEditorTest.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin.ui.itest/src/org/apache/ace/useradmin/ui/test/UserEditorTest.java?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- 
ace/trunk/org.apache.ace.useradmin.ui.itest/src/org/apache/ace/useradmin/ui/test/UserEditorTest.java
 (original)
+++ 
ace/trunk/org.apache.ace.useradmin.ui.itest/src/org/apache/ace/useradmin/ui/test/UserEditorTest.java
 Fri Feb 19 08:36:10 2016
@@ -291,11 +291,7 @@ public class UserEditorTest extends Inte
             "name", "users",
             "customer", "apache",
             "master", "true");
-        
configure("org.apache.ace.configurator.useradmin.task.UpdateUserAdminTask",
-            "repositoryName", "users",
-            "repositoryCustomer", "apache");
-        configure("org.apache.ace.scheduler",
-            "org.apache.ace.configurator.useradmin.task.UpdateUserAdminTask", 
"100");
+        
     }
 
     @Override

Modified: ace/trunk/org.apache.ace.useradmin.ui/bnd.bnd
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin.ui/bnd.bnd?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.useradmin.ui/bnd.bnd (original)
+++ ace/trunk/org.apache.ace.useradmin.ui/bnd.bnd Fri Feb 19 08:36:10 2016
@@ -13,7 +13,7 @@
        org.apache.felix.http.servlet-api,\
        org.apache.ace.webui.vaadin;version=latest
 Bundle-Activator: org.apache.ace.useradmin.ui.osgi.Activator
-Bundle-Version: 2.0.1
+Bundle-Version: 2.0.2
 Private-Package: org.apache.ace.useradmin.ui.osgi,\
        org.apache.ace.useradmin.ui.vaadin,\
        org.apache.ace.useradmin.ui.editor.impl

Modified: 
ace/trunk/org.apache.ace.useradmin.ui/src/org/apache/ace/useradmin/ui/editor/UserDTO.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin.ui/src/org/apache/ace/useradmin/ui/editor/UserDTO.java?rev=1731198&r1=1731197&r2=1731198&view=diff
==============================================================================
--- 
ace/trunk/org.apache.ace.useradmin.ui/src/org/apache/ace/useradmin/ui/editor/UserDTO.java
 (original)
+++ 
ace/trunk/org.apache.ace.useradmin.ui/src/org/apache/ace/useradmin/ui/editor/UserDTO.java
 Fri Feb 19 08:36:10 2016
@@ -38,7 +38,7 @@ public class UserDTO implements Comparab
         m_username = (String) user.getProperties().get("username");
         m_previousUsername = m_username;
         m_password = (String) user.getCredentials().get("password");
-        m_groupname = group.getName();
+        m_groupname = group != null? group.getName(): null;
         m_previousGroupname = m_groupname;
     }
 

Added: ace/trunk/org.apache.ace.useradmin/.classpath
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin/.classpath?rev=1731198&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.useradmin/.classpath (added)
+++ ace/trunk/org.apache.ace.useradmin/.classpath Fri Feb 19 08:36:10 2016
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" output="bin" path="src"/>
+       <classpathentry kind="src" output="bin_test" path="test"/>
+       <classpathentry kind="con" 
path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+       <classpathentry kind="con" path="aQute.bnd.classpath.container"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>

Propchange: ace/trunk/org.apache.ace.useradmin/.classpath
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/org.apache.ace.useradmin/.project
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin/.project?rev=1731198&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.useradmin/.project (added)
+++ ace/trunk/org.apache.ace.useradmin/.project Fri Feb 19 08:36:10 2016
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.apache.ace.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>

Propchange: ace/trunk/org.apache.ace.useradmin/.project
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/org.apache.ace.useradmin/bnd.bnd
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin/bnd.bnd?rev=1731198&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.useradmin/bnd.bnd (added)
+++ ace/trunk/org.apache.ace.useradmin/bnd.bnd Fri Feb 19 08:36:10 2016
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under the terms of ASLv2 
(http://www.apache.org/licenses/LICENSE-2.0).
+
+-buildpath: \
+       ${^-buildpath},\
+       ${testng},\
+       osgi.core;version=6.0.0,\
+       osgi.cmpn,\
+       xpp3,\
+       xstream,\
+       org.apache.felix.dependencymanager,\
+       org.apache.ace.connectionfactory;version=latest,\
+       org.apache.ace.range.api;version=latest,\
+       org.apache.ace.repository.api;version=latest,\
+       org.apache.ace.repository.ext;version=latest,\
+       org.apache.ace.resourceprocessor.useradmin;version=latest,\
+       org.apache.ace.test;version=latest,\
+       org.apache.commons.io;version=2.0.1,\
+       org.apache.felix.useradmin
+-sub: *.bnd
\ No newline at end of file

Added: ace/trunk/org.apache.ace.useradmin/repository.bnd
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin/repository.bnd?rev=1731198&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.useradmin/repository.bnd (added)
+++ ace/trunk/org.apache.ace.useradmin/repository.bnd Fri Feb 19 08:36:10 2016
@@ -0,0 +1,71 @@
+# Licensed to the Apache Software Foundation (ASF) under the terms of ASLv2 
(http://www.apache.org/licenses/LICENSE-2.0).
+
+Bundle-Version: 1.0.0
+Private-Package: \
+       org.apache.ace.useradmin.repository,\
+       org.apache.ace.useradmin.repository.xstream,\
+       org.apache.ace.repository.ext,\
+       org.apache.ace.repository.ext.impl,\
+       javax.xml.namespace,\
+       org.xmlpull.mxp1,\
+       org.xmlpull.mxp1_serializer,\
+       org.xmlpull.v1,\
+       org.xmlpull.v1.builder,\
+       org.xmlpull.v1.builder.adapter,\
+       org.xmlpull.v1.builder.impl,\
+       org.xmlpull.v1.dom2_builder,\
+       org.xmlpull.v1.parser_pool,\
+       org.xmlpull.v1.sax2,\
+       org.xmlpull.v1.util,\
+       org.xmlpull.v1.wrapper,\
+       org.xmlpull.v1.wrapper.classic,\
+       org.apache.ace.client.repository.stateful.impl,\
+       org.apache.ace.repository.ext,\
+       org.apache.ace.repository.ext.impl,\
+       com.thoughtworks.xstream,\
+       com.thoughtworks.xstream.alias,\
+       com.thoughtworks.xstream.annotations,\
+       com.thoughtworks.xstream.converters,\
+       com.thoughtworks.xstream.converters.basic,\
+       com.thoughtworks.xstream.converters.collections,\
+       com.thoughtworks.xstream.converters.enums,\
+       com.thoughtworks.xstream.converters.extended,\
+       com.thoughtworks.xstream.converters.javabean,\
+       com.thoughtworks.xstream.converters.reflection,\
+       com.thoughtworks.xstream.core,\
+       com.thoughtworks.xstream.core.util,\
+       com.thoughtworks.xstream.io,\
+       com.thoughtworks.xstream.io.binary,\
+       com.thoughtworks.xstream.io.copy,\
+       com.thoughtworks.xstream.io.json,\
+       com.thoughtworks.xstream.io.path,\
+       com.thoughtworks.xstream.io.xml,\
+       com.thoughtworks.xstream.io.xml.xppdom,\
+       com.thoughtworks.xstream.mapper,\
+       com.thoughtworks.xstream.persistence
+       
+Import-Package: !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,\
+    *
+Bundle-Activator: org.apache.ace.useradmin.repository.Activator
+
+Bundle-Name: Apache ACE UserAdmin RoleRepositoryStore
+Bundle-Description: Felix UserAdmin RoleRepositoryStore implementation backed 
by an ACE Repository
\ No newline at end of file

Added: 
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/Activator.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/Activator.java?rev=1731198&view=auto
==============================================================================
--- 
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/Activator.java
 (added)
+++ 
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/Activator.java
 Fri Feb 19 08:36:10 2016
@@ -0,0 +1,132 @@
+/*
+ * 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.useradmin.repository;
+
+import static 
org.apache.ace.repository.RepositoryConstants.REPOSITORY_CUSTOMER;
+import static org.apache.ace.repository.RepositoryConstants.REPOSITORY_NAME;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.ace.connectionfactory.ConnectionFactory;
+import org.apache.ace.repository.ext.impl.RemoteRepository;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.useradmin.RoleRepositoryStore;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.UserAdminListener;
+
+public class Activator extends DependencyActivatorBase {
+
+    private static final String PID = "org.apache.ace.useradmin.repository";
+    public static final String KEY_REPOSITORY_CUSTOMER = "repositoryCustomer";
+    public static final String KEY_REPOSITORY_NAME = "repositoryName";
+    public static final String KEY_REPOSITORY_LOCATION = "repositoryLocation";
+    
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws 
Exception {
+        
+        manager.add(createComponent().setImplementation(new 
RemoteRepositoryManager())
+            .add(createConfigurationDependency().setPid(PID))
+            );
+    }
+    
+    private static class RemoteRepositoryManager implements ManagedService {
+        
+        private volatile DependencyManager m_manager;
+        private final List<Component> m_components = new ArrayList<>();
+    
+        @Override
+        public void updated(Dictionary<String, ?> properties) throws 
ConfigurationException {
+            if (properties == null) {
+                Iterator<Component> iterator = m_components.iterator();
+                while (iterator.hasNext()) {
+                    Component component = (Component) iterator.next();
+                    m_manager.remove(component);
+                    iterator.remove();
+                }
+                return;
+            }
+            
+            String customer = (String) properties.get(KEY_REPOSITORY_CUSTOMER);
+            if ((customer == null) || "".equals(customer)) {
+                throw new ConfigurationException(KEY_REPOSITORY_CUSTOMER, 
"Repository customer has to be specified.");
+            }
+
+            String name = (String) properties.get(KEY_REPOSITORY_NAME);
+            if ((name == null) || "".equals(name)) {
+                throw new ConfigurationException(KEY_REPOSITORY_NAME, 
"Repository name has to be specified.");
+            }
+            
+            String repositoryUrl = (String) 
properties.get(KEY_REPOSITORY_LOCATION);
+            if ((repositoryUrl == null) || "".equals(repositoryUrl)) {
+                throw new ConfigurationException(KEY_REPOSITORY_LOCATION, 
"Repository location has to be specified.");
+            }
+            
+            try {
+                //CachedRepo
+                RemoteRepository remoteRepository = new RemoteRepository(new 
URL(repositoryUrl), customer, name);
+                Properties repoProps = new Properties();
+                repoProps.put(REPOSITORY_CUSTOMER, customer);
+                repoProps.put(REPOSITORY_NAME, name);
+                
+                Component repositoryComponent = m_manager.createComponent()
+                    .setInterface(RemoteRepository.class.getName(), repoProps)
+                    .setImplementation(remoteRepository)
+                    .add(m_manager.createServiceDependency()
+                        .setService(ConnectionFactory.class)
+                        .setRequired(true)
+                    );
+    
+                m_manager.add(repositoryComponent);
+                m_components.add(repositoryComponent);
+                
+            } catch (MalformedURLException e) {
+                throw new ConfigurationException(KEY_REPOSITORY_LOCATION, 
"Repository location has to be a valid URL.");
+            }
+            
+            String repoFilter = String.format("(&(customer=%s)(name=%s))", 
customer, name);
+            Component storeComponent = m_manager.createComponent()
+                .setInterface(new String[]{ 
RoleRepositoryStore.class.getName(), UserAdminListener.class.getName() }, null)
+                .setImplementation(RepositoryBasedRoleRepositoryStore.class)
+                .add(m_manager.createServiceDependency()
+                    .setService(RemoteRepository.class, repoFilter)
+                    .setRequired(true)
+                )
+                .add(m_manager.createServiceDependency()
+                    .setService(LogService.class)
+                    .setRequired(false)
+                );
+            
+            m_manager.add(storeComponent);
+            m_components.add(storeComponent);
+        }
+        
+    } 
+
+}

Propchange: 
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/Activator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/RepositoryBasedRoleRepositoryStore.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/RepositoryBasedRoleRepositoryStore.java?rev=1731198&view=auto
==============================================================================
--- 
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/RepositoryBasedRoleRepositoryStore.java
 (added)
+++ 
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/RepositoryBasedRoleRepositoryStore.java
 Fri Feb 19 08:36:10 2016
@@ -0,0 +1,316 @@
+/*
+ * 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.useradmin.repository;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.ace.repository.ext.CachedRepository;
+import org.apache.ace.repository.ext.impl.CachedRepositoryImpl;
+import org.apache.ace.repository.ext.impl.FilebasedBackupRepository;
+import org.apache.ace.repository.ext.impl.RemoteRepository;
+import org.apache.ace.useradmin.repository.xstream.GroupDTO;
+import org.apache.ace.useradmin.repository.xstream.RoleDTO;
+import org.apache.ace.useradmin.repository.xstream.UserDTO;
+import org.apache.ace.useradmin.repository.xstream.XStreamFactory;
+import org.apache.felix.useradmin.RoleFactory;
+import org.apache.felix.useradmin.RoleRepositoryStore;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdminEvent;
+import org.osgi.service.useradmin.UserAdminListener;
+
+import com.thoughtworks.xstream.XStream;
+
+/**
+ * Felix UserAdmin RoleRepositoryStore implementation that's backed by an ACE 
Repository
+ *
+ */
+public class RepositoryBasedRoleRepositoryStore implements 
RoleRepositoryStore, UserAdminListener {
+    
+    private volatile BundleContext m_BundleContext;
+    private volatile LogService m_log;
+    private volatile RemoteRepository m_repository;    
+    private volatile CachedRepository m_cachedRepository;
+
+    private volatile AtomicLong m_version;
+    private final Map<String, Role> m_roleMap = new ConcurrentHashMap<>();
+    
+    @SuppressWarnings("unused" /* dependency manager callback */)
+    private void start() throws IOException {
+        File currentFile = m_BundleContext.getDataFile("current.xml");
+        File backupFile = m_BundleContext.getDataFile("backup.xml");
+        
+        if (currentFile.exists()) {
+            currentFile.delete();
+        }
+        
+        if (backupFile.exists()) {
+            backupFile.delete();
+        }
+        
+        FilebasedBackupRepository backupRepo = new 
FilebasedBackupRepository(currentFile, backupFile);
+        m_cachedRepository = new CachedRepositoryImpl(m_repository, 
backupRepo, CachedRepositoryImpl.UNCOMMITTED_VERSION);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void refreshRoleMap() throws Exception {
+        m_roleMap.clear();
+        XStream instance = XStreamFactory.getInstance();
+        
+        try (InputStream inputStream = m_cachedRepository.checkout(true);
+                InputStreamReader inputStreamReader = new 
InputStreamReader(inputStream);
+                ObjectInputStream objectInputStream = 
instance.createObjectInputStream(inputStreamReader)){
+            
+            RoleDTO roleDto;
+            List<RoleDTO> rolesWithMemberships = new ArrayList<>();
+            m_version = new 
AtomicLong(m_cachedRepository.getMostRecentVersion());
+            try {
+                while ((roleDto = (RoleDTO) objectInputStream.readObject()) != 
null) {
+                    User role;
+                    if (roleDto.type == Role.USER) {
+                        role = RoleFactory.createUser(roleDto.name);
+                    } else if (roleDto.type == Role.GROUP) {
+                        role = RoleFactory.createGroup(roleDto.name);
+                    } else {
+                        throw new IllegalStateException("");
+                    }
+                    if (roleDto.properties != null){
+                        for (Entry<Object, Object> entry : 
roleDto.properties.entrySet()) {
+                            role.getProperties().put(entry.getKey(), 
entry.getValue());
+                        }
+                    }
+                    if (roleDto.credentials != null){
+                        for (Entry<Object, Object> entry : 
roleDto.credentials.entrySet()) {
+                            role.getCredentials().put(entry.getKey(), 
entry.getValue());
+                        }
+                    }
+                    if (roleDto.memberOf != null && 
!roleDto.memberOf.isEmpty()){
+                        rolesWithMemberships.add(roleDto);
+                    }
+                    
+                    m_roleMap.put(role.getName(), role);
+                }
+            }catch (EOFException e) {
+                // Ignore, this is the way XStream let's us know we're done 
reading
+            }
+            
+            for (RoleDTO role : rolesWithMemberships) {
+                Role memberRole = m_roleMap.get(role.name);
+                for (String memberOf : role.memberOf) {
+                    Role groupRole = m_roleMap.get(memberOf);
+                    if (groupRole == null){
+                        throw new IllegalStateException("Target group not 
found");
+                    }
+                    
+                    if (groupRole.getType() != Role.GROUP) {
+                        throw new IllegalStateException("Target is not a 
group");
+                    }
+                    
+                    Group group = (Group) groupRole;
+                    group.addMember(memberRole);
+                }
+            }
+            
+            // Wrap users and groups in repository user / group types 
+            for (Entry<String, Role> roleMapEntry : m_roleMap.entrySet()) {
+                m_roleMap.put(roleMapEntry.getKey(), 
wrapRole(roleMapEntry.getValue()));
+            }
+        }
+    }
+    
+    /**
+     * Add a wrapper around a Role that prevents changes to Users / Groups 
when the repository is out of sync
+     * 
+     * @param role User or Group role to be wrapped
+     * @return a wrapped Role
+     */
+    private Role wrapRole(Role role) {
+        if (role.getType() == Role.USER) {
+            return new RepositoryUser((User)role, m_cachedRepository, 
m_version);
+        } else if (role.getType() == Role.GROUP) {
+            return new RepositoryGroup((Group)role, m_cachedRepository, 
m_version);
+        }else {
+            throw new IllegalStateException("");
+        }
+    }
+
+    @Override
+    public Role getRoleByName(String name) throws Exception {
+        if (name == null) {
+            return null;
+        }
+        
+        synchronized (m_roleMap) {
+            if (!m_cachedRepository.isCurrent()) {
+                refreshRoleMap(); 
+            }
+            return m_roleMap.get(name);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Role[] getRoles(String filterString) throws Exception {
+        synchronized (m_roleMap) {
+            if (!m_cachedRepository.isCurrent()) {
+                refreshRoleMap();
+            }
+        
+            if (filterString == null) {
+                return m_roleMap.values().toArray(new Role[0]);
+            }
+            
+            Filter filter = FrameworkUtil.createFilter(filterString);
+            
+            List<Role> matchingRoles = new ArrayList<>();
+            for (Role role: m_roleMap.values()){
+                if (filter.match(role.getProperties())){
+                    matchingRoles.add(role);
+                }
+            }
+            
+            return matchingRoles.toArray(new Role[matchingRoles.size()]);
+        }
+    }
+
+    @Override
+    public Role addRole(String name, int type) throws Exception {
+        Role role;
+        switch (type) {
+            case Role.USER:
+                role = RoleFactory.createUser(name);                
+                break;
+            case Role.GROUP:
+                role = RoleFactory.createGroup(name);
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid group type " + 
type);
+        }
+        synchronized (m_roleMap) {
+            if (m_cachedRepository.getMostRecentVersion() == -1) {
+                refreshRoleMap();
+            }
+            
+            if (m_roleMap.containsKey(name)){
+                return null;
+            }
+            role = wrapRole(role);
+            m_roleMap.put(name, role);
+            roleChanged(null);
+        }
+        return role;
+    }
+    
+    @Override
+    public Role removeRole(String name) throws Exception {
+        Role removedRole;
+        synchronized (m_roleMap) {
+            removedRole = m_roleMap.remove(name);
+            if (removedRole != null){
+                roleChanged(null);
+            }
+        }
+        return removedRole;
+    }
+
+    List<String> memberOf(Role role) {
+        List<String> memberOf = new ArrayList<>();
+        for (Role r: m_roleMap.values()) {
+            if (r instanceof Group) {
+                Group group = (Group) r;
+                Role[] members = group.getMembers();
+                if (members != null) {
+                    if (contains(role, members)) {
+                        memberOf.add(group.getName());
+                    }
+                }
+            }
+        }
+        return memberOf; 
+    }
+    
+    /**
+     * 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) {
+            if (current.equals(t)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void roleChanged(UserAdminEvent event) {
+        synchronized (m_roleMap) {
+            XStream instance = XStreamFactory.getInstance();
+            try (StringWriter writer = new StringWriter();
+                            ObjectOutputStream stream =
+                                instance.createObjectOutputStream(writer, 
"roles");) {
+                
+                for (Role role : m_roleMap.values()) {
+                    List<String> memberOf = memberOf(role);
+                    if (role.getType() == Role.USER) {
+                        stream.writeObject(new UserDTO((User) role, memberOf));
+                    } else if (role.getType() == Role.GROUP) {
+                        GroupDTO obj = new GroupDTO((Group) role, memberOf);
+                        stream.writeObject(obj);
+                    } else {
+                        throw new IllegalStateException("Unsupported role 
type");
+                    }
+                }
+    
+                stream.flush();
+                stream.close();
+                writer.flush();
+                
+                try (ByteArrayInputStream inputStream = new 
ByteArrayInputStream(writer.toString().getBytes())){
+                    m_cachedRepository.writeLocal(inputStream);
+                }
+                
+                m_cachedRepository.commit();
+                m_version.set(m_cachedRepository.getMostRecentVersion());
+            } catch (IOException e) {
+                m_log.log(LogService.LOG_ERROR, "Failed to commit role changes 
to the main role repository", e);
+            } 
+        }
+    }
+    
+}

Propchange: 
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/RepositoryBasedRoleRepositoryStore.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/RepositoryGroup.java
URL: 
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/RepositoryGroup.java?rev=1731198&view=auto
==============================================================================
--- 
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/RepositoryGroup.java
 (added)
+++ 
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/RepositoryGroup.java
 Fri Feb 19 08:36:10 2016
@@ -0,0 +1,67 @@
+/*
+ * 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.useradmin.repository;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.ace.repository.ext.CachedRepository;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+
+/**
+ * Wrapper for {@link Group} that prevents changes to the group when the store 
is out of sync with the main repository
+ */
+public class RepositoryGroup extends RepositoryUser implements Group{
+
+    private Group m_delegate;                           
+    
+    public RepositoryGroup(Group group, CachedRepository cachedRepository, 
AtomicLong version) {
+        super(group, cachedRepository, version);
+        m_delegate = group;
+    }
+    
+    @Override
+    public boolean addMember(Role role) {
+        checkRepoUpToDate();
+        return m_delegate.addMember(role);
+    }
+
+    @Override
+    public boolean addRequiredMember(Role role) {
+        checkRepoUpToDate();
+        return m_delegate.addMember(role);
+    }
+
+    @Override
+    public boolean removeMember(Role role) {
+        checkRepoUpToDate();
+        return m_delegate.removeMember(role);
+    }
+
+    @Override
+    public Role[] getMembers() {
+        return m_delegate.getMembers();
+    }
+
+    @Override
+    public Role[] getRequiredMembers() {
+        return m_delegate.getRequiredMembers();
+    }
+
+}

Propchange: 
ace/trunk/org.apache.ace.useradmin/src/org/apache/ace/useradmin/repository/RepositoryGroup.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to