Skip to content
This repository was archived by the owner on Nov 9, 2022. It is now read-only.

Commit bb1a62d

Browse files
committed
MarkLogic Workflow PoC Proven
Completed test scripts Fixed out of process method for userTask step and process cleanup verified to be accurate
1 parent 14b4ec8 commit bb1a62d

21 files changed

+437
-40
lines changed

data/examples/bpmn2/021-initiating-attachment.bpmn

Lines changed: 222 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,67 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1" targetNamespace="http://marklogic.com/workflow">
3-
<bpmn2:process id="051_domain" name="Default Process" processType="Public">
3+
<bpmn2:interface id="Interface_1" implementationRef="MarkLogic" name="MarkLogic">
4+
<bpmn2:operation id="_Operation_3" implementationRef="LaunchDomain" name="LaunchDomain"/>
5+
</bpmn2:interface>
6+
<bpmn2:process id="051_domain" name="Domain Launched" isExecutable="true" processType="Public">
47
<bpmn2:startEvent id="StartEvent_1">
58
<bpmn2:outgoing>SequenceFlow_1</bpmn2:outgoing>
9+
<bpmn2:dataOutput id="DataOutput_1" name="Message_1_Output"/>
10+
<bpmn2:dataOutputAssociation id="DataOutputAssociation_1">
11+
<bpmn2:sourceRef>DataOutput_1</bpmn2:sourceRef>
12+
</bpmn2:dataOutputAssociation>
13+
<bpmn2:outputSet id="OutputSet_1" name="Output Set 1">
14+
<bpmn2:dataOutputRefs>DataOutput_1</bpmn2:dataOutputRefs>
15+
</bpmn2:outputSet>
16+
<bpmn2:messageEventDefinition id="MessageEventDefinition_1">
17+
<bpmn2:operationRef>_Operation_3</bpmn2:operationRef>
18+
</bpmn2:messageEventDefinition>
619
</bpmn2:startEvent>
7-
<bpmn2:sequenceFlow id="SequenceFlow_1" sourceRef="StartEvent_1" targetRef="EndEvent_1"/>
20+
<bpmn2:sequenceFlow id="SequenceFlow_1" sourceRef="StartEvent_1" targetRef="Task_1"/>
821
<bpmn2:endEvent id="EndEvent_1">
9-
<bpmn2:incoming>SequenceFlow_1</bpmn2:incoming>
22+
<bpmn2:incoming>SequenceFlow_2</bpmn2:incoming>
1023
</bpmn2:endEvent>
24+
<bpmn2:task id="Task_1" name="Do Something">
25+
<bpmn2:incoming>SequenceFlow_1</bpmn2:incoming>
26+
<bpmn2:outgoing>SequenceFlow_2</bpmn2:outgoing>
27+
</bpmn2:task>
28+
<bpmn2:sequenceFlow id="SequenceFlow_2" sourceRef="Task_1" targetRef="EndEvent_1"/>
29+
<bpmn2:textAnnotation id="TextAnnotation_1">
30+
<bpmn2:text>Start event includes a Message definition, configured for a MarkLogic LaunchDomain. This is a CPF Domain linked to a URI folder (depth 1) for a particular process data document. (NOT an initiating attachment - see 021-initiating-attachment for that)</bpmn2:text>
31+
</bpmn2:textAnnotation>
32+
<bpmn2:association id="Association_1" sourceRef="TextAnnotation_1" targetRef="StartEvent_1"/>
1133
</bpmn2:process>
12-
<bpmndi:BPMNDiagram id="BPMNDiagram_1" name="Default Process Diagram">
34+
<bpmndi:BPMNDiagram id="BPMNDiagram_1" name="Domain Launched">
1335
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="051_domain">
1436
<bpmndi:BPMNShape id="BPMNShape_1" bpmnElement="StartEvent_1">
1537
<dc:Bounds height="36.0" width="36.0" x="100.0" y="100.0"/>
1638
</bpmndi:BPMNShape>
1739
<bpmndi:BPMNShape id="BPMNShape_2" bpmnElement="EndEvent_1">
1840
<dc:Bounds height="36.0" width="36.0" x="500.0" y="100.0"/>
1941
</bpmndi:BPMNShape>
20-
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_1" bpmnElement="SequenceFlow_1" sourceElement="BPMNShape_1" targetElement="BPMNShape_2">
42+
<bpmndi:BPMNShape id="BPMNShape_Task_1" bpmnElement="Task_1">
43+
<dc:Bounds height="50.0" width="110.0" x="270.0" y="93.0"/>
44+
</bpmndi:BPMNShape>
45+
<bpmndi:BPMNShape id="BPMNShape_TextAnnotation_1" bpmnElement="TextAnnotation_1">
46+
<dc:Bounds height="100.0" width="291.0" x="160.0" y="180.0"/>
47+
</bpmndi:BPMNShape>
48+
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_1" bpmnElement="SequenceFlow_1" sourceElement="BPMNShape_1" targetElement="BPMNShape_Task_1">
2149
<di:waypoint xsi:type="dc:Point" x="136.0" y="118.0"/>
50+
<di:waypoint xsi:type="dc:Point" x="196.0" y="118.0"/>
51+
<di:waypoint xsi:type="dc:Point" x="196.0" y="118.0"/>
52+
<di:waypoint xsi:type="dc:Point" x="270.0" y="118.0"/>
53+
</bpmndi:BPMNEdge>
54+
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_2" bpmnElement="SequenceFlow_2" sourceElement="BPMNShape_Task_1" targetElement="BPMNShape_2">
55+
<di:waypoint xsi:type="dc:Point" x="380.0" y="118.0"/>
56+
<di:waypoint xsi:type="dc:Point" x="434.0" y="118.0"/>
57+
<di:waypoint xsi:type="dc:Point" x="434.0" y="118.0"/>
2258
<di:waypoint xsi:type="dc:Point" x="500.0" y="118.0"/>
2359
</bpmndi:BPMNEdge>
60+
<bpmndi:BPMNEdge id="BPMNEdge_Association_1" bpmnElement="Association_1" sourceElement="BPMNShape_TextAnnotation_1" targetElement="BPMNShape_1">
61+
<di:waypoint xsi:type="dc:Point" x="160.0" y="230.0"/>
62+
<di:waypoint xsi:type="dc:Point" x="118.0" y="230.0"/>
63+
<di:waypoint xsi:type="dc:Point" x="118.0" y="136.0"/>
64+
</bpmndi:BPMNEdge>
2465
</bpmndi:BPMNPlane>
2566
</bpmndi:BPMNDiagram>
2667
</bpmn2:definitions>

documentation/DEV-NEWACTIVITY.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,15 @@ be transitioned. In Workflow an out of CPF action may need to complete a state.
2929
that a CPF action (genericComplete.xqy) can move the state onwards. This CANNOT be done outside of a CPF action (despite
3030
what the MarkLogic documentation website says).
3131

32-
In order to do this an element (/prop:properties/wf:currentStep/wf:step-status) is initially set to ENTERED, then when
33-
the set up action (E.g. add to a queue) completes, this is set to IN PROGRESS. When the out of sequence action (user task,
34-
web service call) wants the state to complete it sets this to COMPLETE. CPF then in turn runs the isComplete.xqy
35-
condition, which returns true, running the genericComplete.xqy action, which calls wfu:complete.
36-
37-
NEVER call wfu:complete or wfu:completeById outside of a CPF action.
32+
In order to do this :-
33+
- In your initiating CPF action (E.g. userTask.xqy) set an element (/prop:properties/wf:currentStep/wf:step-status) to ENTERED
34+
- Then something out of process happens, setting just this property to either IN PROGRESS, then eventually COMPLETE
35+
- The restart.xqy status change action fires, spots COMPLETE, and forces CPF to the state specified in prop:properties/wf:currentStep/wf:state
36+
- This also calls wfu:complete, which deletes prop:properties/wf:currentStep
37+
- CPF then transitions to the new state, which is where you should have an action to run any cleanup for your out of process activity
38+
- Also, you must call the genericComplete.xqy action, which in turn calls wfu:complete, moving on to the success state specified
39+
40+
NEVER call wfu:complete or wfu:completeById outside of a CPF action - only wfu:finallyComplete (as done in process POST rest api call)
3841

3942
## Notes on the CPF configuration of custom steps
4043

documentation/SPRINTS.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ This PoC development will occur in small sprints until a useful PoC system is av
1616
- SLA timer and routing on failure
1717
- Email notification
1818
- Assigning tasks to MarkLogic roles
19+
- Assigning Role dynamically via XQuery expression
1920
- UK-D-I
2021

2122
## Theoretical requirements
@@ -34,7 +35,7 @@ steps if a duplicate is found. Requires search (by property hash AND not (same u
3435
## Sprint 1 - Basic workflow
3536

3637
- DONE BPMN2: generic blank task
37-
- TEST BPMN2: user task -> aka human step
38+
- DONE BPMN2: user task -> aka human step
3839
- DONE BPMN2: exclusive gateway -> Decision point with one outcome, multiple options
3940
- DONE Evaluation: Support for /xpath/path to process model data
4041
- DONE Evaluation: Support for fn:not(fn:empty(/xpath/evaluation)) style boolean evaluation for true/false conditions in BPMN2 model
@@ -46,7 +47,7 @@ steps if a duplicate is found. Requires search (by property hash AND not (same u
4647
- Create import step for this BPMN2 method
4748
- Create CPF step to represent this
4849
- TEST Evaluation: Support for (/some/path/one,/some/path/two)[1] style evaluation for set task
49-
- TEST Tools: Process Data model XSD (for modeler import)
50+
- DONE Tools: Process Data model XSD (for modeler import)
5051
- IN PROGRESS Tools: Eclipse BPMN 2 Modeler Palette and Process diagram support, including new diagram creation for MarkLogic
5152
- DEFERRED UI: Ridiculously basic HTML widget in MLJS for rendering step and choosing action (for ease of testing)
5253
- TEST Start process using an Alert (content subscription)
@@ -61,10 +62,10 @@ steps if a duplicate is found. Requires search (by property hash AND not (same u
6162
- DONE GET fetch the current state of a business process
6263
- TEST processsubscription.xqy
6364
- TEST PUT create a process subscription (alert) to create a new process instance (creating a content doc creates a process doc with an initiating attachment)
64-
- TEST processinbox.xqy
65-
- TEST processqueue.xqy
65+
- DONE processinbox.xqy
66+
- DONE processqueue.xqy
6667
- TEST support for roles (processroleinbox.xqy) on user tasks (For BD)
67-
- TEST Test scripts for automating install, create, get, update, complete via REST API
68+
- DONE Test scripts for automating install, create, get, update, complete via REST API
6869
- DONE Bug: Change process model URI folder to include major and minor - else doing process doc update may run new pipeline instead of old one
6970
- DONE Bug: Multiple wf:status properties on in process process, complete and running
7071
- BPMN2 specification test process models modified and tested to MarkLogic executable standard

modules/app/models/workflow-actions.xqy

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ xquery version "1.0-ml";
33
module namespace m="http://marklogic.com/workflow-actions";
44

55
import module namespace wfu="http://marklogic.com/workflow-util" at "/app/models/workflow-util.xqy";
6+
import module namespace cpf = "http://marklogic.com/cpf" at "/MarkLogic/cpf/cpf.xqy";
67

78
declare namespace prop = "http://marklogic.com/xdmp/property";
89
declare namespace wf="http://marklogic.com/workflow";
@@ -60,16 +61,18 @@ declare function complete-generic($processId as xs:string) as empty-sequence() {
6061
let $_ := xdmp:log("In wfa:complete-generic: processId: "||$processId)
6162
let $props := wfu:getProperties($processId)
6263
let $_ := xdmp:log($props)
63-
let $next := $props/wf:currentStep/wf:state/text()
64+
(:
65+
let $next := $props/prop:properties/wf:currentStep/wf:state/text() (: WHERE SHOULD THIS BE FROM INSTEAD ? :)
6466
let $_ := xdmp:log($next)
65-
let $transition := $props/wf:currentStep/wf:state-transition/text()
66-
let $_ := xdmp:log($transition)
67-
let $startTime := xs:dateTime($props/wf:currentStep/wf:startTime)
68-
let $_ := xdmp:log($startTime)
67+
:)
68+
let $transition := $props/cpf:state/text()
69+
let $_ := xdmp:log("wfa:complete-generic: transition: " || $transition)
70+
(:) let $startTime := xs:dateTime($props/prop:properties/wf:currentStep/wf:startTime):)
71+
(:let $_ := xdmp:log($startTime):)
6972
(:let $update := xdmp:document-remove-properties(wfu:getProcessUri($processId),xs:QName("wf:currentStep")) :)
7073
(:let $update := xdmp:node-delete($props/wf:currentStep)
7174
let $_ := xdmp:log($update) :)
7275
return
7376
(: wfu:completeById($processId,$transition,xs:anyURI($next),$startTime) :)
74-
wfu:inProgress($processId,$transition)
77+
wfu:finallyComplete($processId,$transition)
7578
};

modules/app/models/workflow-import.xqy

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,17 @@ declare function m:bpmn2-to-cpf($pname as xs:string, $doc as element(b2:definiti
435435
return
436436
p:create($pname,$pname,
437437
p:action("/MarkLogic/cpf/actions/success-action.xqy",(),()),
438-
$failureAction,(),
438+
$failureAction,
439+
(
440+
p:status-transition("updated","Restart process on external action",() (: success :), $failureState,500,
441+
p:action("/workflowengine/actions/restart.xqy",
442+
"Check for restarting process.",() (: options :)
443+
)
444+
,
445+
() (: rules :)
446+
)
447+
) (: status transitions :)
448+
,
439449
(
440450

441451
(: create entry CPF action :)
@@ -587,10 +597,13 @@ declare function m:bpmn2-to-cpf($pname as xs:string, $doc as element(b2:definiti
587597
{
588598
if (fn:not(fn:empty($role))) then <wf:role>{$role}</wf:role> else ()
589599
}
600+
<wf:state>{xs:anyURI("http://marklogic.com/states/"||$pname||"/"||xs:string($state/@id)||"__complete")}</wf:state>
590601
</p:options>
591602
) (: p action :)
592603
,"Apply set up user task action on entry"
593604
) (: p:execute :)
605+
606+
(:
594607
,
595608
p:execute(
596609
p:condition("/workflowengine/conditions/isComplete.xqy","Check if complete",())
@@ -603,10 +616,37 @@ declare function m:bpmn2-to-cpf($pname as xs:string, $doc as element(b2:definiti
603616
),
604617
"Apply default complete action"
605618
) (: p execute :)
619+
:)
606620

607621

608622
) (: execute set :)
609623
) (: state transition :)
624+
,
625+
(:
626+
p:state-transition(xs:anyURI("http://marklogic.com/states/"||$pname||"/"||xs:string($state/@id)||"__inprogress"),
627+
"",(),
628+
$failureState,(),
629+
() (: empty default action :)
630+
,
631+
(
632+
633+
634+
) (: execute set :)
635+
)
636+
,
637+
:)
638+
p:state-transition(xs:anyURI("http://marklogic.com/states/"||$pname||"/"||xs:string($state/@id)||"__complete"),
639+
"",xs:anyURI("http://marklogic.com/states/"||$pname||"/"||xs:string($sf/@targetRef)),
640+
$failureState,(),
641+
p:action("/workflowengine/actions/genericComplete.xqy",
642+
"User completion occurred: "||xs:string($state/@name),() (: options :)
643+
) (: empty default action :)
644+
,
645+
(
646+
647+
648+
) (: execute set :)
649+
)
610650
) (: state transition set :)
611651

612652

modules/app/models/workflow-util.xqy

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,11 @@ declare function m:complete($processUri as xs:string,$transition as node(),$stat
151151
let $_ := xdmp:log($startTime)
152152
let $_ := xdmp:log(" transition")
153153
let $_ := xdmp:log($transition)
154-
let $_ := xdmp:node-replace(xdmp:document-properties($processUri)/prop:properties/wf:status,<wf:status>COMPLETE</wf:status>)
154+
155+
(: clean up BPMN2 activity step properties :)
156+
let $cs := xdmp:document-properties($processUri)/prop:properties/wf:currentStep
157+
let $_ := if (fn:not(fn:empty($cs))) then xdmp:node-delete($cs) else ()
158+
155159
let $_ := m:metric($processUri,$transition/p:state/text(),$startTime,fn:current-dateTime(),fn:true())
156160
(: Add audit event :)
157161
let $_ := m:audit($processUri,$transition/p:state/text(),"ProcessEngine","Completed step",())
@@ -171,13 +175,28 @@ declare function m:completeById($processId as xs:string,$transition as xs:string
171175
};
172176

173177
(:
174-
: Can be called from out of sequence (non CPF) modules - forces a CPF re-evaluation, then complete, in conjunction with the genericComplete.xqy action
178+
: Can be called from out of sequence (non CPF) modules - forces a CPF re-evaluation, then complete, in conjunction with the restart.xqy action
175179
:)
176180
declare function m:finallyComplete($processId as xs:string,$transition as xs:string) as empty-sequence() {
177181
let $processUri := m:getProcessUri($processId)
178-
let $_ := m:audit($processUri,$transition/p:state/text(),"ProcessEngine","Marking as Complete",())
182+
let $props := xdmp:document-properties($processUri)/prop:properties
183+
let $_ := m:audit($processUri,$transition,"ProcessEngine","Marking as Complete",())
179184
return
180-
xdmp:node-replace(xdmp:document-properties($processUri)/prop:properties/wf:currentStep/wf:step-status,<wf:step-status>COMPLETE</wf:step-status>)
185+
(
186+
xdmp:node-replace($props/wf:currentStep/wf:step-status,<wf:step-status>COMPLETE</wf:step-status>)
187+
(:,
188+
xdmp:node-replace($props/cpf:status,<cpf:processing-status>active</cpf:processing-status>)
189+
:)
190+
(:
191+
),
192+
xdmp:node-replace($props/cpf:status,<cpf:state>{$props/wf:currentStep/wf:state/text()}</cpf:state>)
193+
:)
194+
(:
195+
,
196+
(: god awful hack to test CPF updated status change handling :)
197+
xdmp:node-insert-after(fn:doc($processUri)/wf:process/wf:data,<tag>You're it</tag>)
198+
:)
199+
)
181200
};
182201
183202
(:
@@ -186,7 +205,7 @@ declare function m:finallyComplete($processId as xs:string,$transition as xs:str
186205
:)
187206
declare function m:inProgress($processId as xs:string,$transition as xs:string) as empty-sequence() {
188207
let $processUri := m:getProcessUri($processId)
189-
let $_ := m:audit($processUri,$transition/p:state/text(),"ProcessEngine","In Progress",())
208+
let $_ := m:audit($processUri,$transition,"ProcessEngine","In Progress",())
190209
return
191210
xdmp:node-replace(xdmp:document-properties($processUri)/prop:properties/wf:currentStep/wf:step-status,<wf:step-status>IN PROGRESS</wf:step-status>)
192211
};

modules/workflowengine/actions/endEvent.xqy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ try {
3737
)
3838
)
3939
,
40+
xdmp:node-replace(xdmp:document-properties($cpf:document-uri)/prop:properties/wf:status,<wf:status>COMPLETE</wf:status>)
41+
,
4042
wfu:complete( $cpf:document-uri, $cpf:transition, (), $st )
4143
)
4244
} catch ($e) {

modules/workflowengine/actions/genericComplete.xqy

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ declare variable $cpf:transition as node() external;
1111
declare variable $cpf:options as element() external;
1212

1313
try {
14+
let $st := fn:current-dateTime()
15+
let $_ := xdmp:log("MarkLogic Workflow generic complete CPF action called for: "||$cpf:document-uri)
1416
let $props := xdmp:document-properties($cpf:document-uri)/prop:properties
1517
let $_ := xdmp:log($props)
16-
let $next := $cpf:options/wf:state/text()
17-
let $_ := xdmp:log($next)
18-
let $startTime := xs:dateTime($props/wf:currentStep/wf:startTime)
19-
return wfu:complete( $cpf:document-uri, $cpf:transition, $next, $startTime )
18+
19+
(: Allow state transition to happen :)
20+
21+
return wfu:complete( $cpf:document-uri, $cpf:transition, (), $st )
2022
} catch ($e) {
2123
wfu:failure( $cpf:document-uri, $cpf:transition, $e, () )
2224
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
xquery version "1.0-ml";
2+
3+
import module namespace cpf = "http://marklogic.com/cpf" at "/MarkLogic/cpf/cpf.xqy";
4+
import module namespace wfu="http://marklogic.com/workflow-util" at "/app/models/workflow-util.xqy";
5+
6+
declare namespace wf="http://marklogic.com/workflow";
7+
declare namespace prop = "http://marklogic.com/xdmp/property";
8+
9+
declare variable $cpf:document-uri as xs:string external;
10+
declare variable $cpf:transition as node() external;
11+
declare variable $cpf:options as element() external;
12+
13+
(:
14+
: Check for all property-update and document-update eventualities that mean we should restart the process.
15+
:)
16+
17+
18+
try {
19+
let $_ := xdmp:log("MarkLogic Workflow restart CPF action called for: "||$cpf:document-uri)
20+
21+
(: 1. Check for external task completion status (step-status = "COMPLETE") :)
22+
let $_ := xdmp:log("restart condition check for: " || $cpf:document-uri)
23+
let $ready := xdmp:document-properties($cpf:document-uri)/prop:properties/wf:currentStep/wf:step-status
24+
let $_ := xdmp:log($ready)
25+
let $result := "COMPLETE" eq $ready
26+
let $_ := xdmp:log($result)
27+
28+
return
29+
if ($result) then
30+
31+
let $props := xdmp:document-properties($cpf:document-uri)/prop:properties
32+
let $_ := xdmp:log($props)
33+
let $next := xs:string($props/wf:currentStep/wf:state)
34+
let $_ := xdmp:log("Next state: "||$next)
35+
let $startTime := xs:dateTime($props/wf:currentStep/wf:startTime)
36+
return wfu:complete( $cpf:document-uri, $cpf:transition, xs:anyURI($next), $startTime )
37+
else (
38+
(: From set-updated-action.xqy in CPF:)
39+
40+
if (cpf:check-transition($cpf:document-uri,$cpf:transition)) then
41+
(
42+
cpf:document-set-last-updated( $cpf:document-uri, fn:current-dateTime() )
43+
,
44+
cpf:success( $cpf:document-uri, $cpf:transition, () )
45+
)
46+
else ()
47+
48+
) (: do what CPF normally does... :)
49+
} catch ($e) {
50+
wfu:failure( $cpf:document-uri, $cpf:transition, $e, () )
51+
}

0 commit comments

Comments
 (0)