Author: ivol37 at gmail.com
Date: Fri Dec 17 14:15:20 2010
New Revision: 510
Log:
[AMDATU-226] Moved the UserAdmin REST interface to its own bundle
Added:
trunk/amdatu-authorization/useradmin-rest/
trunk/amdatu-authorization/useradmin-rest/pom.xml
trunk/amdatu-authorization/useradmin-rest/src/
trunk/amdatu-authorization/useradmin-rest/src/main/
trunk/amdatu-authorization/useradmin-rest/src/main/java/
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/osgi/
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/osgi/Activator.java
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/GroupsResource.java
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/ResourceBase.java
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/UsersResource.java
trunk/amdatu-web/rest-jaxrs/src/main/java/org/amdatu/web/rest/jaxrs/RESTService.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/RESTTestBase.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/UserAdminRESTTest.java
Removed:
trunk/amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/DummyResourceInterface.java
trunk/amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/rest/GroupsResource.java
trunk/amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/rest/ResourceBase.java
trunk/amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/rest/UsersResource.java
Modified:
trunk/amdatu-authorization/pom.xml
trunk/amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/osgi/Activator.java
trunk/amdatu-release/pom.xml
trunk/amdatu-web/rest-jaxrs/pom.xml
trunk/integration-tests/pom.xml
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
trunk/src/main/resources/conf/felix-config.properties
Modified: trunk/amdatu-authorization/pom.xml
==============================================================================
--- trunk/amdatu-authorization/pom.xml (original)
+++ trunk/amdatu-authorization/pom.xml Fri Dec 17 14:15:20 2010
@@ -48,6 +48,7 @@
<modules>
<module>login-gadget</module>
<module>login-service</module>
+ <module>useradmin-rest</module>
</modules>
</project>
\ No newline at end of file
Added: trunk/amdatu-authorization/useradmin-rest/pom.xml
==============================================================================
--- (empty file)
+++ trunk/amdatu-authorization/useradmin-rest/pom.xml Fri Dec 17 14:15:20 2010
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.amdatu</groupId>
+ <artifactId>org.amdatu.authorization</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.amdatu.authorization.useradmin</groupId>
+ <artifactId>rest</artifactId>
+ <packaging>bundle</packaging>
+ <name>Amdatu Authorization - User Admin REST API</name>
+ <description>Provides a REST API on UserAdmin</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.amdatu.web</groupId>
+ <artifactId>httpcontext</artifactId>
+ <scope>provided</scope>
+ <type>bundle</type>
+ </dependency>
+ <dependency>
+ <groupId>org.amdatu.web.rest</groupId>
+ <artifactId>jaxrs</artifactId>
+ <version>${platform.version}</version>
+ <scope>provided</scope>
+ <type>bundle</type>
+ </dependency>
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20090211</version>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+
<Bundle-Activator>org.amdatu.authorization.useradmin.rest.osgi.Activator</Bundle-Activator>
+ <Bundle-SymbolicName>
org.amdatu.authorization.useradmin.rest</Bundle-SymbolicName>
+ <Embed-Dependency>*;scope=compile</Embed-Dependency>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
Added:
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/osgi/Activator.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/osgi/Activator.java
Fri Dec 17 14:15:20 2010
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.authorization.useradmin.rest.osgi;
+
+import org.amdatu.authorization.useradmin.rest.service.GroupsResource;
+import org.amdatu.authorization.useradmin.rest.service.UsersResource;
+import org.amdatu.web.rest.jaxrs.RESTService;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * This is the activator for the UserAdmin REST API bundle
+ *
+ * @author ivol
+ */
+public class Activator extends DependencyActivatorBase {
+
+ public void init(BundleContext context, DependencyManager manager) throws
Exception {
+ // Create the users resource service and register it as REST service
+ manager.add(createComponent()
+ .setInterface(RESTService.class.getName(), null)
+ .setImplementation(UsersResource.class)
+
.add(createServiceDependency().setService(LogService.class).setRequired(true))
+
.add(createServiceDependency().setService(UserAdmin.class).setRequired(true)));
+
+ // Create the groups resource service and register it as REST service
+ manager.add(createComponent()
+ .setInterface(RESTService.class.getName(), null)
+ .setImplementation(GroupsResource.class)
+
.add(createServiceDependency().setService(LogService.class).setRequired(true))
+
.add(createServiceDependency().setService(UserAdmin.class).setRequired(true)));
+ }
+
+ public void destroy(BundleContext context, DependencyManager manager)
throws Exception {
+ }
+}
Added:
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/GroupsResource.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/GroupsResource.java
Fri Dec 17 14:15:20 2010
@@ -0,0 +1,280 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.authorization.useradmin.rest.service;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.CacheControl;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.amdatu.web.rest.jaxrs.RESTService;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+
+/**
+ * REST service for managing Groups based on the UserAdmin OSGi specification
(see chapter 107 of the Enterprise OSGi
+ * spec version 4.1). This REST service provides the following methods:
<code><pre>
+ * GET /rest/services/groups/groups -> returns all users
+ * GET /rest/services/groups/groups/{name} -> Returns the group with the
specified name
+ * PUT /rest/services/groups/groups/{name} -> Creates a group with the
specified name
+ * PUT /rest/services/groups/groups/{name}/basicmembers/{memberName} -> Adds a
member to the group
+ * PUT /rest/services/groups/groups/{name}/requiredmembers/{memberName} ->
Adds a required member to the group
+ * DELETE /rest/services/groups/groups/{name} -> Deletes the group with the
specified name
+ * DELETE /rest/services/groups/groups/{name}/members/{memberName} -> Deletes
a member from group
+ * </pre></code>
+ * @author ivol
+ */
+ at Path("groups")
+public class GroupsResource extends ResourceBase implements RESTService {
+ // Disable HTTP caching in this REST interface
+ private static CacheControl m_cacheControl;
+ static {
+ m_cacheControl = new CacheControl();
+ m_cacheControl.setNoCache(true);
+ }
+
+ /**
+ * This method can be used to check the availability of the Groups
management service.
+ * @return The text "UserAdmin Groups management service online"
+ */
+ @GET
+ @Produces({MediaType.TEXT_PLAIN})
+ public String status() {
+ return "UserAdmin Groups management service online";
+ }
+
+ /**
+ * Returns all groups that match the specified filter options. This method
can be invoked by making the following
+ * REST call:<code><pre>
+ * GET
/rest/services/groups/groups?filter={filter}&sortOrder={sortOrder}&startIndex={startIndex}&maxResults={maxResults}
+ * </pre></code> For available path and query parameters, see below.
+ * @param filter Filter that the name of the group must match. A group
name is considered to match the specified
+ * filter if the filter equals the group name or the filter is
a substring of the group name.
+ * @param sortOrder 'ascending' to return results in ascending order or
'descending' to return results in descending
+ * order.
+ * @param startIndex The index of the first result to return (default is
1).
+ * @param maxResults The maximum amount of results to return (default is
50).
+ * @return a 400 response with this JSON string containing the results in
case the call was successful: <code><pre>
+ * {
+ * "totalCount":1, => Total amount of available results for
this query, independent of the values of startIndex and maxResults
+ * "resultCount":1, => Amount of results returned, depending
on startIndex and maxResults
+ * "maxResults":50 => The maximum amount of results returned
in the result (if provided as request parameter, this value is the same)
+ * "startIndex":1, => Index of the first search result
returned (if provided as request parameter, this value is the same)
+ * "endIndex":1, => Index of the last search result
returned
+ * "firstStartIndex":1, => Index of the first available result
for this query
+ * "lastStartIndex":1, => Last index of available results for
this query (i.e. if there are 243 results available and maxResults is 50, this
value equals 201)
+ * "entry":[ => Result entries
+ * {
+ * "name":"Administrators", => Name of the group
+ * "properties":{}, => Properties of the group
+ * "members":{} => Members of the group
+ * "requiredMembers":{} => Required members of the group
+ * }]
+ * }
+ * </pre></code> a 500 response in case any exception occurred.
+ */
+ @GET
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response getGroups(@QueryParam("filter") final String filter,
+ @QueryParam("sortOrder") final String sortOrder,
+ @DefaultValue("1") @QueryParam("startIndex") final int startIndex,
+ @DefaultValue("50") @QueryParam("maxResults") final int
maxResults) {
+ return super.getRoles(filter, sortOrder, startIndex, maxResults,
Role.GROUP);
+ }
+
+ /**
+ * Returns the group with the specified name. This method can be invoked
by making the following REST call:
+ * <code><pre>
+ * GET /rest/services/groups/groups/{name}
+ * </pre></code> For available path and query parameters, see below.
+ * @param name Name of the group to retrieve
+ * @return a 400 response in case the group was found and returned. It
returns this JSON string: <code><pre>
+ * {
+ * "name":"Administrators", => Name of the group
+ * "properties":{}, => Properties of the group
+ * "members":{}, => Member of the group
+ * "requiredMembers":{} => Required members of the group
+ * }
+ * </pre></code>a 404 response if the requested group does not exist.<br/>
+ * a 500 response in case any exception occurred.
+ */
+ @GET
+ @Path("{name}")
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response getGroup(@PathParam("name") final String name) {
+ return super.getRole(name, Role.GROUP);
+ }
+
+ /**
+ * Creates the group with the specified name. This method can be invoked
by making the following REST call:
+ * <code><pre>
+ * PUT /rest/services/groups/groups/{name}
+ * </pre></code> For available path and query parameters, see below.
+ * @param name Name of the group to create
+ * @return a 400 response in case the group was created.<br/>
+ * a 304 response in case for whatever reason the group could not
be created (i.e. a group or user with the
+ * specified name already exists).
+ */
+ @PUT
+ @Path("{name}")
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response createGroup(@PathParam("name") final String name) {
+ return super.createRole(name, Role.GROUP);
+ }
+
+ /**
+ * Sets a credential for the group with the specified name. This method
can be invoked by making the following REST
+ * call: <code><pre>
+ * PUT /rest/services/groups/groups/{name}/credentials/{key}
+ * </pre></code> For available path and query parameters, see below.
+ * @param name Name of the group to set the credential for
+ * @param key The key of the credential to set
+ * @param value The value of the credential to set (this should be a
posted form field named 'value')
+ * @return a 400 response in case the credential was updated.<br/>
+ * a 404 response in case the group with the specified name does
not exist.
+ */
+ @PUT
+ @Path("{name}/credentials/{key}")
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response setCredential(@PathParam("name") final String name,
+ @PathParam("key") final String key, @QueryParam("value") final
String value) {
+ return setCredential(name, key, value, Role.GROUP);
+ }
+
+ /**
+ * Sets a property for the group with the specified name. This method can
be invoked by making the following REST
+ * call: <code><pre>
+ * PUT /rest/services/groups/groups/{name}/properties/{key}
+ * </pre></code> For available path and query parameters, see below.
+ * @param name Name of the group to set the property for
+ * @param key The key of the property to set
+ * @param value The value of the property to set (this should be a posted
form field named 'value')
+ * @return a 400 response in case the property was updated.<br/>
+ * a 404 response in case the group with the specified name does
not exist.
+ */
+ @PUT
+ @Path("{name}/properties/{key}")
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response setProperty(@PathParam("name") final String name,
+ @PathParam("key") final String key, @QueryParam("value") final
String value) {
+ return setProperty(name, key, value, Role.USER);
+ }
+
+ /**
+ * Adds a basic member to the group with the specified name. This method
can be invoked by making the following REST
+ * call: <code><pre>
+ * PUT /rest/services/groups/groups/{name}/basicmembers/{memberName}
+ * </pre></code> For available path and query parameters, see below.
+ * @param name Name of the group to add the member to
+ * @param memberName Name of the basic member (User or Group) to add
+ * @return a 400 response in case the group was created.<br/>
+ * a 404 response in case the group or member with the specified
name does not exist.</br/> a 304 response
+ * in case the basic member was already assigned to this group.
+ */
+ @PUT
+ @Path("{name}/basicmembers/{memberName}")
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response addBasicMember(@PathParam("name") final String name,
+ @PathParam("memberName") final String memberName) {
+ return addMember(name, memberName, false);
+ }
+
+ /**
+ * Adds a required member to the group with the specified name. This
method can be invoked by making the following
+ * REST call: <code><pre>
+ * PUT /rest/services/groups/groups/{name}/requiredmembers/{memberName}
+ * </pre></code> For available path and query parameters, see below.
+ * @param name Name of the group to add the member to
+ * @param memberName Name of the required member (User or Group) to add
+ * @return a 400 response in case the group was created.<br/>
+ * a 404 response in case the group or required member with the
specified name does not exist.</br/> a 304
+ * response in case the required member was already assigned to
this group.
+ */
+ @PUT
+ @Path("{name}/requiredmembers/{memberName}")
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response addRequiredMember(@PathParam("name") final String name,
+ @PathParam("memberName") final String memberName) {
+ return addMember(name, memberName, true);
+ }
+
+ /**
+ * Removes the group with the specified name. This method can be invoked
by making the following REST call:
+ * <code><pre>
+ * DELETE /rest/services/groups/groups/{name}
+ * </pre></code> For available path and query parameters, see below.
+ * @param name Name of the group to delete
+ * @return a 400 response in case the group was deleted.<br/>
+ * a 404 response in case a group with the specified name does not
exist.
+ */
+ @DELETE
+ @Path("{name}")
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response removeGroup(@PathParam("name") final String name) {
+ return super.removeRole(name, Role.GROUP);
+ }
+
+ /**
+ * Removes the member (basic or required) from the group with the
specified names. This method can be invoked by
+ * making the following REST call: <code><pre>
+ * DELETE /rest/services/groups/groups/{name}/members/{memberName}
+ * </pre></code> For available path and query parameters, see below.
+ * @param name Name of the group to remove the member from
+ * @param memberName Name of the member (User or Group) to remove
+ * @return a 400 response in case the member was removed.<br/>
+ * a 404 response in case the group or member with the specified
name does not exist.
+ */
+ @DELETE
+ @Path("{name}/members/{memberName}")
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response removeMember(@PathParam("name") final String name,
@PathParam("memberName") final String memberName) {
+ Role role = m_userAdmin.getRole(name);
+ Role member = m_userAdmin.getRole(memberName);
+ if (role != null && role.getType() == Role.GROUP && member != null) {
+ if (((Group) role).removeMember(member)) {
+ return buildOK();
+ } else {
+ return buildNotModified("Member already removed");
+ }
+ } else {
+ return buildNotFound();
+ }
+ }
+
+ private Response addMember(String name, String memberName, boolean
required) {
+ Role role = m_userAdmin.getRole(name);
+ Role member = m_userAdmin.getRole(memberName);
+ if (role != null && role.getType() == Role.GROUP && member != null) {
+ if (!required && ((Group) role).addMember(member)) {
+ return buildOK();
+ } else if (required && ((Group) role).addRequiredMember(member)) {
+ return buildOK();
+ } else {
+ return buildNotModified("Member already added");
+ }
+ } else {
+ return buildNotFound();
+ }
+ }
+}
Added:
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/ResourceBase.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/ResourceBase.java
Fri Dec 17 14:15:20 2010
@@ -0,0 +1,236 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.authorization.useradmin.rest.service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+
+import javax.ws.rs.core.CacheControl;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+abstract class ResourceBase {
+ // Service dependencies injected by the depedency manager
+ protected volatile LogService m_logService;
+ protected volatile UserAdmin m_userAdmin;
+
+ // Disable HTTP caching in this REST interface
+ private static CacheControl m_cacheControl;
+ static {
+ m_cacheControl = new CacheControl();
+ m_cacheControl.setNoCache(true);
+ }
+
+ /**
+ * Returns the roles (users or groups) for the specified filter options.
+ * @param filter the filter to pass to UserAdmin
+ * @param sortOrder The sort order ('ascending' or 'descending')
+ * @param startIndex The startindex
+ * @param maxResults Maximum amount of results to return on a single REST
call
+ * @param roleType The type of role to retrieve
+ * @return The response
+ */
+ protected Response getRoles(String filter, String sortOrder, int
startIndex, int maxResults, int roleType) {
+ try {
+ if (startIndex < 0) {
+ startIndex = 1;
+ }
+ if (maxResults < 0) {
+ maxResults = 50;
+ }
+
+ // First retrieve all roles with the specified filter
+ Role[] roles = m_userAdmin.getRoles(null);
+ final boolean descending = "desc".equalsIgnoreCase(sortOrder) ||
"descending".equalsIgnoreCase(sortOrder);
+
+ // Now filter out the user or groups (we should only return roles
of type roleType)
+ List<Role> filteredRoles = new ArrayList<Role>();
+ if (roles != null) {
+ for (Role role : roles) {
+ if (role.getType() == roleType) {
+ if (filter == null || role.getName().matches(".*" +
filter + ".*")) {
+ filteredRoles.add(role);
+ }
+ }
+ }
+ }
+
+ // Now filter from startIndex - endIndex
+ List<Role> roleRange = new ArrayList<Role>();
+ for (int i = (startIndex - 1); i < (startIndex + maxResults - 1)
&& i < filteredRoles.size(); i++) {
+ roleRange.add(filteredRoles.get(i));
+ }
+
+ // Finally sort it
+ Comparator<Role> userComparator = new Comparator<Role>() {
+ public int compare(Role r1, Role r2) {
+ if (descending) {
+ return -r1.getName().compareTo(r2.getName());
+ } else {
+ return r1.getName().compareTo(r2.getName());
+ }
+ }
+ };
+ Arrays.sort(roleRange.toArray(new Role[roleRange.size()]),
userComparator);
+
+ JSONObject jsonObject = new JSONObject();
+ for (Role role : roleRange) {
+ JSONObject jsonUser = getJSON(role);
+ jsonObject.append("entry", jsonUser);
+ }
+
+ jsonObject.put("startIndex", roleRange.size() > 0 ? Math.max(1,
startIndex) : 0);
+ jsonObject.put("endIndex", (startIndex + roleRange.size() - 1));
+ jsonObject.put("firstStartIndex", roleRange.size() > 0 ? 1 : 0);
+ if (filteredRoles.size() % maxResults == 0) {
+ jsonObject.put("lastStartIndex", Math.max(0,
filteredRoles.size() - maxResults + 1));
+ } else {
+ jsonObject.put("lastStartIndex", 1 + filteredRoles.size() -
(filteredRoles.size() % maxResults));
+ }
+ jsonObject.put("maxResults", maxResults);
+ jsonObject.put("resultCount", roleRange.size());
+ jsonObject.put("totalCount", filteredRoles.size());
+
+ return buildOK(jsonObject);
+ } catch (InvalidSyntaxException e) {
+ m_logService.log(LogService.LOG_ERROR, "Unable to retrieve roles
for filter '" + filter + "', startIndex '"
+ + startIndex + "' maxResults '" + maxResults + "'", e);
+ } catch (JSONException e) {
+ m_logService.log(LogService.LOG_ERROR, "Unable to retrieve roles
for filter '" + filter + "', startIndex '"
+ + startIndex + "' maxResults '" + maxResults + "'", e);
+ }
+ return buildServerError();
+ }
+
+ protected Response getRole(String name, int roleType) {
+ try {
+ Role role = m_userAdmin.getRole(name);
+ if (role != null && role.getType() == roleType) {
+ JSONObject jsonRole = getJSON(role);
+ return buildOK(jsonRole);
+ } else {
+ return buildNotFound();
+ }
+ } catch (JSONException e) {
+ m_logService.log(LogService.LOG_ERROR, "Unable to retrieve role
named '" + name + "'", e);
+ }
+ return buildServerError();
+ }
+
+ protected Response createRole(String name, int roleType) {
+ Role role = m_userAdmin.createRole(name, roleType);
+ if (role != null) {
+ return buildOK();
+ } else {
+ return buildNotModified("Role could not be created");
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Response setCredential(String name, String key, String value,
int roleType) {
+ Role role = m_userAdmin.getRole(name);
+ if (role != null && role.getType() == roleType) {
+ ((User) role).getCredentials().put(key, value);
+ return buildOK();
+ } else {
+ return buildNotFound();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Response setProperty(String name, String key, String value, int
roleType) {
+ Role role = m_userAdmin.getRole(name);
+ if (role != null && role.getType() == roleType) {
+ role.getProperties().put(key, value);
+ return buildOK();
+ } else {
+ return buildNotFound();
+ }
+ }
+
+ protected Response removeRole(String name, int roleType) {
+ Role role = m_userAdmin.getRole(name);
+ if (role != null && role.getType() == roleType) {
+ if (m_userAdmin.removeRole(name)) {
+ return buildOK();
+ } else {
+ return buildNotModified("Role to remove not found");
+ }
+ } else {
+ return buildNotModified("Role to remove not found");
+ }
+ }
+
+ private JSONObject getJSON(Role role) throws JSONException {
+ JSONObject jsonRole = new JSONObject();
+ jsonRole.put("name", role.getName());
+ jsonRole.put("properties", role.getProperties());
+ if (role.getType() == Role.GROUP) {
+ Role[] members = ((Group) role).getMembers();
+ JSONObject jsonMembers = new JSONObject();
+ if (members != null) {
+ for (Role member : members) {
+ JSONObject jsonMember = getJSON(member);
+ jsonMember.append("member", jsonMember);
+ }
+ }
+ jsonRole.put("members", jsonMembers);
+
+ Role[] reqMembers = ((Group) role).getRequiredMembers();
+ JSONObject jsonReqMembers = new JSONObject();
+ if (reqMembers != null) {
+ for (Role member : reqMembers) {
+ JSONObject jsonMember = getJSON(member);
+ jsonMember.append("member", jsonMember);
+ }
+ }
+ jsonRole.put("requiredMembers", jsonReqMembers);
+ }
+ return jsonRole;
+ }
+
+ protected Response buildOK() {
+ return Response.ok().cacheControl(m_cacheControl).build();
+ }
+
+ protected Response buildOK(JSONObject jsonObject) {
+ return Response.ok(jsonObject.toString(),
MediaType.APPLICATION_JSON_TYPE).cacheControl(m_cacheControl).build();
+ }
+
+ protected Response buildNotFound() {
+ return
Response.status(Response.Status.NOT_FOUND).cacheControl(m_cacheControl).build();
+ }
+
+ protected Response buildNotModified(String msg) {
+ return Response.notModified(msg).cacheControl(m_cacheControl).build();
+ }
+
+ protected Response buildServerError() {
+ return Response.serverError().cacheControl(m_cacheControl).build();
+ }
+}
Added:
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/UsersResource.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/UsersResource.java
Fri Dec 17 14:15:20 2010
@@ -0,0 +1,175 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.authorization.useradmin.rest.service;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.amdatu.web.rest.jaxrs.RESTService;
+import org.osgi.service.useradmin.Role;
+
+/**
+ * REST service for managing Users based on the UserAdmin OSGi specification
(see chapter 107 of the Enterprise OSGi
+ * spec version 4.1). This REST service provides the following methods:
<code><pre>
+ * GET /rest/services/users/users -> returns all users
+ * GET /rest/services/groups/groups/{name} -> Returns the group with the
specified name
+ * PUT /rest/services/groups/groups/{name} -> Creates a group with the
specified name
+ * DELETE /rest/services/groups/groups/{name} -> Deletes the group with the
specified name
+ * </pre></code>
+ * @author ivol
+ */
+ at Path("users")
+public class UsersResource extends ResourceBase implements RESTService {
+ /**
+ * Returns all users that match the specified filter options. This method
can be invoked by making the following
+ * REST call:<code><pre>
+ * GET
/rest/services/users/users?filter={filter}&sortOrder={sortOrder}&startIndex={startIndex}&maxResults={maxResults}
+ * </pre></code> For available path and query parameters, see below.
+ * @param filter Filter that the name of the user must match. A user name
is considered to match the specified
+ * filter if the filter equals the user name or the filter is a
substring of the user name.
+ * @param sortOrder 'ascending' to return results in ascending order or
'descending' to return results in descending
+ * order.
+ * @param startIndex The index of the first result to return (default is
1).
+ * @param maxResults The maximum amount of results to return (default is
50).
+ * @return a 400 response with this JSON string containing the results in
case the call was successful: <code><pre>
+ * {
+ * "totalCount":1, => Total amount of available results for
this query, independent of the values of startIndex and maxResults
+ * "resultCount":1, => Amount of results returned, depending
on startIndex and maxResults
+ * "maxResults":50 => The maximum amount of results returned
in the result (if provided as request parameter, this value is the same)
+ * "startIndex":1, => Index of the first search result
returned (if provided as request parameter, this value is the same)
+ * "endIndex":1, => Index of the last search result
returned
+ * "firstStartIndex":1, => Index of the first available result
for this query
+ * "lastStartIndex":1, => Last index of available results for
this query (i.e. if there are 243 results available and maxResults is 50, this
value equals 201)
+ * "entry":[ => Result entries
+ * {
+ * "name":"Administrator", => Name of the user
+ * "properties":{} => Properties of the user
+ * }]
+ * }
+ * </pre></code> a 500 response in case any exception occurred.
+ */
+ @GET
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response getUsers(
+ @QueryParam("filter") final String filter,
+ @QueryParam("sortOrder") final String sortOrder,
+ @DefaultValue("1") @QueryParam("startIndex") final int startIndex,
+ @DefaultValue("50") @QueryParam("maxResults") final int
maxResults) {
+ return super.getRoles(filter, sortOrder, startIndex, maxResults,
Role.USER);
+ }
+
+ /**
+ * Returns the user with the specified name. This method can be invoked by
making the following REST call:
+ * <code><pre>
+ * GET /rest/services/users/users/{name}
+ * </pre></code> For available path and query parameters, see below.
+ * @param name Name of the user to retrieve
+ * @return a 400 response in case the user was found and returned. It
returns this JSON string: <code><pre>
+ * {
+ * "name":"Administrator", => Name of the user
+ * "properties":{} => Properties of the user
+ * }
+ * </pre></code>a 404 response if the requested user does not exist.<br/>
+ * a 500 response in case any exception occurred.
+ */
+ @GET
+ @Path("{name}")
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response getUser(@PathParam("name") final String name) {
+ return super.getRole(name, Role.USER);
+ }
+
+ /**
+ * Creates the user with the specified name. This method can be invoked by
making the following REST call:
+ * <code><pre>
+ * PUT /rest/services/users/users/{name}
+ * </pre></code> For available path and query parameters, see below.
+ * @param name Name of the user to create
+ * @return a 400 response in case the user was created.<br/>
+ * a 304 response in case for whatever reason the user could not
be created (i.e. a group or user with the
+ * specified name already exists).
+ */
+ @PUT
+ @Path("{name}")
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response createUser(@PathParam("name") final String name) {
+ return super.createRole(name, Role.USER);
+ }
+
+ /**
+ * Sets a credential for the user with the specified name. This method can
be invoked by making the following REST
+ * call: <code><pre>
+ * PUT /rest/services/users/users/{name}/credentials/{key}
+ * </pre></code> For available path and query parameters, see below.
+ * @param name Name of the user to set the credential for
+ * @param key The key of the credential to set
+ * @param value The value of the credential to set (this should be a
posted form field named 'value')
+ * @return a 400 response in case the credential was updated.<br/>
+ * a 404 response in case the user with the specified name does
not exist.
+ */
+ @PUT
+ @Path("{name}/credentials/{key}")
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response setCredential(@PathParam("name") final String name,
+ @PathParam("key") final String key, @FormParam("value") final
String value) {
+ return setCredential(name, key, value, Role.USER);
+ }
+
+ /**
+ * Sets a property for the user with the specified name. This method can
be invoked by making the following REST
+ * call: <code><pre>
+ * PUT /rest/services/users/users/{name}/properties/{key}
+ * </pre></code> For available path and query parameters, see below.
+ * @param name Name of the user to set the property for
+ * @param key The key of the property to set
+ * @param value The value of the property to set (this should be a posted
form field named 'value')
+ * @return a 400 response in case the property was updated.<br/>
+ * a 404 response in case the user with the specified name does
not exist.
+ */
+ @PUT
+ @Path("{name}/properties/{key}")
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response setProperty(@PathParam("name") final String name,
+ @PathParam("key") final String key, @FormParam("value") final
String value) {
+ return setProperty(name, key, value, Role.USER);
+ }
+
+ /**
+ * Removes the user with the specified name. This method can be invoked by
making the following REST call:
+ * <code><pre>
+ * DELETE /rest/services/users/users/{name}
+ * </pre></code> For available path and query parameters, see below.
+ * @param name Name of the user to delete
+ * @return a 400 response in case the user was deleted.<br/>
+ * a 404 response in case a user with the specified name does not
exist.
+ */
+ @DELETE
+ @Path("{name}")
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response removeUser(@PathParam("name") final String name) {
+ return super.removeRole(name, Role.USER);
+ }
+}
Modified:
trunk/amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/osgi/Activator.java
==============================================================================
---
trunk/amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/osgi/Activator.java
(original)
+++
trunk/amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/osgi/Activator.java
Fri Dec 17 14:15:20 2010
@@ -22,10 +22,7 @@
import org.amdatu.cassandra.listener.ColumnFamilyAvailable;
import org.amdatu.cassandra.listener.ColumnFamilyProvider;
import org.amdatu.cassandra.persistencemanager.CassandraPersistenceManager;
-import org.amdatu.cassandra.useradminstore.DummyResourceInterface;
-import org.amdatu.cassandra.useradminstore.rest.GroupsResource;
import
org.amdatu.cassandra.useradminstore.rest.HttpContextRegistrationServiceImpl;
-import org.amdatu.cassandra.useradminstore.rest.UsersResource;
import org.amdatu.cassandra.useradminstore.service.CassandraStorageProvider;
import org.amdatu.cassandra.useradminstore.service.RoleColumnFamilyProvider;
import org.amdatu.web.httpcontext.HttpContextServiceFactory;
@@ -37,7 +34,6 @@
import org.osgi.framework.BundleContext;
import org.osgi.service.http.HttpService;
import org.osgi.service.log.LogService;
-import org.osgi.service.useradmin.UserAdmin;
/**
* This is the bundle activator for the UserAdmin bundle.
@@ -75,20 +71,6 @@
.add(createServiceDependency().setService(ColumnFamilyAvailable.class,
roleFilter).setRequired(true))
.add(createServiceDependency().setService(CassandraDaemonService.class).setRequired(true)));
- // Create the users resource and register it as REST service
- manager.add(createComponent()
- .setInterface(DummyResourceInterface.class.getName(), null)
- .setImplementation(UsersResource.class)
-
.add(createServiceDependency().setService(LogService.class).setRequired(true))
-
.add(createServiceDependency().setService(UserAdmin.class).setRequired(true)));
-
- // Create the users resource and register it as REST service
- manager.add(createComponent()
- .setImplementation(GroupsResource.class)
- .setInterface(DummyResourceInterface.class.getName(), null)
-
.add(createServiceDependency().setService(LogService.class).setRequired(true))
-
.add(createServiceDependency().setService(UserAdmin.class).setRequired(true)));
-
// Create and register the http context registration service
manager.add(createComponent()
.setInterface(ResourceProvider.class.getName(), null)
Modified: trunk/amdatu-release/pom.xml
==============================================================================
--- trunk/amdatu-release/pom.xml (original)
+++ trunk/amdatu-release/pom.xml Fri Dec 17 14:15:20 2010
@@ -70,6 +70,13 @@
<scope>compile</scope>
<type>bundle</type>
</dependency>
+ <dependency>
+ <groupId>org.amdatu.authorization.useradmin</groupId>
+ <artifactId>rest</artifactId>
+ <version>${platform.version}</version>
+ <scope>compile</scope>
+ <type>bundle</type>
+ </dependency>
<!-- Core bundles -->
<dependency>
Modified: trunk/amdatu-web/rest-jaxrs/pom.xml
==============================================================================
--- trunk/amdatu-web/rest-jaxrs/pom.xml (original)
+++ trunk/amdatu-web/rest-jaxrs/pom.xml Fri Dec 17 14:15:20 2010
@@ -43,6 +43,7 @@
javax.ws.rs.*;version=${jsr311-api.version},
javax.annotation.security
</_exportcontents>
+ <Export-Package>org.amdatu.web.rest.jaxrs</Export-Package>
</instructions>
</configuration>
</plugin>
Added:
trunk/amdatu-web/rest-jaxrs/src/main/java/org/amdatu/web/rest/jaxrs/RESTService.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-web/rest-jaxrs/src/main/java/org/amdatu/web/rest/jaxrs/RESTService.java
Fri Dec 17 14:15:20 2010
@@ -0,0 +1,30 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.web.rest.jaxrs;
+
+/**
+ * Interface implemented by REST services. In the current Wink implementation
each REST service must
+ * implement an interface to be able to read the JAX-RS annotations from it.
Note that it really
+ * doesn't matter what interface is implemented by this service, any interface
will do. As a result some
+ * 'dummy' interfaces were created and implemented by the REST service. For
now, this interface can
+ * be used instead.
+ * See http://jira.amdatu.org/jira/browse/AMDATU-221
+ *
+ * @author ivol
+ */
+public interface RESTService {
+}
Modified: trunk/integration-tests/pom.xml
==============================================================================
--- trunk/integration-tests/pom.xml (original)
+++ trunk/integration-tests/pom.xml Fri Dec 17 14:15:20 2010
@@ -183,6 +183,13 @@
<type>bundle</type>
</dependency>
<dependency>
+ <groupId>org.amdatu.authorization.useradmin</groupId>
+ <artifactId>rest</artifactId>
+ <version>${platform.version}</version>
+ <scope>test</scope>
+ <type>bundle</type>
+ </dependency>
+ <dependency>
<groupId>org.amdatu.authentication.oauth</groupId>
<artifactId>api</artifactId>
<version>${platform.version}</version>
Modified:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
==============================================================================
---
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
(original)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
Fri Dec 17 14:15:20 2010
@@ -109,16 +109,25 @@
// And finally deploy ourselves
bundle(integrationTestJarFile().toURI().toString())
));
- if (provisionBundles() == null) {
+
+ Option[] addOptions = getProvisionedBundles();
+ if (addOptions == null || addOptions.length == 0) {
return baseOptions;
}
- Option[] options = new Option[baseOptions.length + 1];
+
+ Option[] options = new Option[baseOptions.length + addOptions.length];
for (int i = 0; i < baseOptions.length; i++) {
options[i] = baseOptions[i];
}
- options[baseOptions.length] = provisionBundles();
+ for (int i = baseOptions.length; i < baseOptions.length +
addOptions.length; i++) {
+ options[i] = addOptions[i-baseOptions.length];
+ }
return options;
}
+
+ protected Option[] getProvisionedBundles() {
+ return new Option[]{provisionBundles()};
+ }
/**
* Return the list of bundles here that are required to run the
integration test.
@@ -302,6 +311,10 @@
return
mavenBundle().groupId("org.amdatu.cassandra").artifactId("useradminstore").versionAsInProject();
}
+ protected static MavenArtifactProvisionOption amdatuUserAdminREST() {
+ return
mavenBundle().groupId("org.amdatu.authorization.useradmin").artifactId("rest").versionAsInProject();
+ }
+
protected static MavenArtifactProvisionOption amdatuUserAdminFSStore() {
return
mavenBundle().groupId("org.amdatu.core").artifactId("useradminstore-fs").versionAsInProject();
}
Added:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/RESTTestBase.java
==============================================================================
--- (empty file)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/RESTTestBase.java
Fri Dec 17 14:15:20 2010
@@ -0,0 +1,132 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.test.integration.base;
+
+import static junit.framework.Assert.assertTrue;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+
+import java.io.IOException;
+
+import org.amdatu.web.httpcontext.HttpContextServiceFactory;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.methods.DeleteMethod;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Before;
+import org.ops4j.pax.exam.Inject;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.osgi.framework.BundleException;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.log.LogService;
+
+/**
+ * This is the base class for REST tests.
+ * @author ivol
+ */
+public abstract class RESTTestBase extends IntegrationTestBase {
+
+ private String m_baseUrl = null;
+
+ @Inject
+ private volatile ConfigurationAdmin m_configAdmin;
+ protected volatile LogService m_logService;
+
+ @Configuration
+ public Option[] configure() {
+ return super.configure();
+ }
+
+ @Override
+ protected Option[] getProvisionedBundles() {
+ return new Option[]{
+ provision(
+ felixHttpServiceJetty(),
+ amdatuHttpContext(),
+ amdatuJaxRs(),
+ amdatuWink(),
+ slingCommons(),
+ slingMime(),
+ commonsHttpClient(),
+ commonsLogging(),
+ commonsCodec()
+ )
+ , provisionBundles()};
+ }
+
+ public Component getTestComponent(DependencyManager manager) {
+ return manager.createComponent().setImplementation(this)
+
.add(manager.createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true))
+
.add(manager.createServiceDependency().setService(HttpService.class).setRequired(true))
+
.add(manager.createServiceDependency().setService(HttpContextServiceFactory.class).setRequired(true));
+ }
+
+ @Before
+ public void initConfig() throws IOException, BundleException {
+ m_configAdmin = getService(ConfigurationAdmin.class);
+ m_logService = getService(LogService.class);
+
+ // Add cassandra and templates configs
+ ConfigProvider configProvider = new ConfigProvider();
+ configProvider.addFelixHttpServiceConfig(m_configAdmin);
+ addConfig(configProvider, m_configAdmin);
+ m_logService.log(LogService.LOG_DEBUG, "HttpService config set to " +
ConfigProvider.HOSTNAME + ":" + ConfigProvider.PORTNR);
+ }
+
+ protected abstract void addConfig(ConfigProvider configProvider,
ConfigurationAdmin configAdmin) throws IOException;
+
+ protected String getBaseUrl() throws Exception {
+ if (m_baseUrl == null) {
+ m_baseUrl = "http://" + ConfigProvider.HOSTNAME + ":" +
ConfigProvider.PORTNR + "/rest/services";
+ }
+ return m_baseUrl;
+ }
+
+ protected String invokeRestApi(String urlPostfix, String httpMethod, int
expectedStatus) throws Exception {
+ String url = getBaseUrl() + urlPostfix;
+ HttpClient httpClient = new HttpClient();
+ m_logService.log(LogService.LOG_DEBUG, "Invoking REST API '" + url +
"'");
+ HttpMethod method = null;
+ if (httpMethod.equals(javax.ws.rs.HttpMethod.GET)) {
+ method = new GetMethod(url);
+ } else if (httpMethod.equals(javax.ws.rs.HttpMethod.PUT)) {
+ method = new PutMethod(url);
+ } else if (httpMethod.equals(javax.ws.rs.HttpMethod.DELETE)) {
+ method = new DeleteMethod(url);
+ } else if (httpMethod.equals(javax.ws.rs.HttpMethod.POST)) {
+ method = new PostMethod(url);
+ }
+ try {
+ // Execute the method, this should return a 200
+ int statusCode = httpClient.executeMethod(method);
+ assertTrue("HTTP '" + httpMethod + "' to '" + url + "' returned "
+ statusCode, statusCode == expectedStatus);
+
+ // Read the response body and return it.
+ return new String(method.getResponseBody(), "UTF-8");
+ }
+ finally {
+ // Release the connection.
+ method.releaseConnection();
+ }
+
+ }
+}
Added:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/UserAdminRESTTest.java
==============================================================================
--- (empty file)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/UserAdminRESTTest.java
Fri Dec 17 14:15:20 2010
@@ -0,0 +1,73 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.test.integration.tests;
+
+import static org.ops4j.pax.exam.CoreOptions.provision;
+
+import java.io.IOException;
+
+import org.amdatu.test.integration.base.ConfigProvider;
+import org.amdatu.test.integration.base.RESTTestBase;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.useradmin.UserAdmin;
+
+ at RunWith(JUnit4TestRunner.class)
+public class UserAdminRESTTest extends RESTTestBase {
+
+ protected Option provisionBundles() {
+ return provision(
+ paxUserAdmin(),
+ amdatuUserAdminFSStore(),
+ amdatuUserAdminREST());
+ }
+
+ public Component[] getDependencies(DependencyManager manager) {
+ Component testComponent = getTestComponent(manager);
+
testComponent.add(manager.createServiceDependency().setService(UserAdmin.class).setRequired(true))
;
+ return new Component[] {
+ testComponent
+ };
+ }
+
+ @Override
+ protected void addConfig(ConfigProvider configProvider, ConfigurationAdmin
configAdmin) throws IOException {
+ configProvider.addFSUserAdminConfig(configAdmin);
+ }
+
+ @Test
+ public void testTheRest() throws Exception {
+ // Test the REST interface of the useradmin bundle. First wait before
it comes up
+ waitForURL(getBaseUrl() + "/users/users", HttpStatus.SC_OK);
+
+ // -1- Test create user
+ String url = "/users/users/" + ConfigProvider.TEST_USERNAME;
+ invokeRestApi(url, javax.ws.rs.HttpMethod.PUT, HttpStatus.SC_OK);
+
+ // -2- Retrieve the user
+ invokeRestApi(url, javax.ws.rs.HttpMethod.GET, HttpStatus.SC_OK);
+
+ // -3- Delete the user
+ invokeRestApi(url, javax.ws.rs.HttpMethod.DELETE, HttpStatus.SC_OK);
+ }
+}
Modified: trunk/src/main/resources/conf/felix-config.properties
==============================================================================
--- trunk/src/main/resources/conf/felix-config.properties (original)
+++ trunk/src/main/resources/conf/felix-config.properties Fri Dec 17
14:15:20 2010
@@ -109,6 +109,7 @@
reference:file:amdatu-application/org.amdatu.web.rest.wink-${platform.version}.jar
felix.auto.start.10=reference:file:amdatu-application/org.amdatu.authorization.login.gadget-${platform.version}.jar
\
reference:file:amdatu-application/org.amdatu.authorization.login.service-${platform.version}.jar
\
+
reference:file:amdatu-application/org.amdatu.authorization.useradmin.rest-${platform.version}.jar
\
reference:file:amdatu-application/org.amdatu.authentication.oauth.api-${platform.version}.jar
\
reference:file:amdatu-application/org.amdatu.authentication.oauth.client-${platform.version}.jar
\
reference:file:amdatu-application/org.amdatu.authentication.oauth.server-${platform.version}.jar
\