Calling Out

If you aren’t comfortable with the environment in which SimPEL processes execute and want to run the process shown in this tutorial, it’s recommended to have a prior look at the first tutorial. But if you’re just looking around, feel free to proceed. All the files mentioned here are located in the distribution under the samples/vote directory or online.

Can I Have Some Vacations? Please?

By now you should be fairly comfortable in writing your own web services with SimPEL. But what about when you need to interact with other complex web services? And even worse, dare I say, with people? This is what we’re going to cover in this tutorial, we’ll do relatively complex service interactions and create tasks for people to complete using Singleshot.

So we’re going to automate an absence request, after all we developer take so much vacations that we need to streamline this. It’s actually a fairly simple process but it should demonstrate enough so you can start composing things together to build richer applications. Here is how it goes:

  • An employee asks for some time off, she just needs to specify when she plans to leave and come back.
  • The employee’s boss get assigned a new task, which is to review and accept or refuse the vacations (we hope he’ll accept).
  • The employee gets notified of her boss decision.

In all this, the process will be completely behind the scene, just telling the task manager what to do and waiting patiently for people to review their tasks.

Caffeinated Interlude: Singleshot

Singleshot is a gifted task manager. It organizes your tasks, makes them availble in any shape or form you desire and enables collaboration. It’s also RESTful, so any other application can create and update tasks easily, with simple HTTP calls.

To complete this tutorial you will need to have Singleshot running. If you’ve downloaded a standalone installation of Simplex you will have to install Singleshot as well, it’s all explained here. If you’ve downloaded Intalio|DE you’re already covered, Singleshot is bundled and pre-integrated.

As with all other samples, you can find the full process under the samples directory of your distribution. It’s also on Github. You will need to have it deployed in the script folder of your Simplex installation to run the sample.

First log in Singleshot (located either under http://localhost:3434/singleshot or http://localhost:3000 depending on your installation) using the default credentials (singleshot / secret). By default we initialize the database with a few things so that you can play around a bit. What we’re interested in now is in the right side panel, you should have an “Absence Request” link under Start. Follow the link, set a start and end date for your leave and then click the Done button. Remember that you should have Simplex running at this point if you’re using Singleshot standalone.

As you’ve requested a leave, your boss Mr. Bond should be asked to approve or refuse it. So logout and login again as Mr. Bond (bond / secret). In the list of task and in the recent notifications you should see that a Mr. Bond has a new task to process called Absence Request. Click on it, approve or refuse and declare it done. Now we’re expecting to have been notified of Mr. Bond’s decision so logout and login again as singleshot. You should have a new message in your inbox informing you of the final decision. That’s it!

It’s a fairly simple sample but all of this has been driven by a just-as-simple process, so from there you can easily extend it at will.

Absence Request Process

Before checking the different helper functions that we defined to support the process execution, we’ll have a look at the process itself to see what’s going on:

process AbsenceRequest {
callback = resource("/callback");
receive(self) { |t|
leave = buildAbsenceRequest("singleshot", passwd, "bond",
myBase callback, t.data.from, t.data.to);
resp = request(shotBase "/tasks", "POST", leave);
print("### waiting for callback for " + resp.headers.Location);

reply(resp);
}

updatedTask = <task/>;
receive(callback) { |msg|
updatedTask = msg;
reply();
}

if (updatedTask.data.accept == "true") {
status = "accepted";
} else {
status = "refused";
}

confirmation = buildNotification("singleshot", passwd, "singleshot",
status, updatedTask.data.from.text() , updatedTask.data.to.text());
request(shotBase + "/notifications", "POST", confirmation);
}

The beginning should look familiar now, it all starts with a receive on the self resource. So what calls it? The process gets started when the “Absence Request” task template is completed in Singleshot, triggering a webhook that’s already setup with the address of the AbsenceRequest process. Singleshot POSTs a request containing the task data to that URL, in the process that data is accessible through the t variable bound to the instantiating receive.

From there, we build the request to create the approval (more on that later). We will authenticate the call as “singleshot”, create an absence request confirmation task for Mr. Bond (our boss) with from and to data coming from the initial task template. We also provide a callback URL under which we expect Singleshot to call us back when the task is completed. Then it’s just a POST under the /tasks sub-URL. Finally, we reply to the first POST that Singleshot triggered, the actual returned data isn’t used for now.

For the process, now it’s just about waiting. Mr. Bond is expected to check the approval task we created for him, approve or refuse, and complete it. When he completes it, Singleshot will call us back on our callback resource. That’s when the process takes over again, getting the updated task data and building the final notification using the status Mr. Bond set.

Setting Up Tasks

It’s now time to look at the data transiting from the SimPEL process to Singleshot. It looks like a big chunk of code but it’s actually just XML literals taking some space:

function addHeaders(login, password, req) {
req.headers.basicAuth.login = login;
req.headers.basicAuth.password = password;
req.headers.Accept = "application/xml";
return req;
}

function buildAbsenceRequest(login, password, assignee, callback, from, to) {
var formHtml = "<fieldset><legend>AbsenceRequest</legend>"
"<p> requested a leave of absence.</p>"
"<dl><dt>Accept</dt><dd><input type='radio' name='data[accept]' value='true'></dd>"
"<dt>Refuse</dt><dd><input type='radio' name='data[accept]' value='false'></dd>"
"<dt>Comment: </dt><dd><textarea name='data[comment]'></textarea></dd>"
"<dt>From: </dt><dd><input name='data[from]' type='text' class='date' value = '" from "'/></dd>"
"<dt>To: </dt><dd><input name='data[to]' type='text' class='date' value='" to "'/></dd>" +
"</dl></fieldset>";
task = <task><title>Leave of absence request</title>
<description>Leave of absence request</description>
<owner>{assignee}</owner>
<webhooks type="array"><webhook><event>completed</event><url>{callback}</url><enctype>application/xml</enctype></webhook></webhooks>
<form><html>{formHtml}</html></form>
</task>;
return addHeaders(login, password, task);
}

function buildNotification(login, password, assignee, result, from, to) {
task = <notification><subject>Absence request response</subject>
<body>Your absence request from {from} to {to} has been {result}.</body>
<recipients><recipient>{assignee}</recipient></recipients>
</notification>;
return addHeaders(login, password, task);
}

The first addHeaders function is used for authentication, we setup the HTTP Basic Auth headers on the request message. As you can see the SimPEL HTTP layer allows the definition of a “magic” headers where all HTTP headers can bet set directly. The basicAuth sub-element is a special one dedicated to HTTP Basic Auth.

The buildAbsenceRequest function prepares the data to create the approval task. The long string definition at the beginning is the HTML code for the form that Singleshot is going to display for that task. Here we just have two radio buttons, one textarea for comments and the two date fields. Then comes an XML literal defining the task document itself. We provide the task assignee and create a webhook to ask Singleshot to call the process back on task completion. The application/xml mime type associated with the webhook tells Singleshot that we’d like the task data to be provided back to us on completion in XML format. Finally, the HTML form is passed between curly braces so E4X can escape the provided string variable for us.

Finally, the buildNotification function builds the notification XML request. Its code is pretty straightforward.

Final Notes

This tutorial should have made much clearer both how to interact with other services and how to use Singleshot. You’ve seen that building requests using Javascript helper functions (that could be externalized and made common across several processes) is fairly straightforward and sending those requests is even easier. For more advanced use cases you can even rely on the header sub-element to get full control of your HTTP requests.

From now, you should be able to start playing around, build your own process-empowered applications and experiment. You should also explore the SimPEL reference to learn about aditional constructs that we haven’t covered in the tutorials. And should you get stuck with a problem, the mailing-list is here to help you. So have fun and enjoy!