diff --git a/modules/activiti-bpmn-converter/src/main/java/org/activiti/bpmn/converter/export/SignalAndMessageDefinitionExport.java b/modules/activiti-bpmn-converter/src/main/java/org/activiti/bpmn/converter/export/SignalAndMessageDefinitionExport.java index 2f4df9bc60ee3ba28f8a3fa380055bf4626e5534..f145fe65732901d00b23f0d1b0d4e55ac817353f 100644 --- a/modules/activiti-bpmn-converter/src/main/java/org/activiti/bpmn/converter/export/SignalAndMessageDefinitionExport.java +++ b/modules/activiti-bpmn-converter/src/main/java/org/activiti/bpmn/converter/export/SignalAndMessageDefinitionExport.java @@ -54,7 +54,7 @@ public class SignalAndMessageDefinitionExport implements BpmnXMLConstants { xtw.writeStartElement(ELEMENT_MESSAGE); String messageId = message.getId(); // remove the namespace from the message id if set - if (messageId.startsWith(model.getTargetNamespace())) { + if (model.getTargetNamespace() != null && messageId.startsWith(model.getTargetNamespace())) { messageId = messageId.replace(model.getTargetNamespace(), ""); messageId = messageId.replaceFirst(":", ""); } else { diff --git a/modules/activiti-common-rest/src/main/java/org/activiti/rest/api/ActivitiUtil.java b/modules/activiti-common-rest/src/main/java/org/activiti/rest/api/ActivitiUtil.java index d1a938d8b42ea0e4854142e5bddfc6323ef5c8d3..731394d4d5a98702cdc0a99fd33117ac8c09765c 100644 --- a/modules/activiti-common-rest/src/main/java/org/activiti/rest/api/ActivitiUtil.java +++ b/modules/activiti-common-rest/src/main/java/org/activiti/rest/api/ActivitiUtil.java @@ -29,22 +29,36 @@ import org.activiti.engine.TaskService; */ public class ActivitiUtil { + private static ActivitiUtilProvider activitiProvider; + + public static void setActivitiProvider(ActivitiUtilProvider provider) { + activitiProvider = provider; + } + /** * Returns the process engine info. * * @return The process engine info */ public static ProcessEngineInfo getProcessEngineInfo() { - return ProcessEngines.getProcessEngineInfo(ProcessEngines.NAME_DEFAULT); + if (activitiProvider != null) { + return activitiProvider.getProcessEngineInfo(); + } else { + return ProcessEngines.getProcessEngineInfo(ProcessEngines.NAME_DEFAULT); + } } - + /** * Returns the process engine. * * @return The process engine */ public static ProcessEngine getProcessEngine() { - return ProcessEngines.getDefaultProcessEngine(); + if (activitiProvider != null) { + return activitiProvider.getProcessEngine(); + } else { + return ProcessEngines.getDefaultProcessEngine(); + } } /** diff --git a/modules/activiti-common-rest/src/main/java/org/activiti/rest/api/ActivitiUtilProvider.java b/modules/activiti-common-rest/src/main/java/org/activiti/rest/api/ActivitiUtilProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..789a9018e1aa4ca45ce6d9faa9eca0c2c458f2c4 --- /dev/null +++ b/modules/activiti-common-rest/src/main/java/org/activiti/rest/api/ActivitiUtilProvider.java @@ -0,0 +1,13 @@ +package org.activiti.rest.api; + +import org.activiti.engine.ProcessEngine; +import org.activiti.engine.ProcessEngineInfo; + +/** + * + * @author fers + */ +public interface ActivitiUtilProvider { + public ProcessEngine getProcessEngine(); + public ProcessEngineInfo getProcessEngineInfo(); +} \ No newline at end of file diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/ProcessEngineConfiguration.java b/modules/activiti-engine/src/main/java/org/activiti/engine/ProcessEngineConfiguration.java index b94dc03a748d9c8b1f53aa002ed696f40f4ba71b..cbaa75de807c33703536543c861712fd5dd44833 100644 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/ProcessEngineConfiguration.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/ProcessEngineConfiguration.java @@ -126,6 +126,8 @@ public abstract class ProcessEngineConfiguration implements EngineServices { protected boolean jpaHandleTransaction; protected boolean jpaCloseEntityManager; + protected String databaseTablePrefix = ""; + protected String xmlEncoding = "UTF-8"; protected String defaultCamelContext = "camelContext"; protected String activityFontName = "Arial"; @@ -549,4 +551,21 @@ public abstract class ProcessEngineConfiguration implements EngineServices { public void setLabelFontName(String labelFontName) { this.labelFontName = labelFontName; } + + public ProcessEngineConfiguration setDatabaseTablePrefix(String databaseTablePrefix) { + this.databaseTablePrefix = databaseTablePrefix; + return this; + } + + public String getDatabaseTablePrefix() { + return databaseTablePrefix; + } + + public String getXmlEncoding() { + return xmlEncoding; + } + + public void setXmlEncoding(String xmlEncoding) { + this.xmlEncoding = xmlEncoding; + } } diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/calendar/DueDateBusinessCalendar.java b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/calendar/DueDateBusinessCalendar.java index c821b149e20ed25fcffd2d7075e67b6a2ce97f67..d6f9bcc10288bf51db59a4cbd0e9dfc4158956c4 100644 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/calendar/DueDateBusinessCalendar.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/calendar/DueDateBusinessCalendar.java @@ -16,6 +16,7 @@ import java.util.Date; import org.activiti.engine.ActivitiException; import org.joda.time.DateTime; +import org.joda.time.Period; public class DueDateBusinessCalendar implements BusinessCalendar { @@ -24,6 +25,12 @@ public class DueDateBusinessCalendar implements BusinessCalendar { public Date resolveDuedate(String duedate) { try { + + // check if due period was specified + if(duedate.startsWith("P")){ + return DateTime.now().plus(Period.parse(duedate)).toDate(); + } + return DateTime.parse(duedate).toDate(); } catch (Exception e) { diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/cfg/ProcessEngineConfigurationImpl.java b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/cfg/ProcessEngineConfigurationImpl.java index df95a6ab7b18b5f337c52ca73939b6c1773f54fb..e71283f80a17ec817879ec70b40b7a0263f70a97 100644 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/cfg/ProcessEngineConfigurationImpl.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/cfg/ProcessEngineConfigurationImpl.java @@ -343,8 +343,6 @@ public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfig protected FailedJobCommandFactory failedJobCommandFactory; - protected String databaseTablePrefix = ""; - /** * Set this to true if you want to have extra checks on the BPMN xml that is parsed. * See http://www.jorambarrez.be/blog/2013/02/19/uploading-a-funny-xml-can-bring-down-your-server/ @@ -365,8 +363,6 @@ public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfig protected int batchSizeProcessInstances = 25; protected int batchSizeTasks = 25; - protected String xmlEncoding = "UTF-8"; - /** * In some situations you want to set the schema to use for table checks / generation if the database metadata * doesn't return that correctly, see https://jira.codehaus.org/browse/ACT-1220, diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/persistence/entity/ExecutionEntity.java b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/persistence/entity/ExecutionEntity.java index 7a76ddcbe6282352719475034905757d93fea1cf..6af3e991dc6d56cfbfa314f63bd86c26c1527ef6 100644 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/persistence/entity/ExecutionEntity.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/persistence/entity/ExecutionEntity.java @@ -280,7 +280,7 @@ public class ExecutionEntity extends VariableScopeImpl implements ActivityExecut public void initialize() { log.debug("initializing {}", this); - ScopeImpl scope = getScope(); + ScopeImpl scope = getScopeObject(); ensureParentInitialized(); // initialize the lists of referenced objects (prevents db queries) @@ -792,7 +792,7 @@ public class ExecutionEntity extends VariableScopeImpl implements ActivityExecut // scopes /////////////////////////////////////////////////////////////////// - protected ScopeImpl getScope() { + protected ScopeImpl getScopeObject() { ScopeImpl scope = null; if (isProcessInstance()) { scope = getProcessDefinition(); diff --git a/modules/activiti-engine/src/test/java/org/activiti/engine/test/bpmn/usertask/TaskDueDateExtensionsTest.java b/modules/activiti-engine/src/test/java/org/activiti/engine/test/bpmn/usertask/TaskDueDateExtensionsTest.java index 1575c160d84a2ec262f0aca07f793172bc391f5a..88749d6112ed2399b56903757922a4147bc043e3 100644 --- a/modules/activiti-engine/src/test/java/org/activiti/engine/test/bpmn/usertask/TaskDueDateExtensionsTest.java +++ b/modules/activiti-engine/src/test/java/org/activiti/engine/test/bpmn/usertask/TaskDueDateExtensionsTest.java @@ -22,6 +22,7 @@ import org.activiti.engine.impl.test.PluggableActivitiTestCase; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; import org.activiti.engine.test.Deployment; +import org.joda.time.Period; /** @@ -60,4 +61,22 @@ public class TaskDueDateExtensionsTest extends PluggableActivitiTestCase { Date date = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").parse("06-07-1986 12:10:00"); assertEquals(date, task.getDueDate()); } + + @Deployment + public void testRelativeDueDateStringExtension() throws Exception { + + Map variables = new HashMap(); + variables.put("dateVariable", "P2DT5H40M"); + + // Start process-instance, passing ISO8601 duration formatted String that should be used to calculate dueDate + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("dueDateExtension", variables); + + Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); + + assertNotNull(task.getDueDate()); + Period period = new Period(task.getCreateTime().getTime(), task.getDueDate().getTime()); + assertEquals(period.getDays(), 2); + assertEquals(period.getHours(), 5); + assertEquals(period.getMinutes(), 40); + } } diff --git a/modules/activiti-engine/src/test/resources/org/activiti/engine/test/bpmn/usertask/TaskDueDateExtensionsTest.testRelativeDueDateStringExtension.bpmn20.xml b/modules/activiti-engine/src/test/resources/org/activiti/engine/test/bpmn/usertask/TaskDueDateExtensionsTest.testRelativeDueDateStringExtension.bpmn20.xml new file mode 100644 index 0000000000000000000000000000000000000000..5897810e252c27d14130b7621897e6e534c70411 --- /dev/null +++ b/modules/activiti-engine/src/test/resources/org/activiti/engine/test/bpmn/usertask/TaskDueDateExtensionsTest.testRelativeDueDateStringExtension.bpmn20.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/activiti-json-converter/src/main/java/org/activiti/editor/language/json/converter/ServiceTaskJsonConverter.java b/modules/activiti-json-converter/src/main/java/org/activiti/editor/language/json/converter/ServiceTaskJsonConverter.java index b1e0a222d9faf2a702f4de7d7a7161d932fd1d7d..5cdc42677d08cd79c319f9b109ac4df5eab1b844 100644 --- a/modules/activiti-json-converter/src/main/java/org/activiti/editor/language/json/converter/ServiceTaskJsonConverter.java +++ b/modules/activiti-json-converter/src/main/java/org/activiti/editor/language/json/converter/ServiceTaskJsonConverter.java @@ -71,6 +71,10 @@ public class ServiceTaskJsonConverter extends BaseBpmnJsonConverter { propertiesNode.put(PROPERTY_SERVICETASK_DELEGATE_EXPRESSION, serviceTask.getImplementation()); } + if (StringUtils.isNotEmpty(serviceTask.getResultVariableName())) { + propertiesNode.put(PROPERTY_SERVICETASK_RESULT_VARIABLE, serviceTask.getResultVariableName()); + } + addFieldExtensions(serviceTask.getFieldExtensions(), propertiesNode); } } @@ -90,6 +94,10 @@ public class ServiceTaskJsonConverter extends BaseBpmnJsonConverter { task.setImplementation(getPropertyValueAsString(PROPERTY_SERVICETASK_DELEGATE_EXPRESSION, elementNode)); } + if (StringUtils.isNotEmpty(getPropertyValueAsString(PROPERTY_SERVICETASK_RESULT_VARIABLE, elementNode))) { + task.setResultVariableName(getPropertyValueAsString(PROPERTY_SERVICETASK_RESULT_VARIABLE, elementNode)); + } + JsonNode fieldsNode = getProperty(PROPERTY_SERVICETASK_FIELDS, elementNode); if (fieldsNode != null) { JsonNode itemsArrayNode = fieldsNode.get(EDITOR_PROPERTIES_GENERAL_ITEMS); diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestUrls.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestUrls.java index 0b989ec216108f4ae630cf83d8515aa29cee0ae1..2dffa3c0d8a9756411c42198ff5db29b4c0c9cef 100644 --- a/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestUrls.java +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestUrls.java @@ -65,6 +65,9 @@ public final class RestUrls { public static final String SEGMENT_INFO = "info"; public static final String SEGMENT_MEMBERS = "members"; public static final String SEGMENT_MODEL = "model"; + public static final String SEGMENT_PROPERTIES = "properties"; + public static final String SEGMENT_ENGINE_INFO = "engine"; + public static final String SEGMENT_ACTIVITIES = "activities"; /** * URL template for the deployment collection: repository/deployments @@ -224,6 +227,11 @@ public final class RestUrls { */ public static final String[] URL_EXECUTION_VARIABLE_DATA = {SEGMENT_RUNTIME_RESOURCES, SEGMENT_EXECUTION_RESOURCE, "{0}", SEGMENT_VARIABLES, "{1}", SEGMENT_VARIABLE_DATA}; + /** + * URL template for all active activities on an execution: runtime/executions/{0:executionId}/activities + */ + public static final String[] URL_EXECUTION_ACTIVITIES_COLLECTION = {SEGMENT_RUNTIME_RESOURCES, SEGMENT_EXECUTION_RESOURCE, "{0}", SEGMENT_ACTIVITIES}; + /** * URL template for execution query: query/executions */ @@ -389,6 +397,16 @@ public final class RestUrls { */ public static final String[] URL_JOB_COLLECTION = {SEGMENT_MANAGEMENT_RESOURCES, SEGMENT_JOBS}; + /** + * URL template for the collection of properties: management/properties + */ + public static final String[] URL_PROPERTIES_COLLECTION = {SEGMENT_MANAGEMENT_RESOURCES, SEGMENT_PROPERTIES}; + + /** + * URL template for the collection of properties: management/properties + */ + public static final String[] URL_ENGINE_INFO = {SEGMENT_MANAGEMENT_RESOURCES, SEGMENT_ENGINE_INFO}; + /** * URL template for the collection of users: identity/users */ diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/engine/ProcessEngineInfoResponse.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/management/ProcessEngineInfoResponse.java similarity index 96% rename from modules/activiti-rest/src/main/java/org/activiti/rest/api/engine/ProcessEngineInfoResponse.java rename to modules/activiti-rest/src/main/java/org/activiti/rest/api/management/ProcessEngineInfoResponse.java index 53ba7c9d645883e89ed5edbdfea53deb6bf5a861..742a2dd21929f5d2604d9a95fbbad02b4991808a 100644 --- a/modules/activiti-rest/src/main/java/org/activiti/rest/api/engine/ProcessEngineInfoResponse.java +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/management/ProcessEngineInfoResponse.java @@ -11,7 +11,7 @@ * limitations under the License. */ -package org.activiti.rest.api.engine; +package org.activiti.rest.api.management; /** * @author Tijs Rademakers diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/engine/ProcessEngineResource.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/management/ProcessEngineResource.java similarity index 74% rename from modules/activiti-rest/src/main/java/org/activiti/rest/api/engine/ProcessEngineResource.java rename to modules/activiti-rest/src/main/java/org/activiti/rest/api/management/ProcessEngineResource.java index 26a2c0b8b940e0c8ee0a004d77018d5c8604e8a0..82145df639a935e7bc5c908f0cbc3377aadf08c4 100644 --- a/modules/activiti-rest/src/main/java/org/activiti/rest/api/engine/ProcessEngineResource.java +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/management/ProcessEngineResource.java @@ -11,7 +11,7 @@ * limitations under the License. */ -package org.activiti.rest.api.engine; +package org.activiti.rest.api.management; import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngineInfo; @@ -28,11 +28,19 @@ public class ProcessEngineResource extends SecuredResource { public ProcessEngineInfoResponse getEngineInfo() { if(authenticate() == false) return null; - ProcessEngineInfo engineInfo = ActivitiUtil.getProcessEngineInfo(); ProcessEngineInfoResponse response = new ProcessEngineInfoResponse(); - response.setName(engineInfo.getName()); - response.setResourceUrl(engineInfo.getResourceUrl()); - response.setException(engineInfo.getException()); + + ProcessEngineInfo engineInfo = ActivitiUtil.getProcessEngineInfo(); + if(engineInfo != null) { + response.setName(engineInfo.getName()); + response.setResourceUrl(engineInfo.getResourceUrl()); + response.setException(engineInfo.getException()); + } else { + // Revert to using process-engine directly + ProcessEngine engine = ActivitiUtil.getProcessEngine(); + response.setName(engine.getName()); + } + response.setVersion(ProcessEngine.VERSION); return response; } diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/management/PropertiesCollectionResource.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/management/PropertiesCollectionResource.java new file mode 100644 index 0000000000000000000000000000000000000000..ad7fafe4068653517e68059f4d1c014423214fe1 --- /dev/null +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/management/PropertiesCollectionResource.java @@ -0,0 +1,35 @@ +/* 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.management; + +import java.util.Map; + +import org.activiti.rest.api.ActivitiUtil; +import org.activiti.rest.api.SecuredResource; +import org.restlet.resource.Get; + +/** + * @author Frederik Heremans + */ +public class PropertiesCollectionResource extends SecuredResource { + + @Get + public Map getProperties() { + if (authenticate() == false) + return null; + + return ActivitiUtil.getManagementService().getProperties(); + } +} + diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/ProcessDefinitionActionRequest.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/ProcessDefinitionActionRequest.java index 6a2c84e3ca317cac8d1ea4eea9a41f4eecc28727..ce77ae390a8800844b12142b8ccfc8f67927acaa 100644 --- a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/ProcessDefinitionActionRequest.java +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/ProcessDefinitionActionRequest.java @@ -28,6 +28,7 @@ public class ProcessDefinitionActionRequest extends RestActionRequest { private boolean includeProcessInstances = false; private Date date; + private String category; public void setIncludeProcessInstances(boolean includeProcessInstances) { this.includeProcessInstances = includeProcessInstances; @@ -41,4 +42,10 @@ public class ProcessDefinitionActionRequest extends RestActionRequest { public Date getDate() { return date; } + public void setCategory(String category) { + this.category = category; + } + public String getCategory() { + return category; + } } diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/ProcessDefinitionResource.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/ProcessDefinitionResource.java index 10c21363b3e4d1e538c5c842b9afe40f9830a708..64c8d9643d7d28fa14991810115fc7a8c4cbdc02 100644 --- a/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/ProcessDefinitionResource.java +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/repository/ProcessDefinitionResource.java @@ -49,15 +49,28 @@ public class ProcessDefinitionResource extends BaseProcessDefinitionResource { ProcessDefinition processDefinition = getProcessDefinitionFromRequest(); - if(actionRequest.getAction() != null) { - if(ProcessDefinitionActionRequest.ACTION_SUSPEND.equals(actionRequest.getAction())) { - return suspendProcessDefinition(processDefinition, actionRequest.isIncludeProcessInstances(), actionRequest.getDate()); - } else if(ProcessDefinitionActionRequest.ACTION_ACTIVATE.equals(actionRequest.getAction())) { - return activateProcessDefinition(processDefinition, actionRequest.isIncludeProcessInstances(), actionRequest.getDate()); + if(actionRequest.getCategory() != null) { + // Update of category required + ActivitiUtil.getRepositoryService().setProcessDefinitionCategory(processDefinition.getId(), actionRequest.getCategory()); + + // No need to re-fetch the ProcessDefinition entity, just update category in response + ProcessDefinitionResponse response = getApplication(ActivitiRestServicesApplication.class).getRestResponseFactory() + .createProcessDefinitionResponse(this, processDefinition); + response.setCategory(actionRequest.getCategory()); + return response; + + } else { + // Actual action + if(actionRequest.getAction() != null) { + if(ProcessDefinitionActionRequest.ACTION_SUSPEND.equals(actionRequest.getAction())) { + return suspendProcessDefinition(processDefinition, actionRequest.isIncludeProcessInstances(), actionRequest.getDate()); + } else if(ProcessDefinitionActionRequest.ACTION_ACTIVATE.equals(actionRequest.getAction())) { + return activateProcessDefinition(processDefinition, actionRequest.isIncludeProcessInstances(), actionRequest.getDate()); + } } + + throw new ActivitiIllegalArgumentException("Invalid action: '" + actionRequest.getAction() + "'."); } - - throw new ActivitiIllegalArgumentException("Invalid action: '" + actionRequest.getAction() + "'."); } protected ProcessDefinitionResponse activateProcessDefinition(ProcessDefinition processDefinition, boolean suspendInstances, Date date) { diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/runtime/process/ExecutionActiveActivitiesCollectionResource.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/runtime/process/ExecutionActiveActivitiesCollectionResource.java new file mode 100644 index 0000000000000000000000000000000000000000..be6906ced6395828be1cd1f5c2a22b77483cc51f --- /dev/null +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/runtime/process/ExecutionActiveActivitiesCollectionResource.java @@ -0,0 +1,37 @@ +/* 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.runtime.Execution; +import org.activiti.rest.api.ActivitiUtil; +import org.restlet.resource.Get; + + +/** + * @author Frederik Heremans + */ +public class ExecutionActiveActivitiesCollectionResource extends ExecutionBaseResource { + + @Get + public List getActiveActivities() { + if(!authenticate()) { + return null; + } + Execution execution = getExecutionFromRequest(); + return ActivitiUtil.getRuntimeService().getActiveActivityIds(execution.getId()); + } +} diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/application/RestServicesInit.java b/modules/activiti-rest/src/main/java/org/activiti/rest/application/RestServicesInit.java index 3a641d1691602fcc73ea9ea85734d1a77554e60e..4c6553c99c745ead1b778c3b5bbc63c6f01a04c2 100644 --- a/modules/activiti-rest/src/main/java/org/activiti/rest/application/RestServicesInit.java +++ b/modules/activiti-rest/src/main/java/org/activiti/rest/application/RestServicesInit.java @@ -1,6 +1,5 @@ package org.activiti.rest.application; -import org.activiti.rest.api.engine.ProcessEngineResource; import org.activiti.rest.api.history.HistoricActivityInstanceCollectionResource; import org.activiti.rest.api.history.HistoricActivityInstanceQueryResource; import org.activiti.rest.api.history.HistoricDetailCollectionResource; @@ -67,6 +66,8 @@ import org.activiti.rest.api.legacy.task.LegacyTaskResource; import org.activiti.rest.api.management.JobCollectionResource; import org.activiti.rest.api.management.JobExceptionStacktraceResource; import org.activiti.rest.api.management.JobResource; +import org.activiti.rest.api.management.ProcessEngineResource; +import org.activiti.rest.api.management.PropertiesCollectionResource; import org.activiti.rest.api.management.TableCollectionResource; import org.activiti.rest.api.management.TableColumnsResource; import org.activiti.rest.api.management.TableDataResource; @@ -83,6 +84,7 @@ import org.activiti.rest.api.repository.ProcessDefinitionModelResource; import org.activiti.rest.api.repository.ProcessDefinitionResource; import org.activiti.rest.api.repository.ProcessDefinitionResourceDataResource; import org.activiti.rest.api.repository.SimpleWorkflowResource; +import org.activiti.rest.api.runtime.process.ExecutionActiveActivitiesCollectionResource; import org.activiti.rest.api.runtime.process.ExecutionCollectionResource; import org.activiti.rest.api.runtime.process.ExecutionQueryResource; import org.activiti.rest.api.runtime.process.ExecutionResource; @@ -168,6 +170,7 @@ public class RestServicesInit { router.attach("/runtime/executions", ExecutionCollectionResource.class); router.attach("/runtime/executions/{executionId}", ExecutionResource.class); + router.attach("/runtime/executions/{executionId}/activities", ExecutionActiveActivitiesCollectionResource.class); router.attach("/runtime/executions/{executionId}/variables", ExecutionVariableCollectionResource.class); router.attach("/runtime/executions/{executionId}/variables/{variableName}", ExecutionVariableResource.class); router.attach("/runtime/executions/{executionId}/variables/{variableName}/data", ExecutionVariableDataResource.class); @@ -191,6 +194,8 @@ public class RestServicesInit { router.attach("/management/jobs", JobCollectionResource.class); router.attach("/management/jobs/{jobId}", JobResource.class); router.attach("/management/jobs/{jobId}/exception-stacktrace", JobExceptionStacktraceResource.class); + router.attach("/management/properties", PropertiesCollectionResource.class); + router.attach("/management/engine", ProcessEngineResource.class); router.attach("/identity/users", UserCollectionResource.class); router.attach("/identity/users/{userId}", UserResource.class); diff --git a/modules/activiti-rest/src/test/java/org/activiti/rest/api/management/PropertiesCollectionResourceTest.java b/modules/activiti-rest/src/test/java/org/activiti/rest/api/management/PropertiesCollectionResourceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b47e12b5336bf319dd0bdffbab551780e9f4bec6 --- /dev/null +++ b/modules/activiti-rest/src/test/java/org/activiti/rest/api/management/PropertiesCollectionResourceTest.java @@ -0,0 +1,45 @@ +package org.activiti.rest.api.management; + +import java.util.Iterator; +import java.util.Map; + +import org.activiti.rest.BaseRestTestCase; +import org.activiti.rest.api.RestUrls; +import org.codehaus.jackson.JsonNode; +import org.restlet.data.Status; +import org.restlet.representation.Representation; +import org.restlet.resource.ClientResource; + +/** + * Test for all REST-operations related to the Job collection and a single + * job resource. + * + * @author Frederik Heremans + */ +public class PropertiesCollectionResourceTest extends BaseRestTestCase { + + + /** + * Test getting the engine properties. + */ + public void testGetProperties() throws Exception { + ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_PROPERTIES_COLLECTION)); + Representation response = client.get(); + assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus()); + + Map properties = managementService.getProperties(); + + JsonNode responseNode = objectMapper.readTree(response.getStream()); + assertNotNull(responseNode); + assertEquals(properties.size(), responseNode.size()); + + Iterator> nodes = responseNode.getFields(); + Map.Entry node = null; + while(nodes.hasNext()) { + node = nodes.next(); + String propValue = properties.get(node.getKey()); + assertNotNull(propValue); + assertEquals(propValue, node.getValue().getTextValue()); + } + } +} \ No newline at end of file diff --git a/modules/activiti-rest/src/test/java/org/activiti/rest/api/repository/ProcessDefinitionResourceTest.java b/modules/activiti-rest/src/test/java/org/activiti/rest/api/repository/ProcessDefinitionResourceTest.java index 3423334e15b269c88e7157222806ab3b801ca2b9..a636e25a4eb715a9b8824ad0739132f11ec4f5f3 100644 --- a/modules/activiti-rest/src/test/java/org/activiti/rest/api/repository/ProcessDefinitionResourceTest.java +++ b/modules/activiti-rest/src/test/java/org/activiti/rest/api/repository/ProcessDefinitionResourceTest.java @@ -375,5 +375,31 @@ public class ProcessDefinitionResourceTest extends BaseRestTestCase { assertEquals("Could not find a process definition with id 'unexisting'.", client.getResponse().getStatus().getDescription()); } } + + /** + * Test activating a suspended process definition delayed. + * POST repository/process-definitions/{processDefinitionId} + */ + @Deployment(resources={"org/activiti/rest/api/repository/oneTaskProcess.bpmn20.xml"}) + public void testUpdateProcessDefinitionCategory() throws Exception { + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult(); + assertEquals(1, repositoryService.createProcessDefinitionQuery().processDefinitionCategory("OneTaskCategory").count()); + + ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_DEFINITION, processDefinition.getId())); + ObjectNode requestNode = objectMapper.createObjectNode(); + requestNode.put("category", "updatedcategory"); + + Representation response = client.put(requestNode); + + // Check "OK" status + assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus()); + + JsonNode responseNode = objectMapper.readTree(response.getStream()); + assertEquals("updatedcategory", responseNode.get("category").getTextValue()); + + // Check actual entry in DB + assertEquals(1, repositoryService.createProcessDefinitionQuery().processDefinitionCategory("updatedcategory").count()); + + } } diff --git a/modules/activiti-rest/src/test/java/org/activiti/rest/api/runtime/ExecutionActiveActivitiesCollectionResourceTest.java b/modules/activiti-rest/src/test/java/org/activiti/rest/api/runtime/ExecutionActiveActivitiesCollectionResourceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ee82655cbed8ba8842d7a5b258cad147c4fbb516 --- /dev/null +++ b/modules/activiti-rest/src/test/java/org/activiti/rest/api/runtime/ExecutionActiveActivitiesCollectionResourceTest.java @@ -0,0 +1,55 @@ +/* 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 java.util.HashSet; +import java.util.Set; + +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.restlet.data.Status; +import org.restlet.representation.Representation; +import org.restlet.resource.ClientResource; + + +/** + * @author Frederik Heremans + */ +public class ExecutionActiveActivitiesCollectionResourceTest extends BaseRestTestCase { + + @Deployment + public void testGetActivities() throws Exception { + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("processOne"); + + ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_EXECUTION_ACTIVITIES_COLLECTION, processInstance.getId())); + Representation response = client.get(); + assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus()); + + // Check resulting instance + JsonNode responseNode = objectMapper.readTree(response.getStream()); + assertNotNull(responseNode); + assertTrue(responseNode.isArray()); + assertEquals(2, responseNode.size()); + + Set states = new HashSet(); + states.add(responseNode.get(0).getTextValue()); + states.add(responseNode.get(1).getTextValue()); + + assertTrue(states.contains("waitState")); + assertTrue(states.contains("anotherWaitState")); + } +} diff --git a/modules/activiti-rest/src/test/resources/org/activiti/rest/api/runtime/ExecutionActiveActivitiesCollectionResourceTest.testGetActivities.bpmn20.xml b/modules/activiti-rest/src/test/resources/org/activiti/rest/api/runtime/ExecutionActiveActivitiesCollectionResourceTest.testGetActivities.bpmn20.xml new file mode 100644 index 0000000000000000000000000000000000000000..2c46b7c620378a4adbd7d971d8c635bfc6f984ff --- /dev/null +++ b/modules/activiti-rest/src/test/resources/org/activiti/rest/api/runtime/ExecutionActiveActivitiesCollectionResourceTest.testGetActivities.bpmn20.xml @@ -0,0 +1,24 @@ + + + + + One task process description + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/activiti-webapp-explorer2/src/main/webapp/diagram-viewer/js/ProcessDiagramCanvas.js b/modules/activiti-webapp-explorer2/src/main/webapp/diagram-viewer/js/ProcessDiagramCanvas.js index 3ad2c7cdd9859260381b5c199d79725d5667807b..9e268c1f47f432519c2026d55d50ba721bfcafcc 100644 --- a/modules/activiti-webapp-explorer2/src/main/webapp/diagram-viewer/js/ProcessDiagramCanvas.js +++ b/modules/activiti-webapp-explorer2/src/main/webapp/diagram-viewer/js/ProcessDiagramCanvas.js @@ -1614,7 +1614,7 @@ ProcessDiagramCanvas.prototype = { drawCollapsedCallActivity: function(name, x, y, width, height) { this.g.setStart(); - this.drawCollapsedTask(name, x, y, width, height, true); + this._drawCollapsedTask(name, x, y, width, height, true); var set = this.g.setFinish(); this.addHandlers(set, x, y, width, height, "task"); }, diff --git a/userguide/src/en/chapters/ch07b-BPMN-Constructs.xml b/userguide/src/en/chapters/ch07b-BPMN-Constructs.xml index a42eed391e04c33feed757af8976aae6730817ea..f546338b4488d824f2508ea9aaaf0d1051cad1ea 100644 --- a/userguide/src/en/chapters/ch07b-BPMN-Constructs.xml +++ b/userguide/src/en/chapters/ch07b-BPMN-Constructs.xml @@ -2781,8 +2781,8 @@ assertEquals("Ship Order", task.getName()); There is an activity extension which allows you to specify an expression in your task-definition to set the initial due date of a task when it is created. The expression should always resolve to a java.util.Date, - java.util.String (ISO8601 formatted) or null. - For example, you could use a date that was entered in a previous form in the process or calculated in a previous Service Task. + java.util.String (ISO8601 formatted), ISO8601 time-duration (eg. PT50M) or null. + For example, you could use a date that was entered in a previous form in the process or calculated in a previous Service Task. In case a time-duration is used, the due-date is calculated based on the current time, incremented by the given period. For example, when "PT30M" is used as dueDate, the task is due in thirty minutes from now. <userTask id="theTask" name="Important task" activiti:dueDate="${dateVariable}"/> diff --git a/userguide/src/en/chapters/ch14-REST.xml b/userguide/src/en/chapters/ch14-REST.xml index 58d395e55a6932e493c7410ecde018023d28b6b2..a262323687709807dd5438a2822dec0b7b4cc833 100644 --- a/userguide/src/en/chapters/ch14-REST.xml +++ b/userguide/src/en/chapters/ch14-REST.xml @@ -1177,6 +1177,49 @@ +
+ Update category for a single process definition + + PUT repository/process-definitions/{processDefinitionId} + + + Body JSON: + +{ + "category" : "updatedcategory" +} + + + + Response codes + + + + Response code + Description + + + + + 200 + Indicates the process was category was altered. + + + 400 + Indicates no category was defined in the request body. + + + 404 + Indicates the requested process definition was not found. + + + +
+
+ + Success response body: see response for repository/process-definitions/{processDefinitionId}. + +
Get a process definition resource content @@ -4498,6 +4541,83 @@ Only the attachment name is required to create a new attachment.
+ +
+ Engine +
+ Get engine properties + + GET management/properties + + + Returns a read-only view of the properties used internally in the engine. + + + Success response body: + +{ + "next.dbid":"101", + "schema.history":"create(5.13)", + "schema.version":"5.13" +} + + Response codes + + + + Response code + Description + + + + + 200 + Indicates the properties are returned. + + + +
+
+
+
+ Get engine info + + GET management/engine + + + Returns a read-only view of the engine that is used in this REST-service. + + + Success response body: + +{ + "name":"default", + "version":"5.13", + "resourceUrl":"file://activiti/activiti.cfg.xml", + "exception":null +} + + Response codes + + + + Response code + Description + + + + + 200 + Indicates the engine info is returned. + + + +
+
+
+
+ +
Jobs