summaryrefslogtreecommitdiffstats
path: root/src/site-docs/adoc/fragments/howto-write-logic/logic-cheatsheet.adoc
blob: fe3cd0d0d0474da2f48aa76d60577c6f5ce34b4f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
//
// ============LICENSE_START=======================================================
//  Copyright (C) 2016-2018 Ericsson. All rights reserved.
// ================================================================================
// This file is licensed under the CREATIVE COMMONS ATTRIBUTION 4.0 INTERNATIONAL LICENSE
// Full license text at https://creativecommons.org/licenses/by/4.0/legalcode
// 
// SPDX-License-Identifier: CC-BY-4.0
// ============LICENSE_END=========================================================
//
// @author Sven van der Meer (sven.van.der.meer@ericsson.com)
//

== Logic Cheatsheet

Examples given here use Javascript (if not stated otherwise), other execution environments will be similar.


=== Add Nashorn

First line in the logic use this import.

.JS Nashorn
[source,javascript,options="nowrap"]
----
load("nashorn:mozilla_compat.js");
----


=== Finish Logic with Success or Error

To finish logic, i.e. return to APEX, with success use the following lines close to the end of the logic.

.JS Success
[source,javascript,options="nowrap"]
----
var returnValueType = Java.type("java.lang.Boolean");
var returnValue = new returnValueType(true);
----

To notify a problem, finish with an error.

.JS Fail
[source,javascript,options="nowrap"]
----
var returnValueType = Java.type("java.lang.Boolean");
var returnValue = new returnValueType(false);
----


=== Logic Logging

Logging can be made easy using a local variable for the logger.
Line 1 below does that.
Then we start with a trace log with the task (or task logic) identifier followed by the infields.

.JS Logging
[source,javascript,options="nowrap"]
----
var logger = executor.logger;
logger.trace("start: " + executor.subject.id);
logger.trace("-- infields: " + executor.inFields);
----

For larger logging blocks you can use the standard logging API to detect log levels, for instance:

.JS Logging Blocks
[source,javascript,options="nowrap"]
----
if(logger.isTraceEnabled()){
    // trace logging block here
}
----

Note: the shown logger here logs to `org.onap.policy.apex.executionlogging`.
The behavior of the actual logging can be specified in the `$APEX_HOME/etc/logback.xml`.

If you want to log into the APEX root logger (which is sometimes necessary to report serious logic errors to the top),
then import the required class and use this logger.

.JS Root Logger
[source,javascript,options="nowrap"]
----
importClass(org.slf4j.LoggerFactory);
var rootLogger = LoggerFactory.getLogger(logger.ROOT_LOGGER_NAME);

rootLogger.error("Serious error in logic detected: " + executor.subject.id);
----

=== Local Variable for Infields

It is a good idea to use local variables for `infields`.
This avoids long code lines and policy evolution.
The following example assumes infields named `nodeName` and `nodeAlias`.

.JS Infields Local Var
[source,javascript,options="nowrap"]
----
var ifNodeName = executor.inFields["nodeName"];
var ifNodeAlias = executor.inFields["nodeAlias"];
----


=== Local Variable for Context Albums

Similar to the `infields` it is good practice to use local variables for context albums as well.
The following example assumes that a task can access a context album `albumTopoNodes`.
The second line gets a particular node from this context album.

.JS Infields Local Var
[source,javascript,options="nowrap"]
----
var albumTopoNodes = executor.getContextAlbum("albumTopoNodes");
var ctxtNode = albumTopoNodes.get(ifNodeName);
----


=== Set Outfields in Logic

The task logic needs to set outfields with content generated.
The exception are outfields that are a direct copy from an infield of the same name, APEX does that autmatically.

.JS Set Outfields
[source,javascript,options="nowrap"]
----
executor.outFields["report"] = "node ctxt :: added node " + ifNodeName;
----


=== Create a instance of an Outfield using Schemas

If an outfield is not an atomic type (string, integer, etc.) but uses a complex schema (with a Java or Avro backend), APEX can help to create new instances.
The `executor` provides a field called `subject`, which provides a schem helper with an API for this.
The complete API of the schema helper is documented here: link:https://ericsson.github.io/apex-docs/javadocs/index.html[API Doc: SchemaHelper].

If the backend is Avro, then an import of the Avro schema library is required:

.JS Import Avro
[source,javascript,options="nowrap"]
----
importClass(org.apache.avro.generic.GenericData.Array);
importClass(org.apache.avro.generic.GenericRecord);
importClass(org.apache.avro.Schema);
----

If the backend is Java, then the Java class implementing the schema needs to be imported.

The following example assumes an outfield `situation`.
The `subject` method `getOutFieldSchemaHelper()` is used to create a new instance.

.JS Outfield Instance with Schema
[source,javascript,options="nowrap"]
----
var situation = executor.subject.getOutFieldSchemaHelper("situation").createNewInstance();
----

If the schema backend is Java, the new instance will be as implemented in the Java class.
If the schema backend is Avro, the new instance will have all fields from the Avro schema specification, but set to `null`.
So any entry here needs to be done separately.
For instance, the `situation` schema has a field `problemID` which we set.

.JS Outfield Instance with Schema, set
[source,javascript,options="nowrap"]
----
situation.put("problemID", "my-problem");
----


=== Create a instance of an Context Album entry using Schemas

Context album instances can be created using very similar to the outfields.
Here, the schema helper comes from the context album directly.
The API of the schema helper is the same as for outfields, see link:https://ericsson.github.io/apex-docs/javadocs/index.html[API Doc: SchemaHelper].

If the backend is Avro, then an import of the Avro schema library is required:

.JS Import Avro
[source,javascript,options="nowrap"]
----
importClass(org.apache.avro.generic.GenericData.Array);
importClass(org.apache.avro.generic.GenericRecord);
importClass(org.apache.avro.Schema);
----

If the backend is Java, then the Java class implementing the schema needs to be imported.

The following example creates a new instance of a context album instance named `albumProblemMap`.

.JS Outfield Instance with Schema
[source,javascript,options="nowrap"]
----
var albumProblemMap = executor.getContextAlbum("albumProblemMap");
var linkProblem = albumProblemMap.getSchemaHelper().createNewInstance();
----

This can of course be also done in a single call without the local variable for the context album.

.JS Outfield Instance with Schema, one line
[source,javascript,options="nowrap"]
----
var linkProblem = executor.getContextAlbum("albumProblemMap").getSchemaHelper().createNewInstance();
----

If the schema backend is Java, the new instance will be as implemented in the Java class.
If the schema backend is Avro, the new instance will have all fields from the Avro schema specification, but set to `null`.
So any entry here needs to be done separately (see above in outfields for an example).


=== Enumerates

When dealing with enumerates (Avro or Java defined), it is sometimes and in some execution environments necessary to convert them to a string.
For example, assume an Avro enumerate schema as:

.Avro Enumerate Schema
[source,json,options="nowrap"]
----
{
  "type": "enum",
  "name": "Status",
  "symbols" : [
    "UP",
    "DOWN"
  ]
}

----

Using a switch over a field initialized with this enumerate in Javascript will fail.
Instead, use the `toString` method, for example:

.JS Outfield Instance with Schema, one line
[source,javascript,options="nowrap"]
----
var switchTest = executor.inFields["status"];
switch(switchTest.toString()){
  case "UP": ...; break;
  case "DOWN": ...; break;
  default: ...;
}
----


=== MVEL Initialize Outfields First!

In MVEL, we observed a problem when accessing (setting) outfields without a prior access to them.
So in any MVEL task logic, before setting any outfield, simply do a get (with any string), to load the outfields into the MVEL cache.

.MVEL Outfield Initialization
[source,java,options="nowrap"]
----
outFields.get("initialize outfields");
----


=== Using Java in Scripting Logic

Since APEX executes the logic inside a JVM, most scripting languages provide access to all standard Java classes.
Simply add an import for the required class and then use it as in actual Java.

The following example imports `java.util.arraylist` into a Javascript logic, and then creates a new list.

.JS Import ArrayList
[source,javascript,options="nowrap"]
----
importClass(java.util.ArrayList);
var myList = new ArrayList();
----