ramverma | af74a62 | 2018-07-31 18:25:39 +0100 | [diff] [blame] | 1 | // |
| 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 | == Logic Cheatsheet |
| 15 | |
| 16 | Examples given here use Javascript (if not stated otherwise), other execution environments will be similar. |
| 17 | |
| 18 | |
| 19 | === Add Nashorn |
| 20 | |
| 21 | First line in the logic use this import. |
| 22 | |
| 23 | .JS Nashorn |
| 24 | [source,javascript,options="nowrap"] |
| 25 | ---- |
| 26 | load("nashorn:mozilla_compat.js"); |
| 27 | ---- |
| 28 | |
| 29 | |
| 30 | === Finish Logic with Success or Error |
| 31 | |
| 32 | To finish logic, i.e. return to APEX, with success use the following lines close to the end of the logic. |
| 33 | |
| 34 | .JS Success |
| 35 | [source,javascript,options="nowrap"] |
| 36 | ---- |
| 37 | var returnValueType = Java.type("java.lang.Boolean"); |
| 38 | var returnValue = new returnValueType(true); |
| 39 | ---- |
| 40 | |
| 41 | To notify a problem, finish with an error. |
| 42 | |
| 43 | .JS Fail |
| 44 | [source,javascript,options="nowrap"] |
| 45 | ---- |
| 46 | var returnValueType = Java.type("java.lang.Boolean"); |
| 47 | var returnValue = new returnValueType(false); |
| 48 | ---- |
| 49 | |
| 50 | |
| 51 | === Logic Logging |
| 52 | |
| 53 | Logging can be made easy using a local variable for the logger. |
| 54 | Line 1 below does that. |
| 55 | Then we start with a trace log with the task (or task logic) identifier followed by the infields. |
| 56 | |
| 57 | .JS Logging |
| 58 | [source,javascript,options="nowrap"] |
| 59 | ---- |
| 60 | var logger = executor.logger; |
| 61 | logger.trace("start: " + executor.subject.id); |
| 62 | logger.trace("-- infields: " + executor.inFields); |
| 63 | ---- |
| 64 | |
| 65 | For larger logging blocks you can use the standard logging API to detect log levels, for instance: |
| 66 | |
| 67 | .JS Logging Blocks |
| 68 | [source,javascript,options="nowrap"] |
| 69 | ---- |
| 70 | if(logger.isTraceEnabled()){ |
| 71 | // trace logging block here |
| 72 | } |
| 73 | ---- |
| 74 | |
| 75 | Note: the shown logger here logs to `org.onap.policy.apex.executionlogging`. |
| 76 | The behavior of the actual logging can be specified in the `$APEX_HOME/etc/logback.xml`. |
| 77 | |
| 78 | If you want to log into the APEX root logger (which is sometimes necessary to report serious logic errors to the top), |
| 79 | then import the required class and use this logger. |
| 80 | |
| 81 | .JS Root Logger |
| 82 | [source,javascript,options="nowrap"] |
| 83 | ---- |
| 84 | importClass(org.slf4j.LoggerFactory); |
| 85 | var rootLogger = LoggerFactory.getLogger(logger.ROOT_LOGGER_NAME); |
| 86 | |
| 87 | rootLogger.error("Serious error in logic detected: " + executor.subject.id); |
| 88 | ---- |
| 89 | |
| 90 | === Local Variable for Infields |
| 91 | |
| 92 | It is a good idea to use local variables for `infields`. |
| 93 | This avoids long code lines and policy evolution. |
| 94 | The following example assumes infields named `nodeName` and `nodeAlias`. |
| 95 | |
| 96 | .JS Infields Local Var |
| 97 | [source,javascript,options="nowrap"] |
| 98 | ---- |
| 99 | var ifNodeName = executor.inFields["nodeName"]; |
| 100 | var ifNodeAlias = executor.inFields["nodeAlias"]; |
| 101 | ---- |
| 102 | |
| 103 | |
| 104 | === Local Variable for Context Albums |
| 105 | |
| 106 | Similar to the `infields` it is good practice to use local variables for context albums as well. |
| 107 | The following example assumes that a task can access a context album `albumTopoNodes`. |
| 108 | The second line gets a particular node from this context album. |
| 109 | |
| 110 | .JS Infields Local Var |
| 111 | [source,javascript,options="nowrap"] |
| 112 | ---- |
| 113 | var albumTopoNodes = executor.getContextAlbum("albumTopoNodes"); |
| 114 | var ctxtNode = albumTopoNodes.get(ifNodeName); |
| 115 | ---- |
| 116 | |
| 117 | |
| 118 | === Set Outfields in Logic |
| 119 | |
| 120 | The task logic needs to set outfields with content generated. |
| 121 | The exception are outfields that are a direct copy from an infield of the same name, APEX does that autmatically. |
| 122 | |
| 123 | .JS Set Outfields |
| 124 | [source,javascript,options="nowrap"] |
| 125 | ---- |
| 126 | executor.outFields["report"] = "node ctxt :: added node " + ifNodeName; |
| 127 | ---- |
| 128 | |
| 129 | |
| 130 | === Create a instance of an Outfield using Schemas |
| 131 | |
| 132 | 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. |
| 133 | The `executor` provides a field called `subject`, which provides a schem helper with an API for this. |
| 134 | The complete API of the schema helper is documented here: link:https://ericsson.github.io/apex-docs/javadocs/index.html[API Doc: SchemaHelper]. |
| 135 | |
| 136 | If the backend is Avro, then an import of the Avro schema library is required: |
| 137 | |
| 138 | .JS Import Avro |
| 139 | [source,javascript,options="nowrap"] |
| 140 | ---- |
| 141 | importClass(org.apache.avro.generic.GenericData.Array); |
| 142 | importClass(org.apache.avro.generic.GenericRecord); |
| 143 | importClass(org.apache.avro.Schema); |
| 144 | ---- |
| 145 | |
| 146 | If the backend is Java, then the Java class implementing the schema needs to be imported. |
| 147 | |
| 148 | The following example assumes an outfield `situation`. |
| 149 | The `subject` method `getOutFieldSchemaHelper()` is used to create a new instance. |
| 150 | |
| 151 | .JS Outfield Instance with Schema |
| 152 | [source,javascript,options="nowrap"] |
| 153 | ---- |
| 154 | var situation = executor.subject.getOutFieldSchemaHelper("situation").createNewInstance(); |
| 155 | ---- |
| 156 | |
| 157 | If the schema backend is Java, the new instance will be as implemented in the Java class. |
| 158 | If the schema backend is Avro, the new instance will have all fields from the Avro schema specification, but set to `null`. |
| 159 | So any entry here needs to be done separately. |
| 160 | For instance, the `situation` schema has a field `problemID` which we set. |
| 161 | |
| 162 | .JS Outfield Instance with Schema, set |
| 163 | [source,javascript,options="nowrap"] |
| 164 | ---- |
| 165 | situation.put("problemID", "my-problem"); |
| 166 | ---- |
| 167 | |
| 168 | |
| 169 | === Create a instance of an Context Album entry using Schemas |
| 170 | |
| 171 | Context album instances can be created using very similar to the outfields. |
| 172 | Here, the schema helper comes from the context album directly. |
| 173 | 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]. |
| 174 | |
| 175 | If the backend is Avro, then an import of the Avro schema library is required: |
| 176 | |
| 177 | .JS Import Avro |
| 178 | [source,javascript,options="nowrap"] |
| 179 | ---- |
| 180 | importClass(org.apache.avro.generic.GenericData.Array); |
| 181 | importClass(org.apache.avro.generic.GenericRecord); |
| 182 | importClass(org.apache.avro.Schema); |
| 183 | ---- |
| 184 | |
| 185 | If the backend is Java, then the Java class implementing the schema needs to be imported. |
| 186 | |
| 187 | The following example creates a new instance of a context album instance named `albumProblemMap`. |
| 188 | |
| 189 | .JS Outfield Instance with Schema |
| 190 | [source,javascript,options="nowrap"] |
| 191 | ---- |
| 192 | var albumProblemMap = executor.getContextAlbum("albumProblemMap"); |
| 193 | var linkProblem = albumProblemMap.getSchemaHelper().createNewInstance(); |
| 194 | ---- |
| 195 | |
| 196 | This can of course be also done in a single call without the local variable for the context album. |
| 197 | |
| 198 | .JS Outfield Instance with Schema, one line |
| 199 | [source,javascript,options="nowrap"] |
| 200 | ---- |
| 201 | var linkProblem = executor.getContextAlbum("albumProblemMap").getSchemaHelper().createNewInstance(); |
| 202 | ---- |
| 203 | |
| 204 | If the schema backend is Java, the new instance will be as implemented in the Java class. |
| 205 | If the schema backend is Avro, the new instance will have all fields from the Avro schema specification, but set to `null`. |
| 206 | So any entry here needs to be done separately (see above in outfields for an example). |
| 207 | |
| 208 | |
| 209 | === Enumerates |
| 210 | |
| 211 | When dealing with enumerates (Avro or Java defined), it is sometimes and in some execution environments necessary to convert them to a string. |
| 212 | For example, assume an Avro enumerate schema as: |
| 213 | |
| 214 | .Avro Enumerate Schema |
| 215 | [source,json,options="nowrap"] |
| 216 | ---- |
| 217 | { |
| 218 | "type": "enum", |
| 219 | "name": "Status", |
| 220 | "symbols" : [ |
| 221 | "UP", |
| 222 | "DOWN" |
| 223 | ] |
| 224 | } |
| 225 | |
| 226 | ---- |
| 227 | |
| 228 | Using a switch over a field initialized with this enumerate in Javascript will fail. |
| 229 | Instead, use the `toString` method, for example: |
| 230 | |
| 231 | .JS Outfield Instance with Schema, one line |
| 232 | [source,javascript,options="nowrap"] |
| 233 | ---- |
| 234 | var switchTest = executor.inFields["status"]; |
| 235 | switch(switchTest.toString()){ |
| 236 | case "UP": ...; break; |
| 237 | case "DOWN": ...; break; |
| 238 | default: ...; |
| 239 | } |
| 240 | ---- |
| 241 | |
| 242 | |
| 243 | === MVEL Initialize Outfields First! |
| 244 | |
| 245 | In MVEL, we observed a problem when accessing (setting) outfields without a prior access to them. |
| 246 | 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. |
| 247 | |
| 248 | .MVEL Outfield Initialization |
| 249 | [source,java,options="nowrap"] |
| 250 | ---- |
| 251 | outFields.get("initialize outfields"); |
| 252 | ---- |
| 253 | |
| 254 | |
| 255 | === Using Java in Scripting Logic |
| 256 | |
| 257 | Since APEX executes the logic inside a JVM, most scripting languages provide access to all standard Java classes. |
| 258 | Simply add an import for the required class and then use it as in actual Java. |
| 259 | |
| 260 | The following example imports `java.util.arraylist` into a Javascript logic, and then creates a new list. |
| 261 | |
| 262 | .JS Import ArrayList |
| 263 | [source,javascript,options="nowrap"] |
| 264 | ---- |
| 265 | importClass(java.util.ArrayList); |
| 266 | var myList = new ArrayList(); |
| 267 | ---- |
| 268 | |
| 269 | |