버전용 도움말 콘텐츠:
- 6.2
- 이전 버전
When customizing and extending your workflows you can access workflow objects:
The workflow Java API consists of the com.adobe.granite.workflow package and several sub-packages. The most significant member of the API is the com.adobe.granite.workflow.WorkflowSession class. The WorkflowSession class provides access to both design-time and runtime workflow objects:
- workflow models
- work items
- workflow instances
- workflow data
- inbox items
The class also provides several methods for intervening in workflow lifecycles.
The following table provides links to the reference documentation of several key Java objects to use when interacting programmatically with workflows. The examples that follow demonstrate how to obtain and use the class objects in code.
Features | Objects |
---|---|
Accessing a workflow |
WorkflowSession |
Executing and querying a workflow instance |
Workflow WorkItem WorkflowData |
Managing a workflow model |
WorkflowModel WorkflowNode WorkflowTransition |
As described in Locating the Script, AEM (via Apache Sling) provides an ECMA script engine that executes server-side ECMA scripts. The org.apache.sling.scripting.core.ScriptHelper class is immediately available to your scripts as the sling variable.
The ScriptHelper class provides access to the SlingHttpServletRequest that you can use to eventually obtain the WorkflowSession object; for example:
var wfsession = sling.getRequest().getResource().getResourceResolver().adaptTo(Packages.com.adobe.granite.workflow.WorkflowSession);
The curl command line tool enables you to use the Workflow REST API to access workflow objects and manage instance lifecycles. The examples that follow demonstrate the use of the REST API via the curl command line tool.
The Workflow console makes heavy use of the REST API; so this page describes the REST API for workflows.
The following actions are supported with the REST API:
- start or stop a workflow service
- create, update or delete workflow models
- start, suspend, resume or terminate workflow instances
- complete or delegate work items
참고:
By using Firebug, a Firefox extension for web development, it is possible to follow the HTTP traffic when the console is operated. For example you can check the parameters and the values sent to the AEM server with a POST request.
In this page it is assumed that AEM runs on localhost at port 4502 and that the installation context is "/" (root). If it is not the case of your installation, the URIs, to which the HTTP requests apply, need to be adapted accordingly.
The rendering supported for GET requests is the JSON rendering. The URLs for GET should have the .json extension, for example:
http://localhost:4502/etc/workflow.json
HTTP request method | Actions |
GET | Lists the available workflow instances. |
POST | Creates a new workflow instance. The parameters are: |
HTTP request method | Actions |
GET | Lists the available workflow instances and their states (RUNNING, SUSPENDED, ABORTED or COMPLETED) |
HTTP request method | Actions |
GET | Gets the instances data (definition and metadata) including the link to the respective workflow model. |
POST | Changes the state of the instance. The new state is sent as the parameter state and must have one of the following values: RUNNING, SUSPENDED, or ABORTED. If the new state is not reachable (for example when suspending a terminated instance) a 409 (CONFLICT) response is sent back to the client. |
HTTP request method | Actions |
GET | Lists the available workflow models. |
POST | Creates a new workflow model. If the parameter title is sent, a new model is created with the specified title. Attaching a JSON model definition as parameter model creates a new workflow model according to the provided definition. A 201 response (CREATED) is sent back with a location header containing the URL of the new workflow model resource. The same happens when a model definition is attached as a file parameter called modelfile. In both the cases of the model and modelfile parameters, an additional parameter called type is required to define the serialization format. New serialization formats can be integrated using the OSGI API. A standard JSON serializer is delivered with the workflow engine. Its type is JSON. See below for an example of the format. |
Example: in the browser, a request to http://localhost:4502/etc/workflow/models.json gets a similar json file to the following one:
[ {"uri":"/etc/workflow/models/collab/comment_moderation"} ,{"uri":"/etc/workflow/models/dam/dam_asset_syncer_and"} ,{"uri":"/etc/workflow/models/dam/delete_asset"} ,{"uri":"/etc/workflow/models/dam/delete_dam_asset"} ,{"uri":"/etc/workflow/models/dam/dam_set_last_modified"} ,{"uri":"/etc/workflow/models/dam/dam_update_dam_content_create"} ,{"uri":"/etc/workflow/models/dam/dam_update_dam_content_del"} ,{"uri":"/etc/workflow/models/dam/dam_update_var_folder_create"} ,{"uri":"/etc/workflow/models/dam/dam_update_var_folder_delete"} ,{"uri":"/etc/workflow/models/dam/update_asset"} ,{"uri":"/etc/workflow/models/dam/update_from_lightbox"} ,{"uri":"/etc/workflow/models/my_workflow"} ,{"uri":"/etc/workflow/models/newsletter_example"} ,{"uri":"/etc/workflow/models/product_of_the_day"} ,{"uri":"/etc/workflow/models/publish_example"} ,{"uri":"/etc/workflow/models/request_for_activation"} ,{"uri":"/etc/workflow/models/request_for_deactivation"} ,{"uri":"/etc/workflow/models/scheduled_activation"} ,{"uri":"/etc/workflow/models/scheduled_deactivation"} ,{"uri":"/etc/workflow/models/translation"} ,{"uri":"/etc/workflow/models/welcome_new_employees"} ]
The following HTTP request methods apply to:
http://localhost:4502{uri}
Where {uri} is the path to the model node in the repository.
HTTP request method | Actions |
GET | Gets the HEAD version of the model (definition and metadata). |
PUT | Updates the HEAD version of the model (creates a new version). The complete model definition for the new version of the model must be added as a parameter called model. Additionally a type parameter is needed as when creating new models and needs to have the value JSON. |
POST | Same behaviour as with PUT. Needed because AEM widgets do not support PUT operations. |
DELETE | Deletes the model. In order to solve firewall/proxy issues a POST that contains an X-HTTP-Method-Override header entry with value DELETE will also be accepted as DELETE request. |
Example: in the browser, a request to http://localhost:4502/etc/workflow/models/publish_example.-1.json returns a json file that is similar to the following code:
{ "description": "This example shows a simple review and publish process.", "title": "Publish Example", "jcr:predecessors": [ ], "sling:resourceType": "cq/workflow/components/model", "jcr:uuid": "675f04fd-eb3c-44b9-9921-90926c8fc0f0", "jcr:versionHistory": "44fb918c-b081-47d8-95b8-dbd68b9cce08", "jcr:baseVersion": "75ce2903-9159-4bf7-8b0d-af232e252fbb", "jcr:primaryType": "cq:WorkflowModel", "jcr:isCheckedOut": false, "metaData": { "tags": "wcm", "jcr:primaryType": "nt:unstructured" }, "nodes": { "jcr:primaryType": "nt:unstructured", "node0": { "title": "Start", "description": "The start node of the workflow.", "type": "START", "jcr:primaryType": "cq:WorkflowNode", "metaData": { "jcr:primaryType": "nt:unstructured" } }, "node1": { "title": "Validate Content", "description": "Validate the modified content.", "type": "PARTICIPANT", "jcr:primaryType": "cq:WorkflowNode", "metaData": { "PARTICIPANT": "admin", "jcr:primaryType": "nt:unstructured" } }, "node2": { "title": "Publish Content", "description": "Publish the modified content.", "type": "PROCESS", "jcr:primaryType": "cq:WorkflowNode", "metaData": { "PROCESS_AUTO_ADVANCE": "true", "PROCESS": "com.day.cq.wcm.workflow.process.ActivatePageProcess", "jcr:primaryType": "nt:unstructured" } }, "node3": { "title": "End", "description": "The end node of the workflow.", "type": "END", "jcr:primaryType": "cq:WorkflowNode", "metaData": { "jcr:primaryType": "nt:unstructured" } } }, "transitions": { "jcr:primaryType": "nt:unstructured", "node0#node1": { "to": "node1", "from": "node0", "jcr:primaryType": "cq:WorkflowTransition", "metaData": { "jcr:primaryType": "nt:unstructured" } }, "node1#node2": { "to": "node2", "from": "node1", "jcr:primaryType": "cq:WorkflowTransition", "metaData": { "jcr:primaryType": "nt:unstructured" } }, "node2#node3": { "to": "node3", "from": "node2", "jcr:primaryType": "cq:WorkflowTransition", "metaData": { "jcr:primaryType": "nt:unstructured" } } } }
The following HTTP request methods apply to:
http://localhost:4502/etc/workflow/models/{id}.{version}
HTTP request method | Actions |
GET | Lists the work items that are in the inbox of the user, who is identified by the HTTP authentication headers. |
POST | Completes the work item whose URI is sent as the parameter item and advances the according workflow instance to the next node(s), that is defined by the parameter route or backroute in case of going a step back. If the parameter delegatee is sent, the work item identified by the parameter item is delegated to the specified participant. |
HTTP request method | Actions |
GET | Gets the data (definition and metadata) of the inbox WorkItem identified by its ID. |
To get a list of all running workflows, do a GET to:
http://localhost:4502/etc/workflow/instances.RUNNING
Example using curl:
curl -u admin:admin http://localhost:4502/etc/workflow/instances.RUNNING.json
To change the Workflow Title displayed in the Instances tab of the workflow console, send a POST command:
- to: http://localhost:4502/etc/workflow/instances/{id}
- with the following parameters:
- action: its value has to be: UPDATE
- workflowTitle: the workflow title
- action: its value has to be: UPDATE
Example using curl:
curl -u admin:admin -d "action=UPDATE&workflowTitle=myWorkflowTitle" http://localhost:4502/etc/workflow/instances/{id}
The com.adobe.granite.workflow.WorkflowSession class is adaptable from a javax.jcr.Session object or a org.apache.sling.api.resource.ResourceResolver object.
In a JSP script (or Java code for a servlet class), use the HTTP request object to obtain a SlingHttpServletRequest object, which provides access to a ResourceResolver object. Adapt the ResourceResolver object to WorkflowSession.
<% %><%@include file="/libs/foundation/global.jsp"%><% %><%@page session="false" import="com.adobe.granite.workflow.WorkflowSession, org.apache.sling.api.SlingHttpServletRequest"%><% SlingHttpServletRequest slingReq = (SlingHttpServletRequest)request; WorkflowSession wfSession = slingReq.getResourceResolver().adaptTo(WorkflowSession.class); %>
Use the sling variable to obtain the SlingHttpServletRequest object that you use to obtain a ResourceResolver object. Adapt the ResourceResolver object to the WorkflowSession object.
var wfsession = sling.getRequest().getResource().getResourceResolver().adaptTo(Packages.com.adobe.granite.workflow.WorkflowSession);
The following examples show how to access workflow models:
- The code for Java and ECMA script uses the WorkflowSession.createNewModel method.
- The curl command accesses the model directly using its URL.
The examples used:
- Create a model (with the ID /etc/workflow/models/mymodel/jcr:content/model).
- Delete the model.
참고:
Deleting the model sets the deleted property of the model's metaData child node to true.
Deletion does not remove the model node.
-
The workflow model editor requires that models use a specific node structure below /etc/workflow/models. The parent node of the model must be of the type cq:Page having a jcr:content node with the following property values:
- sling:resourceType: cq/workflow/components/pages/model
- cq:template: /libs/cq/workflow/templates/model
When you create a model, you must first create this cq:Page node and use its jcr:content node as the parent of the model node.
<%@include file="/libs/foundation/global.jsp"%><% %><%@page session="false" import="com.adobe.granite.workflow.WorkflowSession, com.adobe.granite.workflow.model.WorkflowModel, org.apache.sling.api.SlingHttpServletRequest"%><% SlingHttpServletRequest slingReq = (SlingHttpServletRequest)request; WorkflowSession wfSession = slingReq.getResourceResolver().adaptTo(WorkflowSession.class); /* Create the parent page */ String modelRepo = new String("/etc/workflow/models"); String modelTemplate = new String ("/libs/cq/workflow/templates/model"); String modelName = new String("mymodel"); Page modelParent = pageManager.create(modelRepo, modelName, modelTemplate, "My workflow model"); /* create the model */ String modelId = new String(modelParent.getPath()+"/jcr:content/model") WorkflowModel model = wfSession.createNewModel("Made using Java",modelId); /* delete the model */ wfSession.deleteModel(modelId); %>
var resolver = sling.getRequest().getResource().getResourceResolver(); var wfSession = resolver.adaptTo(Packages.com.adobe.granite.workflow.WorkflowSession); var pageManager = resolver.adaptTo(Packages.com.day.cq.wcm.api.PageManager); //create the parent page node var workflowPage = pageManager.create("/etc/workflow/models", "mymodel", "/libs/cq/workflow/templates/model", "Created via ECMA Script"); var modelId = workflowPage.getPath()+ "/jcr:content/model"; //create the model var model = wfSession.createNewModel("My Model", modelId); //delete the model var model = wfSession.deleteModel(modelId);
# creating the model called "name" curl -u admin:admin -d "title=name" http://localhost:4502/etc/workflow/models # deleting the model by its id curl -u admin:admin -X DELETE http://localhost:4502/etc/workflow/models/{id} # getting the model by its id curl -u admin:admin http://localhost:4502/etc/workflow/models/{id}
// starting a workflow WorkflowModel model = wfSession.getModel(workflowId); WorkflowData wfData = wfSession.newWorkflowData("JCR_PATH", repoPath); wfSession.startWorkflow(model, wfData); // querying and managing a workflow Workflow[] workflows workflows = wfSession.getAllWorkflows(); Workflow workflow= wfSession.getWorkflow(id); wfSession.suspendWorkflow(workflow); wfSession.resumeWorkflow(workflow); wfSession.terminateWorkflow(workflow);
// starting a workflow var model = wfSession.getModel(workflowId); var wfData = wfSession.newWorkflowData("JCR_PATH", repoPath); wfSession.startWorkflow(model, wfData); // querying and managing a workflow var workflows = wfSession.getWorkflows(“RUNNING“); var workflow= wfSession.getWorkflow(id); wfSession.suspendWorkflow(workflow); wfSession.resumeWorkflow(workflow); wfSession.terminateWorkflow(workflow);
# starting a workflow curl -d "model={id}&payloadType={type}&payload={payload}" http://localhost:4502/etc/workflow/instances # for example: curl -u admin:admin -d "model=/etc/workflow/models/name&payloadType=JCR_PATH&payload=/content/geometrixx/en/services" http://localhost:4502/etc/workflow/instances # listing the instances curl -u admin:admin http://localhost:4502/etc/workflow/instances/ # suspending a workflow curl -d "state=SUSPENDED" http://localhost:4502/etc/workflow/instances/{id} # for example: curl -u admin:admin -d "state=SUSPENDED" http://localhost:4502/etc/workflow/instances/2009-12-09/name_1_1260365650960705000 # resuming a workflow curl -d "state=RUNNING" http://localhost:4502/etc/workflow/instances/{id} # for example: curl -u admin:admin -d "state=RUNNING" http://localhost:4502/etc/workflow/instances/2009-12-09/name_1_1260365650960705000 # terminating a workflow curl -d "state=ABORTED" http://localhost:4502/etc/workflow/instances/{id} # for example: curl -u admin:admin -d "state=ABORTED" http://localhost:4502/etc/workflow/instances/2009-12-09/name_1_1260365650960705000
// querying work items WorkItem[] workItems = wfSession.getActiveWorkItems(); WorkItem workItem = wfSession.getWorkItem(id); // getting routes List<Route> routes = wfSession.getRoutes(workItem); // delegating List<Authorizable> delegatees = wfSession.getDelegatees(workItem); wfSession.delegateWorkItem(workItem, delegatees.get(0)); // completing or advancing to the next step wfSession.complete(workItem, routes.get(0));
// querying work items var workItems = wfSession.getActiveWorkItems(); var workItem = wfSession.getWorkItem(id); // getting routes var routes = wfSession.getRoutes(workItem); // delegating var delegatees = wfSession.getDelegatees(workItem); wfSession.delegateWorkItem(workItem, delegatees.get(0)); // completing or advancing to the next step wfSession.complete(workItem, routes.get(0));
# listing the work items curl -u admin:admin http://localhost:4502/bin/workflow/inbox # delegating curl -d "item={item}&delegatee={delegatee}" http://localhost:4502/bin/workflow/inbox # For example: curl -u admin:admin -d "item=/etc/workflow/instances/2010-01-11/test1_1263223169820641000/workItems/node1_etc_workflow_instances_2010-01-11_test1_1263223169820641000&delegatee=author" http://localhost:4502/bin/workflow/inbox # completing or advancing to the next step curl -d "item={item}&route={route}" http://localhost:4502/bin/workflow/inbox # For example: curl -d "item=/etc/workflow/instances/2010-01-11/test1_1263223169820641000/workItems/node1_etc_workflow_instances_2010-01-11_test1_1263223169820641000&route=233123169" http://localhost:4502/bin/workflow/inbox
Use the OSGi event framework to listen for events that the com.adobe.granite.workflow.event.WorkflowEvent class defines. This class also provides several useful methods for obtaining information about the subject of the event. For example, the getWorkItem method returns the WorkItem object for the workitem that is involved in the event.
The following example code defines a service that listens to workflow events and performs tasks according to the type of event.
package com.adobe.example.workflow.listeners; import org.apache.sling.event.jobs.JobProcessor; import org.apache.sling.event.jobs.JobUtil; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Service; import com.adobe.granite.workflow.event.WorkflowEvent; import com.adobe.granite.workflow.exec.WorkItem; /** * The <code>WorkflowEventCatcher</code> class listens to workflow events. */ @Component(metatype=false, immediate=true) @Service(value=org.osgi.service.event.EventHandler.class) public class WorkflowEventCatcher implements EventHandler, JobProcessor { @Property(value=com.adobe.granite.workflow.event.WorkflowEvent.EVENT_TOPIC) static final String EVENT_TOPICS = "event.topics"; private static final Logger logger = LoggerFactory.getLogger(WorkflowEventCatcher.class); public void handleEvent(Event event) { JobUtil.processJob(event, this); } public boolean process(Event event) { logger.info("Received event of topic: " + event.getTopic()); String topic = event.getTopic(); try { if (topic.equals(WorkflowEvent.EVENT_TOPIC)) { WorkflowEvent wfevent = (WorkflowEvent)event; String eventType = wfevent.getEventType(); String instanceId = wfevent.getWorkflowInstanceId(); if (instanceId != null) { //workflow instance events if (eventType.equals(WorkflowEvent.WORKFLOW_STARTED_EVENT) || eventType.equals(WorkflowEvent.WORKFLOW_RESUMED_EVENT) || eventType.equals(WorkflowEvent.WORKFLOW_SUSPENDED_EVENT)) { // your code comes here... } else if ( eventType.equals(WorkflowEvent.WORKFLOW_ABORTED_EVENT) || eventType.equals(WorkflowEvent.WORKFLOW_COMPLETED_EVENT)) { // your code comes here... } // workflow node event if (eventType.equals(WorkflowEvent.NODE_TRANSITION_EVENT)) { WorkItem currentItem = (WorkItem) event.getProperty(WorkflowEvent.WORK_ITEM); // your code comes here... } } } } catch(Exception e){ logger.debug(e.getMessage()); e.printStackTrace(); } return true; } }