提交 8fcd1c66 编写于 作者: F Frederik Heremans

Added identitylinks to process-instance REST

上级 fe7cb41a
......@@ -301,10 +301,10 @@ public class RestResponseFactory {
}
public RestIdentityLink createRestIdentityLink(SecuredResource securedResource, IdentityLink link) {
return createRestIdentityLink(securedResource, link.getType(), link.getUserId(), link.getGroupId(), link.getTaskId(), link.getProcessDefinitionId());
return createRestIdentityLink(securedResource, link.getType(), link.getUserId(), link.getGroupId(), link.getTaskId(), link.getProcessDefinitionId(), link.getProcessInstanceId());
}
public RestIdentityLink createRestIdentityLink(SecuredResource securedResource, String type, String userId, String groupId, String taskId, String processDefinitionId) {
public RestIdentityLink createRestIdentityLink(SecuredResource securedResource, String type, String userId, String groupId, String taskId, String processDefinitionId, String processInstanceId) {
RestIdentityLink result = new RestIdentityLink();
result.setUser(userId);
result.setGroup(groupId);
......@@ -318,8 +318,10 @@ public class RestResponseFactory {
}
if(processDefinitionId != null) {
result.setUrl(securedResource.createFullResourceUrl(RestUrls.URL_PROCESS_DEFINITION_IDENTITYLINK, processDefinitionId, family, (userId != null ? userId : groupId)));
} else {
} else if(taskId != null){
result.setUrl(securedResource.createFullResourceUrl(RestUrls.URL_TASK_IDENTITYLINK, taskId, family, (userId != null ? userId : groupId), type));
} else {
result.setUrl(securedResource.createFullResourceUrl(RestUrls.URL_PROCESS_INSTANCE_IDENTITYLINK, processInstanceId, (userId != null ? userId : groupId), type));
}
return result;
}
......
......@@ -253,6 +253,16 @@ public final class RestUrls {
*/
public static final String[] URL_PROCESS_INSTANCE_COMMENT = {SEGMENT_RUNTIME_RESOURCES, SEGMENT_PROCESS_INSTANCE_RESOURCE, "{0}", SEGMENT_COMMENTS, "{1}"};
/**
* URL template for a process instance's identity links: <i>runtime/process-instances/{0:processInstanceId}/identitylinks</i>
*/
public static final String[] URL_PROCESS_INSTANCE_IDENTITYLINKS_COLLECTION = {SEGMENT_RUNTIME_RESOURCES, SEGMENT_PROCESS_INSTANCE_RESOURCE, "{0}", SEGMENT_IDENTITYLINKS};
/**
* URL template for an identitylink on a process instance: <i>runtime/process-instances/{0:processInstanceId}/identitylinks/users/{1:identityId}/{2:type}</i>
*/
public static final String[] URL_PROCESS_INSTANCE_IDENTITYLINK = {SEGMENT_RUNTIME_RESOURCES, SEGMENT_PROCESS_INSTANCE_RESOURCE, "{0}", SEGMENT_IDENTITYLINKS, SEGMENT_IDENTITYLINKS_FAMILY_USERS, "{1}", "{2}"};
/**
* URL template for a single historic process instance: <i>history/historic-process-instances/{0:processInstanceId}</i>
*/
......
......@@ -78,7 +78,7 @@ public class ProcessDefinitionIdentityLinkCollectionResource extends SecuredReso
setStatus(Status.SUCCESS_CREATED);
return getApplication(ActivitiRestServicesApplication.class).getRestResponseFactory()
.createRestIdentityLink(this, identityLink.getType(), identityLink.getUser(), identityLink.getGroup(), null, processDefinition.getId());
.createRestIdentityLink(this, identityLink.getType(), identityLink.getUser(), identityLink.getGroup(), null, processDefinition.getId(), null);
}
/**
......
......@@ -18,8 +18,10 @@ import java.util.List;
import java.util.Map;
import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.ActivitiObjectNotFoundException;
import org.activiti.engine.impl.ProcessInstanceQueryProperty;
import org.activiti.engine.query.QueryProperty;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.rest.api.ActivitiUtil;
import org.activiti.rest.api.DataResponse;
......@@ -160,4 +162,18 @@ public class ProcessInstanceBaseResource extends SecuredResource {
}
}
}
protected ProcessInstance getProcessInstanceFromRequest() {
String processInstanceId = getAttribute("processInstanceId");
if (processInstanceId == null) {
throw new ActivitiIllegalArgumentException("The processInstanceId cannot be null");
}
ProcessInstance processInstance = ActivitiUtil.getRuntimeService().createProcessInstanceQuery()
.processInstanceId(processInstanceId).singleResult();
if (processInstance == null) {
throw new ActivitiObjectNotFoundException("Could not find a process instance with id '" + processInstanceId + "'.", ProcessInstance.class);
}
return processInstance;
}
}
/* Licensed 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.activiti.rest.api.runtime.process;
import java.util.ArrayList;
import java.util.List;
import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.rest.api.ActivitiUtil;
import org.activiti.rest.api.RestResponseFactory;
import org.activiti.rest.api.engine.RestIdentityLink;
import org.activiti.rest.application.ActivitiRestServicesApplication;
import org.restlet.data.Status;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
/**
* @author Frederik Heremans
*/
public class ProcessInstanceIdentityLinkCollectionResource extends ProcessInstanceBaseResource {
@Get
public List<RestIdentityLink> getIdentityLinks() {
if(!authenticate())
return null;
List<RestIdentityLink> result = new ArrayList<RestIdentityLink>();
ProcessInstance processInstance = getProcessInstanceFromRequest();
List<IdentityLink> identityLinks = ActivitiUtil.getRuntimeService().getIdentityLinksForProcessInstance(processInstance.getId());
RestResponseFactory responseFactory = getApplication(ActivitiRestServicesApplication.class).getRestResponseFactory();
for(IdentityLink link : identityLinks) {
result.add(responseFactory.createRestIdentityLink(this, link));
}
return result;
}
@Post
public RestIdentityLink createIdentityLink(RestIdentityLink identityLink) {
if(!authenticate())
return null;
ProcessInstance processInstance = getProcessInstanceFromRequest();
if(identityLink.getGroup() != null) {
throw new ActivitiIllegalArgumentException("Only user identity links are supported on a process instance.");
}
if(identityLink.getUser() == null) {
throw new ActivitiIllegalArgumentException("The user is required.");
}
if(identityLink.getType() == null) {
throw new ActivitiIllegalArgumentException("The identity link type is required.");
}
ActivitiUtil.getRuntimeService().addUserIdentityLink(processInstance.getId(), identityLink.getUser(), identityLink.getType());
setStatus(Status.SUCCESS_CREATED);
return getApplication(ActivitiRestServicesApplication.class).getRestResponseFactory()
.createRestIdentityLink(this, identityLink.getType(), identityLink.getUser(), identityLink.getGroup(), null, null, processInstance.getId());
}
}
/* Licensed 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.activiti.rest.api.runtime.process;
import java.util.List;
import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.ActivitiObjectNotFoundException;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.rest.api.ActivitiUtil;
import org.activiti.rest.api.engine.RestIdentityLink;
import org.activiti.rest.application.ActivitiRestServicesApplication;
import org.restlet.resource.Get;
/**
* @author Frederik Heremans
*/
public class ProcessInstanceIdentityLinkResource extends ProcessInstanceBaseResource {
@Get
public RestIdentityLink getIdentityLink() {
if(!authenticate())
return null;
ProcessInstance processInstance = getProcessInstanceFromRequest();
// Extract and validate identity link from URL
String identityId = getAttribute("identityId");
String type = getAttribute("type");
validateIdentityLinkArguments(identityId, type);
IdentityLink link = getIdentityLink(identityId, type, processInstance.getId());
return getApplication(ActivitiRestServicesApplication.class).getRestResponseFactory()
.createRestIdentityLink(this, link);
}
protected void validateIdentityLinkArguments(String identityId, String type) {
if(identityId == null) {
throw new ActivitiIllegalArgumentException("IdentityId is required.");
}
if(type == null) {
throw new ActivitiIllegalArgumentException("Type is required.");
}
}
protected IdentityLink getIdentityLink(String identityId, String type, String processInstanceId) {
// Perhaps it would be better to offer getting a single identitylink from the API
List<IdentityLink> allLinks = ActivitiUtil.getRuntimeService().getIdentityLinksForProcessInstance(processInstanceId);
for(IdentityLink link : allLinks) {
if(identityId.equals(link.getUserId()) && link.getType().equals(type)) {
return link;
}
}
throw new ActivitiObjectNotFoundException("Could not find the requested identity link.", IdentityLink.class);
}
}
......@@ -76,6 +76,6 @@ public class TaskIdentityLinkCollectionResource extends TaskBaseResource {
setStatus(Status.SUCCESS_CREATED);
return getApplication(ActivitiRestServicesApplication.class).getRestResponseFactory()
.createRestIdentityLink(this, identityLink.getType(), identityLink.getUser(), identityLink.getGroup(), task.getId(), null);
.createRestIdentityLink(this, identityLink.getType(), identityLink.getUser(), identityLink.getGroup(), task.getId(), null, null);
}
}
......@@ -89,6 +89,8 @@ import org.activiti.rest.api.runtime.process.ProcessDefinitionFormResource;
import org.activiti.rest.api.runtime.process.ProcessDefinitionPropertiesResource;
import org.activiti.rest.api.runtime.process.ProcessInstanceCollectionResource;
import org.activiti.rest.api.runtime.process.ProcessInstanceDiagramResource;
import org.activiti.rest.api.runtime.process.ProcessInstanceIdentityLinkCollectionResource;
import org.activiti.rest.api.runtime.process.ProcessInstanceIdentityLinkResource;
import org.activiti.rest.api.runtime.process.ProcessInstanceQueryResource;
import org.activiti.rest.api.runtime.process.ProcessInstanceResource;
import org.activiti.rest.api.runtime.process.ProcessInstanceSignalExecutionResource;
......@@ -154,6 +156,8 @@ public class RestServicesInit {
router.attach("/runtime/process-instances/{processInstanceId}/variables", ProcessInstanceVariableCollectionResource.class);
router.attach("/runtime/process-instances/{processInstanceId}/variables/{variableName}", ProcessInstanceVariableResource.class);
router.attach("/runtime/process-instances/{processInstanceId}/variables/{variableName}/data", ProcessInstanceVariableDataResource.class);
router.attach("/runtime/process-instances/{processInstanceId}/identitylinks", ProcessInstanceIdentityLinkCollectionResource.class);
router.attach("/runtime/process-instances/{processInstanceId}/identitylinks/users/{identityId}/{type}", ProcessInstanceIdentityLinkResource.class);
router.attach("/runtime/executions", ExecutionCollectionResource.class);
router.attach("/runtime/executions/{executionId}", ExecutionResource.class);
......
/* Licensed 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.activiti.rest.api.runtime;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.test.Deployment;
import org.activiti.rest.BaseRestTestCase;
import org.activiti.rest.api.RestUrls;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ObjectNode;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;
import org.restlet.resource.ResourceException;
/**
* Test for all REST-operations related to a identity links on a Process
* instance resource.
*
* @author Frederik Heremans
*/
public class ProcessInstanceIdentityLinkResourceTest extends BaseRestTestCase {
/**
* Test getting all identity links.
*/
@Deployment(resources = { "org/activiti/rest/api/runtime/ProcessInstanceIdentityLinkResourceTest.process.bpmn20.xml" })
public void testGetIdentityLinks() throws Exception {
// Test candidate user/groups links + manual added identityLink
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess");
runtimeService.addUserIdentityLink(processInstance.getId(), "john", "customType");
runtimeService.addUserIdentityLink(processInstance.getId(), "paul", "candidate");
ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_IDENTITYLINKS_COLLECTION,
processInstance.getId()));
// Execute the request
Representation response = client.get();
assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus());
JsonNode responseNode = objectMapper.readTree(response.getStream());
assertNotNull(responseNode);
assertTrue(responseNode.isArray());
assertEquals(2, responseNode.size());
boolean johnFound = false;
boolean paulFound = false;
for (int i = 0; i < responseNode.size(); i++) {
ObjectNode link = (ObjectNode) responseNode.get(i);
assertNotNull(link);
if (!link.get("user").isNull()) {
if (link.get("user").getTextValue().equals("john")) {
assertEquals("customType", link.get("type").getTextValue());
assertTrue(link.get("group").isNull());
assertTrue(link.get("url").getTextValue()
.endsWith(RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_IDENTITYLINK, processInstance.getId(), "john", "customType")));
johnFound = true;
} else {
assertEquals("paul", link.get("user").getTextValue());
assertEquals("candidate", link.get("type").getTextValue());
assertTrue(link.get("group").isNull());
assertTrue(link.get("url").getTextValue()
.endsWith(RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_IDENTITYLINK, processInstance.getId(), "paul", "candidate")));
paulFound = true;
}
}
}
assertTrue(johnFound);
assertTrue(paulFound);
}
/**
* Test creating an identity link.
*/
@Deployment(resources = { "org/activiti/rest/api/runtime/ProcessInstanceIdentityLinkResourceTest.process.bpmn20.xml" })
public void testCreateIdentityLink() throws Exception {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess");
ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_IDENTITYLINKS_COLLECTION,
processInstance.getId()));
// Add user link
ObjectNode requestNode = objectMapper.createObjectNode();
requestNode.put("user", "kermit");
requestNode.put("type", "myType");
Representation response = client.post(requestNode);
assertEquals(Status.SUCCESS_CREATED, client.getResponse().getStatus());
JsonNode responseNode = objectMapper.readTree(response.getStream());
assertNotNull(responseNode);
assertEquals("kermit", responseNode.get("user").getTextValue());
assertEquals("myType", responseNode.get("type").getTextValue());
assertTrue(responseNode.get("group").isNull());
assertTrue(responseNode.get("url").getTextValue()
.endsWith(RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_IDENTITYLINK, processInstance.getId(), "kermit", "myType")));
// Test with unexisting process
client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_IDENTITYLINKS_COLLECTION, "unexistingprocess"));
try {
client.post(null);
fail("Exception expected");
} catch (ResourceException expected) {
assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
assertEquals("Could not find a process instance with id 'unexistingprocess'.", expected.getStatus().getDescription());
}
// Test with no user
client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_IDENTITYLINKS_COLLECTION, processInstance.getId()));
requestNode = objectMapper.createObjectNode();
requestNode.put("type", "myType");
try {
client.post(requestNode);
fail("Exception expected");
} catch (ResourceException expected) {
assertEquals(Status.CLIENT_ERROR_BAD_REQUEST, expected.getStatus());
assertEquals("The user is required.", expected.getStatus().getDescription());
}
// Test with group (which is not supported on processes)
requestNode = objectMapper.createObjectNode();
requestNode.put("type", "myType");
requestNode.put("group", "sales");
try {
client.release();
client.post(requestNode);
fail("Exception expected");
} catch (ResourceException expected) {
assertEquals(Status.CLIENT_ERROR_BAD_REQUEST, expected.getStatus());
assertEquals("Only user identity links are supported on a process instance.", expected.getStatus().getDescription());
}
// Test with no type
requestNode = objectMapper.createObjectNode();
requestNode.put("user", "kermit");
try {
client.release();
client.post(requestNode);
fail("Exception expected");
} catch (ResourceException expected) {
assertEquals(Status.CLIENT_ERROR_BAD_REQUEST, expected.getStatus());
assertEquals("The identity link type is required.", expected.getStatus().getDescription());
}
}
/**
* Test getting a single identity link for a process instance.
*/
@Deployment(resources = { "org/activiti/rest/api/runtime/ProcessInstanceIdentityLinkResourceTest.process.bpmn20.xml" })
public void testGetSingleIdentityLink() throws Exception {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess");
runtimeService.addUserIdentityLink(processInstance.getId(), "kermit", "myType");
ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_IDENTITYLINK,
processInstance.getId(), "kermit", "myType"));
Representation response = client.get();
assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus());
JsonNode responseNode = objectMapper.readTree(response.getStream());
assertNotNull(responseNode);
assertEquals("kermit", responseNode.get("user").getTextValue());
assertEquals("myType", responseNode.get("type").getTextValue());
assertTrue(responseNode.get("group").isNull());
assertTrue(responseNode.get("url").getTextValue().endsWith(
RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_IDENTITYLINK, processInstance.getId(), "kermit", "myType")));
// Test with unexisting process
client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_IDENTITYLINK, "unexistingprocess",
RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_USERS, "kermit", "myType"));
try {
client.get();
fail("Exception expected");
} catch (ResourceException expected) {
assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
assertEquals("Could not find a process instance with id 'unexistingprocess'.", expected.getStatus().getDescription());
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:activiti="http://activiti.org/bpmn"
targetNamespace="OneTaskCategory">
<process id="oneTaskProcess" name="The One Task Process">
<documentation>One task process description</documentation>
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="theTask" />
<userTask id="theTask" name="my task" />
<sequenceFlow id="flow2" sourceRef="theTask" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
</definitions>
......@@ -295,7 +295,7 @@
<section id="restVariables">
<title>Variable representation</title>
<para>
When working with variables (execution/procees and task), the REST-api uses some common principles and JSON-format for both reading and writing. The JSON representation of a variable looks like this:
When working with variables (execution/process and task), the REST-api uses some common principles and JSON-format for both reading and writing. The JSON representation of a variable looks like this:
<programlisting>
{
"name" : "variableName",
......@@ -1852,7 +1852,7 @@
<entry>active</entry>
<entry>No</entry>
<entry>Boolean</entry>
<entry>If <literal>true</literal>, only return tasks that are not suspended (either part of a process that is not suspended or not part of a process at all). If false, only tasks that are part of suspende process instances are returned.</entry>
<entry>If <literal>true</literal>, only return tasks that are not suspended (either part of a process that is not suspended or not part of a process at all). If false, only tasks that are part of suspended process instances are returned.</entry>
</row>
<row>
<entry namest="c1" nameend="c4"><para>The general <link linkend="restPagingAndSort">paging and sorting query-parameters</link> can be used for this URL.</para></entry>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册