Expand my Community achievements bar.

SOLVED

How to pass a string from a WorkflowSession back to a SlingServlet?

Avatar

Level 8

So I have facility in my AEM code to import an comma-delimited file and turn that into pages (cq:page type) within AEM.

The flow goes like this: browser => AJAX call => SlingServlet => Workflow => SlingServer => browser

I want to pass a string from the Workflow back to my SlingServlet.

@SlingServlet(paths = "/services/courses/start-import", methods = "POST", metatype = true, label = "my-label-here")

public class myImportServlet extends SlingAllMethodsServlet {

This is the main body of the servlet

protected String startWorkflow(SlingHttpServletRequest request, WorkflowDescr workflowDescr) throws WorkflowException, ParseException {

    ResourceResolver resourceResolver = request.getResourceResolver();

    Session session = resourceResolver.adaptTo(Session.class);

   

    String message = "my message here";

   

    WorkflowSession wfSession = workflowService.getWorkflowSession(session);

    WorkflowModel model = wfSession.getModel(workflowDescr.getModel());

    WorkflowData data = wfSession.newWorkflowData("JCR_PATH", request.getRequestPathInfo().getResourcePath());

   

    data.getMetaDataMap().put(AbsoluteTimeoutHandler.ABS_TIME, new Date().getTime());

   

    Workflow test = wfSession.startWorkflow(model, data);

   

    return message;

}

I searched the net but didn't see anything useful. Thank you.

1 Accepted Solution

Avatar

Correct answer by
Employee Advisor

Hi,

let's have a look at the details. You mention that the interaction should look like this:

browser => AJAX call => SlingServlet => Workflow => SlingServlet => browser

(I corrected the second mention of "SlingServlet". "SlingServer" does not make any sense here.)

This is an synchronous process, so all parts should be well-suited to work in a synchronous fashion. But the workflow engine triggers workflows asynchronously, and the workflows are processed asynchronous. You cannot include an async process in a full synchronous interaction pattern, unless you are willing to wait until the async eventually finishes. In your case I don't think that you are willing to wait minutes, if not hours (depending on various factors).

You need to make all the functionality async. That means, that you should extract the logic from the workflow steps and make it usable as standalone services. And then a workflow step can call this functionality as well.

HTH,

Jörg

View solution in original post

6 Replies

Avatar

Level 10

Are you using workflow to create the page?

I skeptical if you can return the response from workflow to browser via sling servlet

Avatar

Community Advisor

Hi,

You should be able to perform these in your current format. But, this does feels rather long route to a short and straight forward task.

To respond back simply tell response to print the string e.g.

@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)

   throws ServletException, IOException {

  response.getOutputStream().print(startWorkflow(request, new WorkflowDescr(yourInitVarsHere)));

You might require to either change your architecture or re-think how to solve this, to follow standard AEM patterns for this task.

Regards,

Peter

Avatar

Community Advisor

Hi,

You should be able to perform these in your current format. But, this does feels rather long route to a short and straight forward task.

To respond back simply tell response to print the string e.g.

/**
* Launch workflow to create new page and print workflow ID back
*/
@SlingServlet(paths = "/services/courses/start-import", methods = "POST", metatype = true, label = "my-label-here")

public class myImportServlet extends SlingAllMethodsServlet {

   @Reference
   private WorkflowService workflowService;

   @Reference
   private ResourceResolverFactory resolverFactory;

   private static final Logger LOG = LoggerFactory.getLogger(myImportServlet.class);

   public String startWorkflow(String workflowName, String workflowContent) {

   try
   {

   //Invoke the adaptTo method to create a Session
   ResourceResolver resourceResolver = resolverFactory.getAdministrativeResourceResolver(null);

  Session session = resourceResolver.adaptTo(Session.class);

   //Create a workflow session
   WorkflowSession wfSession = workflowService.getWorkflowSession(session);

   // Get the workflow model
   WorkflowModel wfModel = wfSession.getModel(workflowName);

   // Get the workflow data
  // The first param in the newWorkflowData method is the payloadType. Just a fancy name to let it know what type of workflow it is working with.
   WorkflowData wfData = wfSession.newWorkflowData("JCR_PATH", workflowContent);

   // Run the Workflow.
   Workflow workflow = wfSession.startWorkflow(wfModel, wfData);

   return workflow.getId();

  }

   catch(Exception e)

  {

   LOG.error("Unable to start workflow due to:", e);

  }

   return null;

  }

   @Override
   protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)

   throws IOException {

   // Print the data form workflow back to the page
   response.getOutputStream().print(startWorkflow("createNewPage", "pagename"));

  response.getOutputStream().flush();

  response.setStatus(200);

  response.setContentType(String.valueOf(TEXT_PLAIN));

  }

}

You might require to either change your architecture or re-think how to solve this, to follow standard AEM patterns for this task.

P.S. naming your classes with lower case is unusual in Java.

Regards,

Peter

Avatar

Level 8

hello. I've looked at the sample code and It doesn't really tell me how to return a string from my workflow back to the servlet.

for reference, this is my entry point in my workflow. (can't edit original post)

@Override

public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap metaDataMap) throws WorkflowException {

    try {

        String string1 = "temp message";

    

        log.info("Start Course Import Service");

    

    } catch (Exception e) {

        log.error("Error in Course Import Service", e);

    }

}

I just want to return the contents of the variable string1. Thanks

Avatar

Level 10

I am not sure you can call into a custom Workflow step like you can a Service. I would look at Saving the String value in a JCR node by performing a JCR write operation from the workflow step and then reading it from the Sling Servlet.

Avatar

Correct answer by
Employee Advisor

Hi,

let's have a look at the details. You mention that the interaction should look like this:

browser => AJAX call => SlingServlet => Workflow => SlingServlet => browser

(I corrected the second mention of "SlingServlet". "SlingServer" does not make any sense here.)

This is an synchronous process, so all parts should be well-suited to work in a synchronous fashion. But the workflow engine triggers workflows asynchronously, and the workflows are processed asynchronous. You cannot include an async process in a full synchronous interaction pattern, unless you are willing to wait until the async eventually finishes. In your case I don't think that you are willing to wait minutes, if not hours (depending on various factors).

You need to make all the functionality async. That means, that you should extract the logic from the workflow steps and make it usable as standalone services. And then a workflow step can call this functionality as well.

HTH,

Jörg