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:
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:
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:
(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:
Using this class you can generate the WSDL by pointing to
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
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
Considering your options you have to decide between options:
- 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
- Enable them one-by-one
- Hire Redpill to do an asymmetric modernization
- Build a lateral approval screen across your applications and leave the full web enablement for later
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)
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:
(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 paranoidpolicies 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
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 Stephan H Wissel on 17 November 2014 | Comments (1) | categories: XPages