diff --git a/modules/activiti-common-rest/src/main/java/org/activiti/rest/api/SecuredResource.java b/modules/activiti-common-rest/src/main/java/org/activiti/rest/api/SecuredResource.java index 6d55d9f3ae9307791b9d598295a5876c53684b7e..ae26c921f408cbcf4c72248b5e0e71eaa44cdd97 100644 --- a/modules/activiti-common-rest/src/main/java/org/activiti/rest/api/SecuredResource.java +++ b/modules/activiti-common-rest/src/main/java/org/activiti/rest/api/SecuredResource.java @@ -24,6 +24,7 @@ import java.util.Map; import org.activiti.engine.identity.Group; import org.activiti.rest.application.ActivitiRestApplication; import org.codehaus.jackson.JsonNode; +import org.restlet.data.MediaType; import org.restlet.data.Reference; import org.restlet.data.Status; import org.restlet.resource.ServerResource; @@ -54,6 +55,22 @@ public class SecuredResource extends ServerResource { return url.toString(); } + /** + * @return the {@link MediaType} resolved from the given resource-name. Returns null if the type cannot + * be resolved based on the given name. + */ + public MediaType resolveMediaType(String resourceName) { + return ((ActivitiRestApplication)getApplication()).getMediaTypeResolver().resolveMediaType(resourceName); + } + + /** + * @return the Restlet Application, casted to the given type. + */ + @SuppressWarnings("unchecked") + public T getApplication(Class applicationClass) { + return (T) getApplication(); + } + /** * Get a request attribute value, decoded. */ @@ -103,6 +120,7 @@ public class SecuredResource extends ServerResource { } } + @SuppressWarnings("deprecation") protected Map retrieveVariables(JsonNode jsonNode) { Map variables = new HashMap(); if (jsonNode != null) { @@ -121,6 +139,8 @@ public class SecuredResource extends ServerResource { } else if (valueNode.isTextual()) { variables.put(name, valueNode.getTextValue()); } else { + // Not using asText() due to the fact we expect a null-value to be returned rather than en emtpy string + // when node is not a simple value-node variables.put(name, valueNode.getValueAsText()); } } diff --git a/modules/activiti-common-rest/src/main/java/org/activiti/rest/application/ActivitiRestApplication.java b/modules/activiti-common-rest/src/main/java/org/activiti/rest/application/ActivitiRestApplication.java index 3704d1fe1066739573f707476863d37eb02c8eaf..9513438f8223a13ce1d7232625bafc4f69594ba9 100644 --- a/modules/activiti-common-rest/src/main/java/org/activiti/rest/application/ActivitiRestApplication.java +++ b/modules/activiti-common-rest/src/main/java/org/activiti/rest/application/ActivitiRestApplication.java @@ -29,12 +29,25 @@ public abstract class ActivitiRestApplication extends Application { protected ChallengeAuthenticator authenticator; protected ActivitiStatusService activitiStatusService; + protected MediaTypeResolver mediaTypeResolver; - public ActivitiRestApplication() { activitiStatusService = new ActivitiStatusService(); } + public MediaTypeResolver getMediaTypeResolver() { + if(mediaTypeResolver == null) { + // Revert to default implementation when no custom resolver has been set + mediaTypeResolver = new DefaultMediaTypeResolver(); + } + + return mediaTypeResolver; + } + + public void setMediaTypeResolver(MediaTypeResolver mediaTypeResolver) { + this.mediaTypeResolver = mediaTypeResolver; + } + public void initializeAuthentication() { Verifier verifier = new SecretVerifier() { diff --git a/modules/activiti-common-rest/src/main/java/org/activiti/rest/application/DefaultMediaTypeResolver.java b/modules/activiti-common-rest/src/main/java/org/activiti/rest/application/DefaultMediaTypeResolver.java new file mode 100644 index 0000000000000000000000000000000000000000..1597933de033e7e0a05578c65cb671a0cb09aa5c --- /dev/null +++ b/modules/activiti-common-rest/src/main/java/org/activiti/rest/application/DefaultMediaTypeResolver.java @@ -0,0 +1,41 @@ +/* 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.application; + +import org.restlet.data.MediaType; + + +/** + * Default implementation of a {@link MediaTypeResolver}, resolving a limited set + * of well-known media-types used in the engine. + * + * @author Frederik Heremans + */ +public class DefaultMediaTypeResolver implements MediaTypeResolver { + + @Override + public MediaType resolveMediaType(String resourceName) { + MediaType mediaType = null; + if(resourceName != null && !resourceName.isEmpty()) { + String lowerResourceName = resourceName.toLowerCase(); + + if (lowerResourceName.endsWith("png")) { + mediaType = MediaType.IMAGE_PNG; + } else if (lowerResourceName.endsWith("xml") || lowerResourceName.endsWith("bpmn")) { + mediaType = MediaType.TEXT_XML; + } + } + return mediaType; + } +} diff --git a/modules/activiti-common-rest/src/main/java/org/activiti/rest/application/MediaTypeResolver.java b/modules/activiti-common-rest/src/main/java/org/activiti/rest/application/MediaTypeResolver.java new file mode 100644 index 0000000000000000000000000000000000000000..38c5de5a16589bc772ff1028ce23a182747bf06e --- /dev/null +++ b/modules/activiti-common-rest/src/main/java/org/activiti/rest/application/MediaTypeResolver.java @@ -0,0 +1,32 @@ +/* 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.application; + +import org.restlet.data.MediaType; + + +/** + * Interface describing a class that is capable of resolving the media-type of a resource/file + * based on the resource name. + * + * @author Frederik Heremans + */ +public interface MediaTypeResolver { + + /** + * @return the {@link MediaType} resolved from the given resourcename. Returns null if the + * media-type cannot be resolved. + */ + MediaType resolveMediaType(String resourceName); +} diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/DefaultRestResponseFactory.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/DefaultRestResponseFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..a39183fbea9958b02a0b42714b25ef08814c8d49 --- /dev/null +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/DefaultRestResponseFactory.java @@ -0,0 +1,58 @@ +/* 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; + +import org.activiti.engine.impl.bpmn.deployer.BpmnDeployer; +import org.activiti.engine.repository.Deployment; +import org.activiti.rest.api.repository.DeploymentResourceResponse; +import org.activiti.rest.api.repository.DeploymentResourceResponse.DeploymentResourceType; +import org.activiti.rest.api.repository.DeploymentResponse; +import org.restlet.data.MediaType; + + +/** + * Default implementation of a {@link RestResponseFactory}. + * + * @author Frederik Heremans + */ +public class DefaultRestResponseFactory implements RestResponseFactory { + + @Override + public DeploymentResponse createDeploymentResponse(SecuredResource resourceContext, Deployment deployment) { + return new DeploymentResponse(deployment, resourceContext.createFullResourceUrl(RestUrls.URL_DEPLOYMENT, deployment.getId())); + } + + @Override + public DeploymentResourceResponse createDeploymentResourceResponse(SecuredResource resourceContext, String deploymentId, String resourceId) { + // Create URL's + String resourceUrl = resourceContext.createFullResourceUrl(RestUrls.URL_DEPLOYMENT_RESOURCE, deploymentId, resourceId); + String resourceContentUrl = resourceContext.createFullResourceUrl(RestUrls.URL_DEPLOYMENT_RESOURCE_CONTENT, deploymentId, resourceId); + + // Fetch media-type + MediaType mediaType = resourceContext.resolveMediaType(resourceId); + String mediaTypeString = (mediaType != null) ? mediaType.toString() : null; + + // Determine type + // TODO: do based on the returned resource-POJO from the API once ready instead of doing it here + DeploymentResourceType type = DeploymentResourceType.RESOURCE; + for(String suffix : BpmnDeployer.BPMN_RESOURCE_SUFFIXES) { + if(resourceId.endsWith(suffix)) { + type = DeploymentResourceType.PROCESS_DEFINITION; + break; + } + } + return new DeploymentResourceResponse(resourceId, resourceUrl, resourceContentUrl, mediaTypeString, type); + } + +} diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestResponseFactory.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestResponseFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..e794db3b0de6a5b10d7a302581d9c82c3eec647e --- /dev/null +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestResponseFactory.java @@ -0,0 +1,36 @@ +/* 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; + +import org.activiti.engine.repository.Deployment; +import org.activiti.rest.api.repository.DeploymentResourceResponse; +import org.activiti.rest.api.repository.DeploymentResponse; + + +/** + * Interface that describes a factory class that is capable of creating response objects + * that can be used to return as a result (or part of a result) from a REST-service call. + *
+ * All methods require a {@link SecuredResource}, which is used to create URL in right context and provides + * access to shared logic and the application. + * + * @author Frederik Heremans + */ +public interface RestResponseFactory { + + DeploymentResponse createDeploymentResponse(SecuredResource resourceContext, Deployment deployment); + + DeploymentResourceResponse createDeploymentResourceResponse(SecuredResource resourceContext, String deploymentId, String resourceId); + +} diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentCollectionResource.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentCollectionResource.java index 6ab2fa475d2f3720d2ade43c02defde8e3323bed..365019c99c9adf3b8c13fb10d4275e97e196b024 100644 --- a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentCollectionResource.java +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentCollectionResource.java @@ -27,10 +27,11 @@ import org.activiti.engine.repository.DeploymentBuilder; import org.activiti.engine.repository.DeploymentQuery; import org.activiti.rest.api.ActivitiUtil; import org.activiti.rest.api.DataResponse; -import org.activiti.rest.api.RestUrls; import org.activiti.rest.api.SecuredResource; +import org.activiti.rest.application.ActivitiRestServicesApplication; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.restlet.data.MediaType; import org.restlet.data.Status; import org.restlet.ext.fileupload.RestletFileUpload; import org.restlet.representation.Representation; @@ -87,6 +88,10 @@ public class DeploymentCollectionResource extends SecuredResource { public DeploymentResponse uploadDeployment(Representation entity) { try { if(authenticate() == false) return null; + + if(entity == null || entity.getMediaType() == null || !MediaType.MULTIPART_FORM_DATA.isCompatible(entity.getMediaType())) { + throw new ActivitiIllegalArgumentException("The request should be of type" + MediaType.MULTIPART_FORM_DATA +"."); + } RestletFileUpload upload = new RestletFileUpload(new DiskFileItemFactory()); List items = upload.parseRepresentation(entity); @@ -98,6 +103,10 @@ public class DeploymentCollectionResource extends SecuredResource { } } + if(uploadItem == null) { + throw new ActivitiIllegalArgumentException("No file content was found in request body."); + } + DeploymentBuilder deploymentBuilder = ActivitiUtil.getRepositoryService().createDeployment(); String fileName = uploadItem.getName(); if (fileName.endsWith(".bpmn20.xml") || fileName.endsWith(".bpmn")) { @@ -112,9 +121,8 @@ public class DeploymentCollectionResource extends SecuredResource { setStatus(Status.SUCCESS_CREATED); - DeploymentResponse response = new DeploymentResponse(deployment, - createFullResourceUrl(RestUrls.URL_DEPLOYMENT, deployment.getId())); - return response; + return getApplication(ActivitiRestServicesApplication.class).getRestResponseFactory() + .createDeploymentResponse(this, deployment); } catch (Exception e) { if(e instanceof ActivitiException) { diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResource.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResource.java index 5d5f19a871eb7da335fda0846d92a511c5aacc9e..eab6c1a9afc92e25cd2c699f075364ddfe754ee5 100644 --- a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResource.java +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResource.java @@ -18,8 +18,8 @@ import org.activiti.engine.ActivitiObjectNotFoundException; import org.activiti.engine.repository.Deployment; import org.activiti.rest.api.ActivitiUtil; import org.activiti.rest.api.RequestUtil; -import org.activiti.rest.api.RestUrls; import org.activiti.rest.api.SecuredResource; +import org.activiti.rest.application.ActivitiRestServicesApplication; import org.restlet.data.Status; import org.restlet.resource.Delete; import org.restlet.resource.Get; @@ -45,9 +45,8 @@ public class DeploymentResource extends SecuredResource { if(deployment == null) { throw new ActivitiObjectNotFoundException("Could not find a deployment with id '" + deploymentId + "'.", Deployment.class); } - - DeploymentResponse response = new DeploymentResponse(deployment, createFullResourceUrl(RestUrls.URL_DEPLOYMENT, deploymentId)); - return response; + return getApplication(ActivitiRestServicesApplication.class).getRestResponseFactory() + .createDeploymentResponse(this, deployment); } @Delete diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResourceCollectionResource.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResourceCollectionResource.java index 9240d763a68efb9643ad7b988dc7644969b584df..0bf3c4b1b0f8a58354eec138ecebd239d05c4fb6 100644 --- a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResourceCollectionResource.java +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResourceCollectionResource.java @@ -20,8 +20,9 @@ import org.activiti.engine.ActivitiIllegalArgumentException; import org.activiti.engine.ActivitiObjectNotFoundException; import org.activiti.engine.repository.Deployment; import org.activiti.rest.api.ActivitiUtil; -import org.activiti.rest.api.RestUrls; +import org.activiti.rest.api.RestResponseFactory; import org.activiti.rest.api.SecuredResource; +import org.activiti.rest.application.ActivitiRestServicesApplication; import org.restlet.resource.Get; @@ -50,12 +51,9 @@ public class DeploymentResourceCollectionResource extends SecuredResource { // Add additional metadata to the artifact-strings before returning List resposeList = new ArrayList(); - String resourceUrl = null; - String resourceContentUrl = null; - for(String resource : resourceList) { - resourceUrl = createFullResourceUrl(RestUrls.URL_DEPLOYMENT_RESOURCE, deploymentId, resource); - resourceContentUrl = createFullResourceUrl(RestUrls.URL_DEPLOYMENT_RESOURCE_CONTENT, deploymentId, resource); - resposeList.add(new DeploymentResourceResponse(resource, resourceUrl, resourceContentUrl)); + RestResponseFactory responseFactory = getApplication(ActivitiRestServicesApplication.class).getRestResponseFactory(); + for(String resourceId : resourceList) { + resposeList.add(responseFactory.createDeploymentResourceResponse(this, deploymentId, resourceId)); } return resposeList; } diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResourceResource.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResourceResource.java index 7326847b42f030459ac840e361a9120f36fc5023..6d519b152bf7506068d40bc9f78b6fa64509a58c 100644 --- a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResourceResource.java +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResourceResource.java @@ -19,8 +19,8 @@ import org.activiti.engine.ActivitiIllegalArgumentException; import org.activiti.engine.ActivitiObjectNotFoundException; import org.activiti.engine.repository.Deployment; import org.activiti.rest.api.ActivitiUtil; -import org.activiti.rest.api.RestUrls; import org.activiti.rest.api.SecuredResource; +import org.activiti.rest.application.ActivitiRestServicesApplication; import org.restlet.resource.Get; @@ -52,9 +52,8 @@ public class DeploymentResourceResource extends SecuredResource { if(resourceList.contains(resourceId)) { // Build resource representation - String resourceUrl = createFullResourceUrl(RestUrls.URL_DEPLOYMENT_RESOURCE, deploymentId, resourceId); - String resourceContentUrl = createFullResourceUrl(RestUrls.URL_DEPLOYMENT_RESOURCE_CONTENT, deploymentId, resourceId); - return new DeploymentResourceResponse(resourceId, resourceUrl, resourceContentUrl); + return getApplication(ActivitiRestServicesApplication.class).getRestResponseFactory() + .createDeploymentResourceResponse(this, deploymentId, resourceId); } else { // Resource not found in deployment throw new ActivitiObjectNotFoundException("Could not find a resource with id '" + resourceId diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResourceResponse.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResourceResponse.java index 8a6f8651c911e37b85b79f0a720828ec95fc9557..e55991baba5d245215f84cc39b13269e7bfd7870 100644 --- a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResourceResponse.java +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentResourceResponse.java @@ -21,11 +21,20 @@ public class DeploymentResourceResponse { private String id; private String url; private String contentUrl; + private String mediaType; + private DeploymentResourceType type; - public DeploymentResourceResponse(String resourceId, String url, String contentUrl) { + public DeploymentResourceResponse(String resourceId, String url, String contentUrl, + String mediaType, DeploymentResourceType type) { setId(resourceId); setUrl(url); setContentUrl(contentUrl); + setMediaType(mediaType); + + this.type = type; + if(type == null) { + this.type = DeploymentResourceType.RESOURCE; + } } public String getId() { @@ -46,4 +55,41 @@ public class DeploymentResourceResponse { public String getContentUrl() { return contentUrl; } + public void setMediaType(String mimeType) { + this.mediaType = mimeType; + } + public String getMediaType() { + return mediaType; + } + public String getType() { + switch (type) { + case PROCESS_DEFINITION: + return "processDefinition"; + case PROCESS_IMAGE: + return "processImage"; + default: + return "resource"; + } + } + + /** + * Possible types of resources in a deployment. + * TODO: move to activiti API + * + * @author Frederik Heremans + */ + public enum DeploymentResourceType { + /** + * A simple resource in a deployment. + */ + RESOURCE, + /** + * A resource that contains a process-definition. + */ + PROCESS_DEFINITION, + /** + * A resource that is a process-definition image. + */ + PROCESS_IMAGE; + } } diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentsPaginateList.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentsPaginateList.java index 07a840860a0d811933f737730f0eef955bb51238..4bbd009c6acedec359245382feb4277ce51a958c 100644 --- a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentsPaginateList.java +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/DeploymentsPaginateList.java @@ -18,8 +18,9 @@ import java.util.List; import org.activiti.engine.repository.Deployment; import org.activiti.rest.api.AbstractPaginateList; -import org.activiti.rest.api.RestUrls; +import org.activiti.rest.api.RestResponseFactory; import org.activiti.rest.api.SecuredResource; +import org.activiti.rest.application.ActivitiRestServicesApplication; /** * @author Tijs Rademakers @@ -36,10 +37,9 @@ public class DeploymentsPaginateList extends AbstractPaginateList { @Override protected List processList(List list) { List responseList = new ArrayList(); - + RestResponseFactory restResponseFactory = resource.getApplication(ActivitiRestServicesApplication.class).getRestResponseFactory(); for (Object deployment : list) { - responseList.add(new DeploymentResponse((Deployment) deployment, - resource.createFullResourceUrl(RestUrls.URL_DEPLOYMENT, ((Deployment)deployment).getId()))); + responseList.add(restResponseFactory.createDeploymentResponse(resource, (Deployment) deployment)); } return responseList; } diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/application/ActivitiRestServicesApplication.java b/modules/activiti-rest/src/main/java/org/activiti/rest/application/ActivitiRestServicesApplication.java index 90d12cf236b711cd55f7bdfaff55b8c05ad543ea..9cc72d99f4fe633be35b661ca13b942be2895f35 100644 --- a/modules/activiti-rest/src/main/java/org/activiti/rest/application/ActivitiRestServicesApplication.java +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/application/ActivitiRestServicesApplication.java @@ -14,6 +14,8 @@ package org.activiti.rest.application; import org.activiti.rest.api.DefaultResource; +import org.activiti.rest.api.DefaultRestResponseFactory; +import org.activiti.rest.api.RestResponseFactory; import org.activiti.rest.filter.JsonpFilter; import org.restlet.Restlet; import org.restlet.routing.Router; @@ -21,10 +23,13 @@ import org.restlet.routing.Router; * @author Tijs Rademakers */ public class ActivitiRestServicesApplication extends ActivitiRestApplication { + + protected RestResponseFactory restResponseFactory; public ActivitiRestServicesApplication() { super(); } + /** * Creates a root Restlet that will receive all incoming calls. */ @@ -43,4 +48,16 @@ public class ActivitiRestServicesApplication extends ActivitiRestApplication { return authenticator; } + + + public void setRestResponseFactory(RestResponseFactory restResponseFactory) { + this.restResponseFactory = restResponseFactory; + } + + public RestResponseFactory getRestResponseFactory() { + if(restResponseFactory == null) { + restResponseFactory = new DefaultRestResponseFactory(); + } + return restResponseFactory; + } } diff --git a/modules/activiti-rest/src/test/java/org/activiti/rest/api/repository/DeploymentResourceResourceTest.java b/modules/activiti-rest/src/test/java/org/activiti/rest/api/repository/DeploymentResourceResourceTest.java index fd71a31af9ab4efa61117cfc150522f17ef595bc..b700c499b6e2e8feeb7785fe3090c7b2a82f9444 100644 --- a/modules/activiti-rest/src/test/java/org/activiti/rest/api/repository/DeploymentResourceResourceTest.java +++ b/modules/activiti-rest/src/test/java/org/activiti/rest/api/repository/DeploymentResourceResourceTest.java @@ -49,6 +49,8 @@ public class DeploymentResourceResourceTest extends BaseRestTestCase { RestUrls.URL_DEPLOYMENT_RESOURCE, deployment.getId(), encodedResourceId))); assertTrue(responseNode.get("contentUrl").getTextValue().endsWith(RestUrls.createRelativeResourceUrl( RestUrls.URL_DEPLOYMENT_RESOURCE_CONTENT, deployment.getId(), encodedResourceId))); + assertEquals("text/xml", responseNode.get("mediaType").getTextValue()); + assertEquals("processDefinition", responseNode.get("type").getTextValue()); } finally { // Always cleanup any created deployments, even if the test failed diff --git a/modules/activiti-rest/src/test/java/org/activiti/rest/api/repository/DeploymentResourcesResourceTest.java b/modules/activiti-rest/src/test/java/org/activiti/rest/api/repository/DeploymentResourcesResourceTest.java index 6146051f8167b9cda09d29e1e386a738fc556c93..8cabebf3ec432f6c2ee2962059e6c69d987f1fd5 100644 --- a/modules/activiti-rest/src/test/java/org/activiti/rest/api/repository/DeploymentResourcesResourceTest.java +++ b/modules/activiti-rest/src/test/java/org/activiti/rest/api/repository/DeploymentResourcesResourceTest.java @@ -57,6 +57,8 @@ public class DeploymentResourcesResourceTest extends BaseRestTestCase { RestUrls.URL_DEPLOYMENT_RESOURCE, deployment.getId(), "test.txt"))); assertTrue(txtNode.get("contentUrl").getTextValue().endsWith(RestUrls.createRelativeResourceUrl( RestUrls.URL_DEPLOYMENT_RESOURCE_CONTENT, deployment.getId(), "test.txt"))); + assertTrue(txtNode.get("mediaType").isNull()); + assertEquals("resource", txtNode.get("type").getTextValue()); } finally { // Always cleanup any created deployments, even if the test failed diff --git a/userguide/src/en/chapters/ch14-REST.xml b/userguide/src/en/chapters/ch14-REST.xml index 58db260ce12e83cc856655d4182aa84ea9115001..7f25018cfa3af9c86fe97c53c845914032723c41 100644 --- a/userguide/src/en/chapters/ch14-REST.xml +++ b/userguide/src/en/chapters/ch14-REST.xml @@ -5,9 +5,538 @@ REST API +
+ Deployment +
+ List of Deployments + + GET repository/deployments + + + + URL query parameters + + + + Parameter + Required + Value + Description + + + + + deploymentName + No + String + Only return deployments with the given name. + + + deploymentNameLike + No + String + Only return deployments with a name like the given name. + + + deploymentCategory + No + String + Only return deployments with the given category. + + + deploymentCategoryNotEquals + No + String + Only return deployments wich don't have the given category. + + + start + No + Number + The result index to start from. + + + size + No + Number + The size of the resultset, starting from the start index (if defined). + + + order + No + 'asc' (default) or 'desc' + Direction of the sort, to be used toghether with the sort. + + + sort + No + 'id' (default), 'name' or 'deploytime' + Property to sort on, to be used toghether with the sort. + + + +
+
+ + + Response codes + + + + Response code + Description + + + + + 200 + Indicates the request was successful. + + + +
+
+ + Success response body: + +{ + "data": [ + { + "id": "10", + "name": "activiti-examples.bar", + "deploymentTime": "2010-10-13T14:54:26.750+02:00", + "category": "examples", + "url": "http://localhost:8081/service/repository/deployments/10" + } + ], + "total": 1, + "start": 0, + "sort": "id", + "order": "asc", + "size": 1 +} + +
+ +
+ Get a single deployment + + GET repository/deployments/{deploymentId} + + + + URL parameters + + + + Parameter + Required + Value + Description + + + + + deploymentId + Yes + String + The id of the deployment to get. + + + +
+
+ + + Response codes + + + + Response code + Description + + + + + 200 + Indicates the deployment was found and returned. + + + 404 + Indicates the requested deployment was not found. + + + +
+
+ + Success response body: + +{ + "id": "10", + "name": "activiti-examples.bar", + "deploymentTime": "2010-10-13T14:54:26.750+02:00", + "category": "examples", + "url": "http://localhost:8081/service/repository/deployments/10" +} + +
+ +
+ Create a new deployment + + POST repository/deployments + + + Request body: + + The request should body should contain data of type multipart/form-data. There should be only exactly file in the request, any additional files will be ignored. + + + Response codes + + + + Response code + Description + + + + + 201 + Indicates the deployment was created. + + + 400 + Indicates there was no content present in the request body or the content mime-type is not supported for deployment. The status-description contains additional information. + + + +
+
+ + Success response body: + +{ + "id": "10", + "name": "activiti-examples.bar", + "deploymentTime": "2010-10-13T14:54:26.750+02:00", + "category": null, + "url": "http://localhost:8081/service/repository/deployments/10" +} + +
+
+ Delete a deployment + + DELETE repository/deployments/{deploymentId} + + + + URL parameters + + + + Parameter + Required + Value + Description + + + + + deploymentId + Yes + String + The id of the deployment to delete. + + + +
+
+ + + Response codes + + + + Response code + Description + + + + + 204 + Indicates the deployment was found and has been deleted. Response-body is intentionally empty. + + + 404 + Indicates the requested deployment was not found. + + + +
+
+
+
+ List resources in a deployment + + GET repository/deployments/{deploymentId}/resources + + + + URL parameters + + + + Parameter + Required + Value + Description + + + + + deploymentId + Yes + String + The id of the deployment to get the resources for. + + + +
+
+ + + Response codes + + + + Response code + Description + + + + + 200 + Indicates the deployment was found and the resource list has been returned. + + + 404 + Indicates the requested deployment was not found. + + + +
+
+ + Success response body: + +[ + { + "id": "diagrams/my-process.bpmn20.xml", + "url": "http://localhost:8081/activiti-rest/service/repository/deployments/10/resources/diagrams%2Fmy-process.bpmn20.xml", + "dataUrl": "http://localhost:8081/activiti-rest/service/repository/deployments/10/resourcedata/diagrams%2Fmy-process.bpmn20.xml", + "mediaType": "text/xml", + "type": "processDefinition" + }, + { + "id": "image.png", + "url": "http://localhost:8081/activiti-rest/service/repository/deployments/10/resources/image.png", + "dataUrl": "http://localhost:8081/activiti-rest/service/repository/deployments/10/resourcedata/image.png", + "mediaType": "image/png", + "type": "resource" + } +] + + + + mediaType: Contains the media-type the resource has. This is resolved using a (pluggable) MediaTypeResolver and contains, by default, a limited number of mime-type mappings. + + + type: Type of resource, possible values: + + + resource: Plain old resource. + + + processDefinition: Resource that contains one or more process-definitions. This resource is picked up by the deployer. + + + processImage: Resource that represents a deployed process definition's graphical layout. + + + + + + + The dataUrl property in the resulting json for a single resource contains the actual URL to use for retreiving the binary resource. + +
+
+ Get a single deployment resource + + GET repository/deployments/{deploymentId}/resources/{resourceId} + + + + URL parameters + + + + Parameter + Required + Value + Description + + + + + deploymentId + Yes + String + The id of the deployment the requested resource is part of. + + + resourceId + Yes + String + The id of the resource to get. Make sure you URL-encode the resourceId in case it contains forward slashes. Eg: use 'diagrams%2Fmy-process.bpmn20.xml' instead of 'diagrams/Fmy-process.bpmn20.xml'. + + + +
+
+ + + Response codes + + + + Response code + Description + + + + + 200 + Indicates both deployment and resource have been found and the resource has been returned. + + + 404 + Indicates the requested deployment was not found or there is no resource with the given id present in the deployment. The status-description contains additional information. + + + +
+
+ + Success response body: + +{ + "id": "diagrams/my-process.bpmn20.xml", + "url": "http://localhost:8081/activiti-rest/service/repository/deployments/10/resources/diagrams%2Fmy-process.bpmn20.xml", + "dataUrl": "http://localhost:8081/activiti-rest/service/repository/deployments/10/resourcedata/diagrams%2Fmy-process.bpmn20.xml", + "mediaType": "text/xml", + "type": "processDefinition" +} + + + + mediaType: Contains the media-type the resource has. This is resolved using a (pluggable) MediaTypeResolver and contains, by default, a limited number of mime-type mappings. + + + type: Type of resource, possible values: + + + resource: Plain old resource. + + + processDefinition: Resource that contains one or more process-definitions. This resource is picked up by the deployer. + + + processImage: Resource that represents a deployed process definition's graphical layout. + + + + + +
+ +
+ Get a deployment resource content + + GET repository/deployments/{deploymentId}/resourcedata/{resourceId} + + + + URL parameters + + + + Parameter + Required + Value + Description + + + + + deploymentId + Yes + String + The id of the deployment the requested resource is part of. + + + resourceId + Yes + String + The id of the resource to get the data for. Make sure you URL-encode the resourceId in case it contains forward slashes. Eg: use 'diagrams%2Fmy-process.bpmn20.xml' instead of 'diagrams/Fmy-process.bpmn20.xml'. + + + +
+
+ + + Response codes + + + + Response code + Description + + + + + 200 + Indicates both deployment and resource have been found and the resource data has been returned. + + + 404 + Indicates the requested deployment was not found or there is no resource with the given id present in the deployment. The status-description contains additional information. + + + +
+
+ + Success response body: + + + The response body will contain the binary resource-content for the requested resource. The response content-type will be the same as the type returned in the resources 'mimeType' property. Also, a content-disposition header is set, + allowing browsers to dowload the file instead of displaying it. + +
+
+ + + + +
- General Usage + Legacy REST - General Usage Activiti includes a REST API to the Activiti Engine that can be installed by deploying the activiti-rest.war file to a servlet container like Apache Tomcat.