You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2015/01/12 18:41:08 UTC
[5/7] syncope git commit: [SYNCOPE-620] server-rest-cxf
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RoleService.java
----------------------------------------------------------------------
diff --git a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RoleService.java b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RoleService.java
new file mode 100644
index 0000000..f0bbf08
--- /dev/null
+++ b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RoleService.java
@@ -0,0 +1,313 @@
+/*
+ * 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.syncope.common.rest.api.service;
+
+import java.util.List;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+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.apache.cxf.jaxrs.model.wadl.Description;
+import org.apache.cxf.jaxrs.model.wadl.Descriptions;
+import org.apache.cxf.jaxrs.model.wadl.DocTarget;
+import org.apache.syncope.common.lib.mod.RoleMod;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.PagedResult;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.types.ResourceAssociationActionType;
+import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
+import org.apache.syncope.common.lib.wrap.ResourceName;
+
+/**
+ * REST operations for roles.
+ */
+@Path("roles")
+public interface RoleService extends JAXRSService {
+
+ /**
+ * Returns children roles of given role.
+ *
+ * @param roleKey key of role to get children from
+ * @return children roles of given role
+ */
+ @GET
+ @Path("{roleKey}/children")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ List<RoleTO> children(@NotNull @PathParam("roleKey") Long roleKey);
+
+ /**
+ * Returns parent role of the given role (or null if no parent exists).
+ *
+ * @param roleKey key of role to get parent role from
+ * @return parent role of the given role (or null if no parent exists)
+ */
+ @GET
+ @Path("{roleKey}/parent")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ RoleTO parent(@NotNull @PathParam("roleKey") Long roleKey);
+
+ /**
+ * Reads the role matching the provided roleKey.
+ *
+ * @param roleKey key of role to be read
+ * @return role with matching id
+ */
+ @GET
+ @Path("{roleKey}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ RoleTO read(@NotNull @PathParam("roleKey") Long roleKey);
+
+ /**
+ * This method is similar to {@link #read(Long)}, but uses different authentication handling to ensure that a user
+ * can read his own roles.
+ *
+ * @param roleKey key of role to be read
+ * @return role with matching id
+ */
+ @Descriptions({
+ @Description(target = DocTarget.METHOD,
+ value = "This method is similar to <tt>read()</tt>, but uses different authentication handling to "
+ + "ensure that a user can read his own roles.")
+ })
+ @GET
+ @Path("{roleKey}/own")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ RoleTO readSelf(@NotNull @PathParam("roleKey") Long roleKey);
+
+ /**
+ * Returns a paged list of existing roles.
+ *
+ * @return paged list of all existing roles
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<RoleTO> list();
+
+ /**
+ * Returns a paged list of existing roles.
+ *
+ * @param orderBy list of ordering clauses, separated by comma
+ * @return paged list of all existing roles
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<RoleTO> list(@QueryParam(PARAM_ORDERBY) String orderBy);
+
+ /**
+ * Returns a paged list of existing roles matching page/size conditions.
+ *
+ * @param page result page number
+ * @param size number of entries per page
+ * @return paged list of existing roles matching page/size conditions
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<RoleTO> list(
+ @NotNull @Min(1) @QueryParam(PARAM_PAGE) @DefaultValue(DEFAULT_PARAM_PAGE) Integer page,
+ @NotNull @Min(1) @QueryParam(PARAM_SIZE) @DefaultValue(DEFAULT_PARAM_SIZE) Integer size);
+
+ /**
+ * Returns a paged list of existing roles matching page/size conditions.
+ *
+ * @param page result page number
+ * @param size number of entries per page
+ * @param orderBy list of ordering clauses, separated by comma
+ * @return paged list of existing roles matching page/size conditions
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<RoleTO> list(
+ @NotNull @Min(1) @QueryParam(PARAM_PAGE) @DefaultValue(DEFAULT_PARAM_PAGE) Integer page,
+ @NotNull @Min(1) @QueryParam(PARAM_SIZE) @DefaultValue(DEFAULT_PARAM_SIZE) Integer size,
+ @QueryParam(PARAM_ORDERBY) String orderBy);
+
+ /**
+ * Returns a paged list of roles matching the provided FIQL search condition.
+ *
+ * @param fiql FIQL search expression
+ * @return paged list of roles matching the provided FIQL search condition
+ */
+ @GET
+ @Path("search")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<RoleTO> search(@NotNull @QueryParam(PARAM_FIQL) String fiql);
+
+ /**
+ * Returns a paged list of roles matching the provided FIQL search condition.
+ *
+ * @param fiql FIQL search expression
+ * @param orderBy list of ordering clauses, separated by comma
+ * @return paged list of roles matching the provided FIQL search condition
+ */
+ @GET
+ @Path("search")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<RoleTO> search(
+ @NotNull @QueryParam(PARAM_FIQL) String fiql, @QueryParam(PARAM_ORDERBY) String orderBy);
+
+ /**
+ * Returns a paged list of roles matching the provided FIQL search condition.
+ *
+ * @param fiql FIQL search expression
+ * @param page result page number
+ * @param size number of entries per page
+ * @return paged list of roles matching the provided FIQL search condition
+ */
+ @GET
+ @Path("search")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<RoleTO> search(@QueryParam(PARAM_FIQL) String fiql,
+ @NotNull @Min(1) @QueryParam(PARAM_PAGE) @DefaultValue(DEFAULT_PARAM_PAGE) Integer page,
+ @NotNull @Min(1) @QueryParam(PARAM_SIZE) @DefaultValue(DEFAULT_PARAM_SIZE) Integer size);
+
+ /**
+ * Returns a paged list of roles matching the provided FIQL search condition.
+ *
+ * @param fiql FIQL search expression
+ * @param page result page number
+ * @param size number of entries per page
+ * @param orderBy list of ordering clauses, separated by comma
+ * @return paged list of roles matching the provided FIQL search condition
+ */
+ @GET
+ @Path("search")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<RoleTO> search(@QueryParam(PARAM_FIQL) String fiql,
+ @NotNull @Min(1) @QueryParam(PARAM_PAGE) @DefaultValue(DEFAULT_PARAM_PAGE) Integer page,
+ @NotNull @Min(1) @QueryParam(PARAM_SIZE) @DefaultValue(DEFAULT_PARAM_SIZE) Integer size,
+ @QueryParam(PARAM_ORDERBY) String orderBy);
+
+ /**
+ * Creates a new role.
+ *
+ * @param roleTO role to be created
+ * @return <tt>Response</tt> object featuring <tt>Location</tt> header of created role as well as the role itself
+ * enriched with propagation status information - {@link RoleTO} as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring <tt>Location</tt> header of created role as well as the "
+ + "role itself enriched with propagation status information - <tt>RoleTO</tt> as <tt>Entity</tt>")
+ })
+ @POST
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response create(@NotNull RoleTO roleTO);
+
+ /**
+ * Updates role matching the provided roleKey.
+ *
+ * @param roleKey key of role to be updated
+ * @param roleMod modification to be applied to role matching the provided roleKey
+ * @return <tt>Response</tt> object featuring the updated role enriched with propagation status information
+ * - {@link RoleTO} as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring the updated role enriched with propagation status information - "
+ + "<tt>RoleTO</tt> as <tt>Entity</tt>")
+ })
+ @POST
+ @Path("{roleKey}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response update(@NotNull @PathParam("roleKey") Long roleKey, @NotNull RoleMod roleMod);
+
+ /**
+ * Deletes role matching provided roleKey.
+ *
+ * @param roleKey key of role to be deleted
+ * @return <tt>Response</tt> object featuring the deleted role enriched with propagation status information
+ * - {@link RoleTO} as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring the deleted role enriched with propagation status information - "
+ + "<tt>RoleTO</tt> as <tt>Entity</tt>")
+ })
+ @DELETE
+ @Path("{roleKey}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response delete(@NotNull @PathParam("roleKey") Long roleKey);
+
+ /**
+ * Executes resource-related operations on given role.
+ *
+ * @param roleKey role id.
+ * @param type resource association action type
+ * @param resourceNames external resources to be used for propagation-related operations
+ * @return <tt>Response</tt> object featuring
+ * {@link org.apache.syncope.common.reqres.BulkActionResult} as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring <tt>BulkActionResult</tt> as <tt>Entity</tt>")
+ })
+ @POST
+ @Path("{roleKey}/deassociate/{type}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response bulkDeassociation(@NotNull @PathParam("roleKey") Long roleKey,
+ @NotNull @PathParam("type") ResourceDeassociationActionType type,
+ @NotNull List<ResourceName> resourceNames);
+
+ /**
+ * Executes resource-related operations on given role.
+ *
+ * @param roleKey role id.
+ * @param type resource association action type
+ * @param resourceNames external resources to be used for propagation-related operations
+ * @return <tt>Response</tt> object featuring {@link org.apache.syncope.common.reqres.BulkActionResult}
+ * as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring <tt>BulkActionResult</tt> as <tt>Entity</tt>")
+ })
+ @POST
+ @Path("{roleKey}/associate/{type}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response bulkAssociation(@NotNull @PathParam("roleKey") Long roleKey,
+ @NotNull @PathParam("type") ResourceAssociationActionType type,
+ @NotNull List<ResourceName> resourceNames);
+
+ /**
+ * Executes the provided bulk action.
+ *
+ * @param bulkAction list of role ids against which the bulk action will be performed.
+ * @return Bulk action result
+ */
+ @POST
+ @Path("bulk")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ BulkActionResult bulk(@NotNull BulkAction bulkAction);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SchemaService.java
----------------------------------------------------------------------
diff --git a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SchemaService.java b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SchemaService.java
new file mode 100644
index 0000000..d3f850b
--- /dev/null
+++ b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SchemaService.java
@@ -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.syncope.common.rest.api.service;
+
+import java.util.List;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.apache.cxf.jaxrs.model.wadl.Descriptions;
+import org.apache.cxf.jaxrs.model.wadl.DocTarget;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.SchemaType;
+
+/**
+ * REST operations for attribute schemas.
+ */
+@Path("schemas/{kind}/{type}")
+public interface SchemaService extends JAXRSService {
+
+ /**
+ * Returns schema matching the given kind, type and name.
+ *
+ * @param <T> actual SchemaTO
+ * @param attrType kind for schemas to be read
+ * @param schemaType type for schemas to be read
+ * @param schemaKey name of schema to be read
+ * @return schema matching the given kind, type and name
+ */
+ @GET
+ @Path("{key}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ <T extends AbstractSchemaTO> T read(@NotNull @PathParam("kind") AttributableType attrType,
+ @NotNull @PathParam("type") SchemaType schemaType, @NotNull @PathParam("key") String schemaKey);
+
+ /**
+ * Returns a list of schemas with matching kind and type.
+ *
+ * @param <T> actual SchemaTO
+ * @param attrType kind for schemas to be listed
+ * @param schemaType type for schemas to be listed
+ * @return list of schemas with matching kind and type
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ <T extends AbstractSchemaTO> List<T> list(
+ @NotNull @PathParam("kind") AttributableType attrType, @NotNull @PathParam("type") SchemaType schemaType);
+
+ /**
+ * Creates a new schema.
+ *
+ * @param <T> actual SchemaTO
+ * @param attrType kind for schema to be created
+ * @param schemaType type for schema to be created
+ * @param schemaTO schema to be created
+ * @return <tt>Response</tt> object featuring <tt>Location</tt> header of created schema
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE, value = "Featuring <tt>Location</tt> header of created schema")
+ })
+ @POST
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ <T extends AbstractSchemaTO> Response create(@NotNull @PathParam("kind") AttributableType attrType,
+ @NotNull @PathParam("type") SchemaType schemaType, @NotNull T schemaTO);
+
+ /**
+ * Updates the schema matching the given kind, type and name.
+ *
+ * @param <T> actual SchemaTO
+ * @param attrType kind for schemas to be updated
+ * @param schemaType type for schemas to be updated
+ * @param schemaKey name of schema to be updated
+ * @param schemaTO updated schema to be stored
+ */
+ @PUT
+ @Path("{key}")
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ <T extends AbstractSchemaTO> void update(@NotNull @PathParam("kind") AttributableType attrType,
+ @NotNull @PathParam("type") SchemaType schemaType,
+ @NotNull @PathParam("key") String schemaKey, @NotNull T schemaTO);
+
+ /**
+ * Deletes the schema matching the given kind, type and name.
+ *
+ * @param attrType kind for schema to be deleted
+ * @param schemaType type for schema to be deleted
+ * @param schemaKey name of schema to be deleted
+ */
+ @DELETE
+ @Path("{key}")
+ void delete(@NotNull @PathParam("kind") AttributableType attrType,
+ @NotNull @PathParam("type") SchemaType schemaType,
+ @NotNull @PathParam("key") String schemaKey);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SecurityQuestionService.java
----------------------------------------------------------------------
diff --git a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SecurityQuestionService.java b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SecurityQuestionService.java
new file mode 100644
index 0000000..12a73cf
--- /dev/null
+++ b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SecurityQuestionService.java
@@ -0,0 +1,110 @@
+/*
+ * 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.syncope.common.rest.api.service;
+
+import java.util.List;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.apache.cxf.jaxrs.model.wadl.Descriptions;
+import org.apache.cxf.jaxrs.model.wadl.DocTarget;
+import org.apache.syncope.common.lib.to.SecurityQuestionTO;
+
+/**
+ * REST operations for configuration.
+ */
+@Path("securityQuestions")
+public interface SecurityQuestionService extends JAXRSService {
+
+ /**
+ * Returns a list of all security questions.
+ *
+ * @return list of all security questions
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ List<SecurityQuestionTO> list();
+
+ /**
+ * Returns security question with matching id.
+ *
+ * @param securityQuestionId security question id to be read
+ * @return security question with matching id
+ */
+ @GET
+ @Path("{securityQuestionId}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ SecurityQuestionTO read(@NotNull @PathParam("securityQuestionId") Long securityQuestionId);
+
+ /**
+ * Creates a new security question.
+ *
+ * @param securityQuestionTO security question to be created
+ * @return <tt>Response</tt> object featuring <tt>Location</tt> header of created security question
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring <tt>Location</tt> header of created security question")
+ })
+ @POST
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response create(@NotNull SecurityQuestionTO securityQuestionTO);
+
+ /**
+ * Updates the security question matching the provided id.
+ *
+ * @param securityQuestionId security question id to be updated
+ * @param securityQuestionTO security question to be stored
+ */
+ @PUT
+ @Path("{securityQuestionId}")
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ void update(@NotNull @PathParam("securityQuestionId") Long securityQuestionId,
+ @NotNull SecurityQuestionTO securityQuestionTO);
+
+ /**
+ * Deletes the security question matching the provided id.
+ *
+ * @param securityQuestionId security question id to be deleted
+ */
+ @DELETE
+ @Path("{securityQuestionId}")
+ void delete(@NotNull @PathParam("securityQuestionId") Long securityQuestionId);
+
+ /**
+ * Ask for security question configured for the user matching the given username, if any.
+ *
+ * @param username username for which the security question is requested
+ * @return security question, if configured for the user matching the given username
+ */
+ @GET
+ @Path("byUser/{username}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ SecurityQuestionTO readByUser(@NotNull @PathParam("username") String username);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/TaskService.java
----------------------------------------------------------------------
diff --git a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/TaskService.java b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/TaskService.java
new file mode 100644
index 0000000..c3296dd
--- /dev/null
+++ b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/TaskService.java
@@ -0,0 +1,245 @@
+/*
+ * 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.syncope.common.rest.api.service;
+
+import java.util.List;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.MatrixParam;
+import javax.ws.rs.POST;
+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.apache.cxf.jaxrs.model.wadl.Description;
+import org.apache.cxf.jaxrs.model.wadl.Descriptions;
+import org.apache.cxf.jaxrs.model.wadl.DocTarget;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.PagedResult;
+import org.apache.syncope.common.lib.to.ReportExecTO;
+import org.apache.syncope.common.lib.to.SchedTaskTO;
+import org.apache.syncope.common.lib.to.TaskExecTO;
+import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.common.lib.wrap.JobClass;
+import org.apache.syncope.common.lib.wrap.PushActionClass;
+import org.apache.syncope.common.lib.wrap.SyncActionClass;
+
+/**
+ * REST operations for tasks.
+ */
+@Path("tasks")
+public interface TaskService extends JAXRSService {
+
+ /**
+ * Returns a list of classes to be used for jobs.
+ *
+ * @return list of classes to be used for jobs
+ */
+ @GET
+ @Path("jobClasses")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ List<JobClass> getJobClasses();
+
+ /**
+ * Returns a list of classes to be used as synchronization actions.
+ *
+ * @return list of classes to be used as synchronization actions
+ */
+ @GET
+ @Path("syncActionsClasses")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ List<SyncActionClass> getSyncActionsClasses();
+
+ /**
+ * Returns a list of classes to be used as push actions.
+ *
+ * @return list of classes to be used as push actions
+ */
+ @GET
+ @Path("pushActionsClasses")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ List<PushActionClass> getPushActionsClasses();
+
+ /**
+ * Returns the task matching the given id.
+ *
+ * @param taskKey key of task to be read
+ * @param <T> type of taskTO
+ * @return task with matching id
+ */
+ @GET
+ @Path("{taskKey}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ <T extends AbstractTaskTO> T read(@NotNull @PathParam("taskKey") Long taskKey);
+
+ /**
+ * Returns the task execution with the given id.
+ *
+ * @param executionKey key of task execution to be read
+ * @return task execution with matching Id
+ */
+ @GET
+ @Path("executions/{executionKey}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ TaskExecTO readExecution(@NotNull @PathParam("executionKey") Long executionKey);
+
+ /**
+ * Returns a list of tasks with matching type.
+ *
+ * @param taskType type of tasks to be listed
+ * @param <T> type of taskTO
+ * @return list of tasks with matching type
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ <T extends AbstractTaskTO> PagedResult<T> list(@NotNull @MatrixParam("type") TaskType taskType);
+
+ /**
+ * Returns a list of tasks with matching type.
+ *
+ * @param taskType type of tasks to be listed
+ * @param orderBy list of ordering clauses, separated by comma
+ * @param <T> type of taskTO
+ * @return list of tasks with matching type
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ <T extends AbstractTaskTO> PagedResult<T> list(@NotNull @MatrixParam("type") TaskType taskType,
+ @QueryParam(PARAM_ORDERBY) String orderBy);
+
+ /**
+ * Returns a paged list of existing tasks matching type and page/size conditions.
+ *
+ * @param taskType type of tasks to be listed
+ * @param page page number of tasks in relation to page size
+ * @param size number of tasks listed per page
+ * @param orderBy list of ordering clauses, separated by comma
+ * @param <T> type of taskTO
+ * @return paged list of existing tasks matching type and page/size conditions
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ <T extends AbstractTaskTO> PagedResult<T> list(@NotNull @MatrixParam("type") TaskType taskType,
+ @NotNull @Min(1) @QueryParam(PARAM_PAGE) @DefaultValue(DEFAULT_PARAM_PAGE) Integer page,
+ @NotNull @Min(1) @QueryParam(PARAM_SIZE) @DefaultValue(DEFAULT_PARAM_SIZE) Integer size,
+ @QueryParam(PARAM_ORDERBY) String orderBy);
+
+ /**
+ * Returns a paged list of existing tasks matching type and page/size conditions.
+ *
+ * @param taskType type of tasks to be listed
+ * @param page page number of tasks in relation to page size
+ * @param size number of tasks listed per page
+ * @param <T> type of taskTO
+ * @return paged list of existing tasks matching type and page/size conditions
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ <T extends AbstractTaskTO> PagedResult<T> list(@MatrixParam("type") TaskType taskType,
+ @NotNull @Min(1) @QueryParam(PARAM_PAGE) @DefaultValue(DEFAULT_PARAM_PAGE) Integer page,
+ @NotNull @Min(1) @QueryParam(PARAM_SIZE) @DefaultValue(DEFAULT_PARAM_SIZE) Integer size);
+
+ /**
+ * Creates a new task.
+ *
+ * @param taskTO task to be created
+ * @param <T> type of taskTO
+ * @return <tt>Response</tt> object featuring <tt>Location</tt> header of created task
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE, value = "Featuring <tt>Location</tt> header of created task")
+ })
+ @POST
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ <T extends SchedTaskTO> Response create(@NotNull T taskTO);
+
+ /**
+ * Updates the task matching the provided key.
+ *
+ * @param taskKey key of task to be updated
+ * @param taskTO updated task to be stored
+ */
+ @PUT
+ @Path("{taskKey}")
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ void update(@NotNull @PathParam("taskKey") Long taskKey, @NotNull AbstractTaskTO taskTO);
+
+ /**
+ * Deletes the task matching the provided key.
+ *
+ * @param taskKey key of task to be deleted
+ */
+ @DELETE
+ @Path("{taskKey}")
+ void delete(@NotNull @PathParam("taskKey") Long taskKey);
+
+ /**
+ * Deletes the task execution matching the provided key.
+ *
+ * @param executionKey key of task execution to be deleted
+ */
+ @DELETE
+ @Path("executions/{executionKey}")
+ void deleteExecution(@NotNull @PathParam("executionKey") Long executionKey);
+
+ /**
+ * Executes the task matching the given id.
+ *
+ * @param taskKey key of task to be executed
+ * @param dryRun if true, task will only be simulated
+ * @return execution report for the task matching the given id
+ */
+ @POST
+ @Path("{taskKey}/execute")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ TaskExecTO execute(@NotNull @PathParam("taskKey") Long taskKey,
+ @QueryParam("dryRun") @DefaultValue("false") boolean dryRun);
+
+ /**
+ * Reports task execution result.
+ *
+ * @param executionKey key of task execution being reported
+ * @param reportExec execution being reported
+ */
+ @POST
+ @Path("executions/{executionKey}/report")
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ void report(@NotNull @PathParam("executionKey") Long executionKey, @NotNull ReportExecTO reportExec);
+
+ /**
+ * Executes the provided bulk action.
+ *
+ * @param bulkAction list of task ids against which the bulk action will be performed.
+ * @return Bulk action result
+ */
+ @POST
+ @Path("bulk")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ BulkActionResult bulk(@NotNull BulkAction bulkAction);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserSelfService.java
----------------------------------------------------------------------
diff --git a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserSelfService.java b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserSelfService.java
new file mode 100644
index 0000000..cd3a302
--- /dev/null
+++ b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserSelfService.java
@@ -0,0 +1,145 @@
+/*
+ * 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.syncope.common.rest.api.service;
+
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+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.apache.cxf.jaxrs.model.wadl.Description;
+import org.apache.cxf.jaxrs.model.wadl.Descriptions;
+import org.apache.cxf.jaxrs.model.wadl.DocTarget;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.UserTO;
+
+/**
+ * REST operations for user self-management.
+ */
+@Path("users/self")
+public interface UserSelfService extends JAXRSService {
+
+ /**
+ * Checks whether self-registration is allowed.
+ *
+ * @return <tt>Response</tt> contains special Syncope HTTP header indicating if user self registration and / or
+ * password reset is allowed
+ * @see org.apache.syncope.common.types.RESTHeaders#SELFREG_ALLOWED
+ * @see org.apache.syncope.common.types.RESTHeaders#PWDRESET_ALLOWED
+ * @see org.apache.syncope.common.types.RESTHeaders#PWDRESET_NEEDS_SECURITYQUESTIONS
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Contains special Syncope HTTP header indicating if user self registration "
+ + "and / or password reset is allowed")
+ })
+ @OPTIONS
+ Response getOptions();
+
+ /**
+ * Returns the user making the service call.
+ *
+ * @return calling user data
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ UserTO read();
+
+ /**
+ * Self-registration for new user.
+ *
+ * @param userTO user to be created
+ * @param storePassword whether password shall be stored internally
+ * @return <tt>Response</tt> object featuring <tt>Location</tt> header of self-registered user as well as the user
+ * itself - {@link UserTO} as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring <tt>Location</tt> header of self-registered user as well "
+ + "as the user itself - {@link UserTO} as <tt>Entity</tt>")
+ })
+ @POST
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response create(@NotNull UserTO userTO,
+ @DefaultValue("true") @QueryParam("storePassword") boolean storePassword);
+
+ /**
+ * Self-updates user.
+ *
+ * @param userKey id of user to be updated
+ * @param userMod modification to be applied to user matching the provided userKey
+ * @return <tt>Response</tt> object featuring the updated user - {@link UserTO} as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring the updated user - <tt>UserTO</tt> as <tt>Entity</tt>")
+ })
+ @POST
+ @Path("{userKey}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response update(@NotNull @PathParam("userKey") Long userKey, @NotNull UserMod userMod);
+
+ /**
+ * Self-deletes user.
+ *
+ * @return <tt>Response</tt> object featuring the deleted user - {@link UserTO} as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring the deleted user - <tt>UserTO</tt> as <tt>Entity</tt>")
+ })
+ @DELETE
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response delete();
+
+ /**
+ * Provides answer for the security question configured for user matching the given username, if any.
+ * If provided anwser matches the one stored for that user, a password reset token is internally generated,
+ * otherwise an error is returned.
+ *
+ * @param username username for which the security answer is provided
+ * @param securityAnswer actual answer text
+ */
+ @POST
+ @Path("requestPasswordReset")
+ void requestPasswordReset(@NotNull @QueryParam("username") String username, String securityAnswer);
+
+ /**
+ * Reset the password value for the user matching the provided token, if available and still valid.
+ * If the token actually matches one of users, and if it is still valid at the time of submission, the matching
+ * user's password value is set as provided. The new password value will need anyway to comply with all relevant
+ * password policies.
+ *
+ * @param token password reset token
+ * @param password new password to be set
+ */
+ @POST
+ @Path("confirmPasswordReset")
+ void confirmPasswordReset(@NotNull @QueryParam("token") String token, String password);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
----------------------------------------------------------------------
diff --git a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
new file mode 100644
index 0000000..ea1d197
--- /dev/null
+++ b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
@@ -0,0 +1,321 @@
+/*
+ * 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.syncope.common.rest.api.service;
+
+import java.util.List;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+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.apache.cxf.jaxrs.model.wadl.Description;
+import org.apache.cxf.jaxrs.model.wadl.Descriptions;
+import org.apache.cxf.jaxrs.model.wadl.DocTarget;
+import org.apache.syncope.common.lib.mod.ResourceAssociationMod;
+import org.apache.syncope.common.lib.mod.StatusMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.PagedResult;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.ResourceAssociationActionType;
+import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
+import org.apache.syncope.common.lib.wrap.ResourceName;
+
+/**
+ * REST operations for users.
+ */
+@Path("users")
+public interface UserService extends JAXRSService {
+
+ /**
+ * Gives the username for the provided user key.
+ *
+ * @param userKey user key
+ * @return <tt>Response</tt> object featuring HTTP header with username matching the given userKey
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring HTTP header with username matching the given userKey")
+ })
+ @OPTIONS
+ @Path("{userKey}/username")
+ Response getUsername(@NotNull @PathParam("userKey") Long userKey);
+
+ /**
+ * Gives the user key for the provided username.
+ *
+ * @param username username
+ * @return <tt>Response</tt> object featuring HTTP header with userKey matching the given username
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring HTTP header with userKey matching the given username")
+ })
+ @OPTIONS
+ @Path("{username}/userKey")
+ Response getUserId(@NotNull @PathParam("username") String username);
+
+ /**
+ * Reads the user matching the provided userKey.
+ *
+ * @param userKey id of user to be read
+ * @return User matching the provided userKey
+ */
+ @GET
+ @Path("{userKey}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ UserTO read(@NotNull @PathParam("userKey") Long userKey);
+
+ /**
+ * Returns a paged list of existing users.
+ *
+ * @return paged list of all existing users
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<UserTO> list();
+
+ /**
+ * Returns a paged list of existing users.
+ *
+ * @param orderBy list of ordering clauses, separated by comma
+ * @return paged list of all existing users
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<UserTO> list(@QueryParam(PARAM_ORDERBY) String orderBy);
+
+ /**
+ * Returns a paged list of existing users matching page/size conditions.
+ *
+ * @param page result page number
+ * @param size number of entries per page
+ * @return paged list of existing users matching page/size conditions
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<UserTO> list(
+ @NotNull @Min(1) @QueryParam(PARAM_PAGE) @DefaultValue(DEFAULT_PARAM_PAGE) Integer page,
+ @NotNull @Min(1) @QueryParam(PARAM_SIZE) @DefaultValue(DEFAULT_PARAM_SIZE) Integer size);
+
+ /**
+ * Returns a paged list of existing users matching page/size conditions.
+ *
+ * @param page result page number
+ * @param size number of entries per page
+ * @param orderBy list of ordering clauses, separated by comma
+ * @return paged list of existing users matching page/size conditions
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<UserTO> list(
+ @NotNull @Min(1) @QueryParam(PARAM_PAGE) @DefaultValue(DEFAULT_PARAM_PAGE) Integer page,
+ @NotNull @Min(1) @QueryParam(PARAM_SIZE) @DefaultValue(DEFAULT_PARAM_SIZE) Integer size,
+ @QueryParam(PARAM_ORDERBY) String orderBy);
+
+ /**
+ * Returns a paged list of users matching the provided FIQL search condition.
+ *
+ * @param fiql FIQL search expression
+ * @return paged list of users matching the provided FIQL search condition
+ */
+ @GET
+ @Path("search")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<UserTO> search(@NotNull @QueryParam(PARAM_FIQL) String fiql);
+
+ /**
+ * Returns a paged list of users matching the provided FIQL search condition.
+ *
+ * @param fiql FIQL search expression
+ * @param orderBy list of ordering clauses, separated by comma
+ * @return paged list of users matching the provided FIQL search condition
+ */
+ @GET
+ @Path("search")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<UserTO> search(@NotNull @QueryParam(PARAM_FIQL) String fiql, @QueryParam(PARAM_ORDERBY) String orderBy);
+
+ /**
+ * Returns a paged list of users matching the provided FIQL search condition.
+ *
+ * @param fiql FIQL search expression
+ * @param page result page number
+ * @param size number of entries per page
+ * @return paged list of users matching the provided FIQL search condition
+ */
+ @GET
+ @Path("search")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<UserTO> search(@QueryParam(PARAM_FIQL) String fiql,
+ @NotNull @Min(1) @QueryParam(PARAM_PAGE) @DefaultValue(DEFAULT_PARAM_PAGE) Integer page,
+ @NotNull @Min(1) @QueryParam(PARAM_SIZE) @DefaultValue(DEFAULT_PARAM_SIZE) Integer size);
+
+ /**
+ * Returns a paged list of users matching the provided FIQL search condition.
+ *
+ * @param fiql FIQL search expression
+ * @param page result page number
+ * @param size number of entries per page
+ * @param orderBy list of ordering clauses, separated by comma
+ * @return paged list of users matching the provided FIQL search condition
+ */
+ @GET
+ @Path("search")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ PagedResult<UserTO> search(@QueryParam(PARAM_FIQL) String fiql,
+ @NotNull @Min(1) @QueryParam(PARAM_PAGE) @DefaultValue(DEFAULT_PARAM_PAGE) Integer page,
+ @NotNull @Min(1) @QueryParam(PARAM_SIZE) @DefaultValue(DEFAULT_PARAM_SIZE) Integer size,
+ @QueryParam(PARAM_ORDERBY) String orderBy);
+
+ /**
+ * Creates a new user.
+ *
+ * @param userTO user to be created
+ * @param storePassword whether password shall be stored internally
+ * @return <tt>Response</tt> object featuring <tt>Location</tt> header of created user as well as the user itself
+ * enriched with propagation status information - {@link UserTO} as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring <tt>Location</tt> header of created user as well as the "
+ + "user itself enriched with propagation status information - <tt>UserTO</tt> as <tt>Entity</tt>")
+ })
+ @POST
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response create(@NotNull UserTO userTO,
+ @DefaultValue("true") @QueryParam("storePassword") boolean storePassword);
+
+ /**
+ * Updates user matching the provided userKey.
+ *
+ * @param userKey id of user to be updated
+ * @param userMod modification to be applied to user matching the provided userKey
+ * @return <tt>Response</tt> object featuring the updated user enriched with propagation status information
+ * - {@link UserTO} as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring the updated user enriched with propagation status information - "
+ + "<tt>UserTO</tt> as <tt>Entity</tt>")
+ })
+ @POST
+ @Path("{userKey}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response update(@NotNull @PathParam("userKey") Long userKey, @NotNull UserMod userMod);
+
+ /**
+ * Performs a status update on user matching provided userKey.
+ *
+ * @param userKey id of user to be subjected to status update
+ * @param statusMod status update details
+ * @return <tt>Response</tt> object featuring the updated user enriched with propagation status information
+ * - {@link UserTO} as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring the updated user enriched with propagation status information - "
+ + "<tt>UserTO</tt> as <tt>Entity</tt>")
+ })
+ @POST
+ @Path("{userKey}/status")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response status(@NotNull @PathParam("userKey") Long userKey, @NotNull StatusMod statusMod);
+
+ /**
+ * Deletes user matching provided userKey.
+ *
+ * @param userKey id of user to be deleted
+ * @return <tt>Response</tt> object featuring the deleted user enriched with propagation status information
+ * - {@link UserTO} as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring the deleted user enriched with propagation status information - "
+ + "<tt>UserTO</tt> as <tt>Entity</tt>")
+ })
+ @DELETE
+ @Path("{userKey}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response delete(@NotNull @PathParam("userKey") Long userKey);
+
+ /**
+ * Executes resource-related operations on given user.
+ *
+ * @param userKey user key
+ * @param type resource de-association action type
+ * @param resourceNames external resources to be used for propagation-related operations
+ * @return <tt>Response</tt> object featuring {@link BulkActionResult} as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Featuring <tt>BulkActionResult</tt> as <tt>Entity</tt>")
+ })
+ @POST
+ @Path("{userKey}/bulkDeassociation/{type}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response bulkDeassociation(@NotNull @PathParam("userKey") Long userKey,
+ @NotNull @PathParam("type") ResourceDeassociationActionType type,
+ @NotNull List<ResourceName> resourceNames);
+
+ /**
+ * Executes resource-related operations on given user.
+ *
+ * @param userKey user key.
+ * @param type resource association action type
+ * @param associationMod external resources to be used for propagation-related operations
+ * @return <tt>Response</tt> object featuring {@link BulkActionResult} as <tt>Entity</tt>
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE, value = "Featuring <tt>BulkActionResult</tt> as <tt>Entity</tt>")
+ })
+ @POST
+ @Path("{userKey}/bulkAssociation/{type}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response bulkAssociation(@NotNull @PathParam("userKey") Long userKey,
+ @NotNull @PathParam("type") ResourceAssociationActionType type,
+ @NotNull ResourceAssociationMod associationMod);
+
+ /**
+ * Executes the provided bulk action.
+ *
+ * @param bulkAction list of user keys against which the bulk action will be performed.
+ * @return Bulk action result
+ */
+ @POST
+ @Path("bulk")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ BulkActionResult bulk(@NotNull BulkAction bulkAction);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserWorkflowService.java
----------------------------------------------------------------------
diff --git a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserWorkflowService.java b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserWorkflowService.java
new file mode 100644
index 0000000..256317d
--- /dev/null
+++ b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserWorkflowService.java
@@ -0,0 +1,108 @@
+/*
+ * 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.syncope.common.rest.api.service;
+
+import java.util.List;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.to.WorkflowFormTO;
+
+/**
+ * REST operations related to user workflow.
+ */
+@Path("userworkflow")
+public interface UserWorkflowService extends JAXRSService {
+
+ /**
+ * Returns a list of all available workflow forms.
+ *
+ * @return list of all available workflow forms
+ */
+ @GET
+ @Path("forms")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ List<WorkflowFormTO> getForms();
+
+ /**
+ * Returns a list of all available workflow forms with matching name, for the given user key.
+ *
+ * @param userKey user key
+ * @param name form name
+ * @return list of all available workflow forms with matching name, fir the given user key.
+ */
+ @GET
+ @Path("forms/{userKey}/{name}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ List<WorkflowFormTO> getFormsByName(
+ @NotNull @PathParam("userKey") final Long userKey, @NotNull @PathParam("name") final String name);
+
+ /**
+ * Returns a list of available forms for the given user key.
+ *
+ * @param userKey user key
+ * @return list of available forms for the given user key
+ */
+ @GET
+ @Path("forms/{userKey}")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ WorkflowFormTO getFormForUser(@NotNull @PathParam("userKey") Long userKey);
+
+ /**
+ * Claims the form for the given task id.
+ *
+ * @param taskId workflow task id
+ * @return the workflow form for the given task id
+ */
+ @POST
+ @Path("forms/{taskId}/claim")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ WorkflowFormTO claimForm(@NotNull @PathParam("taskId") String taskId);
+
+ /**
+ * Submits a workflow form.
+ *
+ * @param form workflow form.
+ * @return updated user
+ */
+ @POST
+ @Path("forms")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ UserTO submitForm(@NotNull WorkflowFormTO form);
+
+ /**
+ * Executes workflow task for matching id.
+ *
+ * @param taskId workflow task id
+ * @param userTO argument to be passed to workflow task
+ * @return updated user
+ */
+ @POST
+ @Path("tasks/{taskId}/execute")
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ UserTO executeTask(@NotNull @PathParam("taskId") String taskId, @NotNull UserTO userTO);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/WorkflowService.java
----------------------------------------------------------------------
diff --git a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/WorkflowService.java b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/WorkflowService.java
new file mode 100644
index 0000000..709ab37
--- /dev/null
+++ b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/WorkflowService.java
@@ -0,0 +1,90 @@
+/*
+ * 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.syncope.common.rest.api.service;
+
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.apache.cxf.jaxrs.model.wadl.Descriptions;
+import org.apache.cxf.jaxrs.model.wadl.DocTarget;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+
+/**
+ * REST operations for workflow definition management.
+ */
+@Path("workflows/{kind}")
+public interface WorkflowService extends JAXRSService {
+
+ /**
+ * Checks whether Activiti is enabled (for users or roles).
+ *
+ * @param kind user or role
+ * @return <tt>Response</tt> contains special syncope HTTP header indicating if Activiti is enabled for
+ * users / roles
+ * @see org.apache.syncope.common.types.RESTHeaders#ACTIVITI_USER_ENABLED
+ * @see org.apache.syncope.common.types.RESTHeaders#ACTIVITI_ROLE_ENABLED
+ */
+ @Descriptions({
+ @Description(target = DocTarget.RESPONSE,
+ value = "Contains special syncope HTTP header indicating if Activiti is enabled for users / roles")
+ })
+ @OPTIONS
+ Response getOptions(@NotNull @PathParam("kind") SubjectType kind);
+
+ /**
+ * Exports workflow definition for matching kind.
+ *
+ * @param kind user or role
+ * @return workflow definition for matching kind
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ Response exportDefinition(@NotNull @PathParam("kind") SubjectType kind);
+
+ /**
+ * Exports workflow diagram representation.
+ *
+ * @param kind user or role
+ * @return workflow diagram representation
+ */
+ @GET
+ @Path("diagram.png")
+ @Produces({ RESTHeaders.MEDIATYPE_IMAGE_PNG })
+ Response exportDiagram(@NotNull @PathParam("kind") SubjectType kind);
+
+ /**
+ * Imports workflow definition for matching kind.
+ *
+ * @param kind user or role
+ * @param definition workflow definition for matching kind
+ */
+ @PUT
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ void importDefinition(@NotNull @PathParam("kind") SubjectType kind, @NotNull String definition);
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/WorkflowLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/WorkflowLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/WorkflowLogic.java
index 2e5ae74..f7a11fd 100644
--- a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/WorkflowLogic.java
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/WorkflowLogic.java
@@ -93,6 +93,7 @@ public class WorkflowLogic extends AbstractTransactionalLogic<AbstractBaseBean>
private void importDefinition(
final WorkflowAdapter adapter, final WorkflowDefinitionFormat format, final String definition) {
+
adapter.importDefinition(format, definition);
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/server/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/server/pom.xml b/syncope620/server/pom.xml
index 9db6358..240c8c3 100644
--- a/syncope620/server/pom.xml
+++ b/syncope620/server/pom.xml
@@ -42,6 +42,7 @@ under the License.
<module>workflow-api</module>
<module>workflow-java</module>
<module>logic</module>
+ <module>rest-cxf</module>
</modules>
</project>
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/server/rest-cxf/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/server/rest-cxf/pom.xml b/syncope620/server/rest-cxf/pom.xml
new file mode 100644
index 0000000..c8e020c
--- /dev/null
+++ b/syncope620/server/rest-cxf/pom.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.syncope</groupId>
+ <artifactId>syncope-server</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </parent>
+
+ <name>Apache Syncope Server REST CXF</name>
+ <description>Apache Syncope Server REST CXF</description>
+ <groupId>org.apache.syncope.server</groupId>
+ <artifactId>syncope-server-rest-cxf</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-jpa_2.0_spec</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-orm</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.jaxrs</groupId>
+ <artifactId>jackson-jaxrs-json-provider</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.module</groupId>
+ <artifactId>jackson-module-afterburner</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-extension-providers</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-extension-search</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-frontend-jaxws</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-service-description</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-client</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.syncope.server</groupId>
+ <artifactId>syncope-server-logic</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.syncope.common</groupId>
+ <artifactId>syncope-common-rest-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/QueryResourceInfoComparator.java
----------------------------------------------------------------------
diff --git a/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/QueryResourceInfoComparator.java b/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/QueryResourceInfoComparator.java
new file mode 100644
index 0000000..7c879c8
--- /dev/null
+++ b/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/QueryResourceInfoComparator.java
@@ -0,0 +1,113 @@
+/*
+ * 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.syncope.server.rest.cxf;
+
+import java.util.List;
+import java.util.Map;
+import org.apache.cxf.jaxrs.ext.ResourceComparator;
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.model.OperationResourceInfo;
+import org.apache.cxf.jaxrs.model.OperationResourceInfoComparator;
+import org.apache.cxf.jaxrs.model.Parameter;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
+import org.apache.cxf.message.Message;
+
+public class QueryResourceInfoComparator extends OperationResourceInfoComparator implements ResourceComparator {
+
+ public QueryResourceInfoComparator() {
+ super(null, null);
+ }
+
+ @Override
+ public int compare(final ClassResourceInfo cri1, final ClassResourceInfo cri2, final Message message) {
+ // Leave Class selection to CXF
+ return 0;
+ }
+
+ @Override
+ public int compare(final OperationResourceInfo oper1, final OperationResourceInfo oper2, final Message message) {
+ // Check if CXF can make a decision
+ int cxfResult = super.compare(oper1, oper2);
+ if (cxfResult != 0) {
+ return cxfResult;
+ }
+
+ int op1Counter = getMatchingRate(oper1, message);
+ int op2Counter = getMatchingRate(oper2, message);
+
+ return op1Counter == op2Counter
+ ? 0
+ : op1Counter < op2Counter
+ ? 1
+ : -1;
+ }
+
+ /**
+ * This method calculates a number indicating a good or bad match between values provided within the request and
+ * expected method parameters. A higher number means a better match.
+ *
+ * @param operation The operation to be rated, based on contained parameterInfo values.
+ * @param message A message containing query and header values from user request
+ * @return A positive or negative number, indicating a good match between query and method
+ */
+ protected int getMatchingRate(final OperationResourceInfo operation, final Message message) {
+ List<Parameter> params = operation.getParameters();
+ if (params == null || params.isEmpty()) {
+ return 0;
+ }
+
+ // Get Request QueryParams
+ String query = (String) message.get(Message.QUERY_STRING);
+ String path = (String) message.get(Message.REQUEST_URI);
+ Map<String, List<String>> qParams = JAXRSUtils.getStructuredParams(query, "&", true, false);
+ Map<String, List<String>> mParams = JAXRSUtils.getMatrixParams(path, true);
+ // Get Request Headers
+ Map<?, ?> qHeader = (java.util.Map<?, ?>) message.get(Message.PROTOCOL_HEADERS);
+
+ int rate = 0;
+ for (Parameter p : params) {
+ switch (p.getType()) {
+ case QUERY:
+ if (qParams.containsKey(p.getName())) {
+ rate += 2;
+ } else if (p.getDefaultValue() == null) {
+ rate -= 1;
+ }
+ break;
+ case MATRIX:
+ if (mParams.containsKey(p.getName())) {
+ rate += 2;
+ } else if (p.getDefaultValue() == null) {
+ rate -= 1;
+ }
+ break;
+ case HEADER:
+ if (qHeader.containsKey(p.getName())) {
+ rate += 2;
+ } else if (p.getDefaultValue() == null) {
+ rate -= 1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return rate;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/AbstractServiceImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/AbstractServiceImpl.java b/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/AbstractServiceImpl.java
new file mode 100644
index 0000000..9168ab1
--- /dev/null
+++ b/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/AbstractServiceImpl.java
@@ -0,0 +1,227 @@
+/*
+ * 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.syncope.server.rest.cxf.service;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.EntityTag;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.cxf.jaxrs.ext.MessageContext;
+import org.apache.cxf.jaxrs.ext.search.SearchBean;
+import org.apache.cxf.jaxrs.ext.search.SearchCondition;
+import org.apache.cxf.jaxrs.ext.search.SearchContext;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.PagedResult;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.rest.api.service.JAXRSService;
+import org.apache.syncope.common.rest.api.Preference;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.server.misc.search.SearchCondVisitor;
+import org.apache.syncope.server.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.server.persistence.api.dao.search.SearchCond;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+abstract class AbstractServiceImpl implements JAXRSService {
+
+ /**
+ * Logger.
+ */
+ protected static final Logger LOG = LoggerFactory.getLogger(AbstractServiceImpl.class);
+
+ protected static final String OPTIONS_ALLOW = "GET,POST,OPTIONS,HEAD";
+
+ @Context
+ protected UriInfo uriInfo;
+
+ @Context
+ protected MessageContext messageContext;
+
+ @Context
+ protected SearchContext searchContext;
+
+ /**
+ * Reads <tt>Prefer</tt> header from request and parses into a <tt>Preference</tt> instance.
+ *
+ * @return a <tt>Preference</tt> instance matching the passed <tt>Prefer</tt> header,
+ * or <tt>Preference.NONE</tt> if missing.
+ */
+ protected Preference getPreference() {
+ return Preference.fromString(messageContext.getHttpHeaders().getHeaderString(RESTHeaders.PREFER));
+ }
+
+ /**
+ * Builds response to successful <tt>create</tt> request, taking into account any <tt>Prefer</tt> header.
+ *
+ * @param id identifier of the created entity
+ * @param entity the entity just created
+ * @return response to successful <tt>create</tt> request
+ */
+ protected Response createResponse(final Object id, final Object entity) {
+ URI location = uriInfo.getAbsolutePathBuilder().path(String.valueOf(id)).build();
+
+ Response.ResponseBuilder builder = Response.
+ created(location).
+ header(RESTHeaders.RESOURCE_ID, id);
+
+ switch (getPreference()) {
+ case RETURN_NO_CONTENT:
+ break;
+
+ case RETURN_CONTENT:
+ case NONE:
+ default:
+ builder = builder.entity(entity);
+ break;
+
+ }
+ if (getPreference() == Preference.RETURN_CONTENT || getPreference() == Preference.RETURN_NO_CONTENT) {
+ builder = builder.header(RESTHeaders.PREFERENCE_APPLIED, getPreference().toString());
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Builds response to successful modification request, taking into account any <tt>Prefer</tt> header.
+ *
+ * @param entity the entity just modified
+ * @return response to successful modification request
+ */
+ protected Response modificationResponse(final Object entity) {
+ Response.ResponseBuilder builder;
+ switch (getPreference()) {
+ case RETURN_NO_CONTENT:
+ builder = Response.noContent();
+ break;
+
+ case RETURN_CONTENT:
+ case NONE:
+ default:
+ builder = Response.ok(entity);
+ break;
+ }
+ if (getPreference() == Preference.RETURN_CONTENT || getPreference() == Preference.RETURN_NO_CONTENT) {
+ builder = builder.header(RESTHeaders.PREFERENCE_APPLIED, getPreference().toString());
+ }
+
+ return builder.build();
+ }
+
+ protected void checkETag(final String etag) {
+ Response.ResponseBuilder builder = messageContext.getRequest().evaluatePreconditions(new EntityTag(etag));
+ if (builder != null) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.ConcurrentModification);
+ sce.getElements().add("Mismatching ETag value");
+ throw sce;
+ }
+ }
+
+ protected SearchCond getSearchCond(final String fiql) {
+ try {
+ SearchCondVisitor visitor = new SearchCondVisitor();
+ SearchCondition<SearchBean> sc = searchContext.getCondition(fiql, SearchBean.class);
+ sc.accept(visitor);
+
+ return visitor.getQuery();
+ } catch (Exception e) {
+ LOG.error("Invalid FIQL expression: {}", fiql, e);
+
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSearchExpression);
+ sce.getElements().add(fiql);
+ throw sce;
+ }
+ }
+
+ protected List<OrderByClause> getOrderByClauses(final String orderBy) {
+ if (StringUtils.isBlank(orderBy)) {
+ return Collections.<OrderByClause>emptyList();
+ }
+
+ List<OrderByClause> result = new ArrayList<OrderByClause>();
+
+ for (String clause : orderBy.split(",")) {
+ String[] elems = clause.split(" ");
+
+ if (elems.length > 0 && StringUtils.isNotBlank(elems[0])) {
+ OrderByClause obc = new OrderByClause();
+ obc.setField(elems[0].trim());
+ if (elems.length > 1 && StringUtils.isNotBlank(elems[1])) {
+ obc.setDirection(elems[1].trim().equalsIgnoreCase(OrderByClause.Direction.ASC.name())
+ ? OrderByClause.Direction.ASC : OrderByClause.Direction.DESC);
+ }
+ result.add(obc);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Builds a paged result out of a list of items and additional information.
+ *
+ * @param <T> result type
+ * @param list bare list of items to be returned
+ * @param page current page
+ * @param size requested size
+ * @param totalCount total result size (not considering pagination)
+ * @return paged result
+ */
+ protected <T extends AbstractBaseBean> PagedResult<T> buildPagedResult(
+ final List<T> list, final int page, final int size, final int totalCount) {
+
+ PagedResult<T> result = new PagedResult<T>();
+ result.getResult().addAll(list);
+
+ result.setPage(page);
+ result.setSize(result.getResult().size());
+ result.setTotalCount(totalCount);
+
+ UriBuilder builder = uriInfo.getAbsolutePathBuilder();
+ MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
+ for (Map.Entry<String, List<String>> queryParam : queryParams.entrySet()) {
+ builder = builder.queryParam(queryParam.getKey(), queryParam.getValue().toArray());
+ }
+
+ if (result.getPage() > 1) {
+ result.setPrev(builder.
+ replaceQueryParam(PARAM_PAGE, result.getPage() - 1).
+ replaceQueryParam(PARAM_SIZE, size).
+ build());
+ }
+ if ((result.getPage() - 1) * size + result.getSize() < totalCount) {
+ result.setNext(builder.
+ replaceQueryParam(PARAM_PAGE, result.getPage() + 1).
+ replaceQueryParam(PARAM_SIZE, size).
+ build());
+ }
+
+ return result;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/AddETagFilter.java
----------------------------------------------------------------------
diff --git a/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/AddETagFilter.java b/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/AddETagFilter.java
new file mode 100644
index 0000000..164e1be
--- /dev/null
+++ b/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/AddETagFilter.java
@@ -0,0 +1,50 @@
+/*
+ * 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.syncope.server.rest.cxf.service;
+
+import java.io.IOException;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerResponseContext;
+import javax.ws.rs.container.ContainerResponseFilter;
+import javax.ws.rs.core.EntityTag;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.ext.Provider;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.to.AbstractAnnotatedBean;
+
+/**
+ * Adds the <tt>ETag</tt> filter to any response containing an instance of <tt>AbstractSysInfoTO</tt> as entity.
+ * The actual ETag value is computed on the basis of last change date (or creation date if not available).
+ *
+ * @see AbstractSysInfoTO
+ */
+@Provider
+public class AddETagFilter implements ContainerResponseFilter {
+
+ @Override
+ public void filter(final ContainerRequestContext reqCtx, final ContainerResponseContext resCtx) throws IOException {
+ if (resCtx.getEntity() instanceof AbstractAnnotatedBean && resCtx.getEntityTag() == null) {
+ AbstractAnnotatedBean sysInfo = (AbstractAnnotatedBean) resCtx.getEntity();
+ String etagValue = sysInfo.getETagValue();
+ if (StringUtils.isNotBlank(etagValue)) {
+ resCtx.getHeaders().add(HttpHeaders.ETAG, new EntityTag(etagValue).toString());
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/8b4e52d7/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/ConfigurationServiceImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/ConfigurationServiceImpl.java b/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/ConfigurationServiceImpl.java
new file mode 100644
index 0000000..3a06c51
--- /dev/null
+++ b/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/ConfigurationServiceImpl.java
@@ -0,0 +1,91 @@
+/*
+ * 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.syncope.server.rest.cxf.service;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.ConfTO;
+import org.apache.syncope.common.lib.wrap.MailTemplate;
+import org.apache.syncope.common.lib.wrap.Validator;
+import org.apache.syncope.common.rest.api.CollectionWrapper;
+import org.apache.syncope.common.rest.api.service.ConfigurationService;
+import org.apache.syncope.server.logic.ConfigurationLogic;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ConfigurationServiceImpl extends AbstractServiceImpl implements ConfigurationService {
+
+ private static final String CONTENT_XML = "content.xml";
+
+ @Autowired
+ private ConfigurationLogic logic;
+
+ @Override
+ public Response export() {
+ StreamingOutput sout = new StreamingOutput() {
+
+ @Override
+ public void write(final OutputStream os) throws IOException {
+ logic.export(os);
+ }
+ };
+ return Response.ok(sout).
+ type(MediaType.TEXT_XML).
+ header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + CONTENT_XML).
+ build();
+ }
+
+ @Override
+ public void delete(final String key) {
+ logic.delete(key);
+ }
+
+ @Override
+ public List<MailTemplate> getMailTemplates() {
+ return CollectionWrapper.wrap(logic.getMailTemplates(), MailTemplate.class);
+ }
+
+ @Override
+ public List<Validator> getValidators() {
+ return CollectionWrapper.wrap(logic.getValidators(), Validator.class);
+ }
+
+ @Override
+ public ConfTO list() {
+ return logic.list();
+ }
+
+ @Override
+ public AttrTO read(final String key) {
+ return logic.read(key);
+ }
+
+ @Override
+ public void set(final String key, final AttrTO value) {
+ value.setSchema(key);
+ logic.set(value);
+ }
+}