diff --git a/useradmin/itest/pom.xml b/useradmin/itest/pom.xml
index 88adb09dde1..fbfdf53b1b0 100644
--- a/useradmin/itest/pom.xml
+++ b/useradmin/itest/pom.xml
@@ -39,12 +39,6 @@
jar
Integration tests for the UserAdmin OSGi compendium service.
-
- org.osgi
- org.osgi.core
- ${osgi.version}
- provided
-
org.osgi
org.osgi.compendium
@@ -62,6 +56,18 @@
1.0.3-SNAPSHOT
test
+
+ org.apache.felix
+ org.apache.felix.useradmin.mongodb
+ 1.0.2-SNAPSHOT
+ test
+
+
+ org.mongodb
+ mongo-java-driver
+ 2.8.0
+ test
+
org.apache.felix
org.apache.felix.dependencymanager
diff --git a/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/BaseIntegrationTest.java b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/BaseIntegrationTest.java
index 4f6746f0f61..feb6995291d 100644
--- a/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/BaseIntegrationTest.java
+++ b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/BaseIntegrationTest.java
@@ -46,22 +46,26 @@
*
* @author Felix Project Team
*/
-public abstract class BaseIntegrationTest {
+public abstract class BaseIntegrationTest
+{
- private static final int DEFAULT_TIMEOUT = 10000;
-
- protected static final String ORG_APACHE_FELIX_USERADMIN = "org.apache.felix.useradmin";
- protected static final String ORG_APACHE_FELIX_USERADMIN_FILESTORE = "org.apache.felix.useradmin.filestore";
+ private static final int DEFAULT_TIMEOUT = 10000;
+
+ protected static final String ORG_APACHE_FELIX_USERADMIN = "org.apache.felix.useradmin";
+ protected static final String ORG_APACHE_FELIX_USERADMIN_FILESTORE = "org.apache.felix.useradmin.filestore";
+ protected static final String ORG_APACHE_FELIX_USERADMIN_MONGODBSTORE = "org.apache.felix.useradmin.mongodb";
+ protected static final String ORG_MONGODB_MONGO_JAVA_DRIVER = "org.mongodb.mongo-java-driver";
@Inject
protected volatile BundleContext m_context;
@Configuration
- public Option[] config() {
+ public Option[] config()
+ {
return options(
bootDelegationPackage("sun.*"),
cleanCaches(),
- CoreOptions.systemProperty("logback.configurationFile").value("file:src/test/resources/logback.xml"),
+ CoreOptions.systemProperty("logback.configurationFile").value("file:src/test/resources/logback.xml"), //
// CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8787"),
mavenBundle("org.slf4j", "slf4j-api").version("1.6.5").startLevel(START_LEVEL_SYSTEM_BUNDLES),
@@ -79,15 +83,15 @@ public Option[] config() {
url("link:classpath:META-INF/links/org.apache.geronimo.specs.atinject.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
mavenBundle("org.apache.felix", ORG_APACHE_FELIX_USERADMIN).versionAsInProject().startLevel(START_LEVEL_SYSTEM_BUNDLES),
- mavenBundle("org.apache.felix", ORG_APACHE_FELIX_USERADMIN_FILESTORE).versionAsInProject().startLevel(START_LEVEL_SYSTEM_BUNDLES),
-
- junitBundles(),
- frameworkStartLevel(START_LEVEL_TEST_BUNDLE),
- felix());
+ mavenBundle("org.apache.felix", ORG_APACHE_FELIX_USERADMIN_FILESTORE).versionAsInProject().noStart(),
+ mavenBundle("org.apache.felix", ORG_APACHE_FELIX_USERADMIN_MONGODBSTORE).versionAsInProject().noStart(), mavenBundle("org.mongodb", "mongo-java-driver").versionAsInProject().noStart(),
+
+ junitBundles(), frameworkStartLevel(START_LEVEL_TEST_BUNDLE), felix());
}
@Before
- public void setUp() throws Exception {
+ public void setUp() throws Exception
+ {
assertNotNull("No bundle context?!", m_context);
}
@@ -97,55 +101,86 @@ public void setUp() throws Exception {
* @return
* @throws Exception
*/
- protected T awaitService(String serviceName) throws Exception {
+ protected T awaitService(String serviceName) throws Exception
+ {
ServiceTracker tracker = new ServiceTracker(m_context, serviceName, null);
tracker.open();
T result;
- try {
+ try
+ {
result = (T) tracker.waitForService(DEFAULT_TIMEOUT);
}
- finally {
+ finally
+ {
tracker.close();
}
return result;
}
+ /**
+ * @param bsn
+ * @return
+ */
+ protected Bundle findBundle(String bsn)
+ {
+ for (Bundle bundle : m_context.getBundles())
+ {
+ if (bsn.equals(bundle.getSymbolicName()))
+ {
+ return bundle;
+ }
+ }
+ return null;
+ }
+
+ protected Bundle getFileStoreBundle()
+ {
+ Bundle b = findBundle(ORG_APACHE_FELIX_USERADMIN_FILESTORE);
+ assertNotNull("Filestore bundle not found?!", b);
+ return b;
+ }
+
+ protected Bundle getMongoDBStoreBundle()
+ {
+ Bundle b = findBundle(ORG_APACHE_FELIX_USERADMIN_MONGODBSTORE);
+ assertNotNull("MongoDB store bundle not found?!", b);
+ return b;
+ }
+
+ protected Bundle getMongoDBBundle()
+ {
+ Bundle b = findBundle(ORG_MONGODB_MONGO_JAVA_DRIVER);
+ assertNotNull("MongoDB bundle not found?!", b);
+ return b;
+ }
+
/**
* Obtains a service without waiting for it to become available.
* @param serviceName
* @return
* @throws Exception
*/
- protected T getService(String serviceName) throws Exception {
+ protected T getService(String serviceName) throws Exception
+ {
ServiceTracker tracker = new ServiceTracker(m_context, serviceName, null);
tracker.open();
T result;
- try {
+ try
+ {
result = (T) tracker.getService();
}
- finally {
+ finally
+ {
tracker.close();
}
return result;
}
-
+
/**
* @return the {@link UserAdmin} service instance.
*/
- protected UserAdmin getUserAdmin() throws Exception {
+ protected UserAdmin getUserAdmin() throws Exception
+ {
return getService(UserAdmin.class.getName());
}
-
- /**
- * @param bsn
- * @return
- */
- protected Bundle findBundle(String bsn) {
- for (Bundle bundle : m_context.getBundles()) {
- if (bsn.equals(bundle.getSymbolicName())) {
- return bundle;
- }
- }
- return null;
- }
}
diff --git a/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/FileStoreInitializationTest.java b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/FileStoreInitializationTest.java
index 0b712b818f5..fd854e0970f 100644
--- a/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/FileStoreInitializationTest.java
+++ b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/FileStoreInitializationTest.java
@@ -36,51 +36,54 @@
* @author Felix Project Team
*/
@RunWith(JUnit4TestRunner.class)
-public class FileStoreInitializationTest extends BaseIntegrationTest {
-
- /**
- * Tests that initialization and closing of the repository store is
- * performed correctly.
- */
- @Test
- public void testStoreIsInitializedAndClosedProperlyOk() throws Exception {
- UserAdmin ua = getUserAdmin();
-
- // Create two roles...
- User user = (User) ua.createRole("user1", Role.USER);
- assertNotNull(user);
-
- Group group = (Group) ua.createRole("group1", Role.GROUP);
- assertNotNull(group);
-
- group.addMember(user);
- group.addRequiredMember(ua.getRole(Role.USER_ANYONE));
-
- // Stop the file store; should persist the two roles...
- Bundle fileStoreBundle = findBundle(ORG_APACHE_FELIX_USERADMIN_FILESTORE);
- assertNotNull(fileStoreBundle);
- fileStoreBundle.stop();
-
- Thread.sleep(100); // Wait a little until the bundle is really stopped...
-
- // Retrieve the roles again; should both yield null due to the store not being available...
- user = (User) ua.getRole("user1");
- assertNull(user);
-
- group = (Group) ua.getRole("group1");
- assertNull(group);
-
- // This will not succeed: no backend to store the user in...
- assertNull(ua.createRole("user2", Role.USER));
-
- fileStoreBundle.start();
-
- awaitService(ORG_APACHE_FELIX_USERADMIN_FILESTORE);
-
+public class FileStoreInitializationTest extends BaseIntegrationTest
+{
+
+ /**
+ * Tests that initialization and closing of the repository store is
+ * performed correctly.
+ */
+ @Test
+ public void testStoreIsInitializedAndClosedProperlyOk() throws Exception
+ {
+ UserAdmin ua = getUserAdmin();
+ // Start the file store bundle...
+ Bundle fileStoreBundle = getFileStoreBundle();
+ fileStoreBundle.start();
+
+ // Create two roles...
+ User user = (User) ua.createRole("user1", Role.USER);
+ assertNotNull(user);
+
+ Group group = (Group) ua.createRole("group1", Role.GROUP);
+ assertNotNull(group);
+
+ group.addMember(user);
+ group.addRequiredMember(ua.getRole(Role.USER_ANYONE));
+
+ // Stop the file store; should persist the two roles...
+ fileStoreBundle.stop();
+
+ Thread.sleep(100); // Wait a little until the bundle is really stopped...
+
+ // Retrieve the roles again; should both yield null due to the store not being available...
+ user = (User) ua.getRole("user1");
+ assertNull(user);
+
+ group = (Group) ua.getRole("group1");
+ assertNull(group);
+
+ // This will not succeed: no backend to store the user in...
+ assertNull(ua.createRole("user2", Role.USER));
+
+ fileStoreBundle.start();
+
+ awaitService(ORG_APACHE_FELIX_USERADMIN_FILESTORE);
+
// Retrieve the roles again; should both yield valid values...
user = (User) ua.getRole("user1");
assertNotNull(user);
-
+
group = (Group) ua.getRole("group1");
assertNotNull(group);
@@ -93,8 +96,8 @@ public void testStoreIsInitializedAndClosedProperlyOk() throws Exception {
assertNotNull(members);
assertEquals(1, members.length);
assertEquals(Role.USER_ANYONE, members[0].getName());
-
+
user = (User) ua.getRole("user2");
assertNull(user);
- }
+ }
}
diff --git a/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/MongoDBStoreTest.java b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/MongoDBStoreTest.java
new file mode 100644
index 00000000000..371d0960860
--- /dev/null
+++ b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/MongoDBStoreTest.java
@@ -0,0 +1,201 @@
+/*
+ * 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.felix.useradmin.itest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.CommandResult;
+import com.mongodb.DB;
+import com.mongodb.DBCollection;
+import com.mongodb.Mongo;
+import com.mongodb.WriteConcern;
+
+/**
+ * Main integration test for the user admin service.
+ *
+ * @author Felix Project Team
+ */
+@RunWith(JUnit4TestRunner.class)
+public class MongoDBStoreTest extends BaseIntegrationTest
+{
+ /**
+ * Tests that fetching an empty role without properties or other roles does not cause a NPE.
+ */
+ @Test
+ public void testFelix4399_FetchEmptyRoleOk() throws Exception
+ {
+ UserAdmin ua = getUserAdmin();
+
+ String roleName = "emptyRole";
+
+ if (canRunTest())
+ {
+ Role emptyRole = ua.createRole(roleName, Role.USER);
+ assertNotNull("Collection not empty?!", emptyRole);
+
+ Role readRole = ua.getRole(roleName);
+
+ assertNotNull("Unable to read back created empty role?!", readRole);
+ assertEquals("Names not equal?!", emptyRole.getName(), readRole.getName());
+ assertEquals("Types not equal?!", emptyRole.getType(), readRole.getType());
+
+ Role[] readRoles = ua.getRoles(null);
+
+ assertNotNull("Unable to read back created empty role?!", readRoles);
+ assertEquals(1, readRoles.length);
+ }
+ }
+
+ /**
+ * Tests that creating a new role returns the actual created role.
+ */
+ @Test
+ public void testFelix4400_CreateRoleReturnsNonNullOk() throws Exception
+ {
+ UserAdmin ua = getUserAdmin();
+
+ String roleName = "newRole";
+
+ if (canRunTest())
+ {
+ Role newRole = ua.createRole(roleName, Role.USER);
+ assertNotNull("Felix-4400 not resolved?!", newRole);
+
+ assertEquals("Names not equal?!", roleName, newRole.getName());
+ assertEquals("Types not equal?!", Role.USER, newRole.getType());
+ }
+ }
+
+ /**
+ * Tests that removing a role works correctly.
+ */
+ @Test
+ public void testRemoveRoleOk() throws Exception
+ {
+ UserAdmin ua = getUserAdmin();
+
+ String roleName = "newRole";
+ Role[] readRoles;
+
+ if (canRunTest())
+ {
+ Role role = ua.createRole(roleName, Role.USER);
+ assertNotNull("Collection not empty?!", role);
+
+ readRoles = ua.getRoles(null);
+
+ assertNotNull("No roles stored?!", readRoles);
+ assertEquals(1, readRoles.length);
+
+ ua.removeRole(roleName);
+
+ readRoles = ua.getRoles(null);
+
+ assertNull("Still roles stored?!", readRoles);
+ }
+ }
+
+ /**
+ * Tests that removing a role works correctly.
+ */
+ @Test
+ public void testUpdateRoleOk() throws Exception
+ {
+ UserAdmin ua = getUserAdmin();
+
+ String roleName = "role1";
+ Role[] readRoles;
+
+ if (canRunTest())
+ {
+ User role = (User) ua.createRole(roleName, Role.USER);
+ assertNotNull("Collection not empty?!", role);
+
+ readRoles = ua.getRoles(null);
+
+ assertNotNull("No roles stored?!", readRoles);
+ assertEquals(1, readRoles.length);
+
+ role.getProperties().put("key", "value");
+
+ Thread.sleep(100); // Wait a little to ensure everything is written...
+
+ readRoles = ua.getRoles("(key=value)");
+
+ assertNotNull("Role not updated?!", readRoles);
+ assertEquals(1, readRoles.length);
+ }
+ }
+
+ /**
+ * Sets up MongoDB and tries to clear the useradmin collection. When this fails, it is assumed that no MongoDB service is available.
+ */
+ private boolean canRunTest() throws BundleException
+ {
+ Bundle mongoBundle = getMongoDBBundle();
+ mongoBundle.start();
+
+ Bundle mongoStoreBundle = getMongoDBStoreBundle();
+ mongoStoreBundle.start();
+
+ // Provision an empty configuration...
+ BundleContext context = mongoStoreBundle.getBundleContext();
+
+ ServiceReference serviceRef = context.getServiceReference(ManagedService.class.getName());
+ assertNotNull(serviceRef);
+
+ ManagedService service = (ManagedService) context.getService(serviceRef);
+ try
+ {
+ service.updated(null);
+
+ Mongo mongo = new Mongo();
+ DB db = mongo.getDB("ua_repo");
+ DBCollection collection = db.getCollection("useradmin");
+ // we always get a collection back, regardless if there is an actual MongoDB listening, hence we should do
+ // some actual calls that cause a connection to MongoDB to be created...
+ collection.remove(new BasicDBObject(), WriteConcern.SAFE);
+
+ CommandResult lastError = db.getLastError();
+
+ return (lastError.getException() == null && collection.getCount() == 0L);
+ }
+ catch (Exception e)
+ {
+ // Ignore; apparently, we failed to connect to MongoDB...
+ }
+
+ return false;
+ }
+}
diff --git a/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/UserAdminIntegrationTest.java b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/UserAdminIntegrationTest.java
index 4dd5db429ae..c09916e8bd9 100644
--- a/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/UserAdminIntegrationTest.java
+++ b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/UserAdminIntegrationTest.java
@@ -35,108 +35,112 @@
* @author Felix Project Team
*/
@RunWith(JUnit4TestRunner.class)
-public class UserAdminIntegrationTest extends BaseIntegrationTest {
-
- /**
- * Tests that stopping a filled store and starting it again will cause it to
- * properly restore its state.
- */
- @Test
- public void testFelix3735_StopRunningStoreRetainsDataOk() throws Exception {
- final String userName = "testUser";
- final String groupName = "testGroup";
-
- UserAdmin userAdmin = awaitService(UserAdmin.class.getName());
-
- // Fill the user admin with some data...
- User testUser = (User) userAdmin.createRole(userName, Role.USER);
- testUser.getProperties().put("key", "value");
-
- Group testGroup = (Group) userAdmin.createRole(groupName, Role.GROUP);
- testGroup.addMember(testUser);
-
- // Stop the file store...
- Bundle fileStoreBundle = findBundle(ORG_APACHE_FELIX_USERADMIN_FILESTORE);
- assertNotNull(fileStoreBundle);
- fileStoreBundle.stop();
-
- // retrieve the useradmin again...
- userAdmin = awaitService(UserAdmin.class.getName());
-
- // Verify the user + group are gone (no store available)...
- assertNull(userAdmin.getRole(userName));
- assertNull(userAdmin.getRole(groupName));
-
- // Start the file store...
- fileStoreBundle.start();
-
- // Verify the user + group are gone (no store available)...
- User readUser = (User) userAdmin.getRole(userName);
- assertNotNull(readUser);
- assertEquals(userName, readUser.getName());
- assertEquals("value", readUser.getProperties().get("key"));
-
- Group readGroup = (Group) userAdmin.getRole(groupName);
- assertNotNull(readGroup);
- assertEquals(groupName, readGroup.getName());
- assertEquals(1, readGroup.getMembers().length);
- assertEquals(readUser, readGroup.getMembers()[0]);
- }
-
- /**
- * Tests that starting the file store after the user admin service
- * is started will cause it to be properly initialized.
- */
- @Test
- public void testFelix3735_StartStoreAfterUserAdminInitializesOk() throws Exception {
- final String userName = "anotherTestUser";
- final String groupName = "anotherTestGroup";
-
- UserAdmin userAdmin = awaitService(UserAdmin.class.getName());
-
- // Fill the user admin with some data...
- User testUser = (User) userAdmin.createRole(userName, Role.USER);
- testUser.getProperties().put("key", "value");
-
- Group testGroup = (Group) userAdmin.createRole(groupName, Role.GROUP);
- testGroup.addMember(testUser);
-
- // Stop the file store...
- Bundle fileStoreBundle = findBundle(ORG_APACHE_FELIX_USERADMIN_FILESTORE);
- assertNotNull(fileStoreBundle);
- fileStoreBundle.stop();
-
- Bundle userAdminBundle = findBundle(ORG_APACHE_FELIX_USERADMIN);
- assertNotNull(userAdminBundle);
- userAdminBundle.stop();
-
- // Obtain user admin service again; shouldn't be available...
- userAdmin = getService(UserAdmin.class.getName());
- assertNull(userAdmin);
-
- userAdminBundle.start();
-
- // Obtain user admin service again; should be available now...
- userAdmin = awaitService(UserAdmin.class.getName());
- assertNotNull(userAdmin);
-
- // Verify the user + group are gone (no store available)...
- assertNull(userAdmin.getRole(userName));
- assertNull(userAdmin.getRole(groupName));
-
- // Start the file store...
- fileStoreBundle.start();
-
- // Verify the user + group are gone (no store available)...
- User readUser = (User) userAdmin.getRole(userName);
- assertNotNull(readUser);
- assertEquals(userName, readUser.getName());
- assertEquals("value", readUser.getProperties().get("key"));
-
- Group readGroup = (Group) userAdmin.getRole(groupName);
- assertNotNull(readGroup);
- assertEquals(groupName, readGroup.getName());
- assertEquals(1, readGroup.getMembers().length);
- assertEquals(readUser, readGroup.getMembers()[0]);
- }
+public class UserAdminIntegrationTest extends BaseIntegrationTest
+{
+ /**
+ * Tests that stopping a filled store and starting it again will cause it to
+ * properly restore its state.
+ */
+ @Test
+ public void testFelix3735_StopRunningStoreRetainsDataOk() throws Exception
+ {
+ final String userName = "testUser";
+ final String groupName = "testGroup";
+
+ UserAdmin userAdmin = awaitService(UserAdmin.class.getName());
+ Bundle fileStoreBundle = getFileStoreBundle();
+ // Start a suitable storage service...
+ fileStoreBundle.start();
+
+ // Fill the user admin with some data...
+ User testUser = (User) userAdmin.createRole(userName, Role.USER);
+ testUser.getProperties().put("key", "value");
+
+ Group testGroup = (Group) userAdmin.createRole(groupName, Role.GROUP);
+ testGroup.addMember(testUser);
+
+ // Stop the file store...
+ fileStoreBundle.stop();
+
+ // retrieve the useradmin again...
+ userAdmin = awaitService(UserAdmin.class.getName());
+
+ // Verify the user + group are gone (no store available)...
+ assertNull(userAdmin.getRole(userName));
+ assertNull(userAdmin.getRole(groupName));
+
+ // Start the file store...
+ fileStoreBundle.start();
+
+ // Verify the user + group are gone (no store available)...
+ User readUser = (User) userAdmin.getRole(userName);
+ assertNotNull(readUser);
+ assertEquals(userName, readUser.getName());
+ assertEquals("value", readUser.getProperties().get("key"));
+
+ Group readGroup = (Group) userAdmin.getRole(groupName);
+ assertNotNull(readGroup);
+ assertEquals(groupName, readGroup.getName());
+ assertEquals(1, readGroup.getMembers().length);
+ assertEquals(readUser, readGroup.getMembers()[0]);
+ }
+
+ /**
+ * Tests that starting the file store after the user admin service
+ * is started will cause it to be properly initialized.
+ */
+ @Test
+ public void testFelix3735_StartStoreAfterUserAdminInitializesOk() throws Exception
+ {
+ final String userName = "anotherTestUser";
+ final String groupName = "anotherTestGroup";
+
+ UserAdmin userAdmin = awaitService(UserAdmin.class.getName());
+ Bundle fileStoreBundle = getFileStoreBundle();
+ // Start a suitable storage service...
+ fileStoreBundle.start();
+
+ // Fill the user admin with some data...
+ User testUser = (User) userAdmin.createRole(userName, Role.USER);
+ testUser.getProperties().put("key", "value");
+
+ Group testGroup = (Group) userAdmin.createRole(groupName, Role.GROUP);
+ testGroup.addMember(testUser);
+
+ // Stop the file store...
+ fileStoreBundle.stop();
+
+ Bundle userAdminBundle = findBundle(ORG_APACHE_FELIX_USERADMIN);
+ assertNotNull(userAdminBundle);
+ userAdminBundle.stop();
+
+ // Obtain user admin service again; shouldn't be available...
+ userAdmin = getService(UserAdmin.class.getName());
+ assertNull(userAdmin);
+
+ userAdminBundle.start();
+
+ // Obtain user admin service again; should be available now...
+ userAdmin = awaitService(UserAdmin.class.getName());
+ assertNotNull(userAdmin);
+
+ // Verify the user + group are gone (no store available)...
+ assertNull(userAdmin.getRole(userName));
+ assertNull(userAdmin.getRole(groupName));
+
+ // Start the file store...
+ fileStoreBundle.start();
+
+ // Verify the user + group are gone (no store available)...
+ User readUser = (User) userAdmin.getRole(userName);
+ assertNotNull(readUser);
+ assertEquals(userName, readUser.getName());
+ assertEquals("value", readUser.getProperties().get("key"));
+
+ Group readGroup = (Group) userAdmin.getRole(groupName);
+ assertNotNull(readGroup);
+ assertEquals(groupName, readGroup.getName());
+ assertEquals(1, readGroup.getMembers().length);
+ assertEquals(readUser, readGroup.getMembers()[0]);
+ }
}
diff --git a/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/MongoDBStore.java b/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/MongoDBStore.java
index 1e66bffb6f2..fd80e86e692 100644
--- a/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/MongoDBStore.java
+++ b/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/MongoDBStore.java
@@ -147,7 +147,8 @@ public Role addRole(String roleName, int type) throws MongoException {
result.getLastError().throwOnError();
}
- return role;
+ // FELIX-4400: ensure we return the correct role...
+ return getRole(roleName);
}
/**
diff --git a/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/MongoSerializerHelper.java b/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/MongoSerializerHelper.java
index 48e48d837b2..06a80052edc 100644
--- a/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/MongoSerializerHelper.java
+++ b/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/MongoSerializerHelper.java
@@ -34,26 +34,28 @@
/**
* Provides a helper class for (de)serializing data to/from MongoDB.
*/
-final class MongoSerializerHelper {
-
+final class MongoSerializerHelper
+{
+
static final String TYPE = "type";
static final String NAME = "name";
-
+
static final String PROPERTIES = "properties";
static final String CREDENTIALS = "credentials";
static final String MEMBERS = "members";
static final String REQUIRED_MEMBERS = "requiredMembers";
-
+
static final String SET = "$set";
-
+
private final RoleProvider m_roleProvider;
-
+
/**
* Creates a new {@link MongoSerializerHelper} instance.
*
* @param roleProvider the role provider to use, cannot be null
.
*/
- public MongoSerializerHelper(RoleProvider roleProvider) {
+ public MongoSerializerHelper(RoleProvider roleProvider)
+ {
m_roleProvider = roleProvider;
}
@@ -63,29 +65,34 @@ public MongoSerializerHelper(RoleProvider roleProvider) {
* @param object the {@link DBObject} to convert, cannot be null
.
* @return a {@link Role} instance, never null
.
*/
- public Role deserialize(DBObject object) {
+ public Role deserialize(DBObject object)
+ {
int type = ((Integer) object.get(TYPE)).intValue();
String name = (String) object.get(NAME);
Role result = RoleFactory.createRole(type, name);
// Read the generic properties of the role...
deserializeDictionary(result.getProperties(), (DBObject) object.get(PROPERTIES));
-
- if ((Role.GROUP == type) || (Role.USER == type)) {
+
+ if ((Role.GROUP == type) || (Role.USER == type))
+ {
// This is safe, as Group extends from User...
deserializeDictionary(((User) result).getCredentials(), (DBObject) object.get(CREDENTIALS));
- if (Role.GROUP == type) {
- for (Role member : getRoles((BasicDBList) object.get(MEMBERS))) {
+ if (Role.GROUP == type)
+ {
+ for (Role member : getRoles((BasicDBList) object.get(MEMBERS)))
+ {
((Group) result).addMember(member);
}
- for (Role member : getRoles((BasicDBList) object.get(REQUIRED_MEMBERS))) {
+ for (Role member : getRoles((BasicDBList) object.get(REQUIRED_MEMBERS)))
+ {
((Group) result).addRequiredMember(member);
}
}
}
-
+
return result;
}
@@ -95,24 +102,27 @@ public Role deserialize(DBObject object) {
* @param role the {@link Role} to serialize, cannot be null
(unchecked!).
* @return a {@link DBObject} representing the given {@link Role}, never null
.
*/
- public DBObject serialize(Role role) {
+ public DBObject serialize(Role role)
+ {
BasicDBObject data = new BasicDBObject();
-
+
int type = role.getType();
-
+
data.put(TYPE, type);
data.put(NAME, role.getName());
data.put(PROPERTIES, serializeDictionary(role.getProperties()));
- if ((Role.GROUP == type) || (Role.USER == type)) {
+ if ((Role.GROUP == type) || (Role.USER == type))
+ {
data.put(CREDENTIALS, serializeDictionary(((User) role).getCredentials()));
- if (Role.GROUP == type) {
+ if (Role.GROUP == type)
+ {
data.put(MEMBERS, getRoleNames(((Group) role).getMembers()));
data.put(REQUIRED_MEMBERS, getRoleNames(((Group) role).getRequiredMembers()));
}
}
-
+
return data;
}
@@ -123,36 +133,40 @@ public DBObject serialize(Role role) {
* @param type the type of the role to serialize.
* @return a {@link DBObject} representing the role with the given name and type, never null
.
*/
- public DBObject serialize(String roleName, int type) {
+ public DBObject serialize(String roleName, int type)
+ {
BasicDBObject data = new BasicDBObject();
-
+
data.put(TYPE, type);
data.put(NAME, roleName);
-
+
return data;
}
-
+
/**
* Creates a serialized version of the given {@link Role} to be used in an update statement.
*
* @param role the {@link Role} to update, cannot be null
.
* @return a {@link DBObject} representing an update statement for the given {@link Role}.
*/
- public DBObject serializeUpdate(Role role) {
+ public DBObject serializeUpdate(Role role)
+ {
int type = role.getType();
-
+
BasicDBObject changeSet = new BasicDBObject();
-
+
changeSet.put(PROPERTIES, serializeDictionary(role.getProperties()));
- if ((Role.GROUP == type) || (Role.USER == type)) {
+ if ((Role.GROUP == type) || (Role.USER == type))
+ {
changeSet.put(CREDENTIALS, serializeDictionary(((User) role).getCredentials()));
- if (Role.GROUP == type) {
+ if (Role.GROUP == type)
+ {
changeSet.put(MEMBERS, getRoleNames(((Group) role).getMembers()));
changeSet.put(REQUIRED_MEMBERS, getRoleNames(((Group) role).getRequiredMembers()));
}
}
-
+
return new BasicDBObject(SET, changeSet);
}
@@ -163,9 +177,11 @@ public DBObject serializeUpdate(Role role) {
* @return a member instance, never null
.
* @throws MongoException in case the requested member was not found (or any other MongoDB exception).
*/
- final Role findExistingMember(String name) {
+ final Role findExistingMember(String name)
+ {
Role result = m_roleProvider.getRole(name);
- if (result == null) {
+ if (result == null)
+ {
throw new MongoException("No such role: " + name);
}
return result;
@@ -174,40 +190,53 @@ final Role findExistingMember(String name) {
/**
* Deserializes the given {@link DBObject} into the given {@link Dictionary}.
*
- * @param dictionary the dictionary to fill;
- * @param object the {@link DBObject} to deserialize.
+ * @param dictionary the dictionary to fill, cannot be null
;
+ * @param object the {@link DBObject} to deserialize, can be null
.
*/
- private void deserializeDictionary(Dictionary dictionary, DBObject object) {
- for (String key : object.keySet()) {
- dictionary.put(KeyCodec.decode(key), object.get(key));
+ private void deserializeDictionary(Dictionary dictionary, DBObject object)
+ {
+ // FELIX-4399: MongoDB does return null for empty properties...
+ if (object != null)
+ {
+ for (String key : object.keySet())
+ {
+ dictionary.put(KeyCodec.decode(key), object.get(key));
+ }
}
}
-
+
/**
* Serializes a given array of {@link Role}s to an list for storing in a {@link DBObject}.
*
* @param members the {@link Role}s to serialize, cannot be null
.
* @return the "serialized" array, never null
.
*/
- private List getRoleNames(Role[] members) {
+ private List getRoleNames(Role[] members)
+ {
List result = new ArrayList();
- if (members != null) {
- for (Role member : members) {
+ if (members != null)
+ {
+ for (Role member : members)
+ {
result.add(member.getName());
}
}
return result;
}
-
+
/**
* Returns all roles mentioned in the given list.
*
- * @param list the list with role names to convert.
+ * @param list the list with role names to convert, can be null
.
* @return a list with {@link Role}s, never null
.
*/
- private List getRoles(BasicDBList list) {
+ private List getRoles(BasicDBList list)
+ {
List result = new ArrayList();
- for (int i = 0, size = list.size(); i < size; i++) {
+ // FELIX-4399: MongoDB does return null for empty properties...
+ int size = (list == null) ? 0 : list.size();
+ for (int i = 0; i < size; i++)
+ {
final String memberName = (String) list.get(i);
result.add(findExistingMember(memberName));
}
@@ -220,17 +249,19 @@ private List getRoles(BasicDBList list) {
* @param properties the {@link Dictionary} to serialize, cannot be null
.
* @return the serialized dictionary, never null
.
*/
- private DBObject serializeDictionary(Dictionary properties) {
+ private DBObject serializeDictionary(Dictionary properties)
+ {
BasicDBObject result = new BasicDBObject();
-
+
Enumeration keysEnum = properties.keys();
- while (keysEnum.hasMoreElements()) {
+ while (keysEnum.hasMoreElements())
+ {
String key = keysEnum.nextElement();
Object value = properties.get(key);
-
+
result.append(KeyCodec.encode(key), value);
}
-
+
return result;
}
}