{"id":4940,"date":"2018-08-20T12:43:48","date_gmt":"2018-08-20T07:13:48","guid":{"rendered":"\/?p=4940"},"modified":"2020-08-17T11:44:57","modified_gmt":"2020-08-17T06:14:57","slug":"triggering-a-workflow-using-event-listeners-in-aem","status":"publish","type":"post","link":"https:\/\/www.argildx.us\/technology\/triggering-a-workflow-using-event-listeners-in-aem\/","title":{"rendered":"How to Trigger a Workflow in AEM using Event Listeners"},"content":{"rendered":"
Trigger a Workflow in AEM<\/strong><\/h5>\n

We can trigger a workflow in AEM 6.2 when a DAM Asset is created, modified, or deleted within a given path. In this article, we will explore triggering workflows from our code based on events in the JCR.<\/p>\n

Suppose you have a workflow that creates custom renditions of assets in addition to the default AEM renditions, when the asset is under \u201c\/content\/dam\/ProjectName\/images\/\u201d. You would have set up two workflow launchers for triggering this workflow: one with event type as \u201cNode Create\u201d and one with \u201cNode Modified\u201d. We can also achieve the same functionality through our code, without touching the GUI.<\/p>\n

Requirements<\/strong><\/h5>\n

When assets are moved into a certain folder structure in DAM, trigger a workflow that creates a 100px X 100px thumbnail of our image.<\/p>\n

\"no \"image<\/div>\n

Fig 1: Before Moving the asset, no custom thumbnail.\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Fig 2: Desired result after moving the asset, the new\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0thumbnail.<\/p>\n

Analysis<\/strong><\/h5>\n

The intuitive thought is that when an asset is moved, a new node is created in the new location and the old one is deleted. However, experience shows that AEM does not create a new node in the destination folder on Node Move. We know this because the \u2018jcr:Created\u2019 property does not change. AEM does not even change the last modified date.<\/p>\n

\"Creation \"Creation<\/div>\n

Fig 3: Creation Timestamp Before Moving the Asset.\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Fig 4: Creation Timestamp is the same after moving.<\/p>\n

\"Modification \"Modification<\/div>\n

Fig 5: Modification Timestamp Before Moving the Asset.\u00a0 \u00a0 \u00a0 Fig 6: Modification Timestamp is the same after moving.<\/p>\n

What if we copy the asset?<\/strong><\/h5>\n

On copying the asset, a new version of the same is created. This triggers the Node Creation launcher.<\/p>\n

\n

\"No<\/p>\n

\"version<\/p>\n<\/div>\n

Fig. 7: No versions before copying the asset.\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0Fig. 8: Version created after copy-pasting the asset.<\/p>\n

Approach<\/strong><\/h5>\n

Event Listeners<\/strong><\/p>\n

AEM supports observation, which enables us to receive notifications of persistent changes to the workspace. A persisted change to the workspace is represented by a set of one or more events. Each event reports a single simple change to the structure of the persistent workspace in terms of an item added, changed, moved or removed. There are thus 7 possible events at the JCR level, viz:<\/p>\n

    \n
  1. Node Added<\/li>\n
  2. Node Moved<\/li>\n
  3. Node Modified<\/li>\n
  4. Node Removed<\/li>\n
  5. Property Added<\/li>\n
  6. Property Removed<\/li>\n
  7. Property Changed<\/li>\n<\/ol>\n

    We connect with the observation mechanism by registering an event listener with the workspace. An event listener is a class implementing the EventListener interface, that responds to the stream of events to which it has been subscribed. An event listener is added to a workspace with:<\/p>\n

    void ObservationManager. \r\naddEventListener(EventListener listener, \r\nint eventTypes, \r\nString absPath,\r\nboolean isDeep, \r\nString[] uuid, \r\nString[] nodeTypeName, \r\nboolean noLocal)<\/pre>\n

    (A detailed explanation of each parameter is given with the code example in the package as well as at the end of this article) As defined by the EventListener interface, listener must provide an implementation of the onEvent method:<\/p>\n

    void EventListener.onEvent(EventIterator events)<\/pre>\n

    When an event occurs that falls within the scope of the listener, the repository calls the onEvent method invoking our logic which processes\/responds to the event. In our case, we will register an event listener to listen for \u201cNode Moved\u201d events under \u201c\/content\/dam\/images\u201d so that when an asset is moved to that folder, our workflow can be triggered.<\/p>\n

    Implementation<\/strong><\/h5>\n

    When the component is activated, the activate(\u2026) method is called. It contains a call to ObservationManager.addEventListener(\u2026) for registering the event listener. The deactivate(\u2026) method contains logic for deregistering the event listener, and is triggered when the bundle is being stopped.<\/p>\n

    When the relevant event occurs, the onEvent(\u2026) method is called, which contains logic for processing the event. In our case, we trigger a workflow in AEM.<\/p>\n

    The following is the relevant code from ThumbnailNodeMovedListener.java:<\/strong><\/p>\n

     \r\nprotected void activate(ComponentContext ctx) { \r\n\r\ntry { \r\n. \r\n. \r\n. \r\n\/\/ Building the parameters for adding the event listener \r\n\r\n\r\n\/\/ Whether the subfolders of the given path should also be watched \r\n\r\nboolean isDeep = true; \r\n\r\n\/\/ Only events whose associated node has one of the UUIDs in this list will be \r\n\r\n\/\/ received. If this parameter is null then no UUID-related restriction is \r\n\r\n\/\/ placed on events received. \r\n\r\nString[] uuid = null; \r\n\r\n\/\/ Only events whose associated node has one of the node types (or a subtype of \r\n\r\n\/\/ one of the node types) in this list will be received. If this parameter is \r\n\r\n\/\/ null then no node type-related restriction is placed on events received. \r\n\r\nString[] nodeTypeName = null; \r\n \r\n\r\n\/\/ If noLocal is true, then events generated by the session through which the \r\n\r\n\/\/ listener was registered are ignored. Otherwise, they are not ignored. \r\n\r\nboolean noLocal = true; \r\n\r\n\/\/ Registering the event listener \r\n\r\nobservationManager.addEventListener(this, Event.NODE_MOVED, ASSET_UPDATE_PATH, isDeep, uuid, nodeTypeName, \r\n\r\nnoLocal); \r\n\r\n} \r\n\r\n} \r\n\r\n \r\n\r\npublic void onEvent(EventIterator itr) { \r\n\r\nwhile (itr.hasNext()) { \r\n\r\nEvent currentEvent = itr.nextEvent(); \r\n\r\ntry { \r\n. \r\n. \r\n.  \r\n\r\n\/\/ Create a workflow session \r\n\r\nWorkflowSession wfSession = workflowService.getWorkflowSession(localSession); \r\n\r\n\/\/ Get the workflow model \r\n\r\nWorkflowModel wfModel = wfSession.getModel(THUMBNAIL_WORKFLOW_PATH); \r\n\r\n\r\n\/\/ Get the Workflow data. The first parameter in the newWorkflowData method is \r\n\r\n\/\/ the payloadType. Just a fancy name to let it know what type of workflow it is \r\n\r\n\/\/ working with. \r\n\r\nWorkflowData wfData = wfSession.newWorkflowData(JCR_PATH, currentEvent.getPath()+ORIGINAL_RENDITION_RELATIVE_PATH); \r\n\r\n\/\/ Start the Workflow. \r\n\r\nwfSession.startWorkflow(wfModel, wfData); \r\n\r\n} \r\n. \r\n. \r\n.<\/pre>\n

    Download <\/a> this code (including the workflow):<\/p>\n

    Build it using<\/p>\n

    mvn clean install -PautoInstallPackage<\/pre>\n

    N.B: Creating a workflow is not part of this tutorial, and therefore a ready workflow has been provided in the code package. However, if you want to learn how to create custom workflows, here is an excellent resource.<\/a><\/p>\n

    References<\/strong><\/h5>\n

    Adobe Consulting Services. (2018, March 20). acs-aem-samples\/SampleJcrEventListener.java at master \u00b7 Adobe-Consulting-Services\/acs-aem-samples. Retrieved from Github: https:\/\/github.com\/Adobe-Consulting-Services\/acs-aem-samples\/blob\/master\/bundle\/src\/main\/java\/com\/adobe\/acs\/samples\/events\/impl\/SampleJcrEventListener.java<\/a><\/p>\n

    Day Software AG. (2018, March 20). JCR 2.0: 12 Observation (Content Repository for Java Technology API v2.0). Retrieved from Adobe Docs: https:\/\/docs.adobe.com\/docs\/en\/spec\/jcr\/2.0\/12_Observation.html<\/a><\/p>\n

    FAQs<\/strong><\/p>\n

      \n
    1. What is an event listener?
      \nAn\u00a0event listener<\/b> is a procedure or function in a program that waits for an event<\/b> to occur.<\/li>\n
    2. What are some examples of an event in a computer program?
      \nSome simple examples of an event<\/b> are users clicking or moving the mouse, pressing a key on the keyboard, or network activity.<\/li>\n
    3. What are workflow launchers?
      \nA workflow launcher<\/strong> is a standard way to invoke or trigger a workflow based on conditions. The workflow launcher monitors changes in the content repository to launch workflows dependent on the location and resource type of the changed node.<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"

      Trigger a Workflow in AEM We can trigger a workflow in AEM 6.2 when a DAM Asset is created, modified, or deleted within a given path. In this article, we will explore triggering workflows from our code based on events in the JCR. Suppose you have a workflow that creates custom renditions of assets in … Read more<\/a><\/p>\n","protected":false},"author":29,"featured_media":6662,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","content-type":"","footnotes":""},"categories":[66],"tags":[81,83,67,69,32,34],"yst_prominent_words":[1084,1086,1088,1803,1085,1081,1806,1843,1844,1804,1082,1800,1802,1805,1083,1811,1801,1700,1845,1087],"acf":[],"yoast_head":"\nLearn How to Trigger a Workflow in AEM using Event Listeners in AEM<\/title>\n<meta name=\"description\" content=\"Let's explore how to trigger a workflow in AEM using event listeners and workflow launchers in the JCR for AEM 6.2 - approach and implementation.\" \/>\n<meta name=\"robots\" content=\"index, follow\" \/>\n<meta name=\"googlebot\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<meta name=\"bingbot\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.argildx.us\/technology\/triggering-a-workflow-using-event-listeners-in-aem\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Learn How to Trigger a Workflow in AEM using Event Listeners in AEM\" \/>\n<meta property=\"og:description\" content=\"Let's explore how to trigger a workflow in AEM using event listeners and workflow launchers in the JCR for AEM 6.2 - approach and implementation.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.argildx.us\/technology\/triggering-a-workflow-using-event-listeners-in-aem\/\" \/>\n<meta property=\"og:site_name\" content=\"Argil DX\" \/>\n<meta property=\"article:published_time\" content=\"2018-08-20T07:13:48+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-08-17T06:14:57+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.argildx.us\/wp-content\/uploads\/2018\/08\/Triggering-a-Workflow-using-Event-Listeners-in-AEM.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1440\" \/>\n\t<meta property=\"og:image:height\" content=\"542\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.argildx.us\/#website\",\"url\":\"https:\/\/www.argildx.us\/\",\"name\":\"Argil DX\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/www.argildx.us\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.argildx.us\/technology\/triggering-a-workflow-using-event-listeners-in-aem\/#primaryimage\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/www.argildx.us\/wp-content\/uploads\/2018\/08\/Triggering-a-Workflow-using-Event-Listeners-in-AEM.jpg\",\"width\":1440,\"height\":542,\"caption\":\"Triggering a Workflow using Event Listeners in AEM\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.argildx.us\/technology\/triggering-a-workflow-using-event-listeners-in-aem\/#webpage\",\"url\":\"https:\/\/www.argildx.us\/technology\/triggering-a-workflow-using-event-listeners-in-aem\/\",\"name\":\"Learn How to Trigger a Workflow in AEM using Event Listeners in AEM\",\"isPartOf\":{\"@id\":\"https:\/\/www.argildx.us\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.argildx.us\/technology\/triggering-a-workflow-using-event-listeners-in-aem\/#primaryimage\"},\"datePublished\":\"2018-08-20T07:13:48+00:00\",\"dateModified\":\"2020-08-17T06:14:57+00:00\",\"author\":{\"@id\":\"https:\/\/www.argildx.us\/#\/schema\/person\/1c5b6f3f2f7218d9acb851588b98551f\"},\"description\":\"Let's explore how to trigger a workflow in AEM using event listeners and workflow launchers in the JCR for AEM 6.2 - approach and implementation.\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.argildx.us\/technology\/triggering-a-workflow-using-event-listeners-in-aem\/\"]}]},{\"@type\":[\"Person\"],\"@id\":\"https:\/\/www.argildx.us\/#\/schema\/person\/1c5b6f3f2f7218d9acb851588b98551f\",\"name\":\"Argil DX Media\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.argildx.us\/#personlogo\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/0ccbc04705942d1269cdf9f789e58484?s=96&d=mm&r=g\",\"caption\":\"Argil DX Media\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","_links":{"self":[{"href":"https:\/\/www.argildx.us\/wp-json\/wp\/v2\/posts\/4940"}],"collection":[{"href":"https:\/\/www.argildx.us\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.argildx.us\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.argildx.us\/wp-json\/wp\/v2\/users\/29"}],"replies":[{"embeddable":true,"href":"https:\/\/www.argildx.us\/wp-json\/wp\/v2\/comments?post=4940"}],"version-history":[{"count":0,"href":"https:\/\/www.argildx.us\/wp-json\/wp\/v2\/posts\/4940\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.argildx.us\/wp-json\/wp\/v2\/media\/6662"}],"wp:attachment":[{"href":"https:\/\/www.argildx.us\/wp-json\/wp\/v2\/media?parent=4940"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.argildx.us\/wp-json\/wp\/v2\/categories?post=4940"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.argildx.us\/wp-json\/wp\/v2\/tags?post=4940"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/www.argildx.us\/wp-json\/wp\/v2\/yst_prominent_words?post=4940"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}