wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

Building a shared approval frontend in XPages


The saying goes: " God would not have been able to create the world in 7 days, if there would have been an installed base to take care of". As much as we wish to have divine powers, we need to make with less and look after an installed base. Point in case: You have a set of approval applications in classic Notes client code, like: Travel, Leave, Expenses, Gifts, Training, BoM changes etc. You are challenged to provide a web and/or mobile interface for them.
Considering your options you have to decide between options:
  1. Dump the applications and rebuild them on a new platform. Hope that it will take long enough, so nobody will ask you to migrate any of the existing data
  2. Enable them one-by-one
  3. Hire Redpill to do an asymmetric modernization
  4. Build a lateral approval screen across your applications and leave the full web enablement for later
While #1 would allow you to silently dump all your technical debt, it will take too long and a potential data migration monster would lurk in the dark. #2 is what non-techies would expect, but again you spend too much time and you will carry forward new technical debt. After all the applications are more similar than different. Hiring Redpill would be a sensible option, but that requires board approval or is against your "we-do-it-inhouse" policy or you simply want to expand your skill horizon.
This leaves you with #4. To do this successful, you need to define your scope clearly. In the rest of the article I will work with the following assumptions, if they don't fit your situation, adjust your plan:
  • The goal is to provide the decision making screen only, not a complete workflow engine (it could evolve to that)
  • Request submission happens in the existing application, providing a new interface for that is outside the current scope
  • The flow logic (how many approvers per level etc.) is determined on submission by the original application
  • Someone from a different department indicated interest to use the approval screen from a complete different system (that is the "scope creep" that happens in any project)
When you look at workflow systems, while planning your application, you will notice, that there are 2 types of data: the flow state/sequence and the specific request data. The flow state is stuff like: what's the current status, what are the potential decisions (usually: Yes, No, More info please), who are the past, current, future approvers. The specific request data is stuff like: duration and type of leave, price of items to purchase, customer involved etc.
In your existing applications the two are stored together (and will stay like that), but you need to extract the flow data to your new approvalCentral application. On the back of a napkin you draw this sequence:
Your approval workflow
(Image created with JS Sequence Diagrams and postprocessed with InkScape)

The green part of the application exists, the first question is: how to design the submission. There are a number of options you could choose from:
  • Have the Approval Central application poll participating applications on schedule. That option is least efficient, but might be your only choice if you can't touch the existing apps at all (happens more often than you think, when admins are paranoid policies are set very cautious
  • Have each application create a flow document directly in the workflow central application. You could use a inherited LotusScript library for that. While that might have been the prefered choice a decade ago, it has two problems: first you limit your participating applications to Notes only (and there are other applications with decision requirements) and you would expose the inner workings of your application prematurely
  • Use a web service interface to implement Contract first development. While REST is the current IT fashion, you pick SOAP. The simple reason: LotusScript can talk SOAP quite well via the Webservice consumer design element, while REST would require your notification code being written in Java. So a SOAP service it is
To get started two classes in LotusScript provide the interface the WebService provider needs to generate the WSDL file for submission. In a production environment you need to add validation and sanity checks to the code (and probably more fields):

Option Public
Option Declare

Public Class ApprovalRequest
public System As String
Public CallbackLocation As String
Public Title As String
Public Requestor As String

End Class

Public Class ApprovalSubmission
Public Function submitForApproval(request As ApprovalRequest) As String
Dim s As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
submitForApproval = "OK"
Set db = s.Currentdatabase
Set doc = db.Createdocument()
call doc.Replaceitemvalue("Form", "approvalRequest" )
Call doc.Replaceitemvalue("System", request.System)
Call doc.Replaceitemvalue("Title", request.Title)
Call doc.Replaceitemvalue("CallbackLocation", request.CallbackLocation )
Call doc.Replaceitemvalue("Created", now)
Call doc.Save(true, true)
End Function
End Class

Using this class you can generate the WSDL by pointing to ApprovalSubmission as PortType class. The resulting WSDL looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<definitions targetNamespace="urn:DefaultNamespace"
     xmlns="http://schemas.xmlsoap.org/wsdl/"
     xmlns:apachesoap="http://xml.apache.org/xml-soap"
     xmlns:impl="urn:DefaultNamespace" xmlns:intf="urn:DefaultNamespace"
     xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
     xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
     xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <wsdl:types>
  <schema targetNamespace="urn:DefaultNamespace" xmlns="http://www.w3.org/2001/XMLSchema">
   <complexType name="APPROVALREQUEST">
    <sequence>
     <element name="SYSTEM" type="xsd:string"/>
     <element name="CALLBACKLOCATION" type="xsd:string"/>
     <element name="TITLE" type="xsd:string"/>
     <element name="REQUESTOR" type="xsd:string"/>
    </sequence>
   </complexType>
   <element name="REQUEST" type="impl:APPROVALREQUEST"/>
   <element name="SUBMITFORAPPROVALReturn" type="xsd:string"/>
  </schema>
 </wsdl:types>
 <message name="SUBMITFORAPPROVALRequest">
  <part element="impl:REQUEST" name="REQUEST"/>
 </message>
 <message name="SUBMITFORAPPROVALResponse">
  <part element="impl:SUBMITFORAPPROVALReturn" name="SUBMITFORAPPROVALReturn"/>
 </message>
 <portType name="ApprovalSubmission">
  <operation name="SUBMITFORAPPROVAL">
   <input message="impl:SUBMITFORAPPROVALRequest" name="SUBMITFORAPPROVALRequest"/>
   <output message="impl:SUBMITFORAPPROVALResponse" name="SUBMITFORAPPROVALResponse"/>
  </operation>
 </portType>
 <binding name="DominoSoapBinding" type="impl:ApprovalSubmission">
  <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
  <operation name="SUBMITFORAPPROVAL">
   <wsdlsoap:operation soapAction="SUBMITFORAPPROVAL"/>
   <input name="SUBMITFORAPPROVALRequest">
    <wsdlsoap:body use="literal"/>
   </input>
   <output name="SUBMITFORAPPROVALResponse">
    <wsdlsoap:body use="literal"/>
   </output>
  </operation>
 </binding>
 <service name="ApprovalSubmissionService">
  <port binding="impl:DominoSoapBinding" name="Domino">
   <wsdlsoap:address location="http://localhost"/>
  </port>
 </service>
</definitions>

Using a SOAP client, you can start testing that interface. When you look at the skeleton API you will see a notable absence of specific data for that request. I was thinking quite hard if the specific data should be included and if yes in what format. In conclusion I opted against it to keep the interface lean. Also the set of potential decisions (Yes,No,Try again etc.) is something I'd rather delegate to a configuration document. This will allow to gradually move the whole flow into the approval application.
The callback location would, for a Notes application, contain the notes://... URL, so session.resolve(CallbackLocation) will give us a handle on the document. Using our newly acquired {{Mustache}} skills, we can call back and pull information out as HTML blob as needed. You might want to pull different information based on the (size) capabilities of your target device.
The callback can later be used to write back values into the application document. Some planning to get that right (and some facade and factories) is required. Another consideration, once your code is working, is caching. Should you pull the data from the applications live on request or pull them when you get the request. Until your application is running well I'd opt for live pulling - unless the access to the servers is slow.
Your next step: pick a UI layout

Posted by on 17 November 2014 | Comments (1) | categories: XPages

Comments

  1. posted by Nathan T. Freeman on Monday 17 November 2014 AD:
    Thanks for the nod, Stephan. For the record, I don't think our pricing requires board level approval but even in the event that it does, you can try before you buy. Setting up an in-house pilot of redpill Now that modernizes at least 100 of your own applications costs less than most firms would charge to build a project plan for your first app.

    Also, though we don't yet provide a centralized workflow model like the one you describe here, we do provide centralized notification for workflow. A few mouse clicks can configure a view in an NSF to act as a notification queue, and all those queues are consolidated into a single per-user notification stream inspired by Facebook's notification model.

    I'll be speaking about how centralized workflow across NSFs might be achieved as part of my talk on the Graph Revolution this Thursday at the DanNotes conference.