blob: 23a05024d79c7ce7ce6c8f053186767bf5491634 [file] [log] [blame]
ramvermaaf74a622018-07-31 18:25:39 +01001//
2// ============LICENSE_START=======================================================
3// Copyright (C) 2016-2018 Ericsson. All rights reserved.
4// ================================================================================
5// This file is licensed under the CREATIVE COMMONS ATTRIBUTION 4.0 INTERNATIONAL LICENSE
6// Full license text at https://creativecommons.org/licenses/by/4.0/legalcode
7//
8// SPDX-License-Identifier: CC-BY-4.0
9// ============LICENSE_END=========================================================
10//
11// @author Sven van der Meer (sven.van.der.meer@ericsson.com)
12//
13
14== Writing APEX Task Logic
15
16Task logic specifies the behavior of an Apex Task.
17This logic can be specified in a number of ways, exploiting Apex's plug-in architecture to support a range of logic executors.
18In Apex scripted Task Logic can be written in any of these languages:
19
20* https://en.wikipedia.org/wiki/MVEL[`MVEL`],
21* https://en.wikipedia.org/wiki/JavaScript[`JavaScript`],
22* https://en.wikipedia.org/wiki/JRuby[`JRuby`] or
23* https://en.wikipedia.org/wiki/Jython[`Jython`].
24
25These languages were chosen because the scripts can be compiled into Java bytecode at runtime and then efficiently executed natively in the JVM.
26Task Logic an also be written directly in Java but needs to be compiled, with the resulting classes added to the classpath.
27There are also a number of other Task Logic types (e.g. Fuzzy Logic), but these are not supported as yet.
28This guide will focus on the scripted Task Logic approaches, with MVEL and JavaScript being our favorite languages.
29In particular this guide will focus on the Apex aspects of the scripts.
30However, this guide does not attempt to teach you about the scripting languages themselves ... that is up to you!
31
32[TIP]
33.JVM-based scripting languages
34====
35For more more information on Scripting for the Java platform see: https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/index.html
36====
37
38[NOTE]
39.What do Tasks do?
40====
41The function of an Apex Task is to provide the logic that can be executed for an Apex State as one of the steps in an Apex Policy.
42Each task receives some _incoming fields_, executes some logic (e.g: make a decision based on _shared state_ or _context_, _incoming fields_, _external context_, etc.), perhaps set some _shared state_ or _context_ and then emits _outgoing fields_.
43The state that uses the task is responsible for extracting the _incoming fields_ from the state input event.
44The state also has an _output mapper_ associated with the task, and this _output mapper_ is responsible for mapping the _outgoing fields_ from the task into an appropriate output event for the state.
45====
46
47First lets start with a sample task, drawn from the "My First Apex Policy" example:
48The task "MorningBoozeCheck" from the "My First Apex Policy" example is available in both MVEL and JavaScript:
49
50.Javascript code for the `MorningBoozeCheck` task
51[source,javascript,options="nowrap"]
52----
53include::{adsite-examples-myfirstpolicy-dir}/main/resources/examples/models/MyFirstPolicy/1/MorningBoozeCheck.js[]
54----
55
56.MVEL code for the `MorningBoozeCheck` task
57[source,java,options="nowrap"]
58----
59include::{adsite-examples-myfirstpolicy-dir}/main/resources/examples/models/MyFirstPolicy/1/MorningBoozeCheck.mvel[]
60----
61
62The role of the task in this simple example is to copy the values in the incoming fields into the outgoing fields, then examine the values in some incoming fields (`item_id` and `time`), then set the values in some other outgoing fields (`authorised` and `message`).
63
64Both MVEL and JavaScript like most JVM-based scripting languages can use standard Java libraries to perform complex tasks.
65Towards the top of the scripts you will see how to import Java classes and packages to be used directly in the logic.
66Another thing to notice is that Task Logic should return a `java.lang.Boolean` value `true` if the logic executed correctly.
67If the logic fails for some reason then `false` can be returned, but this will cause the policy invoking this task will fail and exit.
68
69[NOTE]
70.How to return a value from task logic
71====
72Some languages explicitly support returning values from the script (e.g. MVEL and JRuby) using an explicit return statement (e.g. `return true`), other languages do not (e.g. JavaScript and Jython).
73For languages that do not support the `return` statement, a special field called `returnValue` must be created to hold the result of the task logic operation (i.e. assign a `java.lang.Boolean` value to the `returnValue` field before completing the task).
74
75Also, in MVEL if there is no explicit return statement then the return value of the last executed statement will return (e.g. the statement a=(1+2) will return the value 3).
76====
77
78Besides these imported classes and normal language features Apex provides some natively available parameters and functions that can be used directly.
79At run-time these parameters are populated by the Apex execution environment and made natively available to logic scripts each time the logic script is invoked.
80(These can be accessed using the `executor` keyword for most languages, or can be accessed directly without the `executor` keyword in MVEL):
81
82.The `executor` Fields / Methods
83[width="100%",cols="10l,10d,30m,40a",options="header"]
84|====================
85|Name | Type | Java type | Description
86
87|inFields | Fields | java.util.Map <String,Object> |
88The incoming task fields. This is implemented as a standard Java (unmodifiable) Map.
89
902+| 2+<a|
91*Example:*
92[source,javascript,options="nowrap"]
93----
94executor.logger.debug("Incoming fields: "
95 +executor.inFields.entrySet());
96var item_id = executor.incomingFields["item_ID"];
97if (item_id >=1000) { ... }
98----
99
100|outFields | Fields | java.util.Map <String,Object> |
101The outgoing task fields. This is implemented as a standard initially empty Java (modifiable) Map.
102To create a new schema-compliant instance of a field object see the utility method `subject.getOutFieldSchemaHelper()` below
103
1042+| 2+<a|
105*Example:*
106[source,javascript,options="nowrap"]
107----
108executor.outFields["authorised"] = false;
109----
110
111|logger | Logger | org.slf4j.ext.XLogger | A helpful logger
112
1132+| 2+<a|
114*Example:*
115[source,javascript,options="nowrap"]
116----
117executor.logger.info("Executing task: "
118 +executor.subject.id);
119----
120
121|TRUE/FALSE | boolean | java.land.Boolean | 2 helpful constants. These are useful to retrieve correct return values for the task logic
122
1232+| 2+<a|
124*Example:*
125[source,javascript,options="nowrap"]
126----
127var returnValue = executor.TRUE;
128// functionally equivalent to:
129var returnValueType = Java.type("java.lang.Boolean");
130var returnValue = new returnValueType(true);
131----
132
133|subject | Task | TaskFacade |
134
135This provides some useful information about the task that contains this task logic.
136This object has some useful fields and methods :
137
138[options="compact"]
139- *_AxTask task_* to get access to the full task definition of the host task
140- *_String getTaskName()_* to get the name of the host task
141- *_String getId()_* to get the ID of the host task
142- *_SchemaHelper getInFieldSchemaHelper( String fieldName )_* to get a `SchemaHelper` helper object to manipulate incoming task fields in a schema-aware manner
143- *_SchemaHelper getOutFieldSchemaHelper( String fieldName )_* to get a `SchemaHelper` helper object to manipulate outgoing task fields in a schema-aware manner, e.g. to instantiate new schema-compliant field objects to populate the `executor.outFields` outgoing fields map
144
1452+| 2+<a|
146*Example:*
147[source,javascript,options="nowrap"]
148----
149executor.logger.info("Task name: "
150 +executor.subject.getTaskName());
151executor.logger.info("Task id: "
152 +executor.subject.getId());
153executor.logger.info("Task inputs definitions: "
154 +"executor.subject.task.getInputFieldSet());
155executor.logger.info("Task outputs definitions: "
156 +"executor.subject.task.getOutputFieldSet());
157executor.outFields["authorised"] = executor.subject
158 .getOutFieldSchemaHelper("authorised")
159 .createNewInstance("false");
160----
161
1623+l|ContextAlbum getContextAlbum(
163 String ctxtAlbumName ) |
164A utility method to retrieve a `ContextAlbum` for use in the task. This is how you access the context used by the task. The returned `ContextAlbum` implements the `java.util.Map <String,Object>` interface to get and set context as appropriate. The returned `ContextAlbum` also has methods to lock context albums, get information about the schema of the items to be stored in a context album, and get a `SchemaHelper` to manipulate context album items. How to define and use context in a task is described in the Apex Programmer's Guide and in the My First Apex Policy guide.
165
1662+| 2+<a|
167*Example:*
168[source,javascript,options="nowrap"]
169----
170var bkey = executor.inFields.get("branch_ID");
171var cnts = executor.getContextMap("BranchCounts");
172cnts.lockForWriting(bkey);
173cnts.put(bkey, cnts.get(bkey) + 1);
174cnts.unlockForWriting(bkey);
175----
176|====================
177