ace-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j...@apache.org
Subject svn commit: r1731198 [1/2] - in /ace/trunk: build/ org.apache.ace.authentication.itest/ org.apache.ace.authentication.itest/src/org/apache/ace/it/authentication/ org.apache.ace.client.repository.itest/ org.apache.ace.client.repository/ org.apache.ace.c...
Date Fri, 19 Feb 2016 08:36:12 GMT
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



Mime
View raw message