You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ja...@apache.org on 2012/09/28 14:59:03 UTC
svn commit: r1391437 [1/5] - in /felix/trunk/useradmin: ./ filestore/
filestore/src/ filestore/src/main/ filestore/src/main/java/
filestore/src/main/java/org/ filestore/src/main/java/org/apache/
filestore/src/main/java/org/apache/felix/ filestore/src/m...
Author: jawi
Date: Fri Sep 28 12:58:59 2012
New Revision: 1391437
URL: http://svn.apache.org/viewvc?rev=1391437&view=rev
Log:
FELIX-3600: imported new UserAdmin contribution.
Added:
felix/trunk/useradmin/filestore/ (with props)
felix/trunk/useradmin/filestore/pom.xml (with props)
felix/trunk/useradmin/filestore/src/
felix/trunk/useradmin/filestore/src/main/
felix/trunk/useradmin/filestore/src/main/java/
felix/trunk/useradmin/filestore/src/main/java/org/
felix/trunk/useradmin/filestore/src/main/java/org/apache/
felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/
felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/
felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/
felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/ResettableTimer.java (with props)
felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStore.java (with props)
felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositoryMemoryStore.java (with props)
felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositorySerializer.java (with props)
felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/StubGroupImpl.java (with props)
felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/osgi/
felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/osgi/Activator.java (with props)
felix/trunk/useradmin/filestore/src/test/
felix/trunk/useradmin/filestore/src/test/java/
felix/trunk/useradmin/filestore/src/test/java/org/
felix/trunk/useradmin/filestore/src/test/java/org/apache/
felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/
felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/
felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/
felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/ResettableTimerTest.java (with props)
felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStorePerformanceTest.java (with props)
felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStoreTest.java (with props)
felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/RoleRepositorySerializerTest.java (with props)
felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/StubGroupImplTest.java (with props)
felix/trunk/useradmin/mongodb/ (with props)
felix/trunk/useradmin/mongodb/pom.xml (with props)
felix/trunk/useradmin/mongodb/src/
felix/trunk/useradmin/mongodb/src/main/
felix/trunk/useradmin/mongodb/src/main/java/
felix/trunk/useradmin/mongodb/src/main/java/org/
felix/trunk/useradmin/mongodb/src/main/java/org/apache/
felix/trunk/useradmin/mongodb/src/main/java/org/apache/felix/
felix/trunk/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/
felix/trunk/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/
felix/trunk/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/KeyCodec.java (with props)
felix/trunk/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/MongoDB.java (with props)
felix/trunk/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/MongoDBStore.java (with props)
felix/trunk/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/MongoSerializerHelper.java (with props)
felix/trunk/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/RoleProvider.java (with props)
felix/trunk/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/osgi/
felix/trunk/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/osgi/Activator.java (with props)
felix/trunk/useradmin/mongodb/src/main/java/org/apache/felix/useradmin/mongodb/osgi/LogServiceHelper.java (with props)
felix/trunk/useradmin/mongodb/src/test/
felix/trunk/useradmin/mongodb/src/test/java/
felix/trunk/useradmin/mongodb/src/test/java/org/
felix/trunk/useradmin/mongodb/src/test/java/org/apache/
felix/trunk/useradmin/mongodb/src/test/java/org/apache/felix/
felix/trunk/useradmin/mongodb/src/test/java/org/apache/felix/useradmin/
felix/trunk/useradmin/mongodb/src/test/java/org/apache/felix/useradmin/mongodb/
felix/trunk/useradmin/mongodb/src/test/java/org/apache/felix/useradmin/mongodb/KeyCodecTest.java (with props)
felix/trunk/useradmin/pom.xml (with props)
felix/trunk/useradmin/useradmin/ (with props)
felix/trunk/useradmin/useradmin/pom.xml (with props)
felix/trunk/useradmin/useradmin/src/
felix/trunk/useradmin/useradmin/src/main/
felix/trunk/useradmin/useradmin/src/main/java/
felix/trunk/useradmin/useradmin/src/main/java/org/
felix/trunk/useradmin/useradmin/src/main/java/org/apache/
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/BackendException.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/RoleFactory.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/RoleRepositoryStore.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/AuthorizationImpl.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/EventDispatcher.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleChangeListener.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleChecker.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleRepository.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/UserAdminImpl.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/UserAdminListenerList.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/GroupImpl.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/ObservableDictionary.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/ObservableProperties.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/RoleImpl.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/UserImpl.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/osgi/
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/osgi/Activator.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/osgi/EventAdminHelper.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/osgi/RoleRepositoryStoreHelper.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/osgi/ServiceContext.java (with props)
felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/osgi/UserAdminListenerListHelper.java (with props)
felix/trunk/useradmin/useradmin/src/test/
felix/trunk/useradmin/useradmin/src/test/java/
felix/trunk/useradmin/useradmin/src/test/java/org/
felix/trunk/useradmin/useradmin/src/test/java/org/apache/
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/AuthorizationImplTest.java (with props)
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/EventDispatcherTest.java (with props)
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/MemoryRoleRepositoryStore.java (with props)
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/RoleCheckerTest.java (with props)
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/RoleRepositorySecurityTest.java (with props)
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/RoleRepositoryTest.java (with props)
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/UserAdminImplTest.java (with props)
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/role/
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/role/GroupImplSecurityTest.java (with props)
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/role/GroupImplTest.java (with props)
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/role/ObservableDictionarySecurityTest.java (with props)
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/role/ObservableDictionaryTest.java (with props)
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/role/ObservablePropertiesTest.java (with props)
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/role/RoleImplTest.java (with props)
felix/trunk/useradmin/useradmin/src/test/java/org/apache/felix/useradmin/impl/role/UserImplTest.java (with props)
Propchange: felix/trunk/useradmin/filestore/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Sep 28 12:58:59 2012
@@ -0,0 +1,20 @@
+.settings
+.classpath
+.project
+bin
+build
+target
+classes
+.wtpmodules
+.deployables
+*.iml
+*.ipr
+*.iws
+*.log
+lib
+bundle
+dist
+*.patch
+.externalToolBuilders
+maven-eclipse.xml
+
Added: felix/trunk/useradmin/filestore/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/filestore/pom.xml?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/filestore/pom.xml (added)
+++ felix/trunk/useradmin/filestore/pom.xml Fri Sep 28 12:58:59 2012
@@ -0,0 +1,100 @@
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>felix-parent</artifactId>
+ <groupId>org.apache.felix</groupId>
+ <version>1.2.0</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <artifactId>org.apache.felix.useradmin.filestore</artifactId>
+ <version>1.0.1</version>
+ <packaging>bundle</packaging>
+ <description>Provides a file-based repository store for the UserAdmin OSGi compendium service.</description>
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.useradmin</artifactId>
+ <version>1.0.2</version>
+ <type>bundle</type>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>Apache Felix User Admin file-based repository store</Bundle-Name>
+ <Bundle-Description>
+ A file-based repository store for User Admin Service of Apache Felix.
+ </Bundle-Description>
+ <Bundle-Activator>
+ ${project.artifactId}.osgi.Activator
+ </Bundle-Activator>
+ <Bundle-SymbolicName>
+ ${project.artifactId}
+ </Bundle-SymbolicName>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Import-Package>
+ org.osgi.service.useradmin; version="[1.1,1.2)",
+ org.apache.felix.useradmin; version="[1.0,1.1)",
+ *
+ </Import-Package>
+ <Export-Package>
+ </Export-Package>
+ <Private-Package>
+ ${project.artifactId}.*
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>rat-maven-plugin</artifactId>
+ <configuration>
+ <excludeSubProjects>false</excludeSubProjects>
+ <useEclipseDefaultExcludes>true</useEclipseDefaultExcludes>
+ <useMavenDefaultExcludes>true</useMavenDefaultExcludes>
+ <excludes>
+ <param>doc/*</param>
+ <param>maven-eclipse.xml</param>
+ <param>.checkstyle</param>
+ <param>.externalToolBuilders/*</param>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
Propchange: felix/trunk/useradmin/filestore/pom.xml
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/ResettableTimer.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/ResettableTimer.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/ResettableTimer.java (added)
+++ felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/ResettableTimer.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,114 @@
+/**
+ * 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.filestore;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Provides a timer that can be reset.
+ */
+final class ResettableTimer {
+ private final ScheduledExecutorService m_executor;
+ private final Runnable m_task;
+ private final long m_timeout;
+ private final TimeUnit m_timeUnit;
+ private final AtomicReference m_futureRef;
+
+ /**
+ * Creates a new {@link ResettableTimer} calling a given task when a given
+ * timeout exceeds.
+ *
+ * @param task the task to execute upon timout, cannot be <code>null</code>;
+ * @param timeout the timeout value, > 0;
+ * @param unit the time unit of the timeout value, cannot be <code>null</code>.
+ */
+ public ResettableTimer(Runnable task, long timeout, TimeUnit unit) {
+ this(new ScheduledThreadPoolExecutor(1), task, timeout, unit);
+ }
+
+ /**
+ * Creates a new {@link ResettableTimer} calling a given task when a given
+ * timeout exceeds.
+ *
+ * @param executor the executor to use to execute the task, cannot be <code>null</code>;
+ * @param task the task to execute upon timout, cannot be <code>null</code>;
+ * @param timeout the timeout value, > 0;
+ * @param unit the time unit of the timeout value, cannot be <code>null</code>.
+ */
+ public ResettableTimer(ScheduledExecutorService executor, Runnable task, long timeout, TimeUnit unit) {
+ if (executor == null) {
+ throw new IllegalArgumentException("Executor cannot be null!");
+ }
+ if (task == null) {
+ throw new IllegalArgumentException("Task cannot be null!");
+ }
+ if (timeout <= 0) {
+ throw new IllegalArgumentException("Timeout cannot be negative!");
+ }
+ if (unit == null) {
+ throw new IllegalArgumentException("TimeUnit cannot be null!");
+ }
+
+ m_executor = executor;
+ m_task = task;
+ m_timeout = timeout;
+ m_timeUnit = unit;
+
+ m_futureRef = new AtomicReference();
+ }
+
+ /**
+ * Schedules the task for execution with the contained timeout. If a task
+ * is already pending or running, it will be cancelled (not interrupted).
+ * The new task will be scheduled to run in now + timeout.
+ */
+ public ScheduledFuture schedule() {
+ ScheduledFuture currentTask = cancelCurrentTask();
+ ScheduledFuture newTask = m_executor.schedule(m_task, m_timeout, m_timeUnit);
+ m_futureRef.compareAndSet(currentTask, newTask);
+ return newTask;
+ }
+
+ /**
+ * Shuts down this timer, allowing any pending tasks to execute. After this
+ * method is called, {@link #schedule()} may no longer be called.
+ */
+ public void shutDown() {
+ m_executor.shutdown();
+ try {
+ m_executor.awaitTermination(2 * m_timeout, m_timeUnit);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ /**
+ * @return the current task, or <code>null</code> if no task is available.
+ */
+ private ScheduledFuture cancelCurrentTask() {
+ ScheduledFuture currentTask = (ScheduledFuture) m_futureRef.get();
+ if (currentTask != null) {
+ // Doesn't matter for completed tasks...
+ currentTask.cancel(false /* mayInterruptIfRunning */);
+ }
+ return currentTask;
+ }
+}
Propchange: felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/ResettableTimer.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStore.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStore.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStore.java (added)
+++ felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStore.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,258 @@
+/**
+ * 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.filestore;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.felix.useradmin.RoleRepositoryStore;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.useradmin.UserAdminEvent;
+import org.osgi.service.useradmin.UserAdminListener;
+
+
+/**
+ * Provides an implementation of {@link RoleRepositoryStore} using Java Serialization.
+ */
+public class RoleRepositoryFileStore extends RoleRepositoryMemoryStore implements Runnable, UserAdminListener, ManagedService {
+
+ /** The PID for this service to allow its configuration to be updated. */
+ public static final String PID = "org.apache.felix.useradmin.rolerepositoryfilestore";
+
+ static final String KEY_WRITE_DISABLED = "background.write.disabled";
+ static final String KEY_WRITE_DELAY_VALUE = "background.write.delay.value";
+ static final String KEY_WRITE_DELAY_TIMEUNIT = "background.write.delay.timeunit";
+
+ private static final boolean DEFAULT_WRITE_DISABLED = Boolean.parseBoolean(System.getProperty(KEY_WRITE_DISABLED, "false"));
+ private static final int DEFAULT_WRITE_DELAY_VALUE = Integer.parseInt(System.getProperty(KEY_WRITE_DELAY_VALUE, "500"));
+ private static final TimeUnit DEFAULT_WRITE_DELAY_TIMEUNIT = TimeUnit.MILLISECONDS;
+
+ private static final String FILE_NAME = "ua_repo.dat";
+
+ private final File m_file;
+ private final AtomicReference m_timerRef;
+
+ /**
+ * Creates a new {@link RoleRepositoryStore} instance.
+ *
+ * @param baseDir the base directory where we can store our serialized data, cannot be <code>null</code>.
+ */
+ public RoleRepositoryFileStore(File baseDir) {
+ this(baseDir, !DEFAULT_WRITE_DISABLED);
+ }
+
+ /**
+ * Creates a new {@link RoleRepositoryStore} instance.
+ *
+ * @param baseDir the base directory where we can store our serialized data, cannot be <code>null</code>;
+ * @param backgroundWriteEnabled <code>true</code> if background writing should be enabled, <code>false</code> to disable it.
+ */
+ public RoleRepositoryFileStore(File baseDir, boolean backgroundWriteEnabled) {
+ m_file = new File(baseDir, FILE_NAME);
+
+ m_timerRef = new AtomicReference();
+
+ if (backgroundWriteEnabled) {
+ m_timerRef.set(new ResettableTimer(this, DEFAULT_WRITE_DELAY_VALUE, DEFAULT_WRITE_DELAY_TIMEUNIT));
+ }
+ }
+
+ public void initialize() throws IOException {
+ m_entries.putAll(retrieve());
+ }
+
+ public void roleChanged(UserAdminEvent event) {
+ scheduleTask();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Will be called by m_timer!</p>
+ */
+ public void run() {
+ try {
+ // Persist everything to disk...
+ flush();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Stops this store service.
+ */
+ public void stop() {
+ ResettableTimer timer = (ResettableTimer) m_timerRef.get();
+ if (timer != null) {
+ // Shutdown and await termination...
+ timer.shutDown();
+ // Clear reference...
+ m_timerRef.compareAndSet(timer, null);
+ }
+
+ try {
+ // Write the latest version to disk...
+ flush();
+ }
+ catch (IOException e) {
+ // Nothing we can do about this here...
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void updated(Dictionary properties) throws ConfigurationException {
+ boolean writeDisabled = DEFAULT_WRITE_DISABLED;
+ int writeDelayValue = DEFAULT_WRITE_DELAY_VALUE;
+ TimeUnit writeDelayUnit = DEFAULT_WRITE_DELAY_TIMEUNIT;
+
+ if (properties != null) {
+ Object wd = properties.get(KEY_WRITE_DISABLED);
+ if (wd == null) {
+ throw new ConfigurationException(KEY_WRITE_DISABLED, "Missing write disabled value!");
+ }
+ try {
+ writeDisabled = Boolean.parseBoolean((String) wd);
+ } catch (Exception e) {
+ throw new ConfigurationException(KEY_WRITE_DISABLED, "Invalid write disabled value!");
+ }
+
+ if (!writeDisabled) {
+ Object wdv = properties.get(KEY_WRITE_DELAY_VALUE);
+ if (wdv == null) {
+ throw new ConfigurationException(KEY_WRITE_DELAY_VALUE, "Missing write delay value!");
+ }
+ try {
+ writeDelayValue = Integer.parseInt((String) wdv);
+ } catch (Exception e) {
+ throw new ConfigurationException(KEY_WRITE_DELAY_VALUE, "Invalid write delay value!");
+ }
+ if (writeDelayValue <= 0) {
+ throw new ConfigurationException(KEY_WRITE_DELAY_VALUE, "Invalid write delay value!");
+ }
+
+ Object wdu = properties.get(KEY_WRITE_DELAY_TIMEUNIT);
+ if (wdu != null) {
+ try {
+ writeDelayUnit = TimeUnit.valueOf(((String) wdu).toUpperCase());
+ } catch (Exception e) {
+ throw new ConfigurationException(KEY_WRITE_DELAY_TIMEUNIT, "Invalid write delay unit!");
+ }
+ }
+ }
+ }
+
+ ResettableTimer timer = (ResettableTimer) m_timerRef.get();
+ if (timer != null) {
+ timer.shutDown();
+ }
+ m_timerRef.compareAndSet(timer, writeDisabled ? null : new ResettableTimer(this, writeDelayValue, writeDelayUnit));
+ }
+
+ /**
+ * Retrieves the serialized repository from disk.
+ *
+ * @return the retrieved repository, never <code>null</code>.
+ * @throws IOException in case the retrieval of the repository failed.
+ */
+ protected Map retrieve() throws IOException {
+ InputStream is = null;
+
+ try {
+ is = new BufferedInputStream(new FileInputStream(m_file));
+
+ return new RoleRepositorySerializer().deserialize(is);
+ } catch (FileNotFoundException exception) {
+ // Don't bother; file does not exist...
+ return Collections.emptyMap();
+ } finally {
+ closeSafely(is);
+ }
+ }
+
+ /**
+ * Stores the given repository to disk as serialized objects.
+ *
+ * @param roleRepository the repository to store, cannot be <code>null</code>.
+ * @throws IOException in case storing the repository failed.
+ */
+ protected void store(Map roleRepository) throws IOException {
+ OutputStream os = null;
+
+ try {
+ os = new BufferedOutputStream(new FileOutputStream(m_file));
+
+ new RoleRepositorySerializer().serialize(roleRepository, os);
+ } finally {
+ closeSafely(os);
+ }
+ }
+
+ /**
+ * Closes a given resource, ignoring any exceptions that may come out of this.
+ *
+ * @param resource the resource to close, can be <code>null</code>.
+ */
+ private void closeSafely(Closeable resource) {
+ if (resource != null) {
+ try {
+ resource.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+
+ /**
+ * Flushes the current repository to disk.
+ *
+ * @throws IOException in case of problems storing the repository.
+ */
+ private void flush() throws IOException {
+ store(new HashMap(m_entries));
+ }
+
+ /**
+ * Notifies the background timer to schedule a task for storing the
+ * contents of this store to disk.
+ */
+ private void scheduleTask() {
+ ResettableTimer timer = (ResettableTimer) m_timerRef.get();
+ if (timer != null) {
+ timer.schedule();
+ }
+ }
+}
Propchange: felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStore.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositoryMemoryStore.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositoryMemoryStore.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositoryMemoryStore.java (added)
+++ felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositoryMemoryStore.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,70 @@
+/**
+ * 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.filestore;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.felix.useradmin.RoleRepositoryStore;
+import org.osgi.service.useradmin.Role;
+
+
+/**
+ * Provides a thread-safe in-memory role repository store.
+ */
+public class RoleRepositoryMemoryStore implements RoleRepositoryStore {
+
+ protected final ConcurrentMap m_entries = new ConcurrentHashMap();
+
+ public boolean addRole(Role role) throws IOException {
+ if (role == null) {
+ throw new IllegalArgumentException("Role cannot be null!");
+ }
+ Object result = m_entries.putIfAbsent(role.getName(), role);
+ return result == null;
+ }
+
+ public void close() throws IOException {
+ // Nop
+ }
+
+ public Role[] getAllRoles() throws IOException {
+ Collection roles = m_entries.values();
+ Role[] result = new Role[roles.size()];
+ return (Role[]) roles.toArray(result);
+ }
+
+ public Role getRoleByName(String roleName) throws IOException {
+ if (roleName == null) {
+ throw new IllegalArgumentException("Role name cannot be null!");
+ }
+ return (Role) m_entries.get(roleName);
+ }
+
+ public void initialize() throws IOException {
+ // Nop
+ }
+
+ public boolean removeRole(Role role) throws IOException {
+ if (role == null) {
+ throw new IllegalArgumentException("Role cannot be null!");
+ }
+ return m_entries.remove(role.getName(), role);
+ }
+}
Propchange: felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositoryMemoryStore.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositorySerializer.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositorySerializer.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositorySerializer.java (added)
+++ felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositorySerializer.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,454 @@
+/**
+ * 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.filestore;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+
+import org.apache.felix.useradmin.RoleFactory;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+
+/**
+ * Provides a serializer for a role repository.
+ */
+final class RoleRepositorySerializer {
+
+ private static final int VALUE_TYPE_STRING = 1;
+ private static final int VALUE_TYPE_BARRAY = 2;
+
+ /**
+ * Deserializes a given input stream.
+ *
+ * @param is the input stream to deserialize, cannot be <code>null</code>.
+ * @return a {@link Map} representing the role repository. It provides a
+ * mapping between the name of the role as key and the associated
+ * role as value.
+ * @throws IOException in case of I/O problems;
+ * @throws IllegalArgumentException in case the given stream was <code>null</code>.
+ */
+ public Map deserialize(InputStream is) throws IOException {
+ if (is == null) {
+ throw new IllegalArgumentException("InputStream cannot be null!");
+ }
+ return readRepository(new DataInputStream(is));
+ }
+
+ /**
+ * Serializes a given map to the given output stream.
+ *
+ * @param roleRepository the repository to serialize, cannot be <code>null</code>;
+ * @param os the output stream to serialize to, cannot be <code>null</code>.
+ * @throws IOException in case of I/O problems;
+ * @throws IllegalArgumentException in case the given parameter was <code>null</code>.
+ */
+ public void serialize(Map roleRepository, OutputStream os) throws IOException {
+ if (roleRepository == null) {
+ throw new IllegalArgumentException("Map cannot be null!");
+ }
+ if (os == null) {
+ throw new IllegalArgumentException("OutputStream cannot be null!");
+ }
+ writeRepository(roleRepository, new DataOutputStream(os));
+ }
+
+ /**
+ * Adds all groups, based on the given stub groups.
+ *
+ * @param repository the repository to add the groups to, cannot be <code>null</code>;
+ * @param stubGroups the list with stub groups to replace, cannot be <code>null</code>.
+ * @throws IOException in case a referenced role was not found in the repository.
+ */
+ private void addGroups(Map repository, List stubGroups) throws IOException {
+ // First create "empty" groups in the repository; we'll fill them in later on...
+ Iterator sgIter = stubGroups.iterator();
+ while (sgIter.hasNext()) {
+ StubGroupImpl stubGroup = (StubGroupImpl) sgIter.next();
+
+ Group group = (Group) RoleFactory.createRole(Role.GROUP, stubGroup.getName());
+ copyDictionary(stubGroup.getProperties(), group.getProperties());
+ copyDictionary(stubGroup.getCredentials(), group.getCredentials());
+
+ repository.put(group.getName(), group);
+ }
+
+ int origSize = stubGroups.size();
+ while (!stubGroups.isEmpty()) {
+ List copy = new ArrayList(stubGroups);
+
+ int size = copy.size();
+ for (int i = 0; i < size; i++) {
+ StubGroupImpl stubGroup = (StubGroupImpl) copy.get(i);
+
+ Group group = (Group) repository.get(stubGroup.getName());
+ if (group != null) {
+ resolveGroupMembers(stubGroup, group, repository);
+ stubGroups.remove(stubGroup);
+ }
+ }
+
+ // In case we didn't resolve any groups; we should fail...
+ if (origSize == stubGroups.size()) {
+ throw new IOException("Failed to resolve groups: " + stubGroups);
+ }
+
+ origSize = stubGroups.size();
+ }
+ }
+
+ /**
+ * Converts a given {@link Dictionary} implementation to a {@link Map} implementation.
+ *
+ * @param dictionary the dictionary to convert, cannot be <code>null</code>.
+ * @return a {@link Map} instance with all the same key-value pairs as the given dictionary, never <code>null</code>.
+ */
+ private Map convertToMap(Dictionary dictionary) {
+ Map result = new HashMap();
+ if (dictionary instanceof Map) {
+ result.putAll((Map) dictionary);
+ } else {
+ Enumeration keyEnum = dictionary.keys();
+ while (keyEnum.hasMoreElements()) {
+ Object key = keyEnum.nextElement();
+ result.put(key, dictionary.get(key));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Copies the contents of a given dictionary to a given other dictionary.
+ *
+ * @param source the dictionary to copy from;
+ * @param dest the dictionary to copy to.
+ */
+ private void copyDictionary(Dictionary source, Dictionary dest) {
+ Enumeration keys = source.keys();
+ while (keys.hasMoreElements()) {
+ Object key = keys.nextElement();
+ Object value = source.get(key);
+ dest.put(key, value);
+ }
+ }
+
+ /**
+ * Reads and fills a given dictionary.
+ *
+ * @param dict the dictionary to read & fill, cannot be <code>null</code>;
+ * @param dis the input stream to read the data from, cannot be <code>null</code>.
+ * @throws IOException in case of I/O problems.
+ */
+ private void readDictionary(Dictionary dict, DataInputStream dis) throws IOException {
+ // Read the number of entries...
+ int count = dis.readInt();
+ while (count-- > 0) {
+ // Read the name of the key...
+ String key = dis.readUTF();
+ // Read the type of the value...
+ int type = dis.read();
+ // Read the value & add the actual entry...
+ if (VALUE_TYPE_BARRAY == type) {
+ int length = dis.readInt();
+ byte[] value = new byte[length];
+ if (dis.read(value, 0, length) != length) {
+ throw new IOException("Invalid repository; failed to correctly read dictionary!");
+ }
+ dict.put(key, value);
+ } else if (VALUE_TYPE_STRING == type) {
+ dict.put(key, dis.readUTF());
+ }
+ }
+ }
+
+ /**
+ * Reads a (stub) group from the given input stream.
+ *
+ * @param dis the input stream to read the data from, cannot be <code>null</code>.
+ * @return the read (stub) group, never <code>null</code>.
+ * @throws IOException in case of I/O problems.
+ */
+ private StubGroupImpl readGroup(DataInputStream dis) throws IOException {
+ StubGroupImpl group = new StubGroupImpl(dis.readUTF());
+
+ readDictionary(group.getProperties(), dis);
+ readDictionary(group.getCredentials(), dis);
+
+ // Read the number of basic members...
+ int count = dis.readInt();
+ while (count-- > 0) {
+ group.addMember(dis.readUTF());
+ }
+
+ // Read the number of required members...
+ count = dis.readInt();
+ while (count-- > 0) {
+ group.addRequiredMember(dis.readUTF());
+ }
+
+ return group;
+ }
+
+ /**
+ * Reads the entire repository from the given input stream.
+ *
+ * @param dis the input stream to read the data from, cannot be <code>null</code>.
+ * @return the repository {@link Map}, never <code>null</code>.
+ * @throws IOException in case of I/O problems.
+ */
+ private Map readRepository(DataInputStream dis) throws IOException {
+ Map repository = new HashMap();
+
+ int entryCount = dis.readInt();
+
+ List stubGroups = new ArrayList();
+
+ // Keep reading until no more types can be read...
+ while (entryCount-- > 0) {
+ int type = dis.readInt();
+
+ Role role = null;
+ if (Role.GROUP == type) {
+ stubGroups.add(readGroup(dis));
+ } else if (Role.USER == type) {
+ role = readUser(dis);
+ } else {
+ role = readRole(dis);
+ }
+
+ if (role != null) {
+ repository.put(role.getName(), role);
+ }
+ }
+
+ // Post processing stage: replace all stub groups with real group implementations...
+ addGroups(repository, stubGroups);
+
+ return repository;
+ }
+
+ /**
+ * Reads a role from the given input stream.
+ *
+ * @param dis the input stream to read the data from, cannot be <code>null</code>.
+ * @return the read role, never <code>null</code>.
+ * @throws IOException in case of I/O problems.
+ */
+ private Role readRole(DataInputStream dis) throws IOException {
+ Role role = RoleFactory.createRole(Role.ROLE, dis.readUTF());
+
+ readDictionary(role.getProperties(), dis);
+
+ return role;
+ }
+
+ /**
+ * Reads a user from the given input stream.
+ *
+ * @param dis the input stream to read the data from, cannot be <code>null</code>.
+ * @return the read user, never <code>null</code>.
+ * @throws IOException in case of I/O problems.
+ */
+ private User readUser(DataInputStream dis) throws IOException {
+ User user = (User) RoleFactory.createRole(Role.USER, dis.readUTF());
+
+ readDictionary(user.getProperties(), dis);
+ readDictionary(user.getCredentials(), dis);
+
+ return user;
+ }
+
+ /**
+ * Resolves all basic and required group members for a given group, based on the names from the given stub group.
+ *
+ * @param stubGroup the stub group to convert, cannot be <code>null</code>;
+ * @param repository the repository to take the roles from, cannot be <code>null</code>.
+ * @return a concrete {@link Group} instance with all members resolved, or <code>null</code> if not all members could be resolved.
+ * @throws IOException in case a referenced role was not found in the repository.
+ */
+ private void resolveGroupMembers(StubGroupImpl stubGroup, Group group, Map repository) throws IOException {
+ List names = stubGroup.getMemberNames();
+ int size = names.size();
+
+ for (int i = 0; i < size; i++) {
+ String name = (String) names.get(i);
+ Role role = (Role) repository.get(name);
+ if (role == null) {
+ throw new IOException("Unable to find referenced basic member: " + name);
+ }
+ group.addMember(role);
+ }
+
+ names = stubGroup.getRequiredMemberNames();
+ size = names.size();
+
+ for (int i = 0; i < size; i++) {
+ String name = (String) names.get(i);
+ Role role = (Role) repository.get(name);
+ if (role == null) {
+ throw new IOException("Unable to find referenced required member: " + name);
+ }
+ group.addRequiredMember(role);
+ }
+ }
+
+ /**
+ * Writes a given dictionary to the given output stream.
+ *
+ * @param dict the dictionary to write, cannot be <code>null</code>;
+ * @param dos the output stream to write the data to, cannot be <code>null</code>.
+ * @throws IOException in case of I/O problems.
+ */
+ private void writeDictionary(Dictionary dict, DataOutputStream dos) throws IOException {
+ Map properties = convertToMap(dict);
+
+ Set entries = properties.entrySet();
+ int size = entries.size();
+
+ // Write the number of entries...
+ dos.writeInt(size);
+
+ Iterator entriesIter = entries.iterator();
+ while (entriesIter.hasNext()) {
+ Map.Entry entry = (Entry) entriesIter.next();
+
+ dos.writeUTF((String) entry.getKey());
+
+ Object value = entry.getValue();
+ if (value instanceof String) {
+ dos.write(VALUE_TYPE_STRING);
+ dos.writeUTF((String) value);
+ } else if (value instanceof byte[]) {
+ dos.write(VALUE_TYPE_BARRAY);
+ dos.writeInt(((byte[]) value).length);
+ dos.write((byte[]) value);
+ }
+ }
+ }
+
+ /**
+ * Writes a given group to the given output stream.
+ *
+ * @param group the group to write, cannot be <code>null</code>.
+ * @param dos the output stream to write the data to, cannot be <code>null</code>.
+ * @throws IOException in case of I/O problems.
+ */
+ private void writeGroup(Group group, DataOutputStream dos) throws IOException {
+ dos.writeUTF(group.getName());
+
+ writeDictionary(group.getProperties(), dos);
+ writeDictionary(group.getCredentials(), dos);
+
+ Role[] m = group.getMembers();
+
+ if (m == null) {
+ dos.writeInt(0);
+ } else {
+ // Write the number of basic members...
+ dos.writeInt(m.length);
+ // Write the names of the basic members...
+ for (int i = 0; i < m.length; i++) {
+ dos.writeUTF(m[i].getName());
+ }
+ }
+
+ m = group.getRequiredMembers();
+
+ if (m == null) {
+ dos.writeInt(0);
+ } else {
+ // Write the number of required members...
+ dos.writeInt(m.length);
+ // Write the names of the required members...
+ for (int i = 0; i < m.length; i++) {
+ dos.writeUTF(m[i].getName());
+ }
+ }
+ }
+
+ /**
+ * Writes the given repository to the given output stream.
+ *
+ * @param repository the repository to write, cannot be <code>null</code>;
+ * @param dos the output stream to write the data to, cannot be <code>null</code>.
+ * @throws IOException in case of I/O problems.
+ */
+ private void writeRepository(Map repository, DataOutputStream dos) throws IOException {
+ Collection values = repository.values();
+ Iterator valuesIter = values.iterator();
+
+ // Write the total number of entries in our repository first...
+ dos.writeInt(values.size());
+
+ while (valuesIter.hasNext()) {
+ Role role = (Role) valuesIter.next();
+
+ int type = role.getType();
+
+ dos.writeInt(type);
+
+ if (Role.GROUP == type) {
+ writeGroup((Group) role, dos);
+ } else if (Role.USER == type) {
+ writeUser((User) role, dos);
+ } else {
+ writeRole(role, dos);
+ }
+ }
+ }
+
+ /**
+ * Writes a given role to the given output stream.
+ *
+ * @param role the role to write, cannot be <code>null</code>.
+ * @param dos the output stream to write the data to, cannot be <code>null</code>.
+ * @throws IOException in case of I/O problems.
+ */
+ private void writeRole(Role role, DataOutputStream dos) throws IOException {
+ dos.writeUTF(role.getName());
+
+ writeDictionary(role.getProperties(), dos);
+ }
+
+ /**
+ * Writes a given user to the given output stream.
+ *
+ * @param user the user to write, cannot be <code>null</code>.
+ * @param dos the output stream to write the data to, cannot be <code>null</code>.
+ * @throws IOException in case of I/O problems.
+ */
+ private void writeUser(User user, DataOutputStream dos) throws IOException {
+ dos.writeUTF(user.getName());
+
+ writeDictionary(user.getProperties(), dos);
+ writeDictionary(user.getCredentials(), dos);
+ }
+}
Propchange: felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/RoleRepositorySerializer.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/StubGroupImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/StubGroupImpl.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/StubGroupImpl.java (added)
+++ felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/StubGroupImpl.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,184 @@
+/**
+ * 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.filestore;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+
+/**
+ * Provides a stub group that has "weak" references (based on their names) to its basic/required members.
+ */
+final class StubGroupImpl implements Group {
+
+ private final String m_name;
+ private final List m_basicMembers;
+ private final List m_requiredMembers;
+ private final Dictionary m_credentials;
+ private final Dictionary m_properties;
+
+ /**
+ * Creates a new {@link StubGroupImpl} instance.
+ */
+ public StubGroupImpl(String name) {
+ m_name = name;
+ m_properties = new Properties();
+ m_credentials = new Properties();
+ m_basicMembers = new ArrayList();
+ m_requiredMembers = new ArrayList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean addMember(Role role) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean addMember(String roleName) {
+ return m_basicMembers.add(roleName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean addRequiredMember(Role role) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean addRequiredMember(String roleName) {
+ return m_requiredMembers.add(roleName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((m_name == null) ? 0 : m_name.hashCode());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ StubGroupImpl other = (StubGroupImpl) obj;
+ if (m_name == null) {
+ if (other.m_name != null) {
+ return false;
+ }
+ } else if (!m_name.equals(other.m_name)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Dictionary getCredentials() {
+ return m_credentials;
+ }
+
+ /**
+ * Returns the names of all basic members.
+ *
+ * @return a list with basic member names (as String!), never <code>null</code>.
+ */
+ public List getMemberNames() {
+ return m_basicMembers;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Role[] getMembers() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Dictionary getProperties() {
+ return m_properties;
+ }
+
+ /**
+ * Returns the names of all required members.
+ *
+ * @return a list with required member names (as String!), never <code>null</code>.
+ */
+ public List getRequiredMemberNames() {
+ return m_requiredMembers;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Role[] getRequiredMembers() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getType() {
+ return Role.GROUP;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasCredential(String key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean removeMember(Role role) {
+ throw new UnsupportedOperationException();
+ }
+}
Propchange: felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/StubGroupImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/osgi/Activator.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/osgi/Activator.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/osgi/Activator.java (added)
+++ felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/osgi/Activator.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,53 @@
+/**
+ * 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.filestore.osgi;
+
+import java.util.Properties;
+
+import org.apache.felix.useradmin.RoleRepositoryStore;
+import org.apache.felix.useradmin.filestore.RoleRepositoryFileStore;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.useradmin.UserAdminListener;
+
+/**
+ * Registers the {@link RoleRepositoryFileStore} as {@link RoleRepositoryStore} service.
+ */
+public class Activator implements BundleActivator {
+
+ private RoleRepositoryFileStore m_store;
+
+ public void start(BundleContext context) throws Exception {
+ m_store = new RoleRepositoryFileStore(context.getDataFile(""));
+
+ String[] interfaces = { RoleRepositoryStore.class.getName(), UserAdminListener.class.getName(), ManagedService.class.getName() };
+
+ Properties props = new Properties();
+ props.put(Constants.SERVICE_PID, RoleRepositoryFileStore.PID);
+
+ context.registerService(interfaces, m_store, props);
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ if (m_store != null) {
+ m_store.stop();
+ m_store = null;
+ }
+ }
+}
Propchange: felix/trunk/useradmin/filestore/src/main/java/org/apache/felix/useradmin/filestore/osgi/Activator.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/ResettableTimerTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/ResettableTimerTest.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/ResettableTimerTest.java (added)
+++ felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/ResettableTimerTest.java Fri Sep 28 12:58:59 2012
@@ -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.filestore;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import junit.framework.TestCase;
+
+/**
+ * Test case for {@link ResettableTimer}.
+ */
+public class ResettableTimerTest extends TestCase {
+
+ private ResettableTimer m_timer;
+ private CountDownLatch m_latch;
+
+ /**
+ * Tests that a executor service is mandatory.
+ */
+ public void testExecutorSerivceIsMandatory() throws Exception {
+ Runnable task = createStubTask();
+
+ try {
+ new ResettableTimer(null, task, 10, TimeUnit.HOURS);
+ fail("IllegalArgumentException expected!");
+ } catch (Exception e) {
+ // Ok; expected
+ }
+ }
+
+ /**
+ * Tests that multiple calls to {@link ResettableTimer#schedule()} causes
+ * pending tasks to be cancelled.
+ */
+ public void testScheduleCancelsPendingTasksOk() throws Exception {
+ final AtomicInteger m_counter = new AtomicInteger(0);
+
+ Runnable task = new Runnable() {
+ public void run() {
+ m_counter.incrementAndGet();
+ }
+ };
+
+ m_timer = new ResettableTimer(task, 100, TimeUnit.MILLISECONDS);
+ m_timer.schedule();
+
+ TimeUnit.MILLISECONDS.sleep(75);
+
+ Future f = m_timer.schedule();
+ f.get();
+
+ assertEquals(1, m_counter.get());
+ }
+
+ /**
+ * Test method for {@link org.apache.felix.useradmin.impl.ResettableTimer#schedule()}.
+ */
+ public void testScheduleMultipleTasksOk() throws Exception {
+ final AtomicInteger m_counter = new AtomicInteger(0);
+
+ Runnable task = new Runnable() {
+ public void run() {
+ m_counter.incrementAndGet();
+ }
+ };
+
+ m_timer = new ResettableTimer(task, 100, TimeUnit.MILLISECONDS);
+
+ Future f = m_timer.schedule();
+ f.get();
+
+ f = m_timer.schedule();
+ f.get();
+
+ assertEquals(2, m_counter.get());
+ }
+
+ /**
+ * Tests that a task is invoked as single shot.
+ */
+ public void testScheduleSingleShotOk() throws Exception {
+ m_latch = new CountDownLatch(1);
+
+ Runnable task = new Runnable() {
+ public void run() {
+ m_latch.countDown();
+ }
+ };
+
+ m_timer = new ResettableTimer(task, 100, TimeUnit.MILLISECONDS);
+ m_timer.schedule();
+
+ assertTrue(m_latch.await(200, TimeUnit.MILLISECONDS));
+ }
+
+ /**
+ * Test method for {@link org.apache.felix.useradmin.impl.ResettableTimer#shutDown()}.
+ */
+ public void testShutDownOk() throws Exception {
+ final AtomicInteger m_counter = new AtomicInteger(0);
+
+ Runnable task = new Runnable() {
+ public void run() {
+ m_counter.incrementAndGet();
+ }
+ };
+
+ m_timer = new ResettableTimer(task, 100, TimeUnit.MILLISECONDS);
+ m_timer.schedule();
+
+ TimeUnit.MILLISECONDS.sleep(75);
+
+ m_timer.schedule();
+ m_timer.shutDown();
+
+ assertEquals(1, m_counter.get());
+ }
+
+ /**
+ * Tests that a task is mandatory.
+ */
+ public void testTaskIsMandatory() throws Exception {
+ try {
+ new ResettableTimer(null, 10, TimeUnit.HOURS);
+ fail("IllegalArgumentException expected!");
+ } catch (Exception e) {
+ // Ok; expected
+ }
+ }
+
+ /**
+ * Tests that a timeout cannot be zero.
+ */
+ public void testTimeoutCannotBeNegative() throws Exception {
+ Runnable task = createStubTask();
+
+ try {
+ new ResettableTimer(task, -1, TimeUnit.MILLISECONDS);
+ fail("IllegalArgumentException expected!");
+ } catch (Exception e) {
+ // Ok; expected
+ }
+ }
+
+ /**
+ * Tests that a timeout cannot be zero.
+ */
+ public void testTimeoutCannotBeZero() throws Exception {
+ Runnable task = createStubTask();
+
+ try {
+ new ResettableTimer(task, 0, TimeUnit.MILLISECONDS);
+ fail("IllegalArgumentException expected!");
+ } catch (Exception e) {
+ // Ok; expected
+ }
+ }
+
+ /**
+ * Tests that a time unit is mandatory.
+ */
+ public void testTimeUnitIsMandatory() throws Exception {
+ Runnable task = createStubTask();
+
+ try {
+ new ResettableTimer(task, 10, null);
+ fail("IllegalArgumentException expected!");
+ } catch (Exception e) {
+ // Ok; expected
+ }
+ }
+
+ /**
+ * @return a {@link Runnable} that does nothing, never <code>null</code>.
+ */
+ private Runnable createStubTask() {
+ return new Runnable() {
+ public void run() {
+ // No-op
+ }
+ };
+ }
+}
Propchange: felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/ResettableTimerTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStorePerformanceTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStorePerformanceTest.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStorePerformanceTest.java (added)
+++ felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStorePerformanceTest.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,168 @@
+/**
+ * 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.filestore;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.useradmin.impl.RoleRepository;
+import org.apache.felix.useradmin.impl.role.GroupImpl;
+import org.apache.felix.useradmin.impl.role.UserImpl;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+
+/**
+ * Test case for {@link RoleRepositorySerializer}.
+ */
+public class RoleRepositoryFileStorePerformanceTest extends TestCase {
+
+ private static final int USER_COUNT = 15000;
+ private static final int GROUP_COUNT = 500;
+
+ private Group[] m_groups;
+ private User[] m_users;
+
+ private Map m_repository;
+ private RoleRepositoryFileStore m_store;
+
+ /**
+ * Executes the performance test.
+ */
+ public void testPerformanceOk() throws Exception {
+ allocateMemory();
+
+ writeRepositoryPerformanceTest();
+
+ releaseMemory();
+
+ readRepositoryPerformanceTest();
+ }
+
+ /**
+ * Does a very simple performance test for a large number of users spread over several groups.
+ */
+ protected void readRepositoryPerformanceTest() throws Exception {
+ long r_st = System.currentTimeMillis();
+ Map result = m_store.retrieve();
+ long r_time = System.currentTimeMillis() - r_st;
+
+ assertNotNull(result);
+ assertEquals(GROUP_COUNT + USER_COUNT + 1, result.size());
+
+ System.out.println("Read time : " + (r_time / 1000.0) + "s.");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ m_store = new RoleRepositoryFileStore(new File(System.getProperty("java.io.tmpdir")), false /* disable background writes */);
+
+ m_repository = new HashMap(USER_COUNT + GROUP_COUNT + 1);
+
+ addToRepository(RoleRepository.USER_ANYONE);
+ }
+
+ /**
+ * Does a very simple performance test for writing a large number of users spread over several groups.
+ */
+ protected void writeRepositoryPerformanceTest() throws Exception {
+ long w_st = System.currentTimeMillis();
+ m_store.store(m_repository);
+ long w_time = System.currentTimeMillis() - w_st;
+
+ System.out.println("Write time: " + (w_time / 1000.0) + "s.");
+ }
+
+ private void addToRepository(Role role) {
+ m_repository.put(role.getName(), role);
+ }
+
+ /**
+ *
+ */
+ private void allocateMemory() {
+ m_groups = new Group[GROUP_COUNT];
+ for (int i = 0; i < m_groups.length; i++) {
+ m_groups[i] = createGroup(i+1);
+ m_groups[i].addRequiredMember(RoleRepository.USER_ANYONE);
+
+ addToRepository(m_groups[i]);
+ }
+
+ m_users = new User[USER_COUNT];
+ for (int i = 0; i < m_users.length; i++) {
+ m_users[i] = createUser(i+1);
+
+ int groupIdx = (i % m_groups.length);
+ m_groups[groupIdx].addMember(m_users[i]);
+
+ addToRepository(m_users[i]);
+ }
+ }
+
+ private Group createGroup(int idx) {
+ String name = "Group" + idx;
+
+ Group result = new GroupImpl(name);
+
+ setCredentials(result);
+ setProperties(result);
+
+ return result;
+ }
+
+ private User createUser(int idx) {
+ String name = "User" + idx;
+
+ User result = new UserImpl(name);
+
+ setCredentials(result);
+ setProperties(result);
+
+ return result;
+ }
+
+ /**
+ *
+ */
+ private void releaseMemory() {
+ m_groups = null;
+ m_users = null;
+
+ System.gc();
+ System.gc();
+ System.gc();
+ }
+
+ private void setCredentials(User user) {
+ user.getCredentials().put("name", user.getName());
+ user.getCredentials().put("password", "secret");
+ user.getCredentials().put("certificate", new byte[] { (byte) 0x55, (byte) 0xAA } );
+ }
+
+ private void setProperties(Role role) {
+ role.getProperties().put("key1", "value1");
+ role.getProperties().put("key2", "hello world".getBytes());
+ }
+}
Propchange: felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStorePerformanceTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStoreTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStoreTest.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStoreTest.java (added)
+++ felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStoreTest.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,189 @@
+/**
+ * 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.filestore;
+
+import java.io.File;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+import org.osgi.service.cm.ConfigurationException;
+
+/**
+ * Test cases for {@link RoleRepositoryFileStore}.
+ */
+public class RoleRepositoryFileStoreTest extends TestCase {
+
+ private RoleRepositoryFileStore m_store;
+
+ /**
+ * Tests that calling updated without the key "background.write.disabled" fails.
+ */
+ public void testUpdateConfigurationWithoutKeyWriteDisabledFail() throws Exception {
+ try {
+ m_store.updated(new Properties());
+ fail("ConfigurationException expected!");
+ } catch (ConfigurationException e) {
+ // Ok; expected
+ }
+ }
+
+ /**
+ * Tests that calling updated with the key "background.write.disabled" set to "false" succeeds.
+ */
+ public void testUpdateConfigurationWithKeyWriteDisabledOk() throws Exception {
+ Properties properties = new Properties();
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DISABLED, "true");
+
+ m_store.updated(properties);
+ }
+
+ /**
+ * Tests that calling updated with the key "background.write.disabled" set to a numeric value fails.
+ */
+ public void testUpdateConfigurationWithKeyWriteDisabledInvalidValueFail() throws Exception {
+ Properties properties = new Properties();
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DISABLED, Integer.valueOf(1));
+
+ try {
+ m_store.updated(properties);
+ fail("ConfigurationException expected!");
+ } catch (ConfigurationException e) {
+ // Ok; expected
+ }
+ }
+
+ /**
+ * Tests that calling updated without the key "background.write.delay.value" fails.
+ */
+ public void testUpdateConfigurationWithoutKeyWriteDelayValueFail() throws Exception {
+ Properties properties = new Properties();
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DISABLED, "false");
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DELAY_TIMEUNIT, "seconds");
+
+ try {
+ m_store.updated(properties);
+ fail("ConfigurationException expected!");
+ } catch (ConfigurationException e) {
+ // Ok; expected
+ }
+ }
+
+ /**
+ * Tests that calling updated with the key "background.write.delay.value" set to a non-numeric value fails.
+ */
+ public void testUpdateConfigurationWithKeyWriteDelayValueInvalidValueTypeFail() throws Exception {
+ Properties properties = new Properties();
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DISABLED, "false");
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DELAY_VALUE, "seconds");
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DELAY_TIMEUNIT, "seconds");
+
+ try {
+ m_store.updated(properties);
+ fail("ConfigurationException expected!");
+ } catch (ConfigurationException e) {
+ // Ok; expected
+ }
+ }
+
+ /**
+ * Tests that calling updated with the key "background.write.delay.value" set to zero fails.
+ */
+ public void testUpdateConfigurationWithKeyWriteDelayValueZeroValueFail() throws Exception {
+ Properties properties = new Properties();
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DISABLED, "false");
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DELAY_VALUE, "0");
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DELAY_TIMEUNIT, "seconds");
+
+ try {
+ m_store.updated(properties);
+ fail("ConfigurationException expected!");
+ } catch (ConfigurationException e) {
+ // Ok; expected
+ }
+ }
+
+ /**
+ * Tests that calling updated with the key "background.write.delay.value" set to a negative value fails.
+ */
+ public void testUpdateConfigurationWithKeyWriteDelayValueNegativeValueFail() throws Exception {
+ Properties properties = new Properties();
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DISABLED, "false");
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DELAY_VALUE, "-1");
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DELAY_TIMEUNIT, "seconds");
+
+ try {
+ m_store.updated(properties);
+ fail("ConfigurationException expected!");
+ } catch (ConfigurationException e) {
+ // Ok; expected
+ }
+ }
+
+ /**
+ * Tests that calling updated without the key "background.write.delay.timeunit" succeeds as it is optional.
+ */
+ public void testUpdateConfigurationWithoutKeyWriteDelayTimeUnitOk() throws Exception {
+ Properties properties = new Properties();
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DISABLED, "false");
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DELAY_VALUE, "1");
+
+ m_store.updated(properties);
+ }
+
+ /**
+ * Tests that calling updated with the key "background.write.delay.timeunit" set to an invalid value fails.
+ */
+ public void testUpdateConfigurationWithKeyWriteDelayTimeUnitInvalidValueFail() throws Exception {
+ Properties properties = new Properties();
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DISABLED, "false");
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DELAY_VALUE, "1");
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DELAY_TIMEUNIT, "1");
+
+ try {
+ m_store.updated(properties);
+ fail("ConfigurationException expected!");
+ } catch (ConfigurationException e) {
+ // Ok; expected
+ }
+ }
+
+ /**
+ * Tests that calling updated with all keys succeeds.
+ */
+ public void testUpdateConfigurationWithAllKeysOk() throws Exception {
+ Properties properties = new Properties();
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DISABLED, "false");
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DELAY_VALUE, "1");
+ properties.put(RoleRepositoryFileStore.KEY_WRITE_DELAY_TIMEUNIT, "seconds");
+
+ m_store.updated(properties);
+ }
+
+ /**
+ * Tests that calling updated with a <code>null</code>-dictionary causes the default settings to be applied.
+ */
+ public void testUpdateConfigurationWithoutPropertiesOk() throws Exception {
+ m_store.updated(null);
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ m_store = new RoleRepositoryFileStore(new File(System.getProperty("java.io.tmpdir")), false /* disable background writes */);
+ }
+}
Propchange: felix/trunk/useradmin/filestore/src/test/java/org/apache/felix/useradmin/filestore/RoleRepositoryFileStoreTest.java
------------------------------------------------------------------------------
svn:eol-style = native