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 [3/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...
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/BackendException.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/RoleFactory.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/RoleFactory.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/RoleFactory.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/RoleFactory.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,57 @@
+/**
+ * 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;
+
+
+import org.apache.felix.useradmin.impl.role.GroupImpl;
+import org.apache.felix.useradmin.impl.role.RoleImpl;
+import org.apache.felix.useradmin.impl.role.UserImpl;
+import org.osgi.service.useradmin.Role;
+
+/**
+ * Provides a factory for creating the various role instances, can be used by external
+ * implementations to create new role instances.
+ */
+public final class RoleFactory {
+
+ /**
+ * Creates a new instance of {@link RoleFactory}, not used.
+ */
+ private RoleFactory() {
+ // Nop
+ }
+
+ /**
+ * Creates a new role instance.
+ *
+ * @param type the type of the role to create;
+ * @param name the name of the role to create.
+ * @return a new {@link RoleImpl} instance denoting the requested role, never <code>null</code>.
+ */
+ public static Role createRole(int type, String name) {
+ if (type == Role.USER) {
+ UserImpl result = new UserImpl(name);
+ return result;
+ } else if (type == Role.GROUP) {
+ GroupImpl result = new GroupImpl(name);
+ return result;
+ } else {
+ RoleImpl result = new RoleImpl(name);
+ return result;
+ }
+ }
+}
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/RoleFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/RoleRepositoryStore.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/RoleRepositoryStore.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/RoleRepositoryStore.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/RoleRepositoryStore.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,94 @@
+/**
+ * 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;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+import org.osgi.service.useradmin.Role;
+
+/**
+ * Provides an abstraction to store and retrieve a role repository.
+ */
+public interface RoleRepositoryStore extends Closeable {
+
+ /**
+ * Adds a given role to this backend.
+ * <p>
+ * If the given role is already contained by this backed, this method
+ * should not do anything and return <code>false</code> to denote this.
+ * </p>
+ *
+ * @param role the role to add, cannot be <code>null</code>.
+ * @return <code>true</code> if the role was successfully added, <code>false</code> otherwise.
+ * @throws IllegalArgumentException in case the given argument was <code>null</code>;
+ * @throws IOException in case of I/O problems.
+ */
+ boolean addRole(Role role) throws IOException;
+
+ /**
+ * Closes this store, allowing implementations to free up resources, close
+ * connections, and so on.
+ *
+ * @throws IOException in case of I/O problems.
+ */
+ void close() throws IOException;
+
+ /**
+ * Returns all available roles in this backend.
+ *
+ * @return an array with all roles, never <code>null</code>, but can be empty.
+ * @throws IOException in case of I/O problems.
+ */
+ Role[] getAllRoles() throws IOException;
+
+ /**
+ * Returns a {@link Role} by its name.
+ *
+ * @param roleName the name of the role to return, cannot be <code>null</code>.
+ * @return the role with the given name, or <code>null</code> if no such role exists.
+ * @throws IllegalArgumentException in case the given argument was <code>null</code>;
+ * @throws IOException in case of I/O problems.
+ */
+ Role getRoleByName(String roleName) throws IOException;
+
+ /**
+ * Called once before any other method of this interface is being called.
+ * <p>
+ * Implementations can use this method to create a connection to the
+ * backend, or load the initial set of roles, and so on.
+ * </p>
+ *
+ * @throws IOException in case of I/O problems.
+ */
+ void initialize() throws IOException;
+
+ /**
+ * Removes a given role from this backend.
+ * <p>
+ * If the given role is not contained by this backed, this method
+ * should not do anything and return <code>false</code> to denote this.
+ * </p>
+ *
+ * @param role the role to remove, cannot be <code>null</code>.
+ * @return <code>true</code> if the role was successfully removed, <code>false</code> otherwise.
+ * @throws IllegalArgumentException in case the given argument was <code>null</code>;
+ * @throws IOException in case of I/O problems.
+ */
+ boolean removeRole(Role role) throws IOException;
+
+}
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/RoleRepositoryStore.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/AuthorizationImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/AuthorizationImpl.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/AuthorizationImpl.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/AuthorizationImpl.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,97 @@
+/**
+ * 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.impl;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+
+import org.apache.felix.useradmin.impl.role.RoleImpl;
+import org.osgi.service.useradmin.Authorization;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+
+/**
+ * Provides an implementation for {@link Authorization}.
+ */
+public class AuthorizationImpl implements Authorization {
+
+ private final String m_name;
+ private final User m_user;
+ private final RoleRepository m_roleManager;
+ private final RoleChecker m_roleChecker;
+
+ /**
+ * Creates a new {@link AuthorizationImpl} instance for the given {@link User}.
+ *
+ * @param roleManager the role manager to use for obtaining the roles, cannot be <code>null</code>.
+ */
+ public AuthorizationImpl(RoleRepository roleManager) {
+ this(null, roleManager);
+ }
+
+ /**
+ * Creates a new {@link AuthorizationImpl} instance for the given {@link User}.
+ *
+ * @param user the {@link User} to authorize, may be <code>null</code> for the anonymous user;
+ * @param roleManager the role manager to use for obtaining the roles, cannot be <code>null</code>.
+ */
+ public AuthorizationImpl(User user, RoleRepository roleManager) {
+ m_user = user;
+ m_roleManager = roleManager;
+ m_name = (user != null) ? user.getName() : null;
+ m_roleChecker = new RoleChecker();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasRole(String name) {
+ Role role = m_roleManager.getRoleByName(name);
+ if (role == null) {
+ // No role found, so it is never implied...
+ return false;
+ }
+ return m_roleChecker.isImpliedBy(role, m_user);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String[] getRoles() {
+ List result = new ArrayList();
+
+ Iterator rolesIter = m_roleManager.getRoles(null /* filter */).iterator();
+ while (rolesIter.hasNext()) {
+ RoleImpl role = (RoleImpl) rolesIter.next();
+ if (!Role.USER_ANYONE.equals(role.getName()) && m_roleChecker.isImpliedBy(role, m_user)) {
+ result.add(role.getName());
+ }
+ }
+
+ return result.isEmpty() ? null : (String[]) result.toArray(new String[result.size()]);
+ }
+}
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/AuthorizationImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/EventDispatcher.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/EventDispatcher.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/EventDispatcher.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/EventDispatcher.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,226 @@
+/**
+ * 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.impl;
+
+import java.util.Properties;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.UserAdminEvent;
+import org.osgi.service.useradmin.UserAdminListener;
+
+/**
+ * Provides an event dispatcher for delivering {@link UserAdminEvent}s asynchronously.
+ */
+public final class EventDispatcher implements Runnable {
+
+ private static final String TOPIC_BASE = "org/osgi/service/useradmin/UserAdmin/";
+
+ private final EventAdmin m_eventAdmin;
+ private final UserAdminListenerList m_listenerList;
+ private final BlockingQueue m_eventQueue;
+ private final Thread m_backgroundThread;
+
+ /**
+ * Creates a new {@link EventDispatcher} instance, and starts a background thread to deliver all events.
+ *
+ * @param eventAdmin the event admin to use, cannot be <code>null</code>;
+ * @param listenerList the list with {@link UserAdminListener}s, cannot be <code>null</code>.
+ * @throws IllegalArgumentException in case one of the given parameters was <code>null</code>.
+ */
+ public EventDispatcher(EventAdmin eventAdmin, UserAdminListenerList listenerList) {
+ if (eventAdmin == null) {
+ throw new IllegalArgumentException("EventAdmin cannot be null!");
+ }
+ if (listenerList == null) {
+ throw new IllegalArgumentException("ListenerList cannot be null!");
+ }
+
+ m_eventAdmin = eventAdmin;
+ m_listenerList = listenerList;
+ m_eventQueue = new LinkedBlockingQueue();
+
+ m_backgroundThread = new Thread(this, "UserAdmin event dispatcher");
+ }
+
+ /**
+ * Dispatches a given event for asynchronous delivery to all interested listeners,
+ * including those using the {@link EventAdmin} service.
+ * <p>
+ * This method will perform a best-effort to dispatch the event to all listeners, i.e.,
+ * there is no guarantee that the listeners will actually obtain the event, nor any
+ * notification is given in case delivery fails.
+ * </p>
+ *
+ * @param event the event to dispatch, cannot be <code>null</code>.
+ * @throws IllegalStateException in case this dispatcher is already stopped.
+ */
+ public void dispatch(UserAdminEvent event) {
+ if (!isRunning()) {
+ return;
+ }
+
+ try {
+ m_eventQueue.put(event);
+ } catch (InterruptedException e) {
+ // Restore interrupt flag...
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ /**
+ * Starts this event dispatcher, allowing it to pick up events and deliver them.
+ */
+ public void start() {
+ if (!isRunning()) {
+ m_backgroundThread.start();
+ }
+ }
+
+ /**
+ * Signals this event dispatcher to stop its work and clean up all running threads.
+ */
+ public void stop() {
+ if (!isRunning()) {
+ return;
+ }
+
+ // Add poison object to queue to let the background thread terminate...
+ m_eventQueue.add(EventDispatcher.this);
+
+ try {
+ m_backgroundThread.join();
+ } catch (InterruptedException e) {
+ // We're already stopping; so don't bother...
+ }
+ }
+
+ /**
+ * Returns whether or not the background thread is running.
+ *
+ * @return <code>true</code> if the background thread is running (alive), <code>false</code> otherwise.
+ */
+ final boolean isRunning() {
+ return m_backgroundThread.isAlive();
+ }
+
+ /**
+ * Provides the main event loop, which waits until an event is enqueued in order
+ * to deliver it to any interested listener.
+ */
+ public void run() {
+ try {
+ while (true) {
+ // Blocks until a event is dispatched...
+ Object event = m_eventQueue.take();
+
+ if (event instanceof UserAdminEvent) {
+ // Got a "normal" user admin event; lets dispatch it further...
+ deliverEventSynchronously((UserAdminEvent) event);
+ } else {
+ // Got a "poison" object; this means we must stop running...
+ return;
+ }
+ }
+ } catch (InterruptedException e) {
+ // Restore interrupt flag, and terminate thread...
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ /**
+ * Converts a given {@link UserAdminEvent} to a {@link Event} that can be
+ * dispatched through the {@link EventAdmin} service.
+ *
+ * @param event
+ * the event to convert, cannot be <code>null</code>.
+ * @return a new {@link Event} instance containing the same set of
+ * information as the given event, never <code>null</code>.
+ */
+ private Event convertEvent(UserAdminEvent event) {
+ String topic = getTopicName(event.getType());
+ Role role = event.getRole();
+ ServiceReference serviceRef = event.getServiceReference();
+
+ Properties props = new Properties();
+ props.put(EventConstants.EVENT_TOPIC, TOPIC_BASE.concat(topic));
+ props.put(EventConstants.EVENT, event);
+ props.put("role", role);
+ props.put("role.name", role.getName());
+ props.put("role.type", new Integer(role.getType()));
+ if (serviceRef != null) {
+ props.put(EventConstants.SERVICE, serviceRef);
+ Object property;
+
+ property = serviceRef.getProperty(Constants.SERVICE_ID);
+ if (property != null) {
+ props.put(EventConstants.SERVICE_ID, property);
+ }
+ property = serviceRef.getProperty(Constants.OBJECTCLASS);
+ if (property != null) {
+ props.put(EventConstants.SERVICE_OBJECTCLASS, property);
+ }
+ property = serviceRef.getProperty(Constants.SERVICE_PID);
+ if (property != null) {
+ props.put(EventConstants.SERVICE_PID, property);
+ }
+ }
+
+ return new Event(topic, props);
+ }
+
+ /**
+ * Delivers the given event synchronously to all interested listeners.
+ *
+ * @param event the event to deliver, cannot be <code>null</code>.
+ */
+ private void deliverEventSynchronously(UserAdminEvent event) {
+ // Asynchronously deliver an event to the EventAdmin service...
+ m_eventAdmin.postEvent(convertEvent(event));
+
+ // Synchronously call all UserAdminListeners to deliver the event...
+ UserAdminListener[] listeners = m_listenerList.getListeners();
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].roleChanged(event);
+ }
+ }
+
+ /**
+ * Converts a topic name for the given event-type.
+ *
+ * @param type the type of event to get the topic name for.
+ * @return a topic name, never <code>null</code>.
+ */
+ private String getTopicName(int type) {
+ switch (type) {
+ case UserAdminEvent.ROLE_CREATED:
+ return "ROLE_CREATED";
+ case UserAdminEvent.ROLE_CHANGED:
+ return "ROLE_CHANGED";
+ case UserAdminEvent.ROLE_REMOVED:
+ return "ROLE_REMOVED";
+ default:
+ return null;
+ }
+ }
+}
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/EventDispatcher.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleChangeListener.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleChangeListener.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleChangeListener.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleChangeListener.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,66 @@
+/**
+ * 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.impl;
+
+import org.osgi.service.useradmin.Role;
+
+/**
+ * Provides a callback for listening to role changes.
+ */
+public interface RoleChangeListener {
+
+ /**
+ * Called when a new role is added.
+ *
+ * @param role the role that is added.
+ */
+ void roleAdded(Role role);
+
+ /**
+ * Called when a role is removed.
+ *
+ * @param role the role that is removed.
+ */
+ void roleRemoved(Role role);
+
+ /**
+ * Called when a new property-entry is added to a role.
+ *
+ * @param role the role that changed;
+ * @param key the key of the entry;
+ * @param value the value associated to the key.
+ */
+ void propertyAdded(Role role, Object key, Object value);
+
+ /**
+ * Called when an property-entry is removed from a role.
+ *
+ * @param role the role that changed;
+ * @param key the key of the entry.
+ */
+ void propertyRemoved(Role role, Object key);
+
+ /**
+ * Called when an property-entry is changed for a role.
+ *
+ * @param role the role that changed;
+ * @param key the key of the entry;
+ * @param oldValue the old value associated to the key;
+ * @param newValue the new value associated to the key.
+ */
+ void propertyChanged(Role role, Object key, Object oldValue, Object newValue);
+}
\ No newline at end of file
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleChangeListener.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleChecker.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleChecker.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleChecker.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleChecker.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,132 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.useradmin.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+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;
+
+/**
+ * Helper class to check for implied role memberships.
+ */
+final class RoleChecker {
+
+ /**
+ * Verifies whether the given role is implied by the memberships of the given user.
+ *
+ * @param user the user to check the roles for, cannot be <code>null</code>;
+ * @param impliedRole the implied role to check for, cannot be <code>null</code>.
+ * @return <code>true</code> if the given user has the implied role, <code>false</code> otherwise.
+ */
+ public boolean isImpliedBy(Role role, Role impliedRole) {
+ if (role instanceof Group) {
+ return isGroupImpliedBy((Group) role, impliedRole, new ArrayList());
+ } else if (role instanceof User) {
+ return isUserImpliedBy((User) role, impliedRole);
+ } else {
+ return isRoleImpliedBy(role, impliedRole);
+ }
+ }
+
+ /**
+ * Verifies whether the given group is implied by the given role.
+ *
+ * @param group the group to check, cannot be <code>null</code>;
+ * @param impliedRole the implied role to check for, cannot be <code>null</code>;
+ * @param seenGroups a list of all seen groups, used for detecting cycles in groups, cannot be <code>null</code>.
+ * @return <code>true</code> if the given group has the implied role, <code>false</code> otherwise.
+ */
+ private boolean isGroupImpliedBy(Group group, Role impliedRole, List seenGroups) {
+ Role[] basicRoles = group.getMembers();
+ Role[] requiredRoles = group.getRequiredMembers();
+
+ boolean isImplied = true;
+
+ // Check whether all required roles are implied...
+ for (int i = 0; (requiredRoles != null) && isImplied && (i < requiredRoles.length); i++) {
+ Role requiredRole = requiredRoles[i];
+ if (seenGroups.contains(requiredRole)) {
+ // Found a cycle between groups; always yield false!
+ return false;
+ }
+
+ if (requiredRole instanceof Group) {
+ seenGroups.add(requiredRole);
+ isImplied = isGroupImpliedBy((Group) requiredRole, impliedRole, seenGroups);
+ } else if (requiredRole instanceof User) {
+ isImplied = isUserImpliedBy((User) requiredRole, impliedRole);
+ } else /* if (requiredRoles[i] instanceof RoleImpl) */ {
+ isImplied = isRoleImpliedBy(requiredRole, impliedRole);
+ }
+ }
+
+ // Required role is not implied by the given role; we can stop now...
+ if (!isImplied) {
+ return false;
+ }
+
+ // Ok; all required roles are implied, let's verify whether a least one basic role is implied...
+ isImplied = false;
+
+ // Check whether at least one basic role is implied...
+ for (int i = 0; (basicRoles != null) && !isImplied && (i < basicRoles.length); i++) {
+ Role basicRole = (Role) basicRoles[i];
+ if (seenGroups.contains(basicRole)) {
+ // Found a cycle between groups; always yield false!
+ return false;
+ }
+
+ if (basicRole instanceof Group) {
+ seenGroups.add(basicRole);
+ isImplied = isGroupImpliedBy((Group) basicRole, impliedRole, seenGroups);
+ } else if (basicRole instanceof UserImpl) {
+ isImplied = isUserImpliedBy((User) basicRole, impliedRole);
+ } else /* if (requiredRoles[i] instanceof RoleImpl) */ {
+ isImplied = isRoleImpliedBy(basicRole, impliedRole);
+ }
+ }
+
+ return isImplied;
+ }
+
+ /**
+ * Verifies whether the given user is implied by the given role.
+ *
+ * @param user the user to check, cannot be <code>null</code>;
+ * @param impliedRole the implied role to check for, cannot be <code>null</code>;
+ * @return <code>true</code> if the given user is implied by the given role, <code>false</code> otherwise.
+ */
+ private boolean isUserImpliedBy(User user, Role impliedRole) {
+ return Role.USER_ANYONE.equals(user.getName()) || (impliedRole != null && impliedRole.getName().equals(user.getName()));
+ }
+
+ /**
+ * Verifies whether the given role is implied by the given role.
+ *
+ * @param role the role to check, cannot be <code>null</code>;
+ * @param impliedRole the implied role to check for, cannot be <code>null</code>;
+ * @return <code>true</code> if the given role is implied by the given role, <code>false</code> otherwise.
+ */
+ private boolean isRoleImpliedBy(Role role, Role impliedRole) {
+ return Role.USER_ANYONE.equals(role.getName()) || (impliedRole != null && impliedRole.getName().equals(role.getName()));
+ }
+}
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleChecker.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleRepository.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleRepository.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleRepository.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleRepository.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,367 @@
+/**
+ * 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.impl;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.felix.useradmin.BackendException;
+import org.apache.felix.useradmin.RoleFactory;
+import org.apache.felix.useradmin.RoleRepositoryStore;
+import org.apache.felix.useradmin.impl.role.RoleImpl;
+import org.osgi.framework.Filter;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.UserAdminPermission;
+
+/**
+ * Provides a manager and entry-point for accessing {@link Role}s.
+ */
+public final class RoleRepository {
+
+ /**
+ * Hands off all obtained role change event to a local set of listeners.
+ */
+ final class RoleChangeReflector implements RoleChangeListener {
+ /**
+ * {@inheritDoc}
+ */
+ public void roleAdded(Role role) {
+ Iterator iterator = createListenerIterator();
+ while (iterator.hasNext()) {
+ ((RoleChangeListener) iterator.next()).roleAdded(role);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void roleRemoved(Role role) {
+ Iterator iterator = createListenerIterator();
+ while (iterator.hasNext()) {
+ ((RoleChangeListener) iterator.next()).roleRemoved(role);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void propertyAdded(Role role, Object key, Object value) {
+ Iterator iterator = createListenerIterator();
+ while (iterator.hasNext()) {
+ ((RoleChangeListener) iterator.next()).propertyAdded(role, key, value);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void propertyRemoved(Role role, Object key) {
+ Iterator iterator = createListenerIterator();
+ while (iterator.hasNext()) {
+ ((RoleChangeListener) iterator.next()).propertyRemoved(role, key);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void propertyChanged(Role role, Object key, Object oldValue, Object newValue) {
+ Iterator iterator = createListenerIterator();
+ while (iterator.hasNext()) {
+ ((RoleChangeListener) iterator.next()).propertyChanged(role, key, oldValue, newValue);
+ }
+ }
+ }
+
+ /** The single predefined role. */
+ public static final Role USER_ANYONE = RoleFactory.createRole(Role.ROLE, Role.USER_ANYONE);
+
+ private final RoleRepositoryStore m_store;
+ private final CopyOnWriteArrayList m_listeners;
+ private final RoleChangeReflector m_roleChangeReflector;
+
+ /**
+ * Creates a new {@link RoleRepository} instance.
+ *
+ * @param store the {@link RoleRepositoryStore} to use, cannot be <code>null</code>.
+ */
+ public RoleRepository(RoleRepositoryStore store) {
+ m_store = store;
+
+ m_listeners = new CopyOnWriteArrayList();
+ m_roleChangeReflector = new RoleChangeReflector();
+ }
+
+ /**
+ * Adds a given role to this manager.
+ *
+ * @param role the role to add, cannot be <code>null</code>. If it is already contained by this manager, this method will not do anything.
+ * @return the given role if added, <code>null</code> otherwise.
+ */
+ public Role addRole(Role role) {
+ if (role == null) {
+ throw new IllegalArgumentException("Role cannot be null!");
+ }
+ if (!(role instanceof RoleImpl)) {
+ throw new IllegalArgumentException("Invalid role type!");
+ }
+
+ checkPermissions();
+
+ try {
+ if (m_store.addRole(role)) {
+ m_roleChangeReflector.roleAdded(role);
+ return wireChangeListener(role);
+ }
+
+ return null;
+ }
+ catch (IOException e) {
+ throw new BackendException("Adding role " + role.getName() + " failed!", e);
+ }
+ }
+
+ /**
+ * Adds the given role change listener to be called for upcoming changes in roles.
+ *
+ * @param listener the listener to register, cannot be <code>null</code>.
+ * @throws IllegalArgumentException in case the given listener was <code>null</code>.
+ */
+ public void addRoleChangeListener(RoleChangeListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("RoleChangeListener cannot be null!");
+ }
+
+ m_listeners.addIfAbsent(listener);
+ }
+
+ /**
+ * Returns the by its given name.
+ *
+ * @param roleName the name of the role to return, cannot be <code>null</code>.
+ * @return the role matching the given name, or <code>null</code> if no role matched the given name.
+ */
+ public Role getRoleByName(String roleName) {
+ try {
+ return wireChangeListener(m_store.getRoleByName(roleName));
+ }
+ catch (IOException e) {
+ throw new BackendException("Failed to get role by name: " + roleName + "!", e);
+ }
+ }
+
+ /**
+ * Returns a collection with all roles matching a given filter.
+ *
+ * @param filter the filter to match the individual roles against, can be <code>null</code> if all roles should be returned.
+ * @return a list with all matching roles, can be empty, but never <code>null</code>.
+ */
+ public List getRoles(Filter filter) {
+ List matchingRoles = new ArrayList();
+
+ try {
+ Role[] roles = m_store.getAllRoles();
+ for (int i = 0; i < roles.length; i++) {
+ Role role = roles[i];
+ if (!isPredefinedRole(role) && ((filter == null) || filter.match(role.getProperties()))) {
+ matchingRoles.add(wireChangeListener(role));
+ }
+ }
+ }
+ catch (IOException e) {
+ throw new BackendException("Failed to get roles!", e);
+ }
+
+ return matchingRoles;
+ }
+
+ /**
+ * Returns a collection with all roles matching a given key-value pair.
+ *
+ * @param key the key to search for;
+ * @param value the value to search for.
+ * @return a list with all matching roles, can be empty, but never <code>null</code>.
+ */
+ public List getRoles(String key, String value) {
+ if (key == null) {
+ throw new IllegalArgumentException("Key cannot be null!");
+ }
+ if (value == null) {
+ throw new IllegalArgumentException("Value cannot be null!");
+ }
+
+ List matchingRoles = new ArrayList();
+
+ try {
+ Role[] roles = m_store.getAllRoles();
+ for (int i = 0; i < roles.length; i++) {
+ Role role = roles[i];
+ Dictionary dict = role.getProperties();
+ if (!isPredefinedRole(role) && value.equals(dict.get(key))) {
+ matchingRoles.add(wireChangeListener(role));
+ }
+ }
+ }
+ catch (IOException e) {
+ throw new BackendException("Failed to get roles!", e);
+ }
+
+ return matchingRoles;
+ }
+
+ /**
+ * Removes a given role from this manager.
+ *
+ * @param role the role to remove, cannot be <code>null</code>.
+ * @return <code>true</code> if the role was removed (i.e., it was managed by this manager), or <code>false</code> if it was not found.
+ */
+ public boolean removeRole(Role role) {
+ if (role == null) {
+ throw new IllegalArgumentException("Role cannot be null!");
+ }
+ if (!(role instanceof RoleImpl)) {
+ throw new IllegalArgumentException("Invalid role type!");
+ }
+
+ checkPermissions();
+
+ // Cannot remove predefined roles...
+ if (isPredefinedRole(role)) {
+ return false;
+ }
+
+ try {
+ if (m_store.removeRole(role)) {
+ unwireChangeListener(role);
+ m_roleChangeReflector.roleRemoved(role);
+
+ return true;
+ }
+
+ return false;
+ }
+ catch (IOException e) {
+ throw new BackendException("Failed to remove role " + role.getName() + "!", e);
+ }
+ }
+
+ /**
+ * Removes the given role change listener from be called for changes in roles.
+ *
+ * @param listener the listener to unregister, cannot be <code>null</code>.
+ * @throws IllegalArgumentException in case the given listener was <code>null</code>.
+ */
+ public void removeRoleChangeListener(RoleChangeListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("RoleChangeListener cannot be null!");
+ }
+
+ m_listeners.remove(listener);
+ }
+
+ /**
+ * Starts this repository.
+ */
+ public void start() {
+ try {
+ // The sole predefined role we've got...
+ m_store.addRole(USER_ANYONE);
+
+ m_store.initialize();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Stops this repository, allowing it to clean up.
+ */
+ public void stop() {
+ try {
+ m_store.close();
+ }
+ catch (IOException e) {
+ // Ignore; nothing we can do about this here...
+ }
+ }
+
+ /**
+ * Creates a new iterator for iterating over all listeners.
+ *
+ * @return a new {@link Iterator} instance, never <code>null</code>.
+ */
+ final Iterator createListenerIterator() {
+ return m_listeners.iterator();
+ }
+
+ /**
+ * Verifies whether the caller has the right permissions to add or remove roles.
+ *
+ * @throws SecurityException in case the caller has not the right permissions to perform the action.
+ */
+ private void checkPermissions() throws SecurityException {
+ SecurityManager securityManager = System.getSecurityManager();
+ if (securityManager != null) {
+ securityManager.checkPermission(new UserAdminPermission(UserAdminPermission.ADMIN, null));
+ }
+ }
+
+ /**
+ * Returns whether or not the given role is a predefined role.
+ * <p>
+ * Currently, there's only a single predefined role: {@link Role#USER_ANYONE}.
+ * </p>
+ *
+ * @param role the role to check, may be <code>null</code>.
+ * @return <code>true</code> if the given role is predefined, <code>false</code> otherwise.
+ */
+ private boolean isPredefinedRole(Role role) {
+ return Role.USER_ANYONE.equals(role.getName());
+ }
+
+ /**
+ * Wires the given role to this repository so it can listen for its changes.
+ *
+ * @param role the role to listen for its changes, cannot be <code>null</code>.
+ * @return the given role.
+ * @throws IllegalArgumentException in case the given object was not a {@link RoleImpl} instance.
+ */
+ private Role wireChangeListener(Object role) {
+ RoleImpl result = (RoleImpl) role;
+ if (result != null) {
+ result.setRoleChangeListener(m_roleChangeReflector);
+ }
+ return result;
+ }
+
+ /**
+ * Unwires the given role to this repository so it no longer listens for its changes.
+ *
+ * @param role the role to unwire, cannot be <code>null</code>.
+ * @throws IllegalArgumentException in case the given object was not a {@link RoleImpl} instance.
+ */
+ private void unwireChangeListener(Object role) {
+ RoleImpl result = (RoleImpl) role;
+ result.setRoleChangeListener(null);
+ }
+}
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/RoleRepository.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/UserAdminImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/UserAdminImpl.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/UserAdminImpl.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/UserAdminImpl.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,210 @@
+/**
+ * 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.impl;
+
+import java.util.List;
+
+import org.apache.felix.useradmin.RoleFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.useradmin.Authorization;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+import org.osgi.service.useradmin.UserAdminEvent;
+
+/**
+ * Provides the implementation for {@link UserAdmin}.
+ */
+public class UserAdminImpl implements ServiceFactory, UserAdmin, RoleChangeListener {
+
+ private final RoleRepository m_roleRepository;
+ private final EventDispatcher m_eventDispatcher;
+
+ private volatile ServiceReference m_serviceRef;
+
+ /**
+ * Creates a new {@link UserAdminImpl} implementation.
+ *
+ * @param roleRepository the repository with roles to use for this service;
+ * @param eventDispatcher the event dispatcher to use for this service.
+ *
+ * @throws IllegalArgumentException in case one of the given parameters was <code>null</code>.
+ */
+ public UserAdminImpl(RoleRepository roleRepository, EventDispatcher eventDispatcher) {
+ if (roleRepository == null) {
+ throw new IllegalArgumentException("RoleRepository cannot be null!");
+ }
+ if (eventDispatcher == null) {
+ throw new IllegalArgumentException("EventDispatcher cannot be null!");
+ }
+
+ m_roleRepository = roleRepository;
+ m_eventDispatcher = eventDispatcher;
+
+ m_roleRepository.addRoleChangeListener(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Role createRole(String name, int type) {
+ if ((type != Role.USER) && (type != Role.GROUP)) {
+ throw new IllegalArgumentException("Invalid type, must by either Role.USER or Role.GROUP!");
+ }
+ if (name == null) {
+ throw new IllegalArgumentException("Invalid name, must be non-null and non-empty!");
+ }
+
+ return m_roleRepository.addRole(RoleFactory.createRole(type, name));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Authorization getAuthorization(User user) {
+ return new AuthorizationImpl(user, m_roleRepository);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Role getRole(String name) {
+ return m_roleRepository.getRoleByName(name);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Role[] getRoles(String filter) throws InvalidSyntaxException {
+ List roles = m_roleRepository.getRoles(createFilter(filter));
+ if (roles.isEmpty()) {
+ return null;
+ }
+ return (Role[]) roles.toArray(new Role[roles.size()]);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Overridden in order to get hold of our service reference.</p>
+ */
+ public Object getService(Bundle bundle, ServiceRegistration registration) {
+ m_serviceRef = registration.getReference();
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public User getUser(String key, String value) {
+ User result = null;
+ List roles = m_roleRepository.getRoles(key, value);
+ if (roles.size() == 1) {
+ Role foundRole = (Role) roles.get(0);
+ if (foundRole.getType() == Role.USER) {
+ result = (User) foundRole;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void propertyAdded(Role role, Object key, Object value) {
+ m_eventDispatcher.dispatch(createUserAdminEvent(UserAdminEvent.ROLE_CHANGED, role));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void propertyChanged(Role role, Object key, Object oldValue, Object newValue) {
+ m_eventDispatcher.dispatch(createUserAdminEvent(UserAdminEvent.ROLE_CHANGED, role));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void propertyRemoved(Role role, Object key) {
+ m_eventDispatcher.dispatch(createUserAdminEvent(UserAdminEvent.ROLE_CHANGED, role));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean removeRole(String name) {
+ Role role = getRole(name);
+ if (role == null) {
+ return false;
+ }
+
+ return m_roleRepository.removeRole(role);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void roleAdded(Role role) {
+ m_eventDispatcher.dispatch(createUserAdminEvent(UserAdminEvent.ROLE_CREATED, role));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void roleRemoved(Role role) {
+ m_eventDispatcher.dispatch(createUserAdminEvent(UserAdminEvent.ROLE_REMOVED, role));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+ // Nop; we leave the service as-is...
+ }
+
+ /**
+ * Creates a {@link Filter} instance for the given OSGi/LDAP filter.
+ *
+ * @param filter the filter to convert to a {@link Filter} instance.
+ * @return a {@link Filter} instance corresponding to the given filter string, never <code>null</code>.
+ * @throws InvalidSyntaxException in case the given filter was invalid.
+ */
+ protected Filter createFilter(String filter) throws InvalidSyntaxException {
+ if (filter == null || "".equals(filter.trim())) {
+ return null;
+ }
+ return FrameworkUtil.createFilter(filter);
+ }
+
+ /**
+ * Creates a new {@link UserAdminEvent} instance for the given type and role.
+ *
+ * @param type the type of event to create;
+ * @param role the role to create the event for.
+ * @return a new {@link UserAdminEvent} instance, never <code>null</code>.
+ */
+ private UserAdminEvent createUserAdminEvent(int type, Role role) {
+ return new UserAdminEvent(m_serviceRef, type, role);
+ }
+}
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/UserAdminImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/UserAdminListenerList.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/UserAdminListenerList.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/UserAdminListenerList.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/UserAdminListenerList.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,33 @@
+/**
+ * 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.impl;
+
+import org.osgi.service.useradmin.UserAdminListener;
+
+/**
+ * Provides an abstraction for a list of {@link UserAdminListener}s.
+ */
+public interface UserAdminListenerList {
+
+ /**
+ * Returns all current listeners.
+ *
+ * @return an array of {@link UserAdminListener}s, never <code>null</code>,
+ * but can be an empty array.
+ */
+ UserAdminListener[] getListeners();
+}
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/UserAdminListenerList.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/GroupImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/GroupImpl.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/GroupImpl.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/GroupImpl.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,181 @@
+/**
+ * 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.impl.role;
+
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.UserAdminPermission;
+
+/**
+ * Provides an implementation of {@link Group}.
+ */
+public class GroupImpl extends UserImpl implements Group {
+
+ private static final String BASIC_MEMBER = "basicMember";
+ private static final String REQUIRED_MEMBER = "requiredMember";
+
+ private final Object m_lock = new Object();
+
+ private final Map m_members;
+ private final Map m_requiredMembers;
+
+ /**
+ * Creates a new {@link GroupImpl} instance of type {@link Role#GROUP}.
+ *
+ * @param name the name of this group role, cannot be <code>null</code> or empty.
+ */
+ public GroupImpl(String name) {
+ super(Role.GROUP, name);
+
+ m_members = new HashMap();
+ m_requiredMembers = new HashMap();
+ }
+
+ /**
+ * Creates a new {@link GroupImpl} instance of type {@link Role#GROUP}.
+ *
+ * @param name the name of this group role, cannot be <code>null</code> or empty.
+ */
+ public GroupImpl(String name, Dictionary properties, Dictionary credentials) {
+ super(Role.GROUP, name, properties, credentials);
+
+ m_members = new HashMap();
+ m_requiredMembers = new HashMap();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean addMember(Role role) {
+ checkPermissions();
+
+ Object result;
+ synchronized (m_lock) {
+ if (m_members.containsKey(role.getName()) || m_requiredMembers.containsKey(role.getName())) {
+ return false;
+ }
+ result = m_members.put(role.getName(), role);
+ }
+
+ if (result == null) {
+ // Notify our (optional) listener...
+ entryAdded(BASIC_MEMBER, role);
+ }
+
+ return (result == null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean addRequiredMember(Role role) {
+ checkPermissions();
+
+ Object result;
+ synchronized (m_lock) {
+ if (m_requiredMembers.containsKey(role.getName()) || m_members.containsKey(role.getName())) {
+ return false;
+ }
+ result = m_requiredMembers.put(role.getName(), role);
+ }
+
+ if (result == null) {
+ // Notify our (optional) listener...
+ entryAdded(REQUIRED_MEMBER, role);
+ }
+
+ return (result == null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Role[] getMembers() {
+ Role[] roles;
+ synchronized (m_lock) {
+ Collection values = m_members.values();
+ roles = (Role[]) values.toArray(new Role[values.size()]);
+ }
+
+ return (roles.length == 0) ? null : roles;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Role[] getRequiredMembers() {
+ Role[] roles;
+ synchronized (m_lock) {
+ Collection values = m_requiredMembers.values();
+ roles = (Role[]) values.toArray(new Role[values.size()]);
+ }
+
+ return (roles.length == 0) ? null : roles;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean removeMember(Role role) {
+ checkPermissions();
+
+ String key = null;
+ Object result = null;
+
+ synchronized (m_lock) {
+ if (m_requiredMembers.containsKey(role.getName())) {
+ key = REQUIRED_MEMBER;
+ result = m_requiredMembers.remove(role.getName());
+ }
+ else if (m_members.containsKey(role.getName())) {
+ key = BASIC_MEMBER;
+ result = m_members.remove(role.getName());
+ }
+ }
+
+ if (result != null) {
+ // Notify our (optional) listener...
+ entryRemoved(key);
+ }
+
+ return result != null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String toString() {
+ return "Group(" + getName() + "): R{" + m_requiredMembers + "}, B{" + m_members + "}";
+ }
+
+ /**
+ * Verifies whether the caller has the right permissions to get or change the given key.
+ *
+ * @throws SecurityException in case the caller has not the right permissions to perform the action.
+ */
+ private void checkPermissions() throws SecurityException {
+ SecurityManager securityManager = System.getSecurityManager();
+ if (securityManager != null) {
+ securityManager.checkPermission(new UserAdminPermission(UserAdminPermission.ADMIN, null));
+ }
+ }
+}
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/GroupImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/ObservableDictionary.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/ObservableDictionary.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/ObservableDictionary.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/ObservableDictionary.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,311 @@
+/**
+ * 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.impl.role;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.osgi.service.useradmin.UserAdminPermission;
+
+/**
+ * Provides an observable {@link Dictionary} implementation that emits change
+ * events for the put and remove operations aside checking for security
+ * permissions for all accessor methods.
+ */
+class ObservableDictionary extends Dictionary implements Serializable {
+
+ private static final long serialVersionUID = 9223154895541178975L;
+
+ /**
+ * Provides a listener for changes to a {@link ObservableDictionary}.
+ */
+ static interface DictionaryChangeListener {
+
+ /**
+ * Called when a new entry is added.
+ *
+ * @param key the key of the entry;
+ * @param value the value associated to the key.
+ */
+ void entryAdded(Object key, Object value);
+
+ /**
+ * Called when an entry is changed.
+ *
+ * @param key the key of the entry;
+ * @param oldValue the old value associated to the key;
+ * @param newValue the new value associated to the key.
+ */
+ void entryChanged(Object key, Object oldValue, Object newValue);
+
+ /**
+ * Called when an entry is removed.
+ *
+ * @param key the key of the entry.
+ */
+ void entryRemoved(Object key);
+ }
+
+ /**
+ * Provides a wrapper to convert an {@link Iterator} to an {@link Enumeration} implementation.
+ */
+ static final class IteratorEnumeration implements Enumeration {
+
+ private final Iterator m_iterator;
+
+ /**
+ * Creates a new {@link IteratorEnumeration}.
+ *
+ * @param iterator the {@link Iterator} to convert to a {@link Enumeration}, cannot be <code>null</code>.
+ */
+ public IteratorEnumeration(Iterator iterator) {
+ m_iterator = iterator;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasMoreElements() {
+ return m_iterator.hasNext();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object nextElement() {
+ return m_iterator.next();
+ }
+ }
+
+ /**
+ * 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 static ConcurrentMap convertToMap(Dictionary dictionary) {
+ ConcurrentMap result = new ConcurrentHashMap();
+ 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;
+ }
+
+ private final ConcurrentMap m_properties;
+ private final String m_getAction;
+ private final String m_changeAction;
+
+ private transient volatile DictionaryChangeListener m_listener;
+
+ /**
+ * Creates a new, empty, {@link ObservableDictionary} instance.
+ */
+ public ObservableDictionary(String getAction, String changeAction) {
+ m_getAction = getAction;
+ m_changeAction = changeAction;
+ m_properties = new ConcurrentHashMap();
+ }
+
+ /**
+ * Creates a new {@link ObservableDictionary} instance with the given dictionary as defaults.
+ *
+ * @param dictionary the defaults to set for this properties, cannot be <code>null</code>.
+ */
+ public ObservableDictionary(String getAction, String changeAction, Dictionary dictionary) {
+ if (dictionary == null) {
+ throw new IllegalArgumentException("Dictionary cannot be null!");
+ }
+ m_getAction = getAction;
+ m_changeAction = changeAction;
+ m_properties = convertToMap(dictionary);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Enumeration elements() {
+ Collection values = m_properties.values();
+ return new IteratorEnumeration(values.iterator());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object == null || (getClass() != object.getClass())) {
+ return false;
+ }
+
+ ObservableDictionary other = (ObservableDictionary) object;
+ if (m_properties == null) {
+ if (other.m_properties != null) {
+ return false;
+ }
+ } else if (!m_properties.equals(other.m_properties)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object get(Object key) {
+ if (key == null) {
+ throw new IllegalArgumentException("Key cannot be null!");
+ }
+
+ if (m_getAction != null) {
+ checkPermissions(getAsPermissionKey(key), m_getAction);
+ }
+
+ return m_properties.get(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ final int prime = 37;
+ int result = 1;
+ result = prime * result + ((m_properties == null) ? 0 : m_properties.hashCode());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isEmpty() {
+ return m_properties.isEmpty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Enumeration keys() {
+ Collection keys = m_properties.keySet();
+ return new IteratorEnumeration(keys.iterator());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object put(Object key, Object value) {
+ if (key == null) {
+ throw new IllegalArgumentException("Key cannot be null!");
+ }
+ if (value == null) {
+ throw new IllegalArgumentException("Value cannot be null!");
+ }
+
+ if (m_changeAction != null) {
+ checkPermissions(getAsPermissionKey(key), m_changeAction);
+ }
+
+ Object oldValue = m_properties.put(key, value);
+
+ final DictionaryChangeListener listener = m_listener;
+ if (listener != null) {
+ if (oldValue == null) {
+ listener.entryAdded(key, value);
+ } else {
+ listener.entryChanged(key, oldValue, value);
+ }
+ }
+
+ return oldValue;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object remove(Object key) {
+ if (key == null) {
+ throw new IllegalArgumentException("Key cannot be null!");
+ }
+
+ if (m_changeAction != null) {
+ checkPermissions(getAsPermissionKey(key), m_changeAction);
+ }
+
+ Object oldValue = m_properties.remove(key);
+ final DictionaryChangeListener listener = m_listener;
+ if (listener != null) {
+ listener.entryRemoved(key);
+ }
+
+ return oldValue;
+ }
+
+ /**
+ * Sets a new {@link DictionaryChangeListener} to observe changes to this dictionary.
+ *
+ * @param listener the listener to add, can be <code>null</code> to stop listening for changes.
+ */
+ public void setDictionaryChangeListener(DictionaryChangeListener listener) {
+ m_listener = listener;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int size() {
+ return m_properties.size();
+ }
+
+ /**
+ * @param key
+ * @return
+ */
+ protected String getAsPermissionKey(Object key) {
+ String k = UserAdminPermission.ADMIN;
+ if (key instanceof String) {
+ k = (String) key;
+ }
+ return k;
+ }
+
+ /**
+ * Verifies whether the caller has the right permissions to get or change the given key.
+ *
+ * @param key the name of the property that is to be accessed or changed, cannot be <code>null</code>;
+ * @param action the action name to perform, cannot be <code>null</code>.
+ * @throws SecurityException in case the caller has not the right permissions to perform the action.
+ */
+ private void checkPermissions(String key, String action) throws SecurityException {
+ SecurityManager securityManager = System.getSecurityManager();
+ if (securityManager != null) {
+ securityManager.checkPermission(new UserAdminPermission(key, action));
+ }
+ }
+}
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/ObservableDictionary.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/ObservableProperties.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/ObservableProperties.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/ObservableProperties.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/ObservableProperties.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,80 @@
+/**
+ * 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.impl.role;
+
+import java.util.Dictionary;
+
+/**
+ * Provides an stricter variant of the {@link ObservableDictionary} that only
+ * permits string keys and values of either String or byte[].
+ */
+final class ObservableProperties extends ObservableDictionary {
+
+ private static final long serialVersionUID = -2513082903921734796L;
+
+ /**
+ * Creates a new, empty, {@link ObservableProperties} instance.
+ */
+ public ObservableProperties(String getAction, String changeAction) {
+ super(getAction, changeAction);
+ }
+
+ /**
+ * Creates a new {@link ObservableProperties} instance with the given dictionary as defaults.
+ *
+ * @param dictionary the defaults to set for this properties, cannot be <code>null</code>.
+ */
+ public ObservableProperties(String getAction, String changeAction, Dictionary dictionary) {
+ super(getAction, changeAction, dictionary);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object get(Object key) {
+ if (!(key instanceof String)) {
+ throw new IllegalArgumentException("Key must be of type String!");
+ }
+
+ return super.get(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object put(Object key, Object value) {
+ if (!(key instanceof String)) {
+ throw new IllegalArgumentException("Key must be of type String!");
+ }
+ if (!(value instanceof String) && !(value instanceof byte[])) {
+ throw new IllegalArgumentException("Value must be of type String or byte[]!");
+ }
+
+ return super.put(key, value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object remove(Object key) {
+ if (!(key instanceof String)) {
+ throw new IllegalArgumentException("Key must be of type String!");
+ }
+
+ return super.remove(key);
+ }
+}
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/ObservableProperties.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/RoleImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/RoleImpl.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/RoleImpl.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/RoleImpl.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,185 @@
+/**
+ * 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.impl.role;
+
+import java.util.Dictionary;
+
+
+import org.apache.felix.useradmin.impl.RoleChangeListener;
+import org.apache.felix.useradmin.impl.role.ObservableDictionary.DictionaryChangeListener;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.UserAdminPermission;
+
+/**
+ * Provides an implementation of {@link Role}.
+ */
+public class RoleImpl implements Role, DictionaryChangeListener {
+
+ private final ObservableProperties m_properties;
+ private final String m_name;
+ private final int m_type;
+
+ private volatile RoleChangeListener m_listener;
+
+ /**
+ * Creates a new {@link RoleImpl} instance of type {@link Role#ROLE} and a given name.
+ *
+ * @param name the name of this role, cannot be <code>null</code> or empty.
+ */
+ public RoleImpl(String name) {
+ this(Role.ROLE, name);
+ }
+
+ /**
+ * Creates a new {@link RoleImpl} instance with a given type and name.
+ *
+ * @param type the type of this role, should be {@link Role#ROLE}, {@link Role#USER} or {@link Role#GROUP};
+ * @param name the name of this role, cannot be <code>null</code> or empty.
+ */
+ protected RoleImpl(int type, String name) {
+ if (name == null || "".equals(name.trim())) {
+ throw new IllegalArgumentException("Name cannot be null or empty!");
+ }
+ m_type = type;
+ m_name = name;
+ m_properties = new ObservableProperties(null, UserAdminPermission.CHANGE_PROPERTY);
+ m_properties.setDictionaryChangeListener(this);
+ }
+
+ /**
+ * Creates a new {@link RoleImpl} instance with a given type, name and properties.
+ *
+ * @param type the type of this role, should be {@link Role#ROLE}, {@link Role#USER} or {@link Role#GROUP};
+ * @param name the name of this role, cannot be <code>null</code> or empty;
+ * @param properties the initial properties of this role, cannot be <code>null</code>.
+ */
+ protected RoleImpl(int type, String name, Dictionary properties) {
+ if (name == null || "".equals(name.trim())) {
+ throw new IllegalArgumentException("Name cannot be null or empty!");
+ }
+ m_type = type;
+ m_name = name;
+ m_properties = new ObservableProperties(null, UserAdminPermission.CHANGE_PROPERTY, properties);
+ m_properties.setDictionaryChangeListener(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final void entryAdded(Object key, Object value) {
+ RoleChangeListener listener = m_listener;
+ if (listener != null) {
+ listener.propertyAdded(this, key, value);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final void entryRemoved(Object key) {
+ RoleChangeListener listener = m_listener;
+ if (listener != null) {
+ listener.propertyRemoved(this, key);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final void entryChanged(Object key, Object oldValue, Object newValue) {
+ RoleChangeListener listener = m_listener;
+ if (listener != null) {
+ listener.propertyChanged(this, key, oldValue, newValue);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if ((obj == null) || (getClass() != obj.getClass())) {
+ return false;
+ }
+
+ RoleImpl other = (RoleImpl) obj;
+ if (m_name == null) {
+ if (other.m_name != null) {
+ return false;
+ }
+ } else if (!m_name.equals(other.m_name)) {
+ return false;
+ }
+
+ if (m_type != other.m_type) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Dictionary getProperties() {
+ return m_properties;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getType() {
+ return m_type;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((m_name == null) ? 0 : m_name.hashCode());
+ result = prime * result + m_type;
+ return result;
+ }
+
+ /**
+ * Sets the {@link RoleChangeListener} for this role implementation.
+ *
+ * @param listener the listener to set, may be <code>null</code> to stop listening.
+ */
+ public void setRoleChangeListener(RoleChangeListener listener) {
+ m_listener = listener;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String toString() {
+ return "Role(" + getName() + ")";
+ }
+}
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/RoleImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/UserImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/UserImpl.java?rev=1391437&view=auto
==============================================================================
--- felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/UserImpl.java (added)
+++ felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/UserImpl.java Fri Sep 28 12:58:59 2012
@@ -0,0 +1,119 @@
+/**
+ * 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.impl.role;
+
+import java.util.Arrays;
+import java.util.Dictionary;
+
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdminPermission;
+
+/**
+ * Provides an implementation of {@link User}.
+ */
+public class UserImpl extends RoleImpl implements User {
+
+ private final ObservableProperties m_credentials;
+
+ /**
+ * Creates a new {@link UserImpl} instance with type {@link Role#USER}.
+ *
+ * @param name the name of this user role, cannot be <code>null</code> or empty.
+ */
+ public UserImpl(String name) {
+ this(Role.USER, name);
+ }
+
+ /**
+ * Creates a new {@link UserImpl} instance with a given type.
+ *
+ * @param type the type of this role;
+ * @param name the name of this role, cannot be <code>null</code> or empty.
+ */
+ protected UserImpl(int type, String name) {
+ super(type, name);
+
+ m_credentials = new ObservableProperties(UserAdminPermission.GET_CREDENTIAL, UserAdminPermission.CHANGE_CREDENTIAL);
+ m_credentials.setDictionaryChangeListener(this);
+ }
+
+ /**
+ * Creates a new {@link UserImpl} instance with type {@link Role#USER}.
+ *
+ * @param name the name of this user role, cannot be <code>null</code> or empty.
+ */
+ protected UserImpl(int type, String name, Dictionary properties, Dictionary credentials) {
+ super(type, name, properties);
+
+ m_credentials = new ObservableProperties(UserAdminPermission.GET_CREDENTIAL, UserAdminPermission.CHANGE_CREDENTIAL, credentials);
+ m_credentials.setDictionaryChangeListener(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Dictionary getCredentials() {
+ return m_credentials;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasCredential(String key, Object value) {
+ // Will throw a SecurityException if we're not allowed to do this!
+ Object result = m_credentials.get(key);
+
+ // Be a bit more lenient with the various results we can get...
+ if (result instanceof String) {
+ String s1 = (String) result;
+ String s2;
+ if (value instanceof byte[]) {
+ s2 = new String((byte[]) value);
+ } else if (value instanceof String) {
+ s2 = (String) value;
+ } else {
+ // Not a string or a byte-array!
+ return false;
+ }
+
+ return s1.equals(s2);
+ } else if (result instanceof byte[]) {
+ byte[] b1 = (byte[]) result;
+ byte[] b2;
+ if (value instanceof byte[]) {
+ b2 = (byte[]) value;
+ } else if (value instanceof String) {
+ b2 = ((String) value).getBytes();
+ } else {
+ // Not a string or a byte-array!
+ return false;
+ }
+
+ return Arrays.equals(b1, b2);
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String toString() {
+ return "User(" + getName() + ")";
+ }
+}
Propchange: felix/trunk/useradmin/useradmin/src/main/java/org/apache/felix/useradmin/impl/role/UserImpl.java
------------------------------------------------------------------------------
svn:eol-style = native