Changes to support multiple outputs from a state 07/122107/8
authora.sreekumar <ajith.sreekumar@bell.ca>
Tue, 22 Jun 2021 14:55:46 +0000 (15:55 +0100)
committera.sreekumar <ajith.sreekumar@bell.ca>
Mon, 28 Jun 2021 09:36:48 +0000 (10:36 +0100)
This review addresses two main changes:
1) inputFields and outputFields are not tied to task definition anymore.
   Instead inputEvent and outputEvents associated to a task is populated
   as part of the policy state definition, as the state definition have
   the information anyway.
   - Clean up of the usage of inputFields and outputFields in task
     definition will happen in a future review
   - inputFields and outputFields defined in task definition in
     policies until honolulu will not make the policy invalid as the
     changes are done in backward compatible way.
2) Multiple output events can come out of a final state now.
   - Define another policy state output with the relevant eventName in
     the command file
   - In the task logic, create a map to store the fields of the relevant
     outputEvent, and then just call
     "executor.addFieldsToOutput(<the_map_of_fields>)"
     These 2 steps are enough to send multiple events to relevant
     components as per the apex configuration.

Change-Id: Id88ca402704106404f529e595e1a76f6bf167876
Issue-ID: POLICY-3336
Signed-off-by: a.sreekumar <ajith.sreekumar@bell.ca>
47 files changed:
auth/cli-codegen/src/test/java/org/onap/policy/apex/auth/clicodegen/CodeGeneratorCliEditorTest.java
auth/cli-editor/src/test/java/org/onap/policy/apex/auth/clieditor/CommandLineEditorEventsContextTest.java
auth/cli-editor/src/test/resources/tosca/PolicyModel.json
auth/cli-editor/src/test/resources/tosca/ToscaPolicyOutput_compare.json
core/core-engine/src/main/java/org/onap/policy/apex/core/engine/engine/impl/ApexEngineImpl.java
core/core-engine/src/main/java/org/onap/policy/apex/core/engine/engine/impl/StateMachineHandler.java
core/core-engine/src/main/java/org/onap/policy/apex/core/engine/executor/StateExecutor.java
core/core-engine/src/main/java/org/onap/policy/apex/core/engine/executor/StateMachineExecutor.java
core/core-engine/src/main/java/org/onap/policy/apex/core/engine/executor/StateOutput.java
core/core-engine/src/main/java/org/onap/policy/apex/core/engine/executor/TaskExecutor.java
core/core-engine/src/main/java/org/onap/policy/apex/core/engine/executor/context/AxTaskFacade.java
core/core-engine/src/main/java/org/onap/policy/apex/core/engine/executor/context/TaskExecutionContext.java
core/core-engine/src/test/java/org/onap/policy/apex/core/engine/engine/impl/DummySmExecutor.java
core/core-engine/src/test/java/org/onap/policy/apex/core/engine/executor/DummyTaskExecutor.java
core/core-engine/src/test/java/org/onap/policy/apex/core/engine/executor/StateMachineExecutorTest.java
core/core-engine/src/test/java/org/onap/policy/apex/core/engine/executor/TaskExecutorTest.java
core/core-engine/src/test/java/org/onap/policy/apex/core/engine/executor/context/AxTaskFacadeTest.java
core/core-engine/src/test/java/org/onap/policy/apex/core/engine/executor/context/TaskExecutionContextTest.java
examples/examples-grpc/src/main/resources/examples/config/APEXgRPC/ApexConfig.json
examples/examples-grpc/src/main/resources/examples/events/APEXgRPC/CDSResponseStatusEvent.json [new file with mode: 0644]
examples/examples-grpc/src/main/resources/examples/events/APEXgRPC/LogEvent.json
examples/examples-grpc/src/main/resources/logic/ResponseTask.js
examples/examples-grpc/src/main/resources/policy/APEXgRPCPolicy.apex
examples/examples-grpc/src/test/java/org/onap/policy/apex/examples/grpc/GrpcTestRestSimEndpoint.java
examples/examples-grpc/src/test/java/org/onap/policy/apex/examples/grpc/TestApexGrpcExample.java
model/model-api/src/main/java/org/onap/policy/apex/model/modelapi/impl/ApexModelImpl.java
model/model-api/src/main/java/org/onap/policy/apex/model/modelapi/impl/PolicyFacade.java
model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxPolicyModel.java
model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxStateOutput.java
model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/concepts/AxTask.java
model/policy-model/src/main/java/org/onap/policy/apex/model/policymodel/handling/PolicyAnalyser.java
model/policy-model/src/test/java/org/onap/policy/apex/model/policymodel/concepts/PolicyModelTest.java
model/policy-model/src/test/java/org/onap/policy/apex/model/policymodel/concepts/StateOutputTest.java
model/policy-model/src/test/java/org/onap/policy/apex/model/policymodel/concepts/TasksTest.java
model/policy-model/src/test/java/org/onap/policy/apex/model/policymodel/handling/SupportApexPolicyModelCreator.java
plugins/plugins-executor/plugins-executor-java/src/main/java/org/onap/policy/apex/plugins/executor/java/JavaTaskExecutor.java
plugins/plugins-executor/plugins-executor-java/src/test/java/org/onap/policy/apex/plugins/executor/java/JavaTaskExecutorTest.java
plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutor.java
plugins/plugins-executor/plugins-executor-javascript/src/test/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutorTest.java
plugins/plugins-executor/plugins-executor-jruby/src/main/java/org/onap/policy/apex/plugins/executor/jruby/JrubyTaskExecutor.java
plugins/plugins-executor/plugins-executor-jruby/src/test/java/org/onap/policy/apex/plugins/executor/jruby/JrubyTaskExecutorTest.java
plugins/plugins-executor/plugins-executor-mvel/src/main/java/org/onap/policy/apex/plugins/executor/mvel/MvelTaskExecutor.java
plugins/plugins-executor/plugins-executor-mvel/src/test/java/org/onap/policy/apex/plugins/executor/mvel/MvelTaskExecutorTest.java
services/services-engine/src/test/java/org/onap/policy/apex/service/engine/parameters/dummyclasses/DummyTaskExecutor.java
services/services-onappf/src/test/java/org/onap/policy/apex/services/onappf/parameters/dummyclasses/DummyTaskExecutor.java
tools/model-generator/src/main/java/org/onap/policy/apex/tools/model/generator/model2cli/Model2Cli.java
tools/model-generator/src/main/java/org/onap/policy/apex/tools/model/generator/model2event/Model2JsonEventSchema.java

index 921591b..cec261c 100644 (file)
@@ -3,6 +3,7 @@
  *  Copyright (C) 2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019 Samsung Electronics Co., Ltd.
  *  Modifications Copyright (C) 2020 Nordix Foundation
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -425,8 +426,8 @@ public class CodeGeneratorCliEditorTest {
             final AxReferenceKey outkey = out.getKey();
 
             final ST val = cg.createPolicyStateOutput(kig.getPName(skey), kig.getPVersion(skey), kig.getLName(skey),
-                            kig.getLName(outkey), kig.getName(out.getOutgingEvent()),
-                            kig.getVersion(out.getOutgingEvent()), kig.getLName(out.getNextState()));
+                kig.getLName(outkey), kig.getName(out.getOutgoingEvent()), kig.getVersion(out.getOutgoingEvent()),
+                kig.getLName(out.getNextState()));
 
             ret.add(val);
         }
index d00a923..0e87950 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -84,7 +85,7 @@ public class CommandLineEditorEventsContextTest {
         final int modelCharCount = modelString.replaceAll(SPACES, EMPTY_STRING).length();
 
         assertEquals(25892, logCharCount);
-        assertEquals(46048, modelCharCount);
+        assertEquals(51975, modelCharCount);
     }
 
     /**
@@ -114,7 +115,7 @@ public class CommandLineEditorEventsContextTest {
         final int modelCharCount = modelString.replaceAll(SPACES, EMPTY_STRING).length();
 
         assertEquals(30068, logCharCount);
-        assertEquals(52596, modelCharCount);
+        assertEquals(59015, modelCharCount);
 
     }
 
index 0e9cfca..3672be4 100644 (file)
 {
-   "apexPolicyModel" : {
-      "key" : {
-         "name" : "MyFirstPolicyModel",
-         "version" : "0.0.1"
+  "apexPolicyModel": {
+    "key": {
+      "name": "MyFirstPolicyModel",
+      "version": "0.0.1"
+    },
+    "keyInformation": {
+      "key": {
+        "name": "MyFirstPolicyModel_KeyInfo",
+        "version": "0.0.1"
       },
-      "keyInformation" : {
-         "key" : {
-            "name" : "MyFirstPolicyModel_KeyInfo",
-            "version" : "0.0.1"
-         },
-         "keyInfoMap" : {
-            "entry" : [ {
-               "key" : {
-                  "name" : "MorningBoozeCheck",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "MorningBoozeCheck",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "3351b0f4-cf06-4fa2-8823-edf67bd30223",
-                  "description" : "This task checks if the sales request is for an item that contains alcohol. \nIf the local time is between 00:00:00 and 11:30:00 then the sale is not authorised. Otherwise the sale is authorised. \nIn this implementation we assume that all items with item_ID values between 1000 and 2000 contain alcohol :-)"
-               }
-            }, {
-               "key" : {
-                  "name" : "MyFirstPolicy",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "MyFirstPolicy",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "6c5e410f-489a-46ff-964e-982ce6e8b6d0",
-                  "description" : "This is my first Apex policy. It checks if a sale should be authorised or not."
-               }
-            }, {
-               "key" : {
-                  "name" : "MyFirstPolicyModel",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "MyFirstPolicyModel",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "540226fb-55ee-4f0e-a444-983a0494818e",
-                  "description" : "This is my first Apex Policy Model."
-               }
-            }, {
-               "key" : {
-                  "name" : "MyFirstPolicyModel_Events",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "MyFirstPolicyModel_Events",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "ef281318-5ac9-3ef0-8db3-8f9c4e4a81e2",
-                  "description" : "Generated description for concept referred to by key \"MyFirstPolicyModel_Events:0.0.1\""
-               }
-            }, {
-               "key" : {
-                  "name" : "MyFirstPolicyModel_KeyInfo",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "MyFirstPolicyModel_KeyInfo",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "d9248c6f-7c00-38df-8251-611463ba4065",
-                  "description" : "Generated description for concept referred to by key \"MyFirstPolicyModel_KeyInfo:0.0.1\""
-               }
-            }, {
-               "key" : {
-                  "name" : "MyFirstPolicyModel_Policies",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "MyFirstPolicyModel_Policies",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "77c01a6b-510c-3aa9-b640-b4db356aa03b",
-                  "description" : "Generated description for concept referred to by key \"MyFirstPolicyModel_Policies:0.0.1\""
-               }
-            }, {
-               "key" : {
-                  "name" : "MyFirstPolicyModel_Schemas",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "MyFirstPolicyModel_Schemas",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "d0cc3aa0-ea69-3a43-80ff-a0dbb0ebd885",
-                  "description" : "Generated description for concept referred to by key \"MyFirstPolicyModel_Schemas:0.0.1\""
-               }
-            }, {
-               "key" : {
-                  "name" : "MyFirstPolicyModel_Tasks",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "MyFirstPolicyModel_Tasks",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "b02a7e02-2cd0-39e6-b3cb-946fa83a8f08",
-                  "description" : "Generated description for concept referred to by key \"MyFirstPolicyModel_Tasks:0.0.1\""
-               }
-            }, {
-               "key" : {
-                  "name" : "SALE_AUTH",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "SALE_AUTH",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "c4500941-3f98-4080-a9cc-5b9753ed050b",
-                  "description" : "An event emitted by the Policy to indicate whether the sale of an item has been authorised"
-               }
-            }, {
-               "key" : {
-                  "name" : "SALE_INPUT",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "SALE_INPUT",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "4f04aa98-e917-4f4a-882a-c75ba5a99374",
-                  "description" : "An event raised by the PoS system each time an item is scanned for purchase"
-               }
-            }, {
-               "key" : {
-                  "name" : "assistant_ID_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "assistant_ID_type",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "36df4c71-9616-4206-8b53-976a5cd4bd87",
-                  "description" : "A type for 'assistant_ID' values"
-               }
-            }, {
-               "key" : {
-                  "name" : "authorised_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "authorised_type",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "d48b619e-d00d-4008-b884-02d76ea4350b",
-                  "description" : "A type for 'authorised' values"
-               }
-            }, {
-               "key" : {
-                  "name" : "branch_ID_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "branch_ID_type",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "6468845f-4122-4128-8e49-0f52c26078b5",
-                  "description" : "A type for 'branch_ID' values"
-               }
-            }, {
-               "key" : {
-                  "name" : "item_ID_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "item_ID_type",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "4f227ff1-aee0-453a-b6b6-9a4b2e0da932",
-                  "description" : "A type for 'item_ID' values"
-               }
-            }, {
-               "key" : {
-                  "name" : "message_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "message_type",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "ad1431bb-3155-4e73-b5a3-b89bee498749",
-                  "description" : "A type for 'message' values"
-               }
-            }, {
-               "key" : {
-                  "name" : "notes_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "notes_type",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "eecfde90-896c-4343-8f9c-2603ced94e2d",
-                  "description" : "A type for 'notes' values"
-               }
-            }, {
-               "key" : {
-                  "name" : "price_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "price_type",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "52c2fc45-fd8c-463c-bd6f-d91b0554aea7",
-                  "description" : "A type for 'amount'/'price' values"
-               }
-            }, {
-               "key" : {
-                  "name" : "quantity_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "quantity_type",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "ac3d9842-80af-4a98-951c-bd79a431c613",
-                  "description" : "A type for 'quantity' values"
-               }
-            }, {
-               "key" : {
-                  "name" : "sale_ID_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "sale_ID_type",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "cca47d74-7754-4a61-b163-ca31f66b157b",
-                  "description" : "A type for 'sale_ID' values"
-               }
-            }, {
-               "key" : {
-                  "name" : "timestamp_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "timestamp_type",
-                     "version" : "0.0.1"
-                  },
-                  "UUID" : "fd594e88-411d-4a94-b2be-697b3a0d7adf",
-                  "description" : "A type for 'time' values"
-               }
-            } ]
-         }
+      "keyInfoMap": {
+        "entry": [
+          {
+            "key": {
+              "name": "MorningBoozeCheck",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "MorningBoozeCheck",
+                "version": "0.0.1"
+              },
+              "UUID": "3351b0f4-cf06-4fa2-8823-edf67bd30223",
+              "description": "This task checks if the sales request is for an item that contains alcohol. \nIf the local time is between 00:00:00 and 11:30:00 then the sale is not authorised. Otherwise the sale is authorised. \nIn this implementation we assume that all items with item_ID values between 1000 and 2000 contain alcohol :-)"
+            }
+          },
+          {
+            "key": {
+              "name": "MyFirstPolicy",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "MyFirstPolicy",
+                "version": "0.0.1"
+              },
+              "UUID": "6c5e410f-489a-46ff-964e-982ce6e8b6d0",
+              "description": "This is my first Apex policy. It checks if a sale should be authorised or not."
+            }
+          },
+          {
+            "key": {
+              "name": "MyFirstPolicyModel",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "MyFirstPolicyModel",
+                "version": "0.0.1"
+              },
+              "UUID": "540226fb-55ee-4f0e-a444-983a0494818e",
+              "description": "This is my first Apex Policy Model."
+            }
+          },
+          {
+            "key": {
+              "name": "MyFirstPolicyModel_Events",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "MyFirstPolicyModel_Events",
+                "version": "0.0.1"
+              },
+              "UUID": "ef281318-5ac9-3ef0-8db3-8f9c4e4a81e2",
+              "description": "Generated description for concept referred to by key \"MyFirstPolicyModel_Events:0.0.1\""
+            }
+          },
+          {
+            "key": {
+              "name": "MyFirstPolicyModel_KeyInfo",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "MyFirstPolicyModel_KeyInfo",
+                "version": "0.0.1"
+              },
+              "UUID": "d9248c6f-7c00-38df-8251-611463ba4065",
+              "description": "Generated description for concept referred to by key \"MyFirstPolicyModel_KeyInfo:0.0.1\""
+            }
+          },
+          {
+            "key": {
+              "name": "MyFirstPolicyModel_Policies",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "MyFirstPolicyModel_Policies",
+                "version": "0.0.1"
+              },
+              "UUID": "77c01a6b-510c-3aa9-b640-b4db356aa03b",
+              "description": "Generated description for concept referred to by key \"MyFirstPolicyModel_Policies:0.0.1\""
+            }
+          },
+          {
+            "key": {
+              "name": "MyFirstPolicyModel_Schemas",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "MyFirstPolicyModel_Schemas",
+                "version": "0.0.1"
+              },
+              "UUID": "d0cc3aa0-ea69-3a43-80ff-a0dbb0ebd885",
+              "description": "Generated description for concept referred to by key \"MyFirstPolicyModel_Schemas:0.0.1\""
+            }
+          },
+          {
+            "key": {
+              "name": "MyFirstPolicyModel_Tasks",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "MyFirstPolicyModel_Tasks",
+                "version": "0.0.1"
+              },
+              "UUID": "b02a7e02-2cd0-39e6-b3cb-946fa83a8f08",
+              "description": "Generated description for concept referred to by key \"MyFirstPolicyModel_Tasks:0.0.1\""
+            }
+          },
+          {
+            "key": {
+              "name": "SALE_AUTH",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "SALE_AUTH",
+                "version": "0.0.1"
+              },
+              "UUID": "c4500941-3f98-4080-a9cc-5b9753ed050b",
+              "description": "An event emitted by the Policy to indicate whether the sale of an item has been authorised"
+            }
+          },
+          {
+            "key": {
+              "name": "SALE_INPUT",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "SALE_INPUT",
+                "version": "0.0.1"
+              },
+              "UUID": "4f04aa98-e917-4f4a-882a-c75ba5a99374",
+              "description": "An event raised by the PoS system each time an item is scanned for purchase"
+            }
+          },
+          {
+            "key": {
+              "name": "assistant_ID_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "assistant_ID_type",
+                "version": "0.0.1"
+              },
+              "UUID": "36df4c71-9616-4206-8b53-976a5cd4bd87",
+              "description": "A type for 'assistant_ID' values"
+            }
+          },
+          {
+            "key": {
+              "name": "authorised_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "authorised_type",
+                "version": "0.0.1"
+              },
+              "UUID": "d48b619e-d00d-4008-b884-02d76ea4350b",
+              "description": "A type for 'authorised' values"
+            }
+          },
+          {
+            "key": {
+              "name": "branch_ID_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "branch_ID_type",
+                "version": "0.0.1"
+              },
+              "UUID": "6468845f-4122-4128-8e49-0f52c26078b5",
+              "description": "A type for 'branch_ID' values"
+            }
+          },
+          {
+            "key": {
+              "name": "item_ID_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "item_ID_type",
+                "version": "0.0.1"
+              },
+              "UUID": "4f227ff1-aee0-453a-b6b6-9a4b2e0da932",
+              "description": "A type for 'item_ID' values"
+            }
+          },
+          {
+            "key": {
+              "name": "message_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "message_type",
+                "version": "0.0.1"
+              },
+              "UUID": "ad1431bb-3155-4e73-b5a3-b89bee498749",
+              "description": "A type for 'message' values"
+            }
+          },
+          {
+            "key": {
+              "name": "notes_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "notes_type",
+                "version": "0.0.1"
+              },
+              "UUID": "eecfde90-896c-4343-8f9c-2603ced94e2d",
+              "description": "A type for 'notes' values"
+            }
+          },
+          {
+            "key": {
+              "name": "price_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "price_type",
+                "version": "0.0.1"
+              },
+              "UUID": "52c2fc45-fd8c-463c-bd6f-d91b0554aea7",
+              "description": "A type for 'amount'/'price' values"
+            }
+          },
+          {
+            "key": {
+              "name": "quantity_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "quantity_type",
+                "version": "0.0.1"
+              },
+              "UUID": "ac3d9842-80af-4a98-951c-bd79a431c613",
+              "description": "A type for 'quantity' values"
+            }
+          },
+          {
+            "key": {
+              "name": "sale_ID_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "sale_ID_type",
+                "version": "0.0.1"
+              },
+              "UUID": "cca47d74-7754-4a61-b163-ca31f66b157b",
+              "description": "A type for 'sale_ID' values"
+            }
+          },
+          {
+            "key": {
+              "name": "timestamp_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "timestamp_type",
+                "version": "0.0.1"
+              },
+              "UUID": "fd594e88-411d-4a94-b2be-697b3a0d7adf",
+              "description": "A type for 'time' values"
+            }
+          }
+        ]
+      }
+    },
+    "policies": {
+      "key": {
+        "name": "MyFirstPolicyModel_Policies",
+        "version": "0.0.1"
       },
-      "policies" : {
-         "key" : {
-            "name" : "MyFirstPolicyModel_Policies",
-            "version" : "0.0.1"
-         },
-         "policyMap" : {
-            "entry" : [ {
-               "key" : {
-                  "name" : "MyFirstPolicy",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "policyKey" : {
-                     "name" : "MyFirstPolicy",
-                     "version" : "0.0.1"
-                  },
-                  "template" : "FREEFORM",
-                  "state" : {
-                     "entry" : [ {
-                        "key" : "BoozeAuthDecide",
-                        "value" : {
-                           "stateKey" : {
-                              "parentKeyName" : "MyFirstPolicy",
-                              "parentKeyVersion" : "0.0.1",
-                              "parentLocalName" : "NULL",
-                              "localName" : "BoozeAuthDecide"
-                           },
-                           "trigger" : {
-                              "name" : "SALE_INPUT",
-                              "version" : "0.0.1"
-                           },
-                           "stateOutputs" : {
-                              "entry" : [ {
-                                 "key" : "MorningBoozeCheck_Output_Direct",
-                                 "value" : {
-                                    "key" : {
-                                       "parentKeyName" : "MyFirstPolicy",
-                                       "parentKeyVersion" : "0.0.1",
-                                       "parentLocalName" : "BoozeAuthDecide",
-                                       "localName" : "MorningBoozeCheck_Output_Direct"
-                                    },
-                                    "outgoingEvent" : {
-                                       "name" : "SALE_AUTH",
-                                       "version" : "0.0.1"
-                                    },
-                                    "nextState" : {
-                                       "parentKeyName" : "NULL",
-                                       "parentKeyVersion" : "0.0.0",
-                                       "parentLocalName" : "NULL",
-                                       "localName" : "NULL"
-                                    }
-                                 }
-                              } ]
-                           },
-                           "contextAlbumReference" : [ ],
-                           "taskSelectionLogic" : {
-                              "key" : "NULL",
-                              "logicFlavour" : "UNDEFINED",
-                              "logic" : ""
-                           },
-                           "stateFinalizerLogicMap" : {
-                              "entry" : [ ]
-                           },
-                           "defaultTask" : {
-                              "name" : "MorningBoozeCheck",
-                              "version" : "0.0.1"
-                           },
-                           "taskReferences" : {
-                              "entry" : [ {
-                                 "key" : {
-                                    "name" : "MorningBoozeCheck",
-                                    "version" : "0.0.1"
-                                 },
-                                 "value" : {
-                                    "key" : {
-                                       "parentKeyName" : "MyFirstPolicy",
-                                       "parentKeyVersion" : "0.0.1",
-                                       "parentLocalName" : "BoozeAuthDecide",
-                                       "localName" : "MorningBoozeCheck"
-                                    },
-                                    "outputType" : "DIRECT",
-                                    "output" : {
-                                       "parentKeyName" : "MyFirstPolicy",
-                                       "parentKeyVersion" : "0.0.1",
-                                       "parentLocalName" : "BoozeAuthDecide",
-                                       "localName" : "MorningBoozeCheck_Output_Direct"
-                                    }
-                                 }
-                              } ]
-                           }
-                        }
-                     } ]
-                  },
-                  "firstState" : "BoozeAuthDecide"
-               }
-            } ]
-         }
+      "policyMap": {
+        "entry": [
+          {
+            "key": {
+              "name": "MyFirstPolicy",
+              "version": "0.0.1"
+            },
+            "value": {
+              "policyKey": {
+                "name": "MyFirstPolicy",
+                "version": "0.0.1"
+              },
+              "template": "FREEFORM",
+              "state": {
+                "entry": [
+                  {
+                    "key": "BoozeAuthDecide",
+                    "value": {
+                      "stateKey": {
+                        "parentKeyName": "MyFirstPolicy",
+                        "parentKeyVersion": "0.0.1",
+                        "parentLocalName": "NULL",
+                        "localName": "BoozeAuthDecide"
+                      },
+                      "trigger": {
+                        "name": "SALE_INPUT",
+                        "version": "0.0.1"
+                      },
+                      "stateOutputs": {
+                        "entry": [
+                          {
+                            "key": "MorningBoozeCheck_Output_Direct",
+                            "value": {
+                              "key": {
+                                "parentKeyName": "MyFirstPolicy",
+                                "parentKeyVersion": "0.0.1",
+                                "parentLocalName": "BoozeAuthDecide",
+                                "localName": "MorningBoozeCheck_Output_Direct"
+                              },
+                              "outgoingEvent": {
+                                "name": "SALE_AUTH",
+                                "version": "0.0.1"
+                              },
+                              "outgoingEventReference": [
+                                {
+                                  "name": "SALE_AUTH",
+                                  "version": "0.0.1"
+                                }
+                              ],
+                              "nextState": {
+                                "parentKeyName": "NULL",
+                                "parentKeyVersion": "0.0.0",
+                                "parentLocalName": "NULL",
+                                "localName": "NULL"
+                              }
+                            }
+                          }
+                        ]
+                      },
+                      "contextAlbumReference": [],
+                      "taskSelectionLogic": {
+                        "key": "NULL",
+                        "logicFlavour": "UNDEFINED",
+                        "logic": ""
+                      },
+                      "stateFinalizerLogicMap": {
+                        "entry": []
+                      },
+                      "defaultTask": {
+                        "name": "MorningBoozeCheck",
+                        "version": "0.0.1"
+                      },
+                      "taskReferences": {
+                        "entry": [
+                          {
+                            "key": {
+                              "name": "MorningBoozeCheck",
+                              "version": "0.0.1"
+                            },
+                            "value": {
+                              "key": {
+                                "parentKeyName": "MyFirstPolicy",
+                                "parentKeyVersion": "0.0.1",
+                                "parentLocalName": "BoozeAuthDecide",
+                                "localName": "MorningBoozeCheck"
+                              },
+                              "outputType": "DIRECT",
+                              "output": {
+                                "parentKeyName": "MyFirstPolicy",
+                                "parentKeyVersion": "0.0.1",
+                                "parentLocalName": "BoozeAuthDecide",
+                                "localName": "MorningBoozeCheck_Output_Direct"
+                              }
+                            }
+                          }
+                        ]
+                      }
+                    }
+                  }
+                ]
+              },
+              "firstState": "BoozeAuthDecide"
+            }
+          }
+        ]
+      }
+    },
+    "tasks": {
+      "key": {
+        "name": "MyFirstPolicyModel_Tasks",
+        "version": "0.0.1"
       },
-      "tasks" : {
-         "key" : {
-            "name" : "MyFirstPolicyModel_Tasks",
-            "version" : "0.0.1"
-         },
-         "taskMap" : {
-            "entry" : [ {
-               "key" : {
-                  "name" : "MorningBoozeCheck",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "MorningBoozeCheck",
-                     "version" : "0.0.1"
-                  },
-                  "inputFields" : {
-                     "entry" : [ {
-                        "key" : "amount",
-                        "value" : {
-                           "key" : "amount",
-                           "fieldSchemaKey" : {
-                              "name" : "price_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "assistant_ID",
-                        "value" : {
-                           "key" : "assistant_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "assistant_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "branch_ID",
-                        "value" : {
-                           "key" : "branch_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "branch_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "item_ID",
-                        "value" : {
-                           "key" : "item_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "item_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "notes",
-                        "value" : {
-                           "key" : "notes",
-                           "fieldSchemaKey" : {
-                              "name" : "notes_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : true
-                        }
-                     }, {
-                        "key" : "quantity",
-                        "value" : {
-                           "key" : "quantity",
-                           "fieldSchemaKey" : {
-                              "name" : "quantity_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "sale_ID",
-                        "value" : {
-                           "key" : "sale_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "sale_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "time",
-                        "value" : {
-                           "key" : "time",
-                           "fieldSchemaKey" : {
-                              "name" : "timestamp_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     } ]
-                  },
-                  "outputFields" : {
-                     "entry" : [ {
-                        "key" : "amount",
-                        "value" : {
-                           "key" : "amount",
-                           "fieldSchemaKey" : {
-                              "name" : "price_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "assistant_ID",
-                        "value" : {
-                           "key" : "assistant_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "assistant_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "authorised",
-                        "value" : {
-                           "key" : "authorised",
-                           "fieldSchemaKey" : {
-                              "name" : "authorised_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "branch_ID",
-                        "value" : {
-                           "key" : "branch_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "branch_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "item_ID",
-                        "value" : {
-                           "key" : "item_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "item_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "message",
-                        "value" : {
-                           "key" : "message",
-                           "fieldSchemaKey" : {
-                              "name" : "message_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : true
-                        }
-                     }, {
-                        "key" : "notes",
-                        "value" : {
-                           "key" : "notes",
-                           "fieldSchemaKey" : {
-                              "name" : "notes_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : true
-                        }
-                     }, {
-                        "key" : "quantity",
-                        "value" : {
-                           "key" : "quantity",
-                           "fieldSchemaKey" : {
-                              "name" : "quantity_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "sale_ID",
-                        "value" : {
-                           "key" : "sale_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "sale_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "time",
-                        "value" : {
-                           "key" : "time",
-                           "fieldSchemaKey" : {
-                              "name" : "timestamp_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     } ]
-                  },
-                  "taskParameters" : {
-                     "entry" : [ ]
-                  },
-                  "contextAlbumReference" : [ ],
-                  "taskLogic" : {
-                     "key" : "TaskLogic",
-                     "logicFlavour" : "MVEL",
-                     "logic" : "/*\n * ============LICENSE_START=======================================================\n *  Copyright (C) 2016-2018 Ericsson. All rights reserved.\n *  Modifications Copyright (C) 2019 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\nimport java.util.Date;\nimport java.util.Calendar;\nimport java.util.TimeZone;\nimport java.text.SimpleDateFormat;\n\nlogger.info(\"Task Execution: '\"+subject.id+\"'. Input Fields: '\"+inFields+\"'\");\n\noutFields.put(\"amount\"      , inFields.get(\"amount\"));\noutFields.put(\"assistant_ID\", inFields.get(\"assistant_ID\"));\noutFields.put(\"notes\"       , inFields.get(\"notes\"));\noutFields.put(\"quantity\"    , inFields.get(\"quantity\"));\noutFields.put(\"branch_ID\"   , inFields.get(\"branch_ID\"));\noutFields.put(\"item_ID\"     , inFields.get(\"item_ID\"));\noutFields.put(\"time\"        , inFields.get(\"time\"));\noutFields.put(\"sale_ID\"     , inFields.get(\"sale_ID\"));\n\nitem_id = inFields.get(\"item_ID\");\n\n//The events used later to test this task use GMT timezone!\ngmt = TimeZone.getTimeZone(\"GMT\");\ntimenow = Calendar.getInstance(gmt);\ndf = new SimpleDateFormat(\"HH:mm:ss z\");\ndf.setTimeZone(gmt);\ntimenow.setTimeInMillis(inFields.get(\"time\"));\n\nmidnight = timenow.clone();\nmidnight.set(\n    timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),\n    timenow.get(Calendar.DATE),0,0,0);\neleven30 = timenow.clone();\neleven30.set(\n    timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),\n    timenow.get(Calendar.DATE),11,30,0);\n\nitemisalcohol = false;\nif(item_id != null && item_id >=1000 && item_id < 2000)\n    itemisalcohol = true;\n\nif( itemisalcohol\n    && timenow.after(midnight) && timenow.before(eleven30)){\n  outFields.put(\"authorised\", false);\n  outFields.put(\"message\", \"Sale not authorised by policy task \"+subject.taskName+\n    \" for time \"+df.format(timenow.getTime())+\n    \". Alcohol can not be sold between \"+df.format(midnight.getTime())+\n    \" and \"+df.format(eleven30.getTime()));\n  return true;\n}\nelse{\n  outFields.put(\"authorised\", true);\n  outFields.put(\"message\", \"Sale authorised by policy task \"+subject.taskName+\n    \" for time \"+df.format(timenow.getTime()));\n  return true;\n}\n\n/*\nThis task checks if a sale request is for an item that is an alcoholic drink.\nIf the local time is between 00:00:00 GMT and 11:30:00 GMT then the sale is not\nauthorised. Otherwise the sale is authorised.\nIn this implementation we assume that items with item_ID value between 1000 and\n2000 are all alcoholic drinks :-)\n*/"
+      "taskMap": {
+        "entry": [
+          {
+            "key": {
+              "name": "MorningBoozeCheck",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "MorningBoozeCheck",
+                "version": "0.0.1"
+              },
+              "inputEvent": {
+                "key": {
+                  "name": "SALE_INPUT",
+                  "version": "0.0.1"
+                },
+                "nameSpace": "com.hyperm",
+                "source": "POS",
+                "target": "APEX",
+                "parameter": {
+                  "entry": [
+                    {
+                      "key": "amount",
+                      "value": {
+                        "key": "amount",
+                        "fieldSchemaKey": {
+                          "name": "price_type",
+                          "version": "0.0.1"
+                        },
+                        "optional": false
+                      }
+                    },
+                    {
+                      "key": "assistant_ID",
+                      "value": {
+                        "key": "assistant_ID",
+                        "fieldSchemaKey": {
+                          "name": "assistant_ID_type",
+                          "version": "0.0.1"
+                        },
+                        "optional": false
+                      }
+                    },
+                    {
+                      "key": "branch_ID",
+                      "value": {
+                        "key": "branch_ID",
+                        "fieldSchemaKey": {
+                          "name": "branch_ID_type",
+                          "version": "0.0.1"
+                        },
+                        "optional": false
+                      }
+                    },
+                    {
+                      "key": "item_ID",
+                      "value": {
+                        "key": "item_ID",
+                        "fieldSchemaKey": {
+                          "name": "item_ID_type",
+                          "version": "0.0.1"
+                        },
+                        "optional": false
+                      }
+                    },
+                    {
+                      "key": "notes",
+                      "value": {
+                        "key": "notes",
+                        "fieldSchemaKey": {
+                          "name": "notes_type",
+                          "version": "0.0.1"
+                        },
+                        "optional": true
+                      }
+                    },
+                    {
+                      "key": "quantity",
+                      "value": {
+                        "key": "quantity",
+                        "fieldSchemaKey": {
+                          "name": "quantity_type",
+                          "version": "0.0.1"
+                        },
+                        "optional": false
+                      }
+                    },
+                    {
+                      "key": "sale_ID",
+                      "value": {
+                        "key": "sale_ID",
+                        "fieldSchemaKey": {
+                          "name": "sale_ID_type",
+                          "version": "0.0.1"
+                        },
+                        "optional": false
+                      }
+                    },
+                    {
+                      "key": "time",
+                      "value": {
+                        "key": "time",
+                        "fieldSchemaKey": {
+                          "name": "timestamp_type",
+                          "version": "0.0.1"
+                        },
+                        "optional": false
+                      }
+                    }
+                  ]
+                }
+              },
+              "outputEvents": {
+                "entry": [
+                  {
+                    "key": "SALE_AUTH",
+                    "value": {
+                      "key": {
+                        "name": "SALE_AUTH",
+                        "version": "0.0.1"
+                      },
+                      "nameSpace": "com.hyperm",
+                      "source": "APEX",
+                      "target": "POS",
+                      "parameter": {
+                        "entry": [
+                          {
+                            "key": "amount",
+                            "value": {
+                              "key": "amount",
+                              "fieldSchemaKey": {
+                                "name": "price_type",
+                                "version": "0.0.1"
+                              },
+                              "optional": false
+                            }
+                          },
+                          {
+                            "key": "assistant_ID",
+                            "value": {
+                              "key": "assistant_ID",
+                              "fieldSchemaKey": {
+                                "name": "assistant_ID_type",
+                                "version": "0.0.1"
+                              },
+                              "optional": false
+                            }
+                          },
+                          {
+                            "key": "authorised",
+                            "value": {
+                              "key": "authorised",
+                              "fieldSchemaKey": {
+                                "name": "authorised_type",
+                                "version": "0.0.1"
+                              },
+                              "optional": false
+                            }
+                          },
+                          {
+                            "key": "branch_ID",
+                            "value": {
+                              "key": "branch_ID",
+                              "fieldSchemaKey": {
+                                "name": "branch_ID_type",
+                                "version": "0.0.1"
+                              },
+                              "optional": false
+                            }
+                          },
+                          {
+                            "key": "item_ID",
+                            "value": {
+                              "key": "item_ID",
+                              "fieldSchemaKey": {
+                                "name": "item_ID_type",
+                                "version": "0.0.1"
+                              },
+                              "optional": false
+                            }
+                          },
+                          {
+                            "key": "message",
+                            "value": {
+                              "key": "message",
+                              "fieldSchemaKey": {
+                                "name": "message_type",
+                                "version": "0.0.1"
+                              },
+                              "optional": true
+                            }
+                          },
+                          {
+                            "key": "notes",
+                            "value": {
+                              "key": "notes",
+                              "fieldSchemaKey": {
+                                "name": "notes_type",
+                                "version": "0.0.1"
+                              },
+                              "optional": true
+                            }
+                          },
+                          {
+                            "key": "quantity",
+                            "value": {
+                              "key": "quantity",
+                              "fieldSchemaKey": {
+                                "name": "quantity_type",
+                                "version": "0.0.1"
+                              },
+                              "optional": false
+                            }
+                          },
+                          {
+                            "key": "sale_ID",
+                            "value": {
+                              "key": "sale_ID",
+                              "fieldSchemaKey": {
+                                "name": "sale_ID_type",
+                                "version": "0.0.1"
+                              },
+                              "optional": false
+                            }
+                          },
+                          {
+                            "key": "time",
+                            "value": {
+                              "key": "time",
+                              "fieldSchemaKey": {
+                                "name": "timestamp_type",
+                                "version": "0.0.1"
+                              },
+                              "optional": false
+                            }
+                          }
+                        ]
+                      }
+                    }
+                  }
+                ]
+              },
+              "inputFields": {
+                "entry": [
+                  {
+                    "key": "amount",
+                    "value": {
+                      "key": "amount",
+                      "fieldSchemaKey": {
+                        "name": "price_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "assistant_ID",
+                    "value": {
+                      "key": "assistant_ID",
+                      "fieldSchemaKey": {
+                        "name": "assistant_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "branch_ID",
+                    "value": {
+                      "key": "branch_ID",
+                      "fieldSchemaKey": {
+                        "name": "branch_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "item_ID",
+                    "value": {
+                      "key": "item_ID",
+                      "fieldSchemaKey": {
+                        "name": "item_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "notes",
+                    "value": {
+                      "key": "notes",
+                      "fieldSchemaKey": {
+                        "name": "notes_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": true
+                    }
+                  },
+                  {
+                    "key": "quantity",
+                    "value": {
+                      "key": "quantity",
+                      "fieldSchemaKey": {
+                        "name": "quantity_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "sale_ID",
+                    "value": {
+                      "key": "sale_ID",
+                      "fieldSchemaKey": {
+                        "name": "sale_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "time",
+                    "value": {
+                      "key": "time",
+                      "fieldSchemaKey": {
+                        "name": "timestamp_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
                   }
-               }
-            } ]
-         }
+                ]
+              },
+              "outputFields": {
+                "entry": [
+                  {
+                    "key": "amount",
+                    "value": {
+                      "key": "amount",
+                      "fieldSchemaKey": {
+                        "name": "price_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "assistant_ID",
+                    "value": {
+                      "key": "assistant_ID",
+                      "fieldSchemaKey": {
+                        "name": "assistant_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "authorised",
+                    "value": {
+                      "key": "authorised",
+                      "fieldSchemaKey": {
+                        "name": "authorised_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "branch_ID",
+                    "value": {
+                      "key": "branch_ID",
+                      "fieldSchemaKey": {
+                        "name": "branch_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "item_ID",
+                    "value": {
+                      "key": "item_ID",
+                      "fieldSchemaKey": {
+                        "name": "item_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "message",
+                    "value": {
+                      "key": "message",
+                      "fieldSchemaKey": {
+                        "name": "message_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": true
+                    }
+                  },
+                  {
+                    "key": "notes",
+                    "value": {
+                      "key": "notes",
+                      "fieldSchemaKey": {
+                        "name": "notes_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": true
+                    }
+                  },
+                  {
+                    "key": "quantity",
+                    "value": {
+                      "key": "quantity",
+                      "fieldSchemaKey": {
+                        "name": "quantity_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "sale_ID",
+                    "value": {
+                      "key": "sale_ID",
+                      "fieldSchemaKey": {
+                        "name": "sale_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "time",
+                    "value": {
+                      "key": "time",
+                      "fieldSchemaKey": {
+                        "name": "timestamp_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  }
+                ]
+              },
+              "taskParameters": {
+                "entry": []
+              },
+              "contextAlbumReference": [],
+              "taskLogic": {
+                "key": "TaskLogic",
+                "logicFlavour": "MVEL",
+                "logic": "/*\n * ============LICENSE_START=======================================================\n *  Copyright (C) 2016-2018 Ericsson. All rights reserved.\n *  Modifications Copyright (C) 2019 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\nimport java.util.Date;\nimport java.util.Calendar;\nimport java.util.TimeZone;\nimport java.text.SimpleDateFormat;\n\nlogger.info(\"Task Execution: '\"+subject.id+\"'. Input Fields: '\"+inFields+\"'\");\n\noutFields.put(\"amount\"      , inFields.get(\"amount\"));\noutFields.put(\"assistant_ID\", inFields.get(\"assistant_ID\"));\noutFields.put(\"notes\"       , inFields.get(\"notes\"));\noutFields.put(\"quantity\"    , inFields.get(\"quantity\"));\noutFields.put(\"branch_ID\"   , inFields.get(\"branch_ID\"));\noutFields.put(\"item_ID\"     , inFields.get(\"item_ID\"));\noutFields.put(\"time\"        , inFields.get(\"time\"));\noutFields.put(\"sale_ID\"     , inFields.get(\"sale_ID\"));\n\nitem_id = inFields.get(\"item_ID\");\n\n//The events used later to test this task use GMT timezone!\ngmt = TimeZone.getTimeZone(\"GMT\");\ntimenow = Calendar.getInstance(gmt);\ndf = new SimpleDateFormat(\"HH:mm:ss z\");\ndf.setTimeZone(gmt);\ntimenow.setTimeInMillis(inFields.get(\"time\"));\n\nmidnight = timenow.clone();\nmidnight.set(\n    timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),\n    timenow.get(Calendar.DATE),0,0,0);\neleven30 = timenow.clone();\neleven30.set(\n    timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),\n    timenow.get(Calendar.DATE),11,30,0);\n\nitemisalcohol = false;\nif(item_id != null && item_id >=1000 && item_id < 2000)\n    itemisalcohol = true;\n\nif( itemisalcohol\n    && timenow.after(midnight) && timenow.before(eleven30)){\n  outFields.put(\"authorised\", false);\n  outFields.put(\"message\", \"Sale not authorised by policy task \"+subject.taskName+\n    \" for time \"+df.format(timenow.getTime())+\n    \". Alcohol can not be sold between \"+df.format(midnight.getTime())+\n    \" and \"+df.format(eleven30.getTime()));\n  return true;\n}\nelse{\n  outFields.put(\"authorised\", true);\n  outFields.put(\"message\", \"Sale authorised by policy task \"+subject.taskName+\n    \" for time \"+df.format(timenow.getTime()));\n  return true;\n}\n\n/*\nThis task checks if a sale request is for an item that is an alcoholic drink.\nIf the local time is between 00:00:00 GMT and 11:30:00 GMT then the sale is not\nauthorised. Otherwise the sale is authorised.\nIn this implementation we assume that items with item_ID value between 1000 and\n2000 are all alcoholic drinks :-)\n*/"
+              }
+            }
+          }
+        ]
+      }
+    },
+    "events": {
+      "key": {
+        "name": "MyFirstPolicyModel_Events",
+        "version": "0.0.1"
       },
-      "events" : {
-         "key" : {
-            "name" : "MyFirstPolicyModel_Events",
-            "version" : "0.0.1"
-         },
-         "eventMap" : {
-            "entry" : [ {
-               "key" : {
-                  "name" : "SALE_AUTH",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "SALE_AUTH",
-                     "version" : "0.0.1"
-                  },
-                  "nameSpace" : "com.hyperm",
-                  "source" : "APEX",
-                  "target" : "POS",
-                  "parameter" : {
-                     "entry" : [ {
-                        "key" : "amount",
-                        "value" : {
-                           "key" : "amount",
-                           "fieldSchemaKey" : {
-                              "name" : "price_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "assistant_ID",
-                        "value" : {
-                           "key" : "assistant_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "assistant_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "authorised",
-                        "value" : {
-                           "key" : "authorised",
-                           "fieldSchemaKey" : {
-                              "name" : "authorised_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "branch_ID",
-                        "value" : {
-                           "key" : "branch_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "branch_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "item_ID",
-                        "value" : {
-                           "key" : "item_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "item_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "message",
-                        "value" : {
-                           "key" : "message",
-                           "fieldSchemaKey" : {
-                              "name" : "message_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : true
-                        }
-                     }, {
-                        "key" : "notes",
-                        "value" : {
-                           "key" : "notes",
-                           "fieldSchemaKey" : {
-                              "name" : "notes_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : true
-                        }
-                     }, {
-                        "key" : "quantity",
-                        "value" : {
-                           "key" : "quantity",
-                           "fieldSchemaKey" : {
-                              "name" : "quantity_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "sale_ID",
-                        "value" : {
-                           "key" : "sale_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "sale_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "time",
-                        "value" : {
-                           "key" : "time",
-                           "fieldSchemaKey" : {
-                              "name" : "timestamp_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     } ]
+      "eventMap": {
+        "entry": [
+          {
+            "key": {
+              "name": "SALE_AUTH",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "SALE_AUTH",
+                "version": "0.0.1"
+              },
+              "nameSpace": "com.hyperm",
+              "source": "APEX",
+              "target": "POS",
+              "parameter": {
+                "entry": [
+                  {
+                    "key": "amount",
+                    "value": {
+                      "key": "amount",
+                      "fieldSchemaKey": {
+                        "name": "price_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "assistant_ID",
+                    "value": {
+                      "key": "assistant_ID",
+                      "fieldSchemaKey": {
+                        "name": "assistant_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "authorised",
+                    "value": {
+                      "key": "authorised",
+                      "fieldSchemaKey": {
+                        "name": "authorised_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "branch_ID",
+                    "value": {
+                      "key": "branch_ID",
+                      "fieldSchemaKey": {
+                        "name": "branch_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "item_ID",
+                    "value": {
+                      "key": "item_ID",
+                      "fieldSchemaKey": {
+                        "name": "item_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "message",
+                    "value": {
+                      "key": "message",
+                      "fieldSchemaKey": {
+                        "name": "message_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": true
+                    }
+                  },
+                  {
+                    "key": "notes",
+                    "value": {
+                      "key": "notes",
+                      "fieldSchemaKey": {
+                        "name": "notes_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": true
+                    }
+                  },
+                  {
+                    "key": "quantity",
+                    "value": {
+                      "key": "quantity",
+                      "fieldSchemaKey": {
+                        "name": "quantity_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "sale_ID",
+                    "value": {
+                      "key": "sale_ID",
+                      "fieldSchemaKey": {
+                        "name": "sale_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "time",
+                    "value": {
+                      "key": "time",
+                      "fieldSchemaKey": {
+                        "name": "timestamp_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
                   }
-               }
-            }, {
-               "key" : {
-                  "name" : "SALE_INPUT",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "SALE_INPUT",
-                     "version" : "0.0.1"
-                  },
-                  "nameSpace" : "com.hyperm",
-                  "source" : "POS",
-                  "target" : "APEX",
-                  "parameter" : {
-                     "entry" : [ {
-                        "key" : "amount",
-                        "value" : {
-                           "key" : "amount",
-                           "fieldSchemaKey" : {
-                              "name" : "price_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "assistant_ID",
-                        "value" : {
-                           "key" : "assistant_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "assistant_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "branch_ID",
-                        "value" : {
-                           "key" : "branch_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "branch_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "item_ID",
-                        "value" : {
-                           "key" : "item_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "item_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "notes",
-                        "value" : {
-                           "key" : "notes",
-                           "fieldSchemaKey" : {
-                              "name" : "notes_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : true
-                        }
-                     }, {
-                        "key" : "quantity",
-                        "value" : {
-                           "key" : "quantity",
-                           "fieldSchemaKey" : {
-                              "name" : "quantity_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "sale_ID",
-                        "value" : {
-                           "key" : "sale_ID",
-                           "fieldSchemaKey" : {
-                              "name" : "sale_ID_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     }, {
-                        "key" : "time",
-                        "value" : {
-                           "key" : "time",
-                           "fieldSchemaKey" : {
-                              "name" : "timestamp_type",
-                              "version" : "0.0.1"
-                           },
-                           "optional" : false
-                        }
-                     } ]
+                ]
+              }
+            }
+          },
+          {
+            "key": {
+              "name": "SALE_INPUT",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "SALE_INPUT",
+                "version": "0.0.1"
+              },
+              "nameSpace": "com.hyperm",
+              "source": "POS",
+              "target": "APEX",
+              "parameter": {
+                "entry": [
+                  {
+                    "key": "amount",
+                    "value": {
+                      "key": "amount",
+                      "fieldSchemaKey": {
+                        "name": "price_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "assistant_ID",
+                    "value": {
+                      "key": "assistant_ID",
+                      "fieldSchemaKey": {
+                        "name": "assistant_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "branch_ID",
+                    "value": {
+                      "key": "branch_ID",
+                      "fieldSchemaKey": {
+                        "name": "branch_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "item_ID",
+                    "value": {
+                      "key": "item_ID",
+                      "fieldSchemaKey": {
+                        "name": "item_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "notes",
+                    "value": {
+                      "key": "notes",
+                      "fieldSchemaKey": {
+                        "name": "notes_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": true
+                    }
+                  },
+                  {
+                    "key": "quantity",
+                    "value": {
+                      "key": "quantity",
+                      "fieldSchemaKey": {
+                        "name": "quantity_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "sale_ID",
+                    "value": {
+                      "key": "sale_ID",
+                      "fieldSchemaKey": {
+                        "name": "sale_ID_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
+                  },
+                  {
+                    "key": "time",
+                    "value": {
+                      "key": "time",
+                      "fieldSchemaKey": {
+                        "name": "timestamp_type",
+                        "version": "0.0.1"
+                      },
+                      "optional": false
+                    }
                   }
-               }
-            } ]
-         }
+                ]
+              }
+            }
+          }
+        ]
+      }
+    },
+    "schemas": {
+      "key": {
+        "name": "MyFirstPolicyModel_Schemas",
+        "version": "0.0.1"
       },
-      "schemas" : {
-         "key" : {
-            "name" : "MyFirstPolicyModel_Schemas",
-            "version" : "0.0.1"
-         },
-         "schemas" : {
-            "entry" : [ {
-               "key" : {
-                  "name" : "assistant_ID_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "assistant_ID_type",
-                     "version" : "0.0.1"
-                  },
-                  "schemaFlavour" : "Java",
-                  "schemaDefinition" : "java.lang.Long"
-               }
-            }, {
-               "key" : {
-                  "name" : "authorised_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "authorised_type",
-                     "version" : "0.0.1"
-                  },
-                  "schemaFlavour" : "Java",
-                  "schemaDefinition" : "java.lang.Boolean"
-               }
-            }, {
-               "key" : {
-                  "name" : "branch_ID_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "branch_ID_type",
-                     "version" : "0.0.1"
-                  },
-                  "schemaFlavour" : "Java",
-                  "schemaDefinition" : "java.lang.Long"
-               }
-            }, {
-               "key" : {
-                  "name" : "item_ID_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "item_ID_type",
-                     "version" : "0.0.1"
-                  },
-                  "schemaFlavour" : "Java",
-                  "schemaDefinition" : "java.lang.Long"
-               }
-            }, {
-               "key" : {
-                  "name" : "message_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "message_type",
-                     "version" : "0.0.1"
-                  },
-                  "schemaFlavour" : "Java",
-                  "schemaDefinition" : "java.lang.String"
-               }
-            }, {
-               "key" : {
-                  "name" : "notes_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "notes_type",
-                     "version" : "0.0.1"
-                  },
-                  "schemaFlavour" : "Java",
-                  "schemaDefinition" : "java.lang.String"
-               }
-            }, {
-               "key" : {
-                  "name" : "price_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "price_type",
-                     "version" : "0.0.1"
-                  },
-                  "schemaFlavour" : "Java",
-                  "schemaDefinition" : "java.lang.Long"
-               }
-            }, {
-               "key" : {
-                  "name" : "quantity_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "quantity_type",
-                     "version" : "0.0.1"
-                  },
-                  "schemaFlavour" : "Java",
-                  "schemaDefinition" : "java.lang.Integer"
-               }
-            }, {
-               "key" : {
-                  "name" : "sale_ID_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "sale_ID_type",
-                     "version" : "0.0.1"
-                  },
-                  "schemaFlavour" : "Java",
-                  "schemaDefinition" : "java.lang.Long"
-               }
-            }, {
-               "key" : {
-                  "name" : "timestamp_type",
-                  "version" : "0.0.1"
-               },
-               "value" : {
-                  "key" : {
-                     "name" : "timestamp_type",
-                     "version" : "0.0.1"
-                  },
-                  "schemaFlavour" : "Java",
-                  "schemaDefinition" : "java.lang.Long"
-               }
-            } ]
-         }
+      "schemas": {
+        "entry": [
+          {
+            "key": {
+              "name": "assistant_ID_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "assistant_ID_type",
+                "version": "0.0.1"
+              },
+              "schemaFlavour": "Java",
+              "schemaDefinition": "java.lang.Long"
+            }
+          },
+          {
+            "key": {
+              "name": "authorised_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "authorised_type",
+                "version": "0.0.1"
+              },
+              "schemaFlavour": "Java",
+              "schemaDefinition": "java.lang.Boolean"
+            }
+          },
+          {
+            "key": {
+              "name": "branch_ID_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "branch_ID_type",
+                "version": "0.0.1"
+              },
+              "schemaFlavour": "Java",
+              "schemaDefinition": "java.lang.Long"
+            }
+          },
+          {
+            "key": {
+              "name": "item_ID_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "item_ID_type",
+                "version": "0.0.1"
+              },
+              "schemaFlavour": "Java",
+              "schemaDefinition": "java.lang.Long"
+            }
+          },
+          {
+            "key": {
+              "name": "message_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "message_type",
+                "version": "0.0.1"
+              },
+              "schemaFlavour": "Java",
+              "schemaDefinition": "java.lang.String"
+            }
+          },
+          {
+            "key": {
+              "name": "notes_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "notes_type",
+                "version": "0.0.1"
+              },
+              "schemaFlavour": "Java",
+              "schemaDefinition": "java.lang.String"
+            }
+          },
+          {
+            "key": {
+              "name": "price_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "price_type",
+                "version": "0.0.1"
+              },
+              "schemaFlavour": "Java",
+              "schemaDefinition": "java.lang.Long"
+            }
+          },
+          {
+            "key": {
+              "name": "quantity_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "quantity_type",
+                "version": "0.0.1"
+              },
+              "schemaFlavour": "Java",
+              "schemaDefinition": "java.lang.Integer"
+            }
+          },
+          {
+            "key": {
+              "name": "sale_ID_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "sale_ID_type",
+                "version": "0.0.1"
+              },
+              "schemaFlavour": "Java",
+              "schemaDefinition": "java.lang.Long"
+            }
+          },
+          {
+            "key": {
+              "name": "timestamp_type",
+              "version": "0.0.1"
+            },
+            "value": {
+              "key": {
+                "name": "timestamp_type",
+                "version": "0.0.1"
+              },
+              "schemaFlavour": "Java",
+              "schemaDefinition": "java.lang.Long"
+            }
+          }
+        ]
       }
-   }
+    }
+  }
 }
index ab2ae89..55bd95e 100644 (file)
@@ -1 +1 @@
-{"tosca_definitions_version":"tosca_simple_yaml_1_1_0","topology_template":{"policies":[{"native.sampledomain":{"type":"onap.policies.native.Apex","type_version":"1.0.0","name":"native.sampledomain","version":"1.0.0","properties":{"engineServiceParameters":{"name":"MyFirstPolicyApexEngine","version":"0.0.1","id":101,"instanceCount":4,"deploymentPort":12345,"engineParameters":{"executorParameters":{"MVEL":{"parameterClassName":"org.onap.policy.apex.plugins.executor.mvel.MvelExecutorParameters"},"JAVASCRIPT":{"parameterClassName":"org.onap.policy.apex.plugins.executor.javascript.JavascriptExecutorParameters"}}},"policy_type_impl":{"apexPolicyModel":{"key":{"name":"MyFirstPolicyModel","version":"0.0.1"},"keyInformation":{"key":{"name":"MyFirstPolicyModel_KeyInfo","version":"0.0.1"},"keyInfoMap":{"entry":[{"key":{"name":"MorningBoozeCheck","version":"0.0.1"},"value":{"key":{"name":"MorningBoozeCheck","version":"0.0.1"},"UUID":"3351b0f4-cf06-4fa2-8823-edf67bd30223","description":"This task checks if the sales request is for an item that contains alcohol. \nIf the local time is between 00:00:00 and 11:30:00 then the sale is not authorised. Otherwise the sale is authorised. \nIn this implementation we assume that all items with item_ID values between 1000 and 2000 contain alcohol :-)"}},{"key":{"name":"MyFirstPolicy","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicy","version":"0.0.1"},"UUID":"6c5e410f-489a-46ff-964e-982ce6e8b6d0","description":"This is my first Apex policy. It checks if a sale should be authorised or not."}},{"key":{"name":"MyFirstPolicyModel","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicyModel","version":"0.0.1"},"UUID":"540226fb-55ee-4f0e-a444-983a0494818e","description":"This is my first Apex Policy Model."}},{"key":{"name":"MyFirstPolicyModel_Events","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicyModel_Events","version":"0.0.1"},"UUID":"ef281318-5ac9-3ef0-8db3-8f9c4e4a81e2","description":"Generated description for concept referred to by key \"MyFirstPolicyModel_Events:0.0.1\""}},{"key":{"name":"MyFirstPolicyModel_KeyInfo","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicyModel_KeyInfo","version":"0.0.1"},"UUID":"d9248c6f-7c00-38df-8251-611463ba4065","description":"Generated description for concept referred to by key \"MyFirstPolicyModel_KeyInfo:0.0.1\""}},{"key":{"name":"MyFirstPolicyModel_Policies","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicyModel_Policies","version":"0.0.1"},"UUID":"77c01a6b-510c-3aa9-b640-b4db356aa03b","description":"Generated description for concept referred to by key \"MyFirstPolicyModel_Policies:0.0.1\""}},{"key":{"name":"MyFirstPolicyModel_Schemas","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicyModel_Schemas","version":"0.0.1"},"UUID":"d0cc3aa0-ea69-3a43-80ff-a0dbb0ebd885","description":"Generated description for concept referred to by key \"MyFirstPolicyModel_Schemas:0.0.1\""}},{"key":{"name":"MyFirstPolicyModel_Tasks","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicyModel_Tasks","version":"0.0.1"},"UUID":"b02a7e02-2cd0-39e6-b3cb-946fa83a8f08","description":"Generated description for concept referred to by key \"MyFirstPolicyModel_Tasks:0.0.1\""}},{"key":{"name":"SALE_AUTH","version":"0.0.1"},"value":{"key":{"name":"SALE_AUTH","version":"0.0.1"},"UUID":"c4500941-3f98-4080-a9cc-5b9753ed050b","description":"An event emitted by the Policy to indicate whether the sale of an item has been authorised"}},{"key":{"name":"SALE_INPUT","version":"0.0.1"},"value":{"key":{"name":"SALE_INPUT","version":"0.0.1"},"UUID":"4f04aa98-e917-4f4a-882a-c75ba5a99374","description":"An event raised by the PoS system each time an item is scanned for purchase"}},{"key":{"name":"assistant_ID_type","version":"0.0.1"},"value":{"key":{"name":"assistant_ID_type","version":"0.0.1"},"UUID":"36df4c71-9616-4206-8b53-976a5cd4bd87","description":"A type for 'assistant_ID' values"}},{"key":{"name":"authorised_type","version":"0.0.1"},"value":{"key":{"name":"authorised_type","version":"0.0.1"},"UUID":"d48b619e-d00d-4008-b884-02d76ea4350b","description":"A type for 'authorised' values"}},{"key":{"name":"branch_ID_type","version":"0.0.1"},"value":{"key":{"name":"branch_ID_type","version":"0.0.1"},"UUID":"6468845f-4122-4128-8e49-0f52c26078b5","description":"A type for 'branch_ID' values"}},{"key":{"name":"item_ID_type","version":"0.0.1"},"value":{"key":{"name":"item_ID_type","version":"0.0.1"},"UUID":"4f227ff1-aee0-453a-b6b6-9a4b2e0da932","description":"A type for 'item_ID' values"}},{"key":{"name":"message_type","version":"0.0.1"},"value":{"key":{"name":"message_type","version":"0.0.1"},"UUID":"ad1431bb-3155-4e73-b5a3-b89bee498749","description":"A type for 'message' values"}},{"key":{"name":"notes_type","version":"0.0.1"},"value":{"key":{"name":"notes_type","version":"0.0.1"},"UUID":"eecfde90-896c-4343-8f9c-2603ced94e2d","description":"A type for 'notes' values"}},{"key":{"name":"price_type","version":"0.0.1"},"value":{"key":{"name":"price_type","version":"0.0.1"},"UUID":"52c2fc45-fd8c-463c-bd6f-d91b0554aea7","description":"A type for 'amount'/'price' values"}},{"key":{"name":"quantity_type","version":"0.0.1"},"value":{"key":{"name":"quantity_type","version":"0.0.1"},"UUID":"ac3d9842-80af-4a98-951c-bd79a431c613","description":"A type for 'quantity' values"}},{"key":{"name":"sale_ID_type","version":"0.0.1"},"value":{"key":{"name":"sale_ID_type","version":"0.0.1"},"UUID":"cca47d74-7754-4a61-b163-ca31f66b157b","description":"A type for 'sale_ID' values"}},{"key":{"name":"timestamp_type","version":"0.0.1"},"value":{"key":{"name":"timestamp_type","version":"0.0.1"},"UUID":"fd594e88-411d-4a94-b2be-697b3a0d7adf","description":"A type for 'time' values"}}]}},"policies":{"key":{"name":"MyFirstPolicyModel_Policies","version":"0.0.1"},"policyMap":{"entry":[{"key":{"name":"MyFirstPolicy","version":"0.0.1"},"value":{"policyKey":{"name":"MyFirstPolicy","version":"0.0.1"},"template":"FREEFORM","state":{"entry":[{"key":"BoozeAuthDecide","value":{"stateKey":{"parentKeyName":"MyFirstPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"BoozeAuthDecide"},"trigger":{"name":"SALE_INPUT","version":"0.0.1"},"stateOutputs":{"entry":[{"key":"MorningBoozeCheck_Output_Direct","value":{"key":{"parentKeyName":"MyFirstPolicy","parentKeyVersion":"0.0.1","parentLocalName":"BoozeAuthDecide","localName":"MorningBoozeCheck_Output_Direct"},"outgoingEvent":{"name":"SALE_AUTH","version":"0.0.1"},"nextState":{"parentKeyName":"NULL","parentKeyVersion":"0.0.0","parentLocalName":"NULL","localName":"NULL"}}}]},"contextAlbumReference":[],"taskSelectionLogic":{"key":"NULL","logicFlavour":"UNDEFINED","logic":""},"stateFinalizerLogicMap":{"entry":[]},"defaultTask":{"name":"MorningBoozeCheck","version":"0.0.1"},"taskReferences":{"entry":[{"key":{"name":"MorningBoozeCheck","version":"0.0.1"},"value":{"key":{"parentKeyName":"MyFirstPolicy","parentKeyVersion":"0.0.1","parentLocalName":"BoozeAuthDecide","localName":"MorningBoozeCheck"},"outputType":"DIRECT","output":{"parentKeyName":"MyFirstPolicy","parentKeyVersion":"0.0.1","parentLocalName":"BoozeAuthDecide","localName":"MorningBoozeCheck_Output_Direct"}}}]}}}]},"firstState":"BoozeAuthDecide"}}]}},"tasks":{"key":{"name":"MyFirstPolicyModel_Tasks","version":"0.0.1"},"taskMap":{"entry":[{"key":{"name":"MorningBoozeCheck","version":"0.0.1"},"value":{"key":{"name":"MorningBoozeCheck","version":"0.0.1"},"inputFields":{"entry":[{"key":"amount","value":{"key":"amount","fieldSchemaKey":{"name":"price_type","version":"0.0.1"},"optional":false}},{"key":"assistant_ID","value":{"key":"assistant_ID","fieldSchemaKey":{"name":"assistant_ID_type","version":"0.0.1"},"optional":false}},{"key":"branch_ID","value":{"key":"branch_ID","fieldSchemaKey":{"name":"branch_ID_type","version":"0.0.1"},"optional":false}},{"key":"item_ID","value":{"key":"item_ID","fieldSchemaKey":{"name":"item_ID_type","version":"0.0.1"},"optional":false}},{"key":"notes","value":{"key":"notes","fieldSchemaKey":{"name":"notes_type","version":"0.0.1"},"optional":true}},{"key":"quantity","value":{"key":"quantity","fieldSchemaKey":{"name":"quantity_type","version":"0.0.1"},"optional":false}},{"key":"sale_ID","value":{"key":"sale_ID","fieldSchemaKey":{"name":"sale_ID_type","version":"0.0.1"},"optional":false}},{"key":"time","value":{"key":"time","fieldSchemaKey":{"name":"timestamp_type","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"amount","value":{"key":"amount","fieldSchemaKey":{"name":"price_type","version":"0.0.1"},"optional":false}},{"key":"assistant_ID","value":{"key":"assistant_ID","fieldSchemaKey":{"name":"assistant_ID_type","version":"0.0.1"},"optional":false}},{"key":"authorised","value":{"key":"authorised","fieldSchemaKey":{"name":"authorised_type","version":"0.0.1"},"optional":false}},{"key":"branch_ID","value":{"key":"branch_ID","fieldSchemaKey":{"name":"branch_ID_type","version":"0.0.1"},"optional":false}},{"key":"item_ID","value":{"key":"item_ID","fieldSchemaKey":{"name":"item_ID_type","version":"0.0.1"},"optional":false}},{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"message_type","version":"0.0.1"},"optional":true}},{"key":"notes","value":{"key":"notes","fieldSchemaKey":{"name":"notes_type","version":"0.0.1"},"optional":true}},{"key":"quantity","value":{"key":"quantity","fieldSchemaKey":{"name":"quantity_type","version":"0.0.1"},"optional":false}},{"key":"sale_ID","value":{"key":"sale_ID","fieldSchemaKey":{"name":"sale_ID_type","version":"0.0.1"},"optional":false}},{"key":"time","value":{"key":"time","fieldSchemaKey":{"name":"timestamp_type","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"MVEL","logic":"/*\n * ============LICENSE_START=======================================================\n *  Copyright (C) 2016-2018 Ericsson. All rights reserved.\n *  Modifications Copyright (C) 2019 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\nimport java.util.Date;\nimport java.util.Calendar;\nimport java.util.TimeZone;\nimport java.text.SimpleDateFormat;\n\nlogger.info(\"Task Execution: '\"+subject.id+\"'. Input Fields: '\"+inFields+\"'\");\n\noutFields.put(\"amount\"      , inFields.get(\"amount\"));\noutFields.put(\"assistant_ID\", inFields.get(\"assistant_ID\"));\noutFields.put(\"notes\"       , inFields.get(\"notes\"));\noutFields.put(\"quantity\"    , inFields.get(\"quantity\"));\noutFields.put(\"branch_ID\"   , inFields.get(\"branch_ID\"));\noutFields.put(\"item_ID\"     , inFields.get(\"item_ID\"));\noutFields.put(\"time\"        , inFields.get(\"time\"));\noutFields.put(\"sale_ID\"     , inFields.get(\"sale_ID\"));\n\nitem_id = inFields.get(\"item_ID\");\n\n//The events used later to test this task use GMT timezone!\ngmt = TimeZone.getTimeZone(\"GMT\");\ntimenow = Calendar.getInstance(gmt);\ndf = new SimpleDateFormat(\"HH:mm:ss z\");\ndf.setTimeZone(gmt);\ntimenow.setTimeInMillis(inFields.get(\"time\"));\n\nmidnight = timenow.clone();\nmidnight.set(\n    timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),\n    timenow.get(Calendar.DATE),0,0,0);\neleven30 = timenow.clone();\neleven30.set(\n    timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),\n    timenow.get(Calendar.DATE),11,30,0);\n\nitemisalcohol = false;\nif(item_id != null && item_id >=1000 && item_id < 2000)\n    itemisalcohol = true;\n\nif( itemisalcohol\n    && timenow.after(midnight) && timenow.before(eleven30)){\n  outFields.put(\"authorised\", false);\n  outFields.put(\"message\", \"Sale not authorised by policy task \"+subject.taskName+\n    \" for time \"+df.format(timenow.getTime())+\n    \". Alcohol can not be sold between \"+df.format(midnight.getTime())+\n    \" and \"+df.format(eleven30.getTime()));\n  return true;\n}\nelse{\n  outFields.put(\"authorised\", true);\n  outFields.put(\"message\", \"Sale authorised by policy task \"+subject.taskName+\n    \" for time \"+df.format(timenow.getTime()));\n  return true;\n}\n\n/*\nThis task checks if a sale request is for an item that is an alcoholic drink.\nIf the local time is between 00:00:00 GMT and 11:30:00 GMT then the sale is not\nauthorised. Otherwise the sale is authorised.\nIn this implementation we assume that items with item_ID value between 1000 and\n2000 are all alcoholic drinks :-)\n*/"}}}]}},"events":{"key":{"name":"MyFirstPolicyModel_Events","version":"0.0.1"},"eventMap":{"entry":[{"key":{"name":"SALE_AUTH","version":"0.0.1"},"value":{"key":{"name":"SALE_AUTH","version":"0.0.1"},"nameSpace":"com.hyperm","source":"APEX","target":"POS","parameter":{"entry":[{"key":"amount","value":{"key":"amount","fieldSchemaKey":{"name":"price_type","version":"0.0.1"},"optional":false}},{"key":"assistant_ID","value":{"key":"assistant_ID","fieldSchemaKey":{"name":"assistant_ID_type","version":"0.0.1"},"optional":false}},{"key":"authorised","value":{"key":"authorised","fieldSchemaKey":{"name":"authorised_type","version":"0.0.1"},"optional":false}},{"key":"branch_ID","value":{"key":"branch_ID","fieldSchemaKey":{"name":"branch_ID_type","version":"0.0.1"},"optional":false}},{"key":"item_ID","value":{"key":"item_ID","fieldSchemaKey":{"name":"item_ID_type","version":"0.0.1"},"optional":false}},{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"message_type","version":"0.0.1"},"optional":true}},{"key":"notes","value":{"key":"notes","fieldSchemaKey":{"name":"notes_type","version":"0.0.1"},"optional":true}},{"key":"quantity","value":{"key":"quantity","fieldSchemaKey":{"name":"quantity_type","version":"0.0.1"},"optional":false}},{"key":"sale_ID","value":{"key":"sale_ID","fieldSchemaKey":{"name":"sale_ID_type","version":"0.0.1"},"optional":false}},{"key":"time","value":{"key":"time","fieldSchemaKey":{"name":"timestamp_type","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"SALE_INPUT","version":"0.0.1"},"value":{"key":{"name":"SALE_INPUT","version":"0.0.1"},"nameSpace":"com.hyperm","source":"POS","target":"APEX","parameter":{"entry":[{"key":"amount","value":{"key":"amount","fieldSchemaKey":{"name":"price_type","version":"0.0.1"},"optional":false}},{"key":"assistant_ID","value":{"key":"assistant_ID","fieldSchemaKey":{"name":"assistant_ID_type","version":"0.0.1"},"optional":false}},{"key":"branch_ID","value":{"key":"branch_ID","fieldSchemaKey":{"name":"branch_ID_type","version":"0.0.1"},"optional":false}},{"key":"item_ID","value":{"key":"item_ID","fieldSchemaKey":{"name":"item_ID_type","version":"0.0.1"},"optional":false}},{"key":"notes","value":{"key":"notes","fieldSchemaKey":{"name":"notes_type","version":"0.0.1"},"optional":true}},{"key":"quantity","value":{"key":"quantity","fieldSchemaKey":{"name":"quantity_type","version":"0.0.1"},"optional":false}},{"key":"sale_ID","value":{"key":"sale_ID","fieldSchemaKey":{"name":"sale_ID_type","version":"0.0.1"},"optional":false}},{"key":"time","value":{"key":"time","fieldSchemaKey":{"name":"timestamp_type","version":"0.0.1"},"optional":false}}]}}}]}},"schemas":{"key":{"name":"MyFirstPolicyModel_Schemas","version":"0.0.1"},"schemas":{"entry":[{"key":{"name":"assistant_ID_type","version":"0.0.1"},"value":{"key":{"name":"assistant_ID_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Long"}},{"key":{"name":"authorised_type","version":"0.0.1"},"value":{"key":{"name":"authorised_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Boolean"}},{"key":{"name":"branch_ID_type","version":"0.0.1"},"value":{"key":{"name":"branch_ID_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Long"}},{"key":{"name":"item_ID_type","version":"0.0.1"},"value":{"key":{"name":"item_ID_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Long"}},{"key":{"name":"message_type","version":"0.0.1"},"value":{"key":{"name":"message_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.String"}},{"key":{"name":"notes_type","version":"0.0.1"},"value":{"key":{"name":"notes_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.String"}},{"key":{"name":"price_type","version":"0.0.1"},"value":{"key":{"name":"price_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Long"}},{"key":{"name":"quantity_type","version":"0.0.1"},"value":{"key":{"name":"quantity_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Integer"}},{"key":{"name":"sale_ID_type","version":"0.0.1"},"value":{"key":{"name":"sale_ID_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Long"}},{"key":{"name":"timestamp_type","version":"0.0.1"},"value":{"key":{"name":"timestamp_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Long"}}]}}}}},"eventOutputParameters":{"FirstProducer":{"carrierTechnologyParameters":{"carrierTechnology":"FILE","parameters":{"standardIo":true}},"eventProtocolParameters":{"eventProtocol":"JSON"}}},"eventInputParameters":{"FirstConsumer":{"carrierTechnologyParameters":{"carrierTechnology":"FILE","parameters":{"standardIo":true}},"eventProtocolParameters":{"eventProtocol":"JSON"}}}}}}]}}
\ No newline at end of file
+{"tosca_definitions_version":"tosca_simple_yaml_1_1_0","topology_template":{"policies":[{"native.sampledomain":{"type":"onap.policies.native.Apex","type_version":"1.0.0","name":"native.sampledomain","version":"1.0.0","properties":{"engineServiceParameters":{"name":"MyFirstPolicyApexEngine","version":"0.0.1","id":101,"instanceCount":4,"deploymentPort":12345,"engineParameters":{"executorParameters":{"MVEL":{"parameterClassName":"org.onap.policy.apex.plugins.executor.mvel.MvelExecutorParameters"},"JAVASCRIPT":{"parameterClassName":"org.onap.policy.apex.plugins.executor.javascript.JavascriptExecutorParameters"}}},"policy_type_impl":{"apexPolicyModel":{"key":{"name":"MyFirstPolicyModel","version":"0.0.1"},"keyInformation":{"key":{"name":"MyFirstPolicyModel_KeyInfo","version":"0.0.1"},"keyInfoMap":{"entry":[{"key":{"name":"MorningBoozeCheck","version":"0.0.1"},"value":{"key":{"name":"MorningBoozeCheck","version":"0.0.1"},"UUID":"3351b0f4-cf06-4fa2-8823-edf67bd30223","description":"This task checks if the sales request is for an item that contains alcohol. \nIf the local time is between 00:00:00 and 11:30:00 then the sale is not authorised. Otherwise the sale is authorised. \nIn this implementation we assume that all items with item_ID values between 1000 and 2000 contain alcohol :-)"}},{"key":{"name":"MyFirstPolicy","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicy","version":"0.0.1"},"UUID":"6c5e410f-489a-46ff-964e-982ce6e8b6d0","description":"This is my first Apex policy. It checks if a sale should be authorised or not."}},{"key":{"name":"MyFirstPolicyModel","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicyModel","version":"0.0.1"},"UUID":"540226fb-55ee-4f0e-a444-983a0494818e","description":"This is my first Apex Policy Model."}},{"key":{"name":"MyFirstPolicyModel_Events","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicyModel_Events","version":"0.0.1"},"UUID":"ef281318-5ac9-3ef0-8db3-8f9c4e4a81e2","description":"Generated description for concept referred to by key \"MyFirstPolicyModel_Events:0.0.1\""}},{"key":{"name":"MyFirstPolicyModel_KeyInfo","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicyModel_KeyInfo","version":"0.0.1"},"UUID":"d9248c6f-7c00-38df-8251-611463ba4065","description":"Generated description for concept referred to by key \"MyFirstPolicyModel_KeyInfo:0.0.1\""}},{"key":{"name":"MyFirstPolicyModel_Policies","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicyModel_Policies","version":"0.0.1"},"UUID":"77c01a6b-510c-3aa9-b640-b4db356aa03b","description":"Generated description for concept referred to by key \"MyFirstPolicyModel_Policies:0.0.1\""}},{"key":{"name":"MyFirstPolicyModel_Schemas","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicyModel_Schemas","version":"0.0.1"},"UUID":"d0cc3aa0-ea69-3a43-80ff-a0dbb0ebd885","description":"Generated description for concept referred to by key \"MyFirstPolicyModel_Schemas:0.0.1\""}},{"key":{"name":"MyFirstPolicyModel_Tasks","version":"0.0.1"},"value":{"key":{"name":"MyFirstPolicyModel_Tasks","version":"0.0.1"},"UUID":"b02a7e02-2cd0-39e6-b3cb-946fa83a8f08","description":"Generated description for concept referred to by key \"MyFirstPolicyModel_Tasks:0.0.1\""}},{"key":{"name":"SALE_AUTH","version":"0.0.1"},"value":{"key":{"name":"SALE_AUTH","version":"0.0.1"},"UUID":"c4500941-3f98-4080-a9cc-5b9753ed050b","description":"An event emitted by the Policy to indicate whether the sale of an item has been authorised"}},{"key":{"name":"SALE_INPUT","version":"0.0.1"},"value":{"key":{"name":"SALE_INPUT","version":"0.0.1"},"UUID":"4f04aa98-e917-4f4a-882a-c75ba5a99374","description":"An event raised by the PoS system each time an item is scanned for purchase"}},{"key":{"name":"assistant_ID_type","version":"0.0.1"},"value":{"key":{"name":"assistant_ID_type","version":"0.0.1"},"UUID":"36df4c71-9616-4206-8b53-976a5cd4bd87","description":"A type for 'assistant_ID' values"}},{"key":{"name":"authorised_type","version":"0.0.1"},"value":{"key":{"name":"authorised_type","version":"0.0.1"},"UUID":"d48b619e-d00d-4008-b884-02d76ea4350b","description":"A type for 'authorised' values"}},{"key":{"name":"branch_ID_type","version":"0.0.1"},"value":{"key":{"name":"branch_ID_type","version":"0.0.1"},"UUID":"6468845f-4122-4128-8e49-0f52c26078b5","description":"A type for 'branch_ID' values"}},{"key":{"name":"item_ID_type","version":"0.0.1"},"value":{"key":{"name":"item_ID_type","version":"0.0.1"},"UUID":"4f227ff1-aee0-453a-b6b6-9a4b2e0da932","description":"A type for 'item_ID' values"}},{"key":{"name":"message_type","version":"0.0.1"},"value":{"key":{"name":"message_type","version":"0.0.1"},"UUID":"ad1431bb-3155-4e73-b5a3-b89bee498749","description":"A type for 'message' values"}},{"key":{"name":"notes_type","version":"0.0.1"},"value":{"key":{"name":"notes_type","version":"0.0.1"},"UUID":"eecfde90-896c-4343-8f9c-2603ced94e2d","description":"A type for 'notes' values"}},{"key":{"name":"price_type","version":"0.0.1"},"value":{"key":{"name":"price_type","version":"0.0.1"},"UUID":"52c2fc45-fd8c-463c-bd6f-d91b0554aea7","description":"A type for 'amount'/'price' values"}},{"key":{"name":"quantity_type","version":"0.0.1"},"value":{"key":{"name":"quantity_type","version":"0.0.1"},"UUID":"ac3d9842-80af-4a98-951c-bd79a431c613","description":"A type for 'quantity' values"}},{"key":{"name":"sale_ID_type","version":"0.0.1"},"value":{"key":{"name":"sale_ID_type","version":"0.0.1"},"UUID":"cca47d74-7754-4a61-b163-ca31f66b157b","description":"A type for 'sale_ID' values"}},{"key":{"name":"timestamp_type","version":"0.0.1"},"value":{"key":{"name":"timestamp_type","version":"0.0.1"},"UUID":"fd594e88-411d-4a94-b2be-697b3a0d7adf","description":"A type for 'time' values"}}]}},"policies":{"key":{"name":"MyFirstPolicyModel_Policies","version":"0.0.1"},"policyMap":{"entry":[{"key":{"name":"MyFirstPolicy","version":"0.0.1"},"value":{"policyKey":{"name":"MyFirstPolicy","version":"0.0.1"},"template":"FREEFORM","state":{"entry":[{"key":"BoozeAuthDecide","value":{"stateKey":{"parentKeyName":"MyFirstPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"BoozeAuthDecide"},"trigger":{"name":"SALE_INPUT","version":"0.0.1"},"stateOutputs":{"entry":[{"key":"MorningBoozeCheck_Output_Direct","value":{"key":{"parentKeyName":"MyFirstPolicy","parentKeyVersion":"0.0.1","parentLocalName":"BoozeAuthDecide","localName":"MorningBoozeCheck_Output_Direct"},"outgoingEvent":{"name":"SALE_AUTH","version":"0.0.1"},"outgoingEventReference":[{"name":"SALE_AUTH","version":"0.0.1"}],"nextState":{"parentKeyName":"NULL","parentKeyVersion":"0.0.0","parentLocalName":"NULL","localName":"NULL"}}}]},"contextAlbumReference":[],"taskSelectionLogic":{"key":"NULL","logicFlavour":"UNDEFINED","logic":""},"stateFinalizerLogicMap":{"entry":[]},"defaultTask":{"name":"MorningBoozeCheck","version":"0.0.1"},"taskReferences":{"entry":[{"key":{"name":"MorningBoozeCheck","version":"0.0.1"},"value":{"key":{"parentKeyName":"MyFirstPolicy","parentKeyVersion":"0.0.1","parentLocalName":"BoozeAuthDecide","localName":"MorningBoozeCheck"},"outputType":"DIRECT","output":{"parentKeyName":"MyFirstPolicy","parentKeyVersion":"0.0.1","parentLocalName":"BoozeAuthDecide","localName":"MorningBoozeCheck_Output_Direct"}}}]}}}]},"firstState":"BoozeAuthDecide"}}]}},"tasks":{"key":{"name":"MyFirstPolicyModel_Tasks","version":"0.0.1"},"taskMap":{"entry":[{"key":{"name":"MorningBoozeCheck","version":"0.0.1"},"value":{"key":{"name":"MorningBoozeCheck","version":"0.0.1"},"inputEvent":{"key":{"name":"SALE_INPUT","version":"0.0.1"},"nameSpace":"com.hyperm","source":"POS","target":"APEX","parameter":{"entry":[{"key":"amount","value":{"key":"amount","fieldSchemaKey":{"name":"price_type","version":"0.0.1"},"optional":false}},{"key":"assistant_ID","value":{"key":"assistant_ID","fieldSchemaKey":{"name":"assistant_ID_type","version":"0.0.1"},"optional":false}},{"key":"branch_ID","value":{"key":"branch_ID","fieldSchemaKey":{"name":"branch_ID_type","version":"0.0.1"},"optional":false}},{"key":"item_ID","value":{"key":"item_ID","fieldSchemaKey":{"name":"item_ID_type","version":"0.0.1"},"optional":false}},{"key":"notes","value":{"key":"notes","fieldSchemaKey":{"name":"notes_type","version":"0.0.1"},"optional":true}},{"key":"quantity","value":{"key":"quantity","fieldSchemaKey":{"name":"quantity_type","version":"0.0.1"},"optional":false}},{"key":"sale_ID","value":{"key":"sale_ID","fieldSchemaKey":{"name":"sale_ID_type","version":"0.0.1"},"optional":false}},{"key":"time","value":{"key":"time","fieldSchemaKey":{"name":"timestamp_type","version":"0.0.1"},"optional":false}}]}},"outputEvents":{"entry":[{"key":"SALE_AUTH","value":{"key":{"name":"SALE_AUTH","version":"0.0.1"},"nameSpace":"com.hyperm","source":"APEX","target":"POS","parameter":{"entry":[{"key":"amount","value":{"key":"amount","fieldSchemaKey":{"name":"price_type","version":"0.0.1"},"optional":false}},{"key":"assistant_ID","value":{"key":"assistant_ID","fieldSchemaKey":{"name":"assistant_ID_type","version":"0.0.1"},"optional":false}},{"key":"authorised","value":{"key":"authorised","fieldSchemaKey":{"name":"authorised_type","version":"0.0.1"},"optional":false}},{"key":"branch_ID","value":{"key":"branch_ID","fieldSchemaKey":{"name":"branch_ID_type","version":"0.0.1"},"optional":false}},{"key":"item_ID","value":{"key":"item_ID","fieldSchemaKey":{"name":"item_ID_type","version":"0.0.1"},"optional":false}},{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"message_type","version":"0.0.1"},"optional":true}},{"key":"notes","value":{"key":"notes","fieldSchemaKey":{"name":"notes_type","version":"0.0.1"},"optional":true}},{"key":"quantity","value":{"key":"quantity","fieldSchemaKey":{"name":"quantity_type","version":"0.0.1"},"optional":false}},{"key":"sale_ID","value":{"key":"sale_ID","fieldSchemaKey":{"name":"sale_ID_type","version":"0.0.1"},"optional":false}},{"key":"time","value":{"key":"time","fieldSchemaKey":{"name":"timestamp_type","version":"0.0.1"},"optional":false}}]}}}]},"inputFields":{"entry":[{"key":"amount","value":{"key":"amount","fieldSchemaKey":{"name":"price_type","version":"0.0.1"},"optional":false}},{"key":"assistant_ID","value":{"key":"assistant_ID","fieldSchemaKey":{"name":"assistant_ID_type","version":"0.0.1"},"optional":false}},{"key":"branch_ID","value":{"key":"branch_ID","fieldSchemaKey":{"name":"branch_ID_type","version":"0.0.1"},"optional":false}},{"key":"item_ID","value":{"key":"item_ID","fieldSchemaKey":{"name":"item_ID_type","version":"0.0.1"},"optional":false}},{"key":"notes","value":{"key":"notes","fieldSchemaKey":{"name":"notes_type","version":"0.0.1"},"optional":true}},{"key":"quantity","value":{"key":"quantity","fieldSchemaKey":{"name":"quantity_type","version":"0.0.1"},"optional":false}},{"key":"sale_ID","value":{"key":"sale_ID","fieldSchemaKey":{"name":"sale_ID_type","version":"0.0.1"},"optional":false}},{"key":"time","value":{"key":"time","fieldSchemaKey":{"name":"timestamp_type","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"amount","value":{"key":"amount","fieldSchemaKey":{"name":"price_type","version":"0.0.1"},"optional":false}},{"key":"assistant_ID","value":{"key":"assistant_ID","fieldSchemaKey":{"name":"assistant_ID_type","version":"0.0.1"},"optional":false}},{"key":"authorised","value":{"key":"authorised","fieldSchemaKey":{"name":"authorised_type","version":"0.0.1"},"optional":false}},{"key":"branch_ID","value":{"key":"branch_ID","fieldSchemaKey":{"name":"branch_ID_type","version":"0.0.1"},"optional":false}},{"key":"item_ID","value":{"key":"item_ID","fieldSchemaKey":{"name":"item_ID_type","version":"0.0.1"},"optional":false}},{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"message_type","version":"0.0.1"},"optional":true}},{"key":"notes","value":{"key":"notes","fieldSchemaKey":{"name":"notes_type","version":"0.0.1"},"optional":true}},{"key":"quantity","value":{"key":"quantity","fieldSchemaKey":{"name":"quantity_type","version":"0.0.1"},"optional":false}},{"key":"sale_ID","value":{"key":"sale_ID","fieldSchemaKey":{"name":"sale_ID_type","version":"0.0.1"},"optional":false}},{"key":"time","value":{"key":"time","fieldSchemaKey":{"name":"timestamp_type","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"MVEL","logic":"/*\n * ============LICENSE_START=======================================================\n *  Copyright (C) 2016-2018 Ericsson. All rights reserved.\n *  Modifications Copyright (C) 2019 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\nimport java.util.Date;\nimport java.util.Calendar;\nimport java.util.TimeZone;\nimport java.text.SimpleDateFormat;\n\nlogger.info(\"Task Execution: '\"+subject.id+\"'. Input Fields: '\"+inFields+\"'\");\n\noutFields.put(\"amount\"      , inFields.get(\"amount\"));\noutFields.put(\"assistant_ID\", inFields.get(\"assistant_ID\"));\noutFields.put(\"notes\"       , inFields.get(\"notes\"));\noutFields.put(\"quantity\"    , inFields.get(\"quantity\"));\noutFields.put(\"branch_ID\"   , inFields.get(\"branch_ID\"));\noutFields.put(\"item_ID\"     , inFields.get(\"item_ID\"));\noutFields.put(\"time\"        , inFields.get(\"time\"));\noutFields.put(\"sale_ID\"     , inFields.get(\"sale_ID\"));\n\nitem_id = inFields.get(\"item_ID\");\n\n//The events used later to test this task use GMT timezone!\ngmt = TimeZone.getTimeZone(\"GMT\");\ntimenow = Calendar.getInstance(gmt);\ndf = new SimpleDateFormat(\"HH:mm:ss z\");\ndf.setTimeZone(gmt);\ntimenow.setTimeInMillis(inFields.get(\"time\"));\n\nmidnight = timenow.clone();\nmidnight.set(\n    timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),\n    timenow.get(Calendar.DATE),0,0,0);\neleven30 = timenow.clone();\neleven30.set(\n    timenow.get(Calendar.YEAR),timenow.get(Calendar.MONTH),\n    timenow.get(Calendar.DATE),11,30,0);\n\nitemisalcohol = false;\nif(item_id != null && item_id >=1000 && item_id < 2000)\n    itemisalcohol = true;\n\nif( itemisalcohol\n    && timenow.after(midnight) && timenow.before(eleven30)){\n  outFields.put(\"authorised\", false);\n  outFields.put(\"message\", \"Sale not authorised by policy task \"+subject.taskName+\n    \" for time \"+df.format(timenow.getTime())+\n    \". Alcohol can not be sold between \"+df.format(midnight.getTime())+\n    \" and \"+df.format(eleven30.getTime()));\n  return true;\n}\nelse{\n  outFields.put(\"authorised\", true);\n  outFields.put(\"message\", \"Sale authorised by policy task \"+subject.taskName+\n    \" for time \"+df.format(timenow.getTime()));\n  return true;\n}\n\n/*\nThis task checks if a sale request is for an item that is an alcoholic drink.\nIf the local time is between 00:00:00 GMT and 11:30:00 GMT then the sale is not\nauthorised. Otherwise the sale is authorised.\nIn this implementation we assume that items with item_ID value between 1000 and\n2000 are all alcoholic drinks :-)\n*/"}}}]}},"events":{"key":{"name":"MyFirstPolicyModel_Events","version":"0.0.1"},"eventMap":{"entry":[{"key":{"name":"SALE_AUTH","version":"0.0.1"},"value":{"key":{"name":"SALE_AUTH","version":"0.0.1"},"nameSpace":"com.hyperm","source":"APEX","target":"POS","parameter":{"entry":[{"key":"amount","value":{"key":"amount","fieldSchemaKey":{"name":"price_type","version":"0.0.1"},"optional":false}},{"key":"assistant_ID","value":{"key":"assistant_ID","fieldSchemaKey":{"name":"assistant_ID_type","version":"0.0.1"},"optional":false}},{"key":"authorised","value":{"key":"authorised","fieldSchemaKey":{"name":"authorised_type","version":"0.0.1"},"optional":false}},{"key":"branch_ID","value":{"key":"branch_ID","fieldSchemaKey":{"name":"branch_ID_type","version":"0.0.1"},"optional":false}},{"key":"item_ID","value":{"key":"item_ID","fieldSchemaKey":{"name":"item_ID_type","version":"0.0.1"},"optional":false}},{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"message_type","version":"0.0.1"},"optional":true}},{"key":"notes","value":{"key":"notes","fieldSchemaKey":{"name":"notes_type","version":"0.0.1"},"optional":true}},{"key":"quantity","value":{"key":"quantity","fieldSchemaKey":{"name":"quantity_type","version":"0.0.1"},"optional":false}},{"key":"sale_ID","value":{"key":"sale_ID","fieldSchemaKey":{"name":"sale_ID_type","version":"0.0.1"},"optional":false}},{"key":"time","value":{"key":"time","fieldSchemaKey":{"name":"timestamp_type","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"SALE_INPUT","version":"0.0.1"},"value":{"key":{"name":"SALE_INPUT","version":"0.0.1"},"nameSpace":"com.hyperm","source":"POS","target":"APEX","parameter":{"entry":[{"key":"amount","value":{"key":"amount","fieldSchemaKey":{"name":"price_type","version":"0.0.1"},"optional":false}},{"key":"assistant_ID","value":{"key":"assistant_ID","fieldSchemaKey":{"name":"assistant_ID_type","version":"0.0.1"},"optional":false}},{"key":"branch_ID","value":{"key":"branch_ID","fieldSchemaKey":{"name":"branch_ID_type","version":"0.0.1"},"optional":false}},{"key":"item_ID","value":{"key":"item_ID","fieldSchemaKey":{"name":"item_ID_type","version":"0.0.1"},"optional":false}},{"key":"notes","value":{"key":"notes","fieldSchemaKey":{"name":"notes_type","version":"0.0.1"},"optional":true}},{"key":"quantity","value":{"key":"quantity","fieldSchemaKey":{"name":"quantity_type","version":"0.0.1"},"optional":false}},{"key":"sale_ID","value":{"key":"sale_ID","fieldSchemaKey":{"name":"sale_ID_type","version":"0.0.1"},"optional":false}},{"key":"time","value":{"key":"time","fieldSchemaKey":{"name":"timestamp_type","version":"0.0.1"},"optional":false}}]}}}]}},"schemas":{"key":{"name":"MyFirstPolicyModel_Schemas","version":"0.0.1"},"schemas":{"entry":[{"key":{"name":"assistant_ID_type","version":"0.0.1"},"value":{"key":{"name":"assistant_ID_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Long"}},{"key":{"name":"authorised_type","version":"0.0.1"},"value":{"key":{"name":"authorised_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Boolean"}},{"key":{"name":"branch_ID_type","version":"0.0.1"},"value":{"key":{"name":"branch_ID_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Long"}},{"key":{"name":"item_ID_type","version":"0.0.1"},"value":{"key":{"name":"item_ID_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Long"}},{"key":{"name":"message_type","version":"0.0.1"},"value":{"key":{"name":"message_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.String"}},{"key":{"name":"notes_type","version":"0.0.1"},"value":{"key":{"name":"notes_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.String"}},{"key":{"name":"price_type","version":"0.0.1"},"value":{"key":{"name":"price_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Long"}},{"key":{"name":"quantity_type","version":"0.0.1"},"value":{"key":{"name":"quantity_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Integer"}},{"key":{"name":"sale_ID_type","version":"0.0.1"},"value":{"key":{"name":"sale_ID_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Long"}},{"key":{"name":"timestamp_type","version":"0.0.1"},"value":{"key":{"name":"timestamp_type","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.Long"}}]}}}}},"eventOutputParameters":{"FirstProducer":{"carrierTechnologyParameters":{"carrierTechnology":"FILE","parameters":{"standardIo":true}},"eventProtocolParameters":{"eventProtocol":"JSON"}}},"eventInputParameters":{"FirstConsumer":{"carrierTechnologyParameters":{"carrierTechnology":"FILE","parameters":{"standardIo":true}},"eventProtocolParameters":{"eventProtocol":"JSON"}}}}}}]}}
\ No newline at end of file
index fd5fe13..878d527 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019-2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,9 +24,13 @@ package org.onap.policy.apex.core.engine.engine.impl;
 
 import static org.onap.policy.common.utils.validation.Assertions.argumentNotNull;
 
+import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
 import org.onap.policy.apex.context.ContextAlbum;
 import org.onap.policy.apex.context.ContextException;
 import org.onap.policy.apex.core.engine.context.ApexInternalContext;
@@ -41,7 +46,12 @@ import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
 import org.onap.policy.apex.model.enginemodel.concepts.AxEngineModel;
 import org.onap.policy.apex.model.enginemodel.concepts.AxEngineState;
 import org.onap.policy.apex.model.enginemodel.concepts.AxEngineStats;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
 import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
+import org.onap.policy.apex.model.policymodel.concepts.AxState;
+import org.onap.policy.apex.model.policymodel.concepts.AxStateOutput;
+import org.onap.policy.apex.model.policymodel.concepts.AxStateTaskReference;
+import org.onap.policy.apex.model.policymodel.concepts.AxTask;
 import org.slf4j.ext.XLogger;
 import org.slf4j.ext.XLoggerFactory;
 
@@ -122,6 +132,8 @@ public class ApexEngineImpl implements ApexEngine {
             }
         }
 
+        populateIoEventsToTask(apexModel);
+
         // Create new internal context or update the existing one
         try {
             if (internalContext == null) {
@@ -149,6 +161,48 @@ public class ApexEngineImpl implements ApexEngine {
         LOGGER.exit(UPDATE_MODEL + key.getId());
     }
 
+
+    private void populateIoEventsToTask(AxPolicyModel apexPolicyModel) {
+        Set<AxArtifactKey> updatedTasks = new TreeSet<>();
+        for (var axPolicy : apexPolicyModel.getPolicies().getPolicyMap().values()) {
+            for (var axState : axPolicy.getStateMap().values()) {
+                AxEvent triggerEvent = apexPolicyModel.getEvents().get(axState.getTrigger());
+                axState.getTaskReferences().forEach((taskKey, taskRef) -> {
+                    AxTask task = apexPolicyModel.getTasks().getTaskMap().get(taskKey);
+                    task.setInputEvent(triggerEvent);
+                    updateTaskBasedOnStateOutput(apexPolicyModel, updatedTasks, axState, taskKey, taskRef, task);
+                    updatedTasks.add(taskKey);
+                });
+            }
+        }
+    }
+
+    private void updateTaskBasedOnStateOutput(AxPolicyModel apexPolicyModel, Set<AxArtifactKey> updatedTasks,
+        AxState state, AxArtifactKey taskKey, AxStateTaskReference taskRef, AxTask task) {
+        Map<String, AxEvent> outputEvents = new TreeMap<>();
+        AxStateOutput stateOutput = state.getStateOutputs().get(taskRef.getOutput().getLocalName());
+        if (null == stateOutput.getOutgoingEventSet() || stateOutput.getOutgoingEventSet().isEmpty()) {
+            Set<AxArtifactKey> outEventSet = new TreeSet<>();
+            outEventSet.add(stateOutput.getOutgoingEvent());
+            stateOutput.setOutgoingEventSet(outEventSet);
+        }
+        if (state.getNextStateSet().isEmpty()
+            || state.getNextStateSet().contains(AxReferenceKey.getNullKey().getLocalName())) {
+            stateOutput.getOutgoingEventSet().forEach(outgoingEventKey -> outputEvents.put(outgoingEventKey.getName(),
+                apexPolicyModel.getEvents().get(outgoingEventKey)));
+        } else {
+            AxArtifactKey outgoingEventKey = stateOutput.getOutgoingEvent();
+            outputEvents.put(outgoingEventKey.getName(), apexPolicyModel.getEvents().get(outgoingEventKey));
+        }
+        if (updatedTasks.contains(taskKey)) {
+            // this happens only when same task is used by multiple policies
+            // with different eventName but same fields
+            task.getOutputEvents().putAll(outputEvents);
+        } else {
+            task.setOutputEvents(outputEvents);
+        }
+    }
+
     /**
      * {@inheritDoc}.
      */
@@ -288,7 +342,7 @@ public class ApexEngineImpl implements ApexEngine {
      */
     @Override
     public boolean handleEvent(final EnEvent incomingEvent) {
-        boolean ret = false;
+        var ret = false;
         if (incomingEvent == null) {
             LOGGER.warn("handleEvent()<-{},{}, cannot run engine, incoming event is null", key.getId(), state);
             return ret;
@@ -307,17 +361,17 @@ public class ApexEngineImpl implements ApexEngine {
         LOGGER.debug(message);
 
         // By default we return a null event on errors
-        EnEvent outgoingEvent = null;
+        Collection<EnEvent> outgoingEvents = null;
         try {
             engineStats.executionEnter(incomingEvent.getKey());
-            outgoingEvent = stateMachineHandler.execute(incomingEvent);
+            outgoingEvents = stateMachineHandler.execute(incomingEvent);
             engineStats.executionExit();
             ret = true;
         } catch (final StateMachineException e) {
             LOGGER.warn("handleEvent()<-{},{}, engine execution error: ", key.getId(), state, e);
 
             // Create an exception return event
-            outgoingEvent = createExceptionEvent(incomingEvent, e);
+            outgoingEvents = createExceptionEvent(incomingEvent, e);
         }
 
         // Publish the outgoing event
@@ -325,10 +379,12 @@ public class ApexEngineImpl implements ApexEngine {
             synchronized (eventListeners) {
                 if (eventListeners.isEmpty()) {
                     LOGGER.debug("handleEvent()<-{},{}, There is no listener registered to recieve outgoing event: {}",
-                        key.getId(), state, outgoingEvent);
+                        key.getId(), state, outgoingEvents);
                 }
                 for (final EnEventListener axEventListener : eventListeners.values()) {
-                    axEventListener.onEnEvent(outgoingEvent);
+                    for (var outgoingEvent : outgoingEvents) {
+                        axEventListener.onEnEvent(outgoingEvent);
+                    }
                 }
             }
         } catch (final ApexException e) {
@@ -398,7 +454,7 @@ public class ApexEngineImpl implements ApexEngine {
      */
     @Override
     public AxEngineModel getEngineStatus() {
-        final AxEngineModel engineModel = new AxEngineModel(key);
+        final var engineModel = new AxEngineModel(key);
         engineModel.setTimestamp(System.currentTimeMillis());
         engineModel.setState(state);
         engineModel.setStats(engineStats);
@@ -440,14 +496,14 @@ public class ApexEngineImpl implements ApexEngine {
      * @param eventException The exception that was thrown
      * @return the exception event
      */
-    private EnEvent createExceptionEvent(final EnEvent incomingEvent, final Exception eventException) {
+    private Set<EnEvent> createExceptionEvent(final EnEvent incomingEvent, final Exception eventException) {
         // The exception event is a clone of the incoming event with the exception suffix added to
         // its name and an extra
         // field "ExceptionMessage" added
         final EnEvent exceptionEvent = (EnEvent) incomingEvent.clone();
 
         // Create the cascaded message string
-        final StringBuilder exceptionMessageStringBuilder = new StringBuilder();
+        final var exceptionMessageStringBuilder = new StringBuilder();
         exceptionMessageStringBuilder.append(eventException.getMessage());
 
         Throwable subException = eventException.getCause();
@@ -460,6 +516,6 @@ public class ApexEngineImpl implements ApexEngine {
         // Set the exception message on the event
         exceptionEvent.setExceptionMessage(exceptionMessageStringBuilder.toString());
 
-        return exceptionEvent;
+        return Set.of(exceptionEvent);
     }
 }
index 32f86e4..c173d1f 100644 (file)
@@ -1,6 +1,7 @@
 /*-
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +21,9 @@
 
 package org.onap.policy.apex.core.engine.engine.impl;
 
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.Set;
 import org.onap.policy.apex.core.engine.context.ApexInternalContext;
 import org.onap.policy.apex.core.engine.event.EnEvent;
 import org.onap.policy.apex.core.engine.executor.ExecutorFactory;
@@ -79,8 +82,7 @@ public class StateMachineHandler {
         // Iterate over the policies in the policy model and create a state machine for each one
         for (final AxPolicy policy : ModelService.getModel(AxPolicies.class).getPolicyMap().values()) {
             // Create a state machine for this policy
-            final StateMachineExecutor thisStateMachineExecutor =
-                    new StateMachineExecutor(executorFactory, policy.getKey());
+            final var thisStateMachineExecutor = new StateMachineExecutor(executorFactory, policy.getKey());
 
             // This executor is the top executor so has no parent
             thisStateMachineExecutor.setContext(null, policy, internalContext);
@@ -90,8 +92,7 @@ public class StateMachineHandler {
                     .get(policy.getStateMap().get(policy.getFirstState()).getTrigger());
 
             // Put the state machine executor on the map for this trigger
-            final StateMachineExecutor lastStateMachineExecutor =
-                    stateMachineExecutorMap.put(triggerEvent, thisStateMachineExecutor);
+            final var lastStateMachineExecutor = stateMachineExecutorMap.put(triggerEvent, thisStateMachineExecutor);
             if (lastStateMachineExecutor != null
                     && lastStateMachineExecutor.getSubject() != thisStateMachineExecutor.getSubject()) {
                 LOGGER.error("No more than one policy in a model can have the same trigger event. In model "
@@ -138,32 +139,32 @@ public class StateMachineHandler {
      * @return The result of the state machine execution run
      * @throws StateMachineException On execution errors in a state machine
      */
-    protected EnEvent execute(final EnEvent event) throws StateMachineException {
+    protected Collection<EnEvent> execute(final EnEvent event) throws StateMachineException {
         LOGGER.entry("execute()->" + event.getName());
 
         // Try to execute the state machine for the trigger
-        final StateMachineExecutor stateMachineExecutor = stateMachineExecutorMap.get(event.getAxEvent());
+        final var stateMachineExecutor = stateMachineExecutorMap.get(event.getAxEvent());
         if (stateMachineExecutor == null) {
             final String exceptionMessage =
-                    "state machine execution not possible, policy not found for trigger event " + event.getName();
+                "state machine execution not possible, policy not found for trigger event " + event.getName();
             LOGGER.warn(exceptionMessage);
 
             event.setExceptionMessage(exceptionMessage);
-            return event;
+            return Set.of(event);
         }
 
         // Run the state machine
         try {
             LOGGER.debug("execute(): state machine \"{}\" execution starting  . . .", stateMachineExecutor);
-            final EnEvent outputObject =
-                    stateMachineExecutor.execute(event.getExecutionId(), event.getExecutionProperties(), event);
+            final Collection<EnEvent> outputEvents =
+                stateMachineExecutor.execute(event.getExecutionId(), event.getExecutionProperties(), event);
 
             LOGGER.debug("execute()<-: state machine \"{}\" execution completed", stateMachineExecutor);
-            return outputObject;
+            return outputEvents;
         } catch (final Exception e) {
             LOGGER.warn("execute()<-: state machine \"" + stateMachineExecutor + "\" execution failed", e);
             throw new StateMachineException("execute()<-: execution failed on state machine " + stateMachineExecutor,
-                    e);
+                e);
         }
     }
 
index b04c354..11d0aa1 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019-2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -196,7 +197,7 @@ public class StateExecutor implements Executor<EnEvent, StateOutput, AxState, Ap
             // Execute the task
             final TreeMap<String, Object> incomingValues = new TreeMap<>();
             incomingValues.putAll(incomingEvent);
-            final Map<String, Object> taskExecutionResultMap =
+            final Map<String, Map<String, Object>> taskExecutionResultMap =
                 taskExecutorMap.get(taskKey).execute(executionId, executionProperties, incomingValues);
             final AxTask task = taskExecutorMap.get(taskKey).getSubject();
 
@@ -215,8 +216,9 @@ public class StateExecutor implements Executor<EnEvent, StateOutput, AxState, Ap
 
                 // Execute the state finalizer logic to select a state output and to adjust the
                 // taskExecutionResultMap
-                stateOutputName =
-                    finalizerLogicExecutor.execute(executionId, executionProperties, taskExecutionResultMap);
+                // Multiple event outputs are possible only from final state, otherwise there will be only 1 outputevent
+                stateOutputName = finalizerLogicExecutor.execute(executionId, executionProperties,
+                    taskExecutionResultMap.values().iterator().next());
             }
 
             // Now look up the the actual state output
@@ -227,19 +229,19 @@ public class StateExecutor implements Executor<EnEvent, StateOutput, AxState, Ap
             }
 
             // Create the state output and transfer all the fields across to its event
-            final StateOutput stateOutput = new StateOutput(stateOutputDefinition);
+            final var stateOutput = new StateOutput(stateOutputDefinition);
             this.lastStateOutput = stateOutput;
 
-            stateOutput.setEventFields(task.getRawOutputFields(), taskExecutionResultMap);
+            stateOutput.setEventFields(task.getOutputEvents(), taskExecutionResultMap);
 
             // Copy across fields from the incoming event that are not set on the outgoing event
             stateOutput.copyUnsetFields(incomingEvent);
 
             // Set the ExecutionID for the outgoing event to the value in the incoming event.
-            if (stateOutput.getOutputEvent() != null) {
-                stateOutput.getOutputEvent().setExecutionId(incomingEvent.getExecutionId());
-                stateOutput.getOutputEvent().setExecutionProperties(incomingEvent.getExecutionProperties());
-            }
+            stateOutput.getOutputEvents().values().forEach(outputEvent -> {
+                outputEvent.setExecutionId(incomingEvent.getExecutionId());
+                outputEvent.setExecutionProperties(incomingEvent.getExecutionProperties());
+            });
 
             // That's it, the state execution is complete
             return stateOutput;
index 67a3e6d..52429a2 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +22,8 @@
 
 package org.onap.policy.apex.core.engine.executor;
 
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Map;
 import java.util.Properties;
 import java.util.TreeMap;
@@ -41,7 +44,7 @@ import org.onap.policy.apex.model.policymodel.concepts.AxStateOutput;
  * @author Sven van der Meer (sven.van.der.meer@ericsson.com)
  * @author Liam Fallon (liam.fallon@ericsson.com)
  */
-public class StateMachineExecutor implements Executor<EnEvent, EnEvent, AxPolicy, ApexInternalContext> {
+public class StateMachineExecutor implements Executor<EnEvent, Collection<EnEvent>, AxPolicy, ApexInternalContext> {
     // The Apex Policy and context for this state machine
     private AxPolicy axPolicy = null;
     private Executor<?, ?, ?, ?> parent = null;
@@ -54,7 +57,7 @@ public class StateMachineExecutor implements Executor<EnEvent, EnEvent, AxPolicy
     private StateExecutor firstExecutor = null;
 
     // The next state machine executor
-    private Executor<EnEvent, EnEvent, AxPolicy, ApexInternalContext> nextExecutor = null;
+    private Executor<EnEvent, Collection<EnEvent>, AxPolicy, ApexInternalContext> nextExecutor = null;
 
     // The executor factory
     private ExecutorFactory executorFactory = null;
@@ -120,8 +123,8 @@ public class StateMachineExecutor implements Executor<EnEvent, EnEvent, AxPolicy
      * {@inheritDoc}.
      */
     @Override
-    public EnEvent execute(final long executionId, final Properties executionProperties, final EnEvent incomingEvent)
-            throws StateMachineException, ContextException {
+    public Collection<EnEvent> execute(final long executionId, final Properties executionProperties,
+        final EnEvent incomingEvent) throws StateMachineException, ContextException {
         // Check if there are any states on the state machine
         if (stateExecutorMap.size() == 0) {
             throw new StateMachineException("no states defined on state machine");
@@ -139,8 +142,10 @@ public class StateMachineExecutor implements Executor<EnEvent, EnEvent, AxPolicy
                 incomingEvent.getKey(), firstExecutor.getSubject().getKey()), incomingEvent);
 
         while (true) {
-            // Execute the state, it returns an output or throws an exception
-            stateOutput = stateExecutor.execute(executionId, executionProperties, stateOutput.getOutputEvent());
+            // OutputEventSet in a stateoutput can contain multiple events only when it is of the final state
+            // otherwise, there can be only 1 item in outputEventSet
+            stateOutput = stateExecutor.execute(executionId, executionProperties,
+                stateOutput.getOutputEvents().values().iterator().next());
 
             // Use the next state of the state output to find if all the states have executed
             if (stateOutput.getNextState().equals(AxReferenceKey.getNullKey())) {
@@ -155,7 +160,7 @@ public class StateMachineExecutor implements Executor<EnEvent, EnEvent, AxPolicy
             }
         }
 
-        return stateOutput.getOutputEvent();
+        return stateOutput.getOutputEvents().values();
     }
 
     /**
@@ -229,15 +234,16 @@ public class StateMachineExecutor implements Executor<EnEvent, EnEvent, AxPolicy
      * {@inheritDoc}.
      */
     @Override
-    public final EnEvent getOutgoing() {
-        return null;
+    public final Collection<EnEvent> getOutgoing() {
+        return Collections.emptyList();
     }
 
     /**
      * {@inheritDoc}.
      */
     @Override
-    public final void setNext(final Executor<EnEvent, EnEvent, AxPolicy, ApexInternalContext> newNextExecutor) {
+    public final void setNext(
+        final Executor<EnEvent, Collection<EnEvent>, AxPolicy, ApexInternalContext> newNextExecutor) {
         this.nextExecutor = newNextExecutor;
     }
 
@@ -245,7 +251,7 @@ public class StateMachineExecutor implements Executor<EnEvent, EnEvent, AxPolicy
      * {@inheritDoc}.
      */
     @Override
-    public final Executor<EnEvent, EnEvent, AxPolicy, ApexInternalContext> getNext() {
+    public final Executor<EnEvent, Collection<EnEvent>, AxPolicy, ApexInternalContext> getNext() {
         return nextExecutor;
     }
 
index 9c3c6f8..5355654 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,8 +24,15 @@ package org.onap.policy.apex.core.engine.executor;
 
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+import lombok.Getter;
 import org.onap.policy.apex.core.engine.event.EnEvent;
 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
 import org.onap.policy.apex.model.basicmodel.service.ModelService;
 import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
@@ -38,11 +46,12 @@ import org.onap.policy.common.utils.validation.Assertions;
  *
  * @author Liam Fallon (liam.fallon@ericsson.com)
  */
+@Getter
 public class StateOutput {
     // The state output has a state and an event
     private final AxStateOutput stateOutputDefinition;
-    private final AxEvent outputEventDef;
-    private final EnEvent outputEvent;
+    private AxEvent outputEventDef;
+    private final Map<AxArtifactKey, EnEvent> outputEvents;
 
     /**
      * Create a new state output from a state output definition.
@@ -50,7 +59,7 @@ public class StateOutput {
      * @param axStateOutput the state output definition
      */
     public StateOutput(final AxStateOutput axStateOutput) {
-        this(axStateOutput, new EnEvent(axStateOutput.getOutgingEvent()));
+        this(axStateOutput, new EnEvent(axStateOutput.getOutgoingEvent()));
     }
 
     /**
@@ -64,8 +73,15 @@ public class StateOutput {
         Assertions.argumentNotNull(outputEvent, "outputEvent may not be null");
 
         this.stateOutputDefinition = stateOutputDefinition;
-        this.outputEvent = outputEvent;
-        outputEventDef = ModelService.getModel(AxEvents.class).get(stateOutputDefinition.getOutgingEvent());
+        this.outputEvents = new TreeMap<>();
+        if (stateOutputDefinition.getOutgoingEventSet() != null
+            && !stateOutputDefinition.getOutgoingEventSet().isEmpty()) {
+            stateOutputDefinition.getOutgoingEventSet()
+                .forEach(outEvent -> outputEvents.put(outEvent, new EnEvent(outEvent)));
+        } else {
+            outputEvents.put(outputEvent.getKey(), outputEvent);
+        }
+        outputEventDef = ModelService.getModel(AxEvents.class).get(stateOutputDefinition.getOutgoingEvent());
     }
 
     /**
@@ -77,53 +93,90 @@ public class StateOutput {
         return stateOutputDefinition.getNextState();
     }
 
-    /**
-     * Gets the state output definition.
-     *
-     * @return the state output definition
-     */
-    public AxStateOutput getStateOutputDefinition() {
-        return stateOutputDefinition;
-    }
-
-    /**
-     * Gets the output event.
-     *
-     * @return the output event
-     */
-    public EnEvent getOutputEvent() {
-        return outputEvent;
-    }
-
     /**
      * Transfer the fields from the incoming field map into the event.
      *
-     * @param incomingFieldDefinitionMap definitions of the incoming fields
-     * @param eventFieldMap the event field map
+     * @param incomingEventDefinitionMap definitions of the incoming fields
+     * @param eventFieldMaps the event field map
      * @throws StateMachineException on errors populating the event fields
      */
-    public void setEventFields(final Map<String, AxField> incomingFieldDefinitionMap,
-                    final Map<String, Object> eventFieldMap) throws StateMachineException {
-        Assertions.argumentNotNull(incomingFieldDefinitionMap, "incomingFieldDefinitionMap may not be null");
-        Assertions.argumentNotNull(eventFieldMap, "eventFieldMap may not be null");
-
-        if (!incomingFieldDefinitionMap.keySet().equals(eventFieldMap.keySet())) {
-            throw new StateMachineException(
-                            "field definitions and values do not match for event " + outputEventDef.getId() + '\n'
-                                            + incomingFieldDefinitionMap.keySet() + '\n' + eventFieldMap.keySet());
+    public void setEventFields(final Map<String, AxEvent> incomingEventDefinitionMap,
+        final Map<String, Map<String, Object>> eventFieldMaps) throws StateMachineException {
+        Assertions.argumentNotNull(incomingEventDefinitionMap, "incomingFieldDefinitionMap may not be null");
+        Assertions.argumentNotNull(eventFieldMaps, "eventFieldMaps may not be null");
+
+        for (Entry<String, AxEvent> incomingEventDefinitionEntry : incomingEventDefinitionMap.entrySet()) {
+            String eventName = incomingEventDefinitionEntry.getKey();
+            AxEvent eventDef = incomingEventDefinitionEntry.getValue();
+            if (!eventDef.getParameterMap().keySet().equals(eventFieldMaps.get(eventName).keySet())) {
+                throw new StateMachineException(
+                    "field definitions and values do not match for event " + eventDef.getId() + '\n'
+                        + eventDef.getParameterMap().keySet() + '\n' + eventFieldMaps.get(eventName).keySet());
+            }
+        }
+        var updateOnceFlag = false;
+        if (!outputEvents.keySet().stream().map(AxArtifactKey::getName).collect(Collectors.toSet())
+            .equals(eventFieldMaps.keySet())) {
+            // when same task is used by multiple policies with different eventName but same fields,
+            // state outputs and task output events may be different
+            // in this case, update the output fields in the state output only once to avoid overwriting.
+            updateOnceFlag = true;
         }
-        for (final Entry<String, Object> incomingFieldEntry : eventFieldMap.entrySet()) {
-            final String fieldName = incomingFieldEntry.getKey();
-            final AxField fieldDef = incomingFieldDefinitionMap.get(fieldName);
+        for (Entry<String, Map<String, Object>> eventFieldMapEntry : eventFieldMaps.entrySet()) {
+            String eventName = eventFieldMapEntry.getKey();
+            Map<String, Object> outputEventFields = eventFieldMapEntry.getValue();
+            AxEvent taskOutputEvent = incomingEventDefinitionMap.get(eventName);
+            EnEvent outputEventToUpdate = outputEvents.get(taskOutputEvent.getKey());
+
+            if (null == outputEventToUpdate) {
+                // happens only when same task is used by multiple policies with different eventName but same fields
+                // in this case, just match the fields and get the event in the stateOutput
+                Set<String> outputEventFieldNames = outputEventFields.keySet();
+                Optional<EnEvent> outputEventOpt = outputEvents.values().stream().filter(outputEvent -> outputEvent
+                    .getAxEvent().getParameterMap().keySet().equals(outputEventFieldNames)).findFirst();
+                if (outputEventOpt.isEmpty()) {
+                    throw new StateMachineException(
+                        "Task output event field definition and state output event field doesn't match");
+                } else {
+                    outputEventToUpdate = outputEventOpt.get();
+                }
+            }
+            updateOutputEventFields(taskOutputEvent, outputEventFields, outputEventToUpdate);
+            if (updateOnceFlag) {
+                break;
+            }
+        }
+    }
 
+    private void updateOutputEventFields(AxEvent taskOutputEvent, Map<String, Object> outputEventFields,
+        EnEvent outputEventToUpdate) throws StateMachineException {
+        for (Entry<String, Object> outputEventFieldEntry : outputEventFields.entrySet()) {
+            String fieldName = outputEventFieldEntry.getKey();
+            Object fieldValue = outputEventFieldEntry.getValue();
+            final AxField fieldDef = taskOutputEvent.getParameterMap().get(fieldName);
+
+            Set<AxArtifactKey> outgoingEventSet = new TreeSet<>();
+            if (null == stateOutputDefinition.getOutgoingEventSet()
+                || stateOutputDefinition.getOutgoingEventSet().isEmpty()) {
+                // if current state is not the final state, then the set could be empty.
+                // Just take the outgoingEvent field in this case
+                outgoingEventSet.add(stateOutputDefinition.getOutgoingEvent());
+            } else {
+                outgoingEventSet.addAll(stateOutputDefinition.getOutgoingEventSet());
+            }
             // Check if this field is a field in the event
-            if (!outputEventDef.getFields().contains(fieldDef)) {
-                throw new StateMachineException("field \"" + fieldName + "\" does not exist on event \""
-                                + outputEventDef.getId() + "\"");
+            for (AxArtifactKey outputEventKey : outgoingEventSet) {
+                if (outputEventKey.equals(taskOutputEvent.getKey())) {
+                    outputEventDef = ModelService.getModel(AxEvents.class).get(outputEventKey);
+                    // Check if this field is a field in the state output event
+                    if (!outputEventDef.getFields().contains(fieldDef)) {
+                        throw new StateMachineException(
+                            "field \"" + fieldName + "\" does not exist on event \"" + outputEventDef.getId() + "\"");
+                    }
+                }
             }
-
-            // Set the value in the output event
-            outputEvent.put(fieldName, incomingFieldEntry.getValue());
+            // Set the value in the correct output event
+            outputEventToUpdate.put(fieldName, fieldValue);
         }
     }
 
@@ -135,25 +188,30 @@ public class StateOutput {
      */
     public void copyUnsetFields(final EnEvent incomingEvent) {
         Assertions.argumentNotNull(incomingEvent, "incomingEvent may not be null");
-
-        for (final Entry<String, Object> incomingField : incomingEvent.entrySet()) {
-            final String fieldName = incomingField.getKey();
-
-            // Check if the field exists on the outgoing event
-            if ((!outputEventDef.getParameterMap().containsKey(fieldName))
-
-                            // Check if the field is set on the outgoing event
-                            || (outputEvent.containsKey(fieldName))
-
-                            // Now, check the fields have the same type
-                            || (!incomingEvent.getAxEvent().getParameterMap().get(fieldName)
-                                            .equals(outputEvent.getAxEvent().getParameterMap().get(fieldName)))) {
-                continue;
-            }
-
-            // All checks done, we can copy the value
-            outputEvent.put(fieldName, incomingField.getValue());
+        Set<AxArtifactKey> outgoingEventSet = new TreeSet<>();
+        if (null == stateOutputDefinition.getOutgoingEventSet()
+            || stateOutputDefinition.getOutgoingEventSet().isEmpty()) {
+            // if current state is not the final state, then the set could be empty.
+            // Just take the outgoingEvent field in this case
+            outgoingEventSet.add(stateOutputDefinition.getOutgoingEvent());
+        } else {
+            outgoingEventSet.addAll(stateOutputDefinition.getOutgoingEventSet());
         }
-
+        incomingEvent.forEach((inFieldName, inFieldValue) -> {
+            for (AxArtifactKey outputEventKey : outgoingEventSet) {
+                outputEventDef = ModelService.getModel(AxEvents.class).get(outputEventKey);
+                // Check if the field exists on the outgoing event
+                if (!outputEventDef.getParameterMap().containsKey(inFieldName)
+                    // Check if the field is set in the outgoing event
+                    || outputEvents.get(outputEventKey).containsKey(inFieldName)
+                    // Now, check the fields have the same type
+                    || !incomingEvent.getAxEvent().getParameterMap().get(inFieldName)
+                        .equals(outputEvents.get(outputEventKey).getAxEvent().getParameterMap().get(inFieldName))) {
+                    continue;
+                }
+                // All checks done, we can copy the value
+                outputEvents.get(outputEventKey).put(inFieldName, inFieldValue);
+            }
+        });
     }
 }
index 0150b65..31e27d2 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019-2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,7 +25,6 @@ package org.onap.policy.apex.core.engine.executor;
 import static org.onap.policy.common.utils.validation.Assertions.argumentOfClassNotNull;
 
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -41,8 +41,7 @@ import org.onap.policy.apex.core.engine.executor.context.TaskExecutionContext;
 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
-import org.onap.policy.apex.model.eventmodel.concepts.AxInputField;
-import org.onap.policy.apex.model.eventmodel.concepts.AxOutputField;
+import org.onap.policy.apex.model.eventmodel.concepts.AxField;
 import org.onap.policy.apex.model.policymodel.concepts.AxTask;
 import org.onap.policy.apex.model.policymodel.concepts.AxTaskParameter;
 import org.slf4j.ext.XLogger;
@@ -56,7 +55,7 @@ import org.slf4j.ext.XLoggerFactory;
  * @author Liam Fallon (liam.fallon@ericsson.com)
  */
 public abstract class TaskExecutor
-        implements Executor<Map<String, Object>, Map<String, Object>, AxTask, ApexInternalContext> {
+        implements Executor<Map<String, Object>, Map<String, Map<String, Object>>, AxTask, ApexInternalContext> {
     // Logger for this class
     private static final XLogger LOGGER = XLoggerFactory.getXLogger(TaskExecutor.class);
 
@@ -67,10 +66,11 @@ public abstract class TaskExecutor
 
     // Holds the incoming and outgoing fields
     private Map<String, Object> incomingFields = null;
-    private Map<String, Object> outgoingFields = null;
+    private Map<String, Map<String, Object>> outgoingFieldsMap = null;
 
     // The next task executor
-    private Executor<Map<String, Object>, Map<String, Object>, AxTask, ApexInternalContext> nextExecutor = null;
+    private Executor<Map<String, Object>, Map<String, Map<String, Object>>, AxTask, ApexInternalContext> nextExecutor =
+        null;
 
     // The task execution context; contains the facades for events and context to be used by tasks
     // executed by this task
@@ -104,7 +104,7 @@ public abstract class TaskExecutor
      * {@inheritDoc}.
      */
     @Override
-    public Map<String, Object> execute(final long executionId, final Properties executionProperties,
+    public Map<String, Map<String, Object>> execute(final long executionId, final Properties executionProperties,
             final Map<String, Object> newIncomingFields) throws StateMachineException, ContextException {
         throw new StateMachineException(
                 "execute() not implemented on abstract TaskExecutor class, only on its subclasses");
@@ -120,19 +120,13 @@ public abstract class TaskExecutor
                 + getSubject().getKey().getId() + "," + getSubject().getTaskLogic().getLogic());
 
         // Check that the incoming event has all the input fields for this state
-        final Set<String> missingTaskInputFields = new TreeSet<>(axTask.getInputFields().keySet());
+        Map<String, AxField> inputEventParameterMap = axTask.getInputEvent().getParameterMap();
+        final Set<String> missingTaskInputFields = new TreeSet<>(inputEventParameterMap.keySet());
         missingTaskInputFields.removeAll(newIncomingFields.keySet());
 
         // Remove fields from the set that are optional
-        final Set<String> optionalFields = new TreeSet<>();
-        for (final Iterator<String> missingFieldIterator = missingTaskInputFields.iterator(); missingFieldIterator
-                .hasNext();) {
-            final String missingField = missingFieldIterator.next();
-            if (axTask.getInputFields().get(missingField).getOptional()) {
-                optionalFields.add(missingField);
-            }
-        }
-        missingTaskInputFields.removeAll(optionalFields);
+        missingTaskInputFields.removeIf(missingField -> inputEventParameterMap.get(missingField).getOptional());
+
         if (!missingTaskInputFields.isEmpty()) {
             throw new StateMachineException("task input fields \"" + missingTaskInputFields
                     + "\" are missing for task \"" + axTask.getKey().getId() + "\"");
@@ -142,14 +136,15 @@ public abstract class TaskExecutor
         this.incomingFields = newIncomingFields;
 
         // Initiate the outgoing fields
-        outgoingFields = new TreeMap<>();
-        for (final String outputFieldName : getSubject().getOutputFields().keySet()) {
-            outgoingFields.put(outputFieldName, null);
+        outgoingFieldsMap = new TreeMap<>();
+        for (var outputEventEntry: axTask.getOutputEvents().entrySet()) {
+            Map<String, Object> outgoingFields = new TreeMap<>();
+            outputEventEntry.getValue().getParameterMap().keySet().forEach(field -> outgoingFields.put(field, null));
+            outgoingFieldsMap.put(outputEventEntry.getKey(), outgoingFields);
         }
-
         // Get task context object
         executionContext = new TaskExecutionContext(this, executionId, executionProperties, getSubject(), getIncoming(),
-                getOutgoing(), getContext());
+            outgoingFieldsMap.values(), getContext());
     }
 
     /**
@@ -167,71 +162,77 @@ public abstract class TaskExecutor
             throw new StateMachineException(errorMessage);
         }
 
-        // Copy any unset fields from the input to the output if their data type and names are
-        // identical
-        for (final String field : axTask.getOutputFields().keySet()) {
-            copyInputField2Output(field);
-        }
+        // Copy any unset fields from the input to the output if their data type and names are identical
+        axTask.getOutputEvents().entrySet().forEach(outputEventEntry -> outputEventEntry.getValue().getParameterMap()
+            .keySet().forEach(field -> copyInputField2Output(outputEventEntry.getKey(), field)));
 
         // Finally, check that the outgoing fields have all the output fields defined for this state
-        // and, if not, output
-        // a list of missing fields
-        final Set<String> missingTaskOutputFields = new TreeSet<>(axTask.getOutputFields().keySet());
-        missingTaskOutputFields.removeAll(outgoingFields.keySet());
+        // and, if not, output a list of missing fields
+        Map<String, Set<String>> missingTaskOutputFieldsMap = new TreeMap<>();
+        axTask.getOutputEvents().entrySet().forEach(outputEventEntry -> {
+            Set<String> missingTaskOutputFields = new TreeSet<>();
+            missingTaskOutputFields.addAll(outputEventEntry.getValue().getParameterMap().keySet());
+            String key = outputEventEntry.getKey();
+            missingTaskOutputFields.removeAll(outgoingFieldsMap.get(key).keySet());
+            missingTaskOutputFieldsMap.put(key, missingTaskOutputFields);
+        });
 
         // Remove fields from the set that are optional
-        final Set<String> optionalOrCopiedFields = new TreeSet<>();
-        for (final Iterator<String> missingFieldIterator = missingTaskOutputFields.iterator(); missingFieldIterator
-                .hasNext();) {
-            final String missingField = missingFieldIterator.next();
-            if (axTask.getInputFields().containsKey(missingField)
-                    || axTask.getOutputFields().get(missingField).getOptional()) {
-                optionalOrCopiedFields.add(missingField);
-            }
-        }
-        missingTaskOutputFields.removeAll(optionalOrCopiedFields);
-        if (!missingTaskOutputFields.isEmpty()) {
-            throw new StateMachineException("task output fields \"" + missingTaskOutputFields
-                    + "\" are missing for task \"" + axTask.getKey().getId() + "\"");
+        missingTaskOutputFieldsMap.entrySet()
+            .forEach(missingTaskOutputFieldsEntry -> missingTaskOutputFieldsEntry.getValue()
+                .removeIf(missingField -> axTask.getInputEvent().getParameterMap().containsKey(missingField)
+                    || axTask.getOutputEvents().get(missingTaskOutputFieldsEntry.getKey()).getParameterMap()
+                        .get(missingField).getOptional()));
+        missingTaskOutputFieldsMap.entrySet()
+            .removeIf(missingTaskOutputFieldsEntry -> missingTaskOutputFieldsEntry.getValue().isEmpty());
+        if (!missingTaskOutputFieldsMap.isEmpty()) {
+            throw new StateMachineException("Fields for task output events \"" + missingTaskOutputFieldsMap.keySet()
+                + "\" are missing for task \"" + axTask.getKey().getId() + "\"");
+
         }
 
         // Finally, check that the outgoing field map don't have any extra fields, if present, raise
-        // exception with the
-        // list of extra fields
-        final Set<String> extraTaskOutputFields = new TreeSet<>(outgoingFields.keySet());
-        extraTaskOutputFields.removeAll(axTask.getOutputFields().keySet());
-        if (!extraTaskOutputFields.isEmpty()) {
-            throw new StateMachineException("task output fields \"" + extraTaskOutputFields
-                    + "\" are unwanted for task \"" + axTask.getKey().getId() + "\"");
+        // exception with the list of extra fields
+        final Map<String, Set<String>> extraTaskOutputFieldsMap = new TreeMap<>();
+        outgoingFieldsMap.entrySet().forEach(outgoingFieldsEntry -> extraTaskOutputFieldsMap
+            .put(outgoingFieldsEntry.getKey(), new TreeSet<>(outgoingFieldsEntry.getValue().keySet())));
+        extraTaskOutputFieldsMap.entrySet().forEach(extraTaskOutputFieldsEntry -> extraTaskOutputFieldsEntry.getValue()
+            .removeAll(axTask.getOutputEvents().get(extraTaskOutputFieldsEntry.getKey()).getParameterMap().keySet()));
+        extraTaskOutputFieldsMap.entrySet()
+            .removeIf(extraTaskOutputFieldsEntry -> extraTaskOutputFieldsEntry.getValue().isEmpty());
+        if (!extraTaskOutputFieldsMap.isEmpty()) {
+            throw new StateMachineException("task output event \"" + extraTaskOutputFieldsMap.keySet()
+                + "\" contains fields that are unwanted for task \"" + axTask.getKey().getId() + "\"");
         }
 
-        String message = "execute-post:" + axTask.getKey().getId() + ", returning fields " + outgoingFields.toString();
+        String message =
+            "execute-post:" + axTask.getKey().getId() + ", returning fields " + outgoingFieldsMap.toString();
         LOGGER.debug(message);
     }
 
     /**
      * If the input field exists on the output and it is not set in the task, then it should be copied to the output.
      *
+     * @param eventName the event name
      * @param field the input field
      */
-    private void copyInputField2Output(String field) {
+    private void copyInputField2Output(String eventName, String field) {
+        Map<String, Object> outgoingFields = outgoingFieldsMap.get(eventName);
         // Check if the field exists and is not set on the output
-        if (getOutgoing().containsKey(field) && getOutgoing().get(field) != null) {
+        if (outgoingFields.get(field) != null) {
             return;
         }
 
         // This field is not in the output, check if it's on the input and is the same type
-        // (Note here, the output
-        // field definition has to exist so it's not
-        // null checked)
-        final AxInputField inputFieldDef = axTask.getInputFields().get(field);
-        final AxOutputField outputFieldDef = axTask.getOutputFields().get(field);
+        // (Note here, the output field definition has to exist so it's not null checked)
+        final AxField inputFieldDef = axTask.getInputEvent().getParameterMap().get(field);
+        final AxField outputFieldDef = axTask.getOutputEvents().get(eventName).getParameterMap().get(field);
         if (inputFieldDef == null || !inputFieldDef.getSchema().equals(outputFieldDef.getSchema())) {
             return;
         }
 
         // We have an input field that matches our output field, copy the value across
-        getOutgoing().put(field, getIncoming().get(field));
+        outgoingFields.put(field, getIncoming().get(field));
     }
 
     /**
@@ -308,15 +309,16 @@ public abstract class TaskExecutor
      * {@inheritDoc}.
      */
     @Override
-    public Map<String, Object> getOutgoing() {
-        return outgoingFields;
+    public Map<String, Map<String, Object>> getOutgoing() {
+        return outgoingFieldsMap;
     }
 
     /**
      * {@inheritDoc}.
      */
     @Override
-    public void setNext(final Executor<Map<String, Object>, Map<String, Object>, AxTask, ApexInternalContext> nextEx) {
+    public void setNext(
+        final Executor<Map<String, Object>, Map<String, Map<String, Object>>, AxTask, ApexInternalContext> nextEx) {
         this.nextExecutor = nextEx;
     }
 
@@ -324,7 +326,7 @@ public abstract class TaskExecutor
      * {@inheritDoc}.
      */
     @Override
-    public Executor<Map<String, Object>, Map<String, Object>, AxTask, ApexInternalContext> getNext() {
+    public Executor<Map<String, Object>, Map<String, Map<String, Object>>, AxTask, ApexInternalContext> getNext() {
         return nextExecutor;
     }
 
index f390621..5f39bcd 100644 (file)
@@ -1,6 +1,7 @@
 /*-
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -84,18 +85,34 @@ public class AxTaskFacade {
      */
     public SchemaHelper getInFieldSchemaHelper(final String fieldName) {
         // Find the field for the field name
-        return getFieldSchemaHelper(fieldName, task.getInputFields().get(fieldName), "incoming");
+        return getFieldSchemaHelper(fieldName, task.getInputEvent().getParameterMap().get(fieldName), "incoming");
     }
 
     /**
      * Creates a schema helper for an outgoing field of this task.
+     * This method can be used only when there is a single event output as part of a task
      *
      * @param fieldName The name of the field to get a schema helper for
      * @return the schema helper for this field
      */
     public SchemaHelper getOutFieldSchemaHelper(final String fieldName) {
         // Find the field for the field name
-        return getFieldSchemaHelper(fieldName, task.getOutputFields().get(fieldName), "outgoing");
+        return getFieldSchemaHelper(fieldName,
+            task.getOutputEvents().values().iterator().next().getParameterMap().get(fieldName), "outgoing");
+    }
+
+    /**
+     * Creates a schema helper for an outgoing field of this task.
+     * This method can be used when there are multiple event outputs from a task
+     *
+     * @param eventName the name of the event to which the field belongs to
+     * @param fieldName The name of the field to get a schema helper for
+     * @return the schema helper for this field
+     */
+    public SchemaHelper getOutFieldSchemaHelper(final String eventName, final String fieldName) {
+        // Find the field for the field name
+        return getFieldSchemaHelper(fieldName, task.getOutputEvents().get(eventName).getParameterMap().get(fieldName),
+            "outgoing");
     }
 
     /**
index 49459df..a54252e 100644 (file)
@@ -3,6 +3,7 @@
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2020 Nordix Foundation.
  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,6 +24,7 @@
 package org.onap.policy.apex.core.engine.executor.context;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -72,6 +74,12 @@ public class TaskExecutionContext extends AbstractExecutionContext {
      */
     public final Map<String, Object> outFields;
 
+    /**
+     * The outgoing fields from the task. The task logic can access and set these fields with its logic. A task outputs
+     * its result using these fields.
+     */
+    public final Collection<Map<String, Object>> outFieldsList;
+
     /**
      * Logger for task execution, task logic can use this field to access and log to Apex logging.
      */
@@ -97,12 +105,12 @@ public class TaskExecutionContext extends AbstractExecutionContext {
      * @param executionProperties the execution properties for task execution
      * @param axTask the task definition that is the subject of execution
      * @param inFields the in fields
-     * @param outFields the out fields
+     * @param outFieldsList collection of the out fields
      * @param internalContext the execution context of the Apex engine in which the task is being executed
      */
     public TaskExecutionContext(final TaskExecutor taskExecutor, final long executionId,
             final Properties executionProperties, final AxTask axTask, final Map<String, Object> inFields,
-            final Map<String, Object> outFields, final ApexInternalContext internalContext) {
+            final Collection<Map<String, Object>> outFieldsList, final ApexInternalContext internalContext) {
         super(executionId, executionProperties);
 
         // The subject is the task definition
@@ -113,7 +121,13 @@ public class TaskExecutionContext extends AbstractExecutionContext {
 
         // The input and output fields
         this.inFields = Collections.unmodifiableMap(inFields);
-        this.outFields = outFields;
+        this.outFieldsList = outFieldsList;
+        // if only a single output event needs to fired from a task, the outFields alone can be used too
+        if (outFieldsList.isEmpty()) {
+            this.outFields = new TreeMap<>();
+        } else {
+            this.outFields = outFieldsList.iterator().next();
+        }
 
         // Set up the context albums for this task
         context = new TreeMap<>();
@@ -156,7 +170,7 @@ public class TaskExecutionContext extends AbstractExecutionContext {
      */
     public ContextAlbum getContextAlbum(final String contextAlbumName) {
         // Find the context album
-        final ContextAlbum foundContextAlbum = context.get(contextAlbumName);
+        final var foundContextAlbum = context.get(contextAlbumName);
 
         // Check if the context album exists
         if (foundContextAlbum != null) {
@@ -166,4 +180,16 @@ public class TaskExecutionContext extends AbstractExecutionContext {
                     + "\" on task \"" + subject.getId() + "\"");
         }
     }
+
+    /**
+     * Method to add fields to the output event list.
+     * @param fields the fields to be added
+     */
+    public void addFieldsToOutput(Map<String, Object> fields) {
+        for (Map<String, Object> outputFields : outFieldsList) {
+            if (outputFields.keySet().containsAll(fields.keySet())) {
+                outputFields.replaceAll((name, value) -> fields.get(name));
+            }
+        }
+    }
 }
index 18d3214..df4d927 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +22,8 @@
 
 package org.onap.policy.apex.core.engine.engine.impl;
 
+import java.util.Collection;
+import java.util.List;
 import java.util.Properties;
 import org.onap.policy.apex.core.engine.event.EnEvent;
 import org.onap.policy.apex.core.engine.executor.ExecutorFactory;
@@ -62,8 +65,9 @@ public class DummySmExecutor extends StateMachineExecutor {
      * {@inheritDoc}.
      */
     @Override
-    public EnEvent execute(final long executionId, final Properties executionProperties, final EnEvent incomingEvent) {
-        return incomingEvent;
+    public Collection<EnEvent> execute(final long executionId, final Properties executionProperties,
+        final EnEvent incomingEvent) {
+        return List.of(incomingEvent);
     }
 
     /**
index 8d1aa5f..75c4c0d 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019-2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,12 +28,14 @@ import org.onap.policy.apex.context.ContextException;
 import org.onap.policy.apex.core.engine.event.EnEvent;
 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
 import org.onap.policy.apex.model.policymodel.concepts.AxTask;
 
 /**
  * Dummy task executor for testing.
  */
 public class DummyTaskExecutor extends TaskExecutor {
+    private static final String EVENT_KEY = "Event1:0.0.1";
     private boolean override;
 
     public DummyTaskExecutor() {
@@ -54,14 +57,14 @@ public class DummyTaskExecutor extends TaskExecutor {
      * {@inheritDoc}.
      */
     @Override
-    public Map<String, Object> execute(final long executionId, final Properties executionProperties,
+    public  Map<String, Map<String, Object>> execute(final long executionId, final Properties executionProperties,
             final Map<String, Object> newIncomingFields) throws StateMachineException, ContextException {
         if (!override) {
             super.execute(executionId, executionProperties, newIncomingFields);
         }
 
-        AxArtifactKey event0Key = new AxArtifactKey("Event0:0.0.1");
-        return new EnEvent(event0Key);
+        AxArtifactKey eventKey = new AxArtifactKey(EVENT_KEY);
+        return Map.of(eventKey.getName(), new EnEvent(eventKey));
     }
 
     /**
@@ -74,7 +77,9 @@ public class DummyTaskExecutor extends TaskExecutor {
         }
 
         AxArtifactKey taskKey = new AxArtifactKey("FirstTask:0.0.1");
-        return new AxTask(taskKey);
+        AxTask task = new AxTask(taskKey);
+        task.setOutputEvents(Map.of("Event1", new AxEvent(new AxArtifactKey(EVENT_KEY))));
+        return task;
     }
 
     /**
index 2acb576..2d274bd 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,7 +25,10 @@ package org.onap.policy.apex.core.engine.executor;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
+import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import org.junit.After;
@@ -65,7 +69,7 @@ public class StateMachineExecutorTest {
     private ApexInternalContext internalContextMock;
 
     @Mock
-    private Executor<EnEvent, EnEvent, AxPolicy, ApexInternalContext> nextExecutorMock;
+    private Executor<EnEvent, Collection<EnEvent>, AxPolicy, ApexInternalContext> nextExecutorMock;
 
     @Mock
     private ExecutorFactory executorFactoryMock;
@@ -191,18 +195,18 @@ public class StateMachineExecutorTest {
             .hasMessage("no states defined on state machine");
         executor.setContext(null, axPolicy, internalContextMock);
         assertEquals("Policy:0.0.1", executor.getKey().getId());
-        assertEquals(null, executor.getParent());
+        assertNull(executor.getParent());
         assertEquals(internalContextMock, executor.getContext());
-        assertEquals(null, executor.getNext());
-        assertEquals(null, executor.getIncoming());
-        assertEquals(null, executor.getOutgoing());
+        assertNull(executor.getNext());
+        assertNull(executor.getIncoming());
+        assertTrue(executor.getOutgoing().isEmpty());
         assertEquals(axPolicy, executor.getSubject());
 
         executor.setParameters(new ExecutorParameters());
         executor.setNext(nextExecutorMock);
         assertEquals(nextExecutorMock, executor.getNext());
         executor.setNext(null);
-        assertEquals(null, executor.getNext());
+        assertNull(executor.getNext());
 
         assertThatThrownBy(() -> executor.executePre(0, null, null))
             .hasMessage("execution pre work not implemented on class");
@@ -294,34 +298,37 @@ public class StateMachineExecutorTest {
 
         assertThatThrownBy(() -> output.setEventFields(null, null))
             .hasMessage("incomingFieldDefinitionMap may not be null");
-        Map<String, AxField> incomingFieldDefinitionMap = new LinkedHashMap<>();
+        Map<String, AxEvent> incomingFieldDefinitionMap = new LinkedHashMap<>();
         assertThatThrownBy(() -> output.setEventFields(incomingFieldDefinitionMap, null))
-            .hasMessage("eventFieldMap may not be null");
-        Map<String, Object> eventFieldMap = new LinkedHashMap<>();
-        output.setEventFields(incomingFieldDefinitionMap, eventFieldMap);
-
-        eventFieldMap.put("key", "Value");
-        assertThatThrownBy(() -> output.setEventFields(incomingFieldDefinitionMap, eventFieldMap))
-            .hasMessage("field definitions and values do not match for event Event1:0.0.1\n[]\n[key]");
-        AxField axBadFieldDefinition = new AxField();
-        incomingFieldDefinitionMap.put("key", axBadFieldDefinition);
-        assertThatThrownBy(() -> output.setEventFields(incomingFieldDefinitionMap, eventFieldMap))
+            .hasMessage("eventFieldMaps may not be null");
+        Map<String, Map<String, Object>> eventFieldMaps = new LinkedHashMap<>();
+        output.setEventFields(incomingFieldDefinitionMap, eventFieldMaps);
+        AxEvent event = new AxEvent(new AxArtifactKey("Event1", "0.0.1"));
+        event.setParameterMap(Map.of("key", new AxField()));
+        incomingFieldDefinitionMap.put("Event1", event);
+        eventFieldMaps.put("Event1", Map.of("key2", "value"));
+        assertThatThrownBy(() -> output.setEventFields(incomingFieldDefinitionMap, eventFieldMaps))
+            .hasMessage("field definitions and values do not match for event Event1:0.0.1\n[key]\n[key2]");
+
+        eventFieldMaps.put("Event1", Map.of("key", "value"));
+        assertThatThrownBy(() -> output.setEventFields(incomingFieldDefinitionMap, eventFieldMaps))
             .hasMessage("field \"key\" does not exist on event \"Event1:0.0.1\"");
+
         incomingFieldDefinitionMap.clear();
-        eventFieldMap.clear();
+        eventFieldMaps.clear();
         AxArtifactKey stringSchemaKey = new AxArtifactKey("StringSchema:0.0.1");
         AxReferenceKey fieldKey = new AxReferenceKey("Event1:0.0.1:event:Field0");
         AxField event1Field0Definition = new AxField(fieldKey, stringSchemaKey);
-        incomingFieldDefinitionMap.put("Event1Field0", event1Field0Definition);
-        eventFieldMap.put("Event1Field0", "Value");
-        output.setEventFields(incomingFieldDefinitionMap, eventFieldMap);
+        event.setParameterMap(Map.of("Event1Field0", event1Field0Definition));
+        incomingFieldDefinitionMap.put("Event1", event);
+        eventFieldMaps.put("Event1", Map.of("Event1Field0", "Value"));
+        output.setEventFields(incomingFieldDefinitionMap, eventFieldMaps);
 
         StateOutput outputCopy = new StateOutput(axPolicy.getStateMap().get("State0")
                 .getStateOutputs().get("stateOutput0"));
 
         EnEvent incomingEvent = new EnEvent(new AxArtifactKey("Event0:0.0.1"));
         outputCopy.copyUnsetFields(incomingEvent);
-
         incomingEvent.put("Event1Field0", "Hello");
         outputCopy.copyUnsetFields(incomingEvent);
     }
index bbedb88..1ddc3f5 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,6 +33,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.TreeMap;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -44,6 +46,8 @@ import org.onap.policy.apex.core.engine.context.ApexInternalContext;
 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
+import org.onap.policy.apex.model.eventmodel.concepts.AxField;
 import org.onap.policy.apex.model.eventmodel.concepts.AxInputField;
 import org.onap.policy.apex.model.eventmodel.concepts.AxOutputField;
 import org.onap.policy.apex.model.policymodel.concepts.AxTask;
@@ -76,14 +80,16 @@ public class TaskExecutorTest {
     private AxOutputField axMissingOutputFieldMock;
 
     @Mock
-    private Executor<Map<String, Object>, Map<String, Object>, AxTask, ApexInternalContext> nextExecutorMock;
+    private Executor<Map<String, Object>, Map<String, Map<String, Object>>, AxTask,
+        ApexInternalContext> nextExecutorMock;
 
     @Mock
     private AxTaskLogic taskLogicMock;
 
-    private LinkedHashMap<String, Object> inFieldMap;
-    private LinkedHashMap<String, Object> outFieldMap;
+    private Map<String, AxField> inFieldMap;
+    private Map<String, AxField> outFieldMap;
     private List<TaskParameters> taskParametersFromConfig;
+    private Map<String, AxEvent> outEvents = new TreeMap<>();
 
     /**
      * Set up mocking.
@@ -96,13 +102,17 @@ public class TaskExecutorTest {
         Mockito.doReturn(task0Key).when(axTaskMock).getKey();
         Mockito.doReturn(task0Key.getId()).when(axTaskMock).getId();
 
-        inFieldMap = new LinkedHashMap<>();
+        inFieldMap = Map.of("InField0", axInputFieldMock, "InField1", axOptionalInputFieldMock);
         outFieldMap = new LinkedHashMap<>();
 
-        inFieldMap.put("InField0", axInputFieldMock);
-        inFieldMap.put("InField1", axOptionalInputFieldMock);
         outFieldMap.put("OutField0", axOutputFieldMock);
-        outFieldMap.put("OutField0", axOptionalOutputFieldMock);
+        outFieldMap.put("OutField1", axOptionalOutputFieldMock);
+
+        AxEvent inEvent = new AxEvent();
+        inEvent.setParameterMap(inFieldMap);
+        AxEvent outEvent = new AxEvent(new AxArtifactKey("outputEvent:1.0.0"));
+        outEvent.setParameterMap(outFieldMap);
+        outEvents.put(outEvent.getKey().getName(), outEvent);
 
         AxArtifactKey schemaKey = new AxArtifactKey("Schema:0.0.1");
         Mockito.doReturn(schemaKey).when(axInputFieldMock).getSchema();
@@ -119,6 +129,9 @@ public class TaskExecutorTest {
         Mockito.doReturn(outFieldMap).when(axTaskMock).getOutputFields();
         Mockito.doReturn(taskLogicMock).when(axTaskMock).getTaskLogic();
 
+        Mockito.doReturn(inEvent).when(axTaskMock).getInputEvent();
+        Mockito.doReturn(outEvents).when(axTaskMock).getOutputEvents();
+
         Mockito.doReturn(new AxArtifactKey("Context:0.0.1")).when(internalContextMock).getKey();
 
         Map<String, AxTaskParameter> taskParameters = new HashMap<>();
@@ -162,9 +175,6 @@ public class TaskExecutorTest {
 
         Map<String, Object> incomingFields = new LinkedHashMap<>();
 
-        assertThatThrownBy(() -> executor.executePre(0, new Properties(), incomingFields))
-            .hasMessageContaining("task input fields \"[InField0]\" are missing for task \"Task0:0.0.1\"");
-
         incomingFields.put("InField0", "A Value");
 
         executor.executePre(0, new Properties(), incomingFields);
@@ -184,15 +194,16 @@ public class TaskExecutorTest {
         executor.executePost(true);
 
         outFieldMap.put("MissingField", axMissingOutputFieldMock);
-
-        assertThatThrownBy(() -> executor.executePost(true))
-            .hasMessageContaining("task output fields \"[MissingField]\" are missing for task \"Task0:0.0.1\"");
+        outEvents.get("outputEvent").getParameterMap().put("MissingField", axMissingOutputFieldMock);
+        assertThatThrownBy(() -> executor.executePost(true)).hasMessageContaining(
+            "Fields for task output events \"[outputEvent]\" are missing for task \"Task0:0.0.1\"");
 
         outFieldMap.remove("MissingField");
+        outEvents.get("outputEvent").getParameterMap().remove("MissingField");
         executor.getExecutionContext().outFields.put("BadExtraField", "Howdy!");
 
-        assertThatThrownBy(() -> executor.executePost(true))
-            .hasMessageContaining("task output fields \"[BadExtraField]\" are unwanted for task \"Task0:0.0.1\"");
+        assertThatThrownBy(() -> executor.executePost(true)).hasMessageContaining(
+            "task output event \"[outputEvent]\" contains fields that are unwanted for task \"Task0:0.0.1\"");
 
         executor.getExecutionContext().outFields.remove("BadExtraField");
         outFieldMap.put("InField1", axMissingOutputFieldMock);
@@ -202,6 +213,7 @@ public class TaskExecutorTest {
         executor.executePost(true);
 
         executor.getExecutionContext().outFields.put("InField0", "Output Value");
+        outEvents.get("outputEvent").getParameterMap().put("InField0", axMissingOutputFieldMock);
         executor.executePost(true);
 
         executor.getExecutionContext().outFields.remove("InField0");
index 8ef78ef..6f8402e 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2020 Nordix Foundation
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,8 +26,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
-import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.TreeMap;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -40,6 +41,8 @@ import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
 import org.onap.policy.apex.model.basicmodel.service.ModelService;
 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema;
 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchemas;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
+import org.onap.policy.apex.model.eventmodel.concepts.AxField;
 import org.onap.policy.apex.model.eventmodel.concepts.AxInputField;
 import org.onap.policy.apex.model.eventmodel.concepts.AxOutputField;
 import org.onap.policy.apex.model.policymodel.concepts.AxTask;
@@ -83,13 +86,18 @@ public class AxTaskFacadeTest {
         Mockito.doReturn(task0Key).when(axTaskMock).getKey();
         Mockito.doReturn(task0Key.getId()).when(axTaskMock).getId();
 
-        Map<String, AxInputField> inFieldMap = new LinkedHashMap<>();
-        Map<String, AxOutputField> outFieldMap = new LinkedHashMap<>();
+        Map<String, AxField> inFieldMap = Map.of("InField0", axInputFieldMock, "InFieldBad", axInputFieldBadMock);
+        Map<String, AxField> outFieldMap = Map.of("OutField0", axOutputFieldMock, "OutFieldBad", axOutputFieldBadMock);
 
-        inFieldMap.put("InField0", axInputFieldMock);
-        inFieldMap.put("InFieldBad", axInputFieldBadMock);
-        outFieldMap.put("OutField0", axOutputFieldMock);
-        outFieldMap.put("OutFieldBad", axOutputFieldBadMock);
+        AxEvent inEvent = new AxEvent();
+        inEvent.setParameterMap(inFieldMap);
+        AxEvent outEvent = new AxEvent(new AxArtifactKey("outputEvent:1.0.0"));
+        outEvent.setParameterMap(outFieldMap);
+        Map<String, AxEvent> outEvents = new TreeMap<>();
+        outEvents.put(outEvent.getKey().getName(), outEvent);
+
+        Mockito.doReturn(inEvent).when(axTaskMock).getInputEvent();
+        Mockito.doReturn(outEvents).when(axTaskMock).getOutputEvents();
 
         Mockito.doReturn(inFieldMap).when(axTaskMock).getInputFields();
         Mockito.doReturn(outFieldMap).when(axTaskMock).getOutputFields();
index f8bdc4b..24c5048 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -28,6 +29,8 @@ import static org.junit.Assert.assertNotNull;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import org.junit.Before;
@@ -93,10 +96,10 @@ public class TaskExecutionContextTest {
     @Test
     public void test() {
         final Map<String, Object> inFields = new LinkedHashMap<>();
-        final Map<String, Object> outFields = new LinkedHashMap<>();
+        final List<Map<String, Object>> outFieldsList = new LinkedList<>();
 
-        TaskExecutionContext tec = new TaskExecutionContext(taskExecutorMock, 0, null, axTaskMock, inFields, outFields,
-                        internalContextMock);
+        TaskExecutionContext tec = new TaskExecutionContext(taskExecutorMock, 0, null, axTaskMock, inFields,
+            outFieldsList, internalContextMock);
 
         assertNotNull(tec);
         tec.setMessage("TEC Message");
index fb1c380..c34f9e3 100644 (file)
       "eventProtocolParameters": {
         "eventProtocol": "JSON"
       },
-      "eventNameFilter": "CDSResponseStatusEvent"
+      "eventNameFilter": "(LogEvent|CDSResponseStatusEvent)"
     }
   }
-}
\ No newline at end of file
+}
diff --git a/examples/examples-grpc/src/main/resources/examples/events/APEXgRPC/CDSResponseStatusEvent.json b/examples/examples-grpc/src/main/resources/examples/events/APEXgRPC/CDSResponseStatusEvent.json
new file mode 100644 (file)
index 0000000..9389833
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "name": "CDSResponseStatusEvent",
+  "version": "0.0.1",
+  "nameSpace": "org.onap.policy.apex.onap.pmcontrol",
+  "source": "APEX",
+  "target": "DCAE",
+  "status": {
+    "subscriptionName": "testPolicyB",
+    "nfName": "pnf300",
+    "changeType": "CREATE",
+    "message": "success"
+  }
+}
index a86ccd1..e227b66 100644 (file)
@@ -1,13 +1,9 @@
 {
-  "name": "CDSResponseStatusEvent",
+  "name": "LogEvent",
   "version": "0.0.1",
   "nameSpace": "org.onap.policy.apex.onap.pmcontrol",
   "source": "APEX",
   "target": "DCAE",
-  "status": {
-    "subscriptionName": "testPolicyB",
-    "nfName": "pnf300",
-    "changeType": "CREATE",
-    "message": "success"
-  }
-}
\ No newline at end of file
+  "final_status": "FINAL_SUCCESS",
+  "message": "Operation successfully completed."
+}
index 0451776..dc49489 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2020 Nordix. All rights reserved.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,7 +26,7 @@ var albumID = uuidType.fromString("d0050623-18e5-46c9-9298-9a567990cd7c");
 
 var pmSubscriptionInfo = executor.getContextAlbum("PMSubscriptionAlbum").get(albumID.toString());
 
-var responseStatus = executor.subject.getOutFieldSchemaHelper("status").createNewInstance();
+var responseStatus = executor.subject.getOutFieldSchemaHelper("CDSResponseStatusEvent", "status").createNewInstance();
 
 responseStatus.put("subscriptionName", pmSubscriptionInfo.get("subscription").get("subscriptionName"))
 responseStatus.put("nfName", pmSubscriptionInfo.get("nfName"))
@@ -39,6 +40,12 @@ if ("failure".equals(response.get("create_DasH_subscription_DasH_response").get(
     responseStatus.put("message", "success")
 }
 
-executor.outFields.put("status", responseStatus)
+var cdsResponseEventFields = java.util.HashMap();
+cdsResponseEventFields.put("status", responseStatus);
+executor.addFieldsToOutput(cdsResponseEventFields);
 
+var logEventFields = java.util.HashMap();
+logEventFields.put("final_status", "FINAL_SUCCESS");
+logEventFields.put("message", "Operation successfully completed.");
+executor.addFieldsToOutput(logEventFields);
 true;
index b0cbcb7..636c74b 100644 (file)
@@ -1,6 +1,7 @@
 #-------------------------------------------------------------------------------
 # ============LICENSE_START=======================================================
 #  Copyright (C) 2020 Nordix Foundation.
+#  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -111,69 +112,46 @@ event parameter create name=CDSResponseEvent parName=payload schemaName=CDSRespo
 event create name=CDSResponseStatusEvent nameSpace=org.onap.policy.apex.onap.pmcontrol source=APEX target=DCAE
 event parameter create name=CDSResponseStatusEvent parName=status schemaName=SubscriptionStatusType
 
+event create name=LogEvent nameSpace=org.onap.policy.apex.onap.pmcontrol source=APEX target=DCAE
+event parameter create name=LogEvent parName=final_status schemaName=SimpleStringType
+event parameter create name=LogEvent parName=message schemaName=SimpleStringType
+
 ##
 ## TASKS
 ##
 
 
 task create name=ReceivePMSubscriptionTask
-task inputfield create name=ReceivePMSubscriptionTask fieldName=subscription schemaName=SubscriptionType
-task inputfield create name=ReceivePMSubscriptionTask fieldName=nfName schemaName=SimpleStringType
-task inputfield create name=ReceivePMSubscriptionTask fieldName=policyName schemaName=SimpleStringType
-task inputfield create name=ReceivePMSubscriptionTask fieldName=changeType schemaName=SimpleStringType
-task inputfield create name=ReceivePMSubscriptionTask fieldName=closedLoopControlName schemaName=SimpleStringType
-task outputfield create name=ReceivePMSubscriptionTask fieldName=albumID schemaName=UUIDType
 task contextref create name=ReceivePMSubscriptionTask albumName=PMSubscriptionAlbum
 task logic create name=ReceivePMSubscriptionTask logicFlavour=JAVASCRIPT logic=LS
 #MACROFILE:"src/main/resources/logic/ReceivePMSubscriptionTask.js"
 LE
 
 task create name=CreateSubscriptionPayloadTask
-task inputfield create name=CreateSubscriptionPayloadTask fieldName=albumID schemaName=UUIDType
-task outputfield create name=CreateSubscriptionPayloadTask fieldName=payload schemaName=CDSCreateSubscriptionPayloadType
-task outputfield create name=CreateSubscriptionPayloadTask fieldName=albumID schemaName=UUIDType
 task contextref create name=CreateSubscriptionPayloadTask albumName=PMSubscriptionAlbum
 task logic create name=CreateSubscriptionPayloadTask logicFlavour=JAVASCRIPT logic=LS
 #MACROFILE:"src/main/resources/logic/CreateSubscriptionPayloadTask.js"
 LE
 
 task create name=DeleteSubscriptionPayloadTask
-task inputfield create name=DeleteSubscriptionPayloadTask fieldName=albumID schemaName=UUIDType
-task outputfield create name=DeleteSubscriptionPayloadTask fieldName=payload schemaName=CDSDeleteSubscriptionPayloadType
-task outputfield create name=DeleteSubscriptionPayloadTask fieldName=albumID schemaName=UUIDType
 task contextref create name=DeleteSubscriptionPayloadTask albumName=PMSubscriptionAlbum
 task logic create name=DeleteSubscriptionPayloadTask logicFlavour=JAVASCRIPT logic=LS
 #MACROFILE:"src/main/resources/logic/DeleteSubscriptionPayloadTask.js"
 LE
 
 task create name=CreateSubscriptionRequestTask
-task inputfield create name=CreateSubscriptionRequestTask fieldName=albumID schemaName=UUIDType
-task inputfield create name=CreateSubscriptionRequestTask fieldName=payload schemaName=CDSCreateSubscriptionPayloadType
-task outputfield create name=CreateSubscriptionRequestTask fieldName=commonHeader schemaName=CDSRequestCommonHeaderType
-task outputfield create name=CreateSubscriptionRequestTask fieldName=actionIdentifiers schemaName=CDSActionIdentifiersType
-task outputfield create name=CreateSubscriptionRequestTask fieldName=payload schemaName=CDSCreateSubscriptionPayloadType
 task contextref create name=CreateSubscriptionRequestTask albumName=PMSubscriptionAlbum
 task logic create name=CreateSubscriptionRequestTask logicFlavour=JAVASCRIPT logic=LS
 #MACROFILE:"src/main/resources/logic/CreateSubscriptionRequestTask.js"
 LE
 
 task create name=DeleteSubscriptionRequestTask
-task inputfield create name=DeleteSubscriptionRequestTask fieldName=albumID schemaName=UUIDType
-task inputfield create name=DeleteSubscriptionRequestTask fieldName=payload schemaName=CDSDeleteSubscriptionPayloadType
-task outputfield create name=DeleteSubscriptionRequestTask fieldName=commonHeader schemaName=CDSRequestCommonHeaderType
-task outputfield create name=DeleteSubscriptionRequestTask fieldName=actionIdentifiers schemaName=CDSActionIdentifiersType
-task outputfield create name=DeleteSubscriptionRequestTask fieldName=payload schemaName=CDSDeleteSubscriptionPayloadType
 task contextref create name=DeleteSubscriptionRequestTask albumName=PMSubscriptionAlbum
 task logic create name=DeleteSubscriptionRequestTask logicFlavour=JAVASCRIPT logic=LS
 #MACROFILE:"src/main/resources/logic/DeleteSubscriptionRequestTask.js"
 LE
 
 task create name=CDSResponseTask
-task inputfield create name=CDSResponseTask fieldName=commonHeader schemaName=CDSResponseCommonHeaderType
-task inputfield create name=CDSResponseTask fieldName=actionIdentifiers schemaName=CDSActionIdentifiersType
-task inputfield create name=CDSResponseTask fieldName=status schemaName=CDSResponseStatusType
-task inputfield create name=CDSResponseTask fieldName=payload schemaName=CDSResponsePayloadType
-task outputfield create name=CDSResponseTask fieldName=status schemaName=SubscriptionStatusType
 task contextref create name=CDSResponseTask albumName=PMSubscriptionAlbum
 task logic create name=CDSResponseTask logicFlavour=JAVASCRIPT logic=LS
 #MACROFILE:"src/main/resources/logic/ResponseTask.js"
@@ -227,6 +205,7 @@ policy create name=CDSResponsePolicy template=Freestyle firstState=CDSResponseSt
 # State CDSResponseState
 policy state create name=CDSResponsePolicy stateName=CDSResponseState triggerName=CDSResponseEvent defaultTaskName=CDSResponseTask
 policy state output create name=CDSResponsePolicy stateName=CDSResponseState outputName=ResponseOutput eventName=CDSResponseStatusEvent
+policy state output create name=CDSResponsePolicy stateName=CDSResponseState outputName=ResponseOutput eventName=LogEvent
 policy state taskref create name=CDSResponsePolicy stateName=CDSResponseState taskName=CDSResponseTask outputType=DIRECT outputName=ResponseOutput
 
 validate
\ No newline at end of file
index 4e88afe..17b99c9 100644 (file)
@@ -68,7 +68,7 @@ public class GrpcTestRestSimEndpoint {
     public Response policyLogRequest(final String jsonString) {
         LOGGER.info("\n*** POLICY LOG ENTRY START ***\n {} \n *** POLICY LOG ENTRY END ***", jsonString);
         synchronized (lock) {
-            loggedOutputEvent = jsonString;
+            loggedOutputEvent += jsonString + "\n";
         }
         return Response.status(200).build();
     }
index 7f799c2..a197432 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2020 Nordix Foundation.
- *  Modifications Copyright (C) 2020 Bell Canada. All rights reserved.
+ *  Modifications Copyright (C) 2020-2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,8 +21,8 @@
 
 package org.onap.policy.apex.examples.grpc;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.awaitility.Awaitility.await;
-import static org.junit.Assert.assertEquals;
 
 import java.nio.file.Files;
 import java.nio.file.Paths;
@@ -85,9 +85,12 @@ public class TestApexGrpcExample {
         Response response = client.target(getLoggedEventUrl).request("application/json").get();
         sim.tearDown();
         String responseEntity = response.readEntity(String.class);
-
         String expectedLoggedOutputEvent = Files
             .readString(Paths.get("src/main/resources/examples/events/APEXgRPC/LogEvent.json")).replaceAll("\r", "");
-        assertEquals(expectedLoggedOutputEvent, responseEntity);
+        String expectedStatusEvent =
+            Files.readString(Paths.get("src/main/resources/examples/events/APEXgRPC/CDSResponseStatusEvent.json"))
+                .replaceAll("\r", "");
+        // Both LogEvent and CDSResponseStatusEvent are generated from the final state in the policy
+        assertThat(responseEntity).contains(expectedStatusEvent + expectedLoggedOutputEvent);
     }
 }
index e663228..5e8d1a5 100644 (file)
@@ -3,6 +3,7 @@
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019 Samsung Electronics Co., Ltd.
  *  Modifications Copyright (C) 2019 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,6 +28,8 @@ import org.onap.policy.apex.model.basicmodel.dao.DaoParameters;
 import org.onap.policy.apex.model.modelapi.ApexApiResult;
 import org.onap.policy.apex.model.modelapi.ApexModel;
 import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * This class is an implementation of a facade on an Apex model for editors of Apex models.
@@ -34,6 +37,13 @@ import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
  * @author Liam Fallon (liam.fallon@ericsson.com)
  */
 public final class ApexModelImpl implements ApexModel {
+
+    private static final String FIELDS_DEPRECATED_WARN_MSG =
+        "inputFields and outputFields are deprecated from Task definition and will be removed. "
+            + "Instead, inputEvent and outputEvents are automatically populated to Tasks based on State definition";
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ApexModelImpl.class);
+
     // The policy model being acted upon
     private AxPolicyModel policyModel = new AxPolicyModel();
 
@@ -436,6 +446,7 @@ public final class ApexModelImpl implements ApexModel {
     @Override
     public ApexApiResult createTaskInputField(final String name, final String version, final String fieldName,
             final String dataTypeName, final String dataTypeVersion, final boolean optional) {
+        LOGGER.warn(FIELDS_DEPRECATED_WARN_MSG);
         return taskFacade.createTaskInputField(name, version, fieldName, dataTypeName, dataTypeVersion, optional);
     }
 
@@ -444,6 +455,7 @@ public final class ApexModelImpl implements ApexModel {
      */
     @Override
     public ApexApiResult listTaskInputField(final String name, final String version, final String fieldName) {
+        LOGGER.warn(FIELDS_DEPRECATED_WARN_MSG);
         return taskFacade.listTaskInputField(name, version, fieldName);
     }
 
@@ -452,6 +464,7 @@ public final class ApexModelImpl implements ApexModel {
      */
     @Override
     public ApexApiResult deleteTaskInputField(final String name, final String version, final String fieldName) {
+        LOGGER.warn(FIELDS_DEPRECATED_WARN_MSG);
         return taskFacade.deleteTaskInputField(name, version, fieldName);
     }
 
@@ -461,6 +474,7 @@ public final class ApexModelImpl implements ApexModel {
     @Override
     public ApexApiResult createTaskOutputField(final String name, final String version, final String fieldName,
             final String dataTypeName, final String dataTypeVersion, final boolean optional) {
+        LOGGER.warn(FIELDS_DEPRECATED_WARN_MSG);
         return taskFacade.createTaskOutputField(name, version, fieldName, dataTypeName, dataTypeVersion, optional);
     }
 
@@ -469,6 +483,7 @@ public final class ApexModelImpl implements ApexModel {
      */
     @Override
     public ApexApiResult listTaskOutputField(final String name, final String version, final String fieldName) {
+        LOGGER.warn(FIELDS_DEPRECATED_WARN_MSG);
         return taskFacade.listTaskOutputField(name, version, fieldName);
     }
 
@@ -477,6 +492,7 @@ public final class ApexModelImpl implements ApexModel {
      */
     @Override
     public ApexApiResult deleteTaskOutputField(final String name, final String version, final String fieldName) {
+        LOGGER.warn(FIELDS_DEPRECATED_WARN_MSG);
         return taskFacade.deleteTaskOutputField(name, version, fieldName);
     }
 
index 0c0a516..9480702 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,6 +26,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.Set;
+import java.util.TreeMap;
 import java.util.TreeSet;
 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
@@ -655,9 +657,11 @@ public class PolicyFacade {
             }
 
             final AxReferenceKey refKey = new AxReferenceKey(state.getKey(), outputName);
-            if (state.getStateOutputs().containsKey(refKey.getLocalName())) {
+            // There can be multipe state outputs only when the current state is the final state
+            if (nextState != null && !AxReferenceKey.getNullKey().getLocalName().equals(nextState)
+                && state.getStateOutputs().containsKey(refKey.getLocalName())) {
                 return new ApexApiResult(ApexApiResult.Result.CONCEPT_EXISTS,
-                        "Output concept " + refKey.getId() + ALREADY_EXISTS);
+                    "Output concept " + refKey.getId() + ALREADY_EXISTS);
             }
 
             final AxEvent event = apexModel.getPolicyModel().getEvents().get(eventName, eventVersion);
@@ -680,13 +684,35 @@ public class PolicyFacade {
                 }
             }
 
-            state.getStateOutputs().put(refKey.getLocalName(), new AxStateOutput(refKey, event.getKey(), nextStateKey));
+            populateStateOuputInfo(nextState, state, refKey, event, nextStateKey);
             return new ApexApiResult();
         } catch (final Exception e) {
             return new ApexApiResult(ApexApiResult.Result.FAILED, e);
         }
     }
 
+    private void populateStateOuputInfo(final String nextState, final AxState state, final AxReferenceKey refKey,
+        final AxEvent event, AxReferenceKey nextStateKey) {
+        // nextState is null. There could be multiple events coming out of the state
+        if ((nextState == null || AxReferenceKey.getNullKey().getLocalName().equals(nextState))
+            && state.getStateOutputs().containsKey(refKey.getLocalName())) {
+            AxStateOutput existingStateOutput = state.getStateOutputs().get(refKey.getLocalName());
+            if (null == existingStateOutput.getOutgoingEventSet()
+                || existingStateOutput.getOutgoingEventSet().isEmpty()) {
+                Set<AxArtifactKey> eventSet = new TreeSet<>();
+                eventSet.add(existingStateOutput.getOutgoingEvent());
+                existingStateOutput.setOutgoingEventSet(eventSet);
+            }
+            existingStateOutput.getOutgoingEventSet().add(event.getKey());
+        } else {
+            AxStateOutput axStateOutput = new AxStateOutput(refKey, event.getKey(), nextStateKey);
+            Set<AxArtifactKey> eventSet = new TreeSet<>();
+            eventSet.add(axStateOutput.getOutgoingEvent());
+            axStateOutput.setOutgoingEventSet(eventSet);
+            state.getStateOutputs().put(refKey.getLocalName(), axStateOutput);
+        }
+    }
+
     /**
      * List policy state outputs.
      *
@@ -1086,15 +1112,36 @@ public class PolicyFacade {
                         ApexApiResult.Result.FAILED, "output type " + builder.getOutputType() + " invalid");
             }
 
-            state
-                .getTaskReferences()
-                .put(task.getKey(), new AxStateTaskReference(refKey, stateTaskOutputType, outputRefKey));
+            // add input and output events to the task based on state definition
+            if (state.getStateOutputs().containsKey(outputRefKey.getLocalName())) {
+                populateIoEventsToTask(state, task, outputRefKey);
+            }
+            state.getTaskReferences().put(task.getKey(),
+                new AxStateTaskReference(refKey, stateTaskOutputType, outputRefKey));
             return new ApexApiResult();
         } catch (final Exception e) {
             return new ApexApiResult(ApexApiResult.Result.FAILED, e);
         }
     }
 
+    private void populateIoEventsToTask(final AxState state, final AxTask task, final AxReferenceKey outputRefKey) {
+        AxEvent triggerEvent = apexModel.getPolicyModel().getEvents().get(state.getTrigger());
+        task.setInputEvent(triggerEvent);
+        Map<String, AxEvent> outputEvents = new TreeMap<>();
+        if (state.getNextStateSet().isEmpty()
+            || state.getNextStateSet().contains(AxReferenceKey.getNullKey().getLocalName())) {
+            state.getStateOutputs().get(outputRefKey.getLocalName()).getOutgoingEventSet()
+                .forEach(outgoingEventKey -> outputEvents.put(outgoingEventKey.getName(),
+                    apexModel.getPolicyModel().getEvents().get(outgoingEventKey)));
+        } else {
+            AxArtifactKey outgoingEventKey =
+                state.getStateOutputs().get(outputRefKey.getLocalName()).getOutgoingEvent();
+            outputEvents.put(outgoingEventKey.getName(),
+                apexModel.getPolicyModel().getEvents().get(outgoingEventKey));
+        }
+        task.setOutputEvents(outputEvents);
+    }
+
     /**
      * List policy state task references.
      *
index d55fbd3..4ee176d 100644 (file)
@@ -3,6 +3,7 @@
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019 Nordix Foundation.
  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -502,9 +503,9 @@ public class AxPolicyModel extends AxModel {
         }
 
         for (final AxStateOutput stateOutput : state.getStateOutputs().values()) {
-            if (events.getEventMap().get(stateOutput.getOutgingEvent()) == null) {
+            if (events.getEventMap().get(stateOutput.getOutgoingEvent()) == null) {
                 result.addValidationMessage(new AxValidationMessage(stateOutput.getKey(), this.getClass(),
-                    ValidationResult.INVALID, "output event " + stateOutput.getOutgingEvent().getId()
+                    ValidationResult.INVALID, "output event " + stateOutput.getOutgoingEvent().getId()
                         + " for state output " + stateOutput.getId() + DOES_NOT_EXIST));
             }
         }
@@ -555,10 +556,10 @@ public class AxPolicyModel extends AxModel {
                 ValidationResult.INVALID, "state output on task reference for task " + task.getId() + " is null"));
 
         } else {
-            final AxEvent usedEvent = events.getEventMap().get(stateOutput.getOutgingEvent());
+            final AxEvent usedEvent = events.getEventMap().get(stateOutput.getOutgoingEvent());
             if (usedEvent == null) {
                 result.addValidationMessage(new AxValidationMessage(stateOutput.getKey(), this.getClass(),
-                    ValidationResult.INVALID, "output event " + stateOutput.getOutgingEvent().getId()
+                    ValidationResult.INVALID, "output event " + stateOutput.getOutgoingEvent().getId()
                         + " for state output " + stateOutput.getId() + DOES_NOT_EXIST));
             }
 
index 27c1873..1337e24 100644 (file)
@@ -3,6 +3,7 @@
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019 Nordix Foundation.
  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 package org.onap.policy.apex.model.policymodel.concepts;
 
 import java.util.List;
+import java.util.Set;
 import javax.persistence.AttributeOverride;
+import javax.persistence.CollectionTable;
 import javax.persistence.Column;
+import javax.persistence.ElementCollection;
 import javax.persistence.Embedded;
 import javax.persistence.EmbeddedId;
 import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
 import javax.persistence.Table;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.Setter;
 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
 import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
@@ -68,13 +76,15 @@ import org.onap.policy.common.utils.validation.Assertions;
 @XmlAccessorType(XmlAccessType.FIELD)
 @XmlRootElement(name = "apexStateOutput", namespace = "http://www.onap.org/policy/apex-pdp")
 @XmlType(name = "AxStateOutput", namespace = "http://www.onap.org/policy/apex-pdp",
-        propOrder = {"key", "outgoingEvent", "nextState"})
-
+        propOrder = {"key", "outgoingEvent", "outgoingEventSet", "nextState"})
+@Getter
+@Setter
 public class AxStateOutput extends AxConcept {
     private static final long serialVersionUID = 8041771382337655535L;
 
     @EmbeddedId
     @XmlElement(name = "key", required = true)
+    @NonNull
     private AxReferenceKey key;
 
     // @formatter:off
@@ -83,8 +93,17 @@ public class AxStateOutput extends AxConcept {
     @AttributeOverride(name = "version", column = @Column(name = "outgoingEventVersion"))
     @Column(name = "outgoingEvent")
     @XmlElement(required = true)
+    @NonNull
     private AxArtifactKey outgoingEvent;
 
+    @ElementCollection
+    @CollectionTable(joinColumns = {@JoinColumn(name = "stateParentKeyName", referencedColumnName = "parentKeyName"),
+            @JoinColumn(name = "stateParentKeyVersion", referencedColumnName = "parentKeyVersion"),
+            @JoinColumn(name = "stateParentLocalName", referencedColumnName = "parentLocalName"),
+            @JoinColumn(name = "stateLocalName", referencedColumnName = "localName")})
+    @XmlElement(name = "outgoingEventReference", required = false)
+    private Set<AxArtifactKey> outgoingEventSet;
+
     @Embedded
     @AttributeOverride(name = "parentKeyName", column = @Column(name = "nextStateParentKeyName"))
     @AttributeOverride(name = "parentKeyVersion", column = @Column(name = "nextStateParentKeyVersion"))
@@ -92,6 +111,7 @@ public class AxStateOutput extends AxConcept {
     @AttributeOverride(name = "localName", column = @Column(name = "nextStateLocalName"))
     @Column(name = "nextState")
     @XmlElement(required = true)
+    @NonNull
     private AxReferenceKey nextState;
     // @formatter:on
 
@@ -160,14 +180,6 @@ public class AxStateOutput extends AxConcept {
         this.nextState = nextState;
     }
 
-    /**
-     * {@inheritDoc}.
-     */
-    @Override
-    public AxReferenceKey getKey() {
-        return key;
-    }
-
     /**
      * {@inheritDoc}.
      */
@@ -183,54 +195,6 @@ public class AxStateOutput extends AxConcept {
         return keyList;
     }
 
-    /**
-     * Sets the reference key for the state output.
-     *
-     * @param key the reference key for the state output
-     */
-    public void setKey(final AxReferenceKey key) {
-        Assertions.argumentNotNull(key, "key may not be null");
-        this.key = key;
-    }
-
-    /**
-     * Gets the outgoing event emitted on use of this state output.
-     *
-     * @return the outgoing event emitted on use of this state output
-     */
-    public AxArtifactKey getOutgingEvent() {
-        return outgoingEvent;
-    }
-
-    /**
-     * Sets the outgoing event emitted on use of this state output.
-     *
-     * @param outgoingEvent the outgoing event emitted on use of this state output
-     */
-    public void setOutgoingEvent(final AxArtifactKey outgoingEvent) {
-        Assertions.argumentNotNull(outgoingEvent, "outgoingEvent may not be null");
-        this.outgoingEvent = outgoingEvent;
-    }
-
-    /**
-     * Gets the next state to which execution will pass on use of this state output.
-     *
-     * @return the next state to which execution will pass on use of this state output
-     */
-    public AxReferenceKey getNextState() {
-        return nextState;
-    }
-
-    /**
-     * Sets the next state to which execution will pass on use of this state output.
-     *
-     * @param nextState the next state to which execution will pass on use of this state output
-     */
-    public void setNextState(final AxReferenceKey nextState) {
-        Assertions.argumentNotNull(nextState, "nextState may not be null");
-        this.nextState = nextState;
-    }
-
     /**
      * {@inheritDoc}.
      */
index 04b40e4..a30a80a 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019-2021 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,6 +34,7 @@ import javax.persistence.ElementCollection;
 import javax.persistence.EmbeddedId;
 import javax.persistence.Entity;
 import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
 import javax.persistence.OneToMany;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
@@ -42,6 +44,9 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.Setter;
 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
 import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
@@ -50,6 +55,7 @@ import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage;
 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
 import org.onap.policy.apex.model.eventmodel.concepts.AxField;
 import org.onap.policy.apex.model.eventmodel.concepts.AxInputField;
 import org.onap.policy.apex.model.eventmodel.concepts.AxOutputField;
@@ -90,9 +96,13 @@ import org.onap.policy.common.utils.validation.Assertions;
 
 @XmlAccessorType(XmlAccessType.FIELD)
 @XmlRootElement(name = "apexTask", namespace = "http://www.onap.org/policy/apex-pdp")
-@XmlType(name = "AxTask", namespace = "http://www.onap.org/policy/apex-pdp",
-        propOrder = {"key", "inputFields", "outputFields", "taskParameters", "contextAlbumReferenceSet", "taskLogic"})
-
+@XmlType(
+    name = "AxTask",
+    namespace = "http://www.onap.org/policy/apex-pdp",
+    propOrder = {"key", "inputEvent", "outputEvents", "inputFields", "outputFields", "taskParameters",
+        "contextAlbumReferenceSet", "taskLogic"})
+@Getter
+@Setter
 public class AxTask extends AxConcept {
     private static final String DOES_NOT_EQUAL_TASK_KEY = " does not equal task key";
 
@@ -100,8 +110,25 @@ public class AxTask extends AxConcept {
 
     @EmbeddedId
     @XmlElement(name = "key", required = true)
+    @NonNull
     private AxArtifactKey key;
 
+    @OneToOne(cascade = CascadeType.ALL)
+    @JoinTable(
+        name = "INPUT_EVENT_JT",
+        joinColumns = {@JoinColumn(name = "inEventTaskName", referencedColumnName = "name", updatable = false),
+            @JoinColumn(name = "inEventTaskVersion", referencedColumnName = "version", updatable = false)})
+    @XmlElement(name = "inputEvent", required = false)
+    private AxEvent inputEvent;
+
+    @OneToMany(cascade = CascadeType.ALL)
+    @JoinTable(
+        name = "OUTPUT_EVENT_JT",
+        joinColumns = {@JoinColumn(name = "outEventTaskName", referencedColumnName = "name", updatable = false),
+            @JoinColumn(name = "outEventTaskVersion", referencedColumnName = "version", updatable = false)})
+    @XmlElement(name = "outputEvents", required = false)
+    private Map<String, AxEvent> outputEvents;
+
     @OneToMany(cascade = CascadeType.ALL)
     @XmlElement(name = "inputFields", required = true)
     private Map<String, AxInputField> inputFields;
@@ -119,11 +146,13 @@ public class AxTask extends AxConcept {
     @CollectionTable(joinColumns = {@JoinColumn(name = "contextAlbumName", referencedColumnName = "name"),
         @JoinColumn(name = "contextAlbumVersion", referencedColumnName = "version")})
     @XmlElement(name = "contextAlbumReference")
+    @NonNull
     private Set<AxArtifactKey> contextAlbumReferenceSet;
     // @formatter:on
 
     @OneToOne(cascade = CascadeType.ALL)
     @XmlElement(required = true)
+    @NonNull
     private AxTaskLogic taskLogic;
 
     /**
@@ -215,14 +244,6 @@ public class AxTask extends AxConcept {
         }
     }
 
-    /**
-     * {@inheritDoc}.
-     */
-    @Override
-    public AxArtifactKey getKey() {
-        return key;
-    }
-
     /**
      * {@inheritDoc}.
      */
@@ -245,25 +266,6 @@ public class AxTask extends AxConcept {
         return keyList;
     }
 
-    /**
-     * Sets the key of the task.
-     *
-     * @param key the key of the task
-     */
-    public void setKey(final AxArtifactKey key) {
-        Assertions.argumentNotNull(key, "key may not be null");
-        this.key = key;
-    }
-
-    /**
-     * Gets the input fields that the task expects.
-     *
-     * @return the input fields that the task expects
-     */
-    public Map<String, AxInputField> getInputFields() {
-        return inputFields;
-    }
-
     /**
      * Gets the raw input fields that the task expects as a tree map.
      *
@@ -286,16 +288,6 @@ public class AxTask extends AxConcept {
         return inputFieldSet;
     }
 
-    /**
-     * Sets the input fields that the task expects.
-     *
-     * @param inputFields the input fields that the task expects
-     */
-    public void setInputFields(final Map<String, AxInputField> inputFields) {
-        Assertions.argumentNotNull(inputFields, "inputFields may not be null");
-        this.inputFields = inputFields;
-    }
-
     /**
      * Copy the input fields from the given map into the task. This method is used to get a copy of
      * the input fields, which can be useful for unit testing of policies and tasks.
@@ -313,15 +305,6 @@ public class AxTask extends AxConcept {
         }
     }
 
-    /**
-     * Gets the output fields that the task emits.
-     *
-     * @return the output fields that the task emits
-     */
-    public Map<String, AxOutputField> getOutputFields() {
-        return outputFields;
-    }
-
     /**
      * Gets the raw output fields that the task emits as a tree map.
      *
@@ -344,16 +327,6 @@ public class AxTask extends AxConcept {
         return outputFieldSet;
     }
 
-    /**
-     * Sets the output fields that the task emits.
-     *
-     * @param outputFields the output fields that the task emits
-     */
-    public void setOutputFields(final Map<String, AxOutputField> outputFields) {
-        Assertions.argumentNotNull(outputFields, "outputFields may not be null");
-        this.outputFields = outputFields;
-    }
-
     /**
      * Copy the output fields from the given map into the task. This method is used to get a copy of
      * the output fields, which can be useful for unit testing of policies and tasks.
@@ -371,24 +344,6 @@ public class AxTask extends AxConcept {
         }
     }
 
-    /**
-     * Gets the task parameters that are used to initialize tasks of this type.
-     *
-     * @return the task parameters that are used to initialize tasks of this type
-     */
-    public Map<String, AxTaskParameter> getTaskParameters() {
-        return taskParameters;
-    }
-
-    /**
-     * Sets the task parameters that are used to initialize tasks of this type.
-     *
-     * @param taskParameters the task parameters that are used to initialize tasks of this type
-     */
-    public void setTaskParameters(final Map<String, AxTaskParameter> taskParameters) {
-        Assertions.argumentNotNull(taskParameters, "taskParameters may not be null");
-        this.taskParameters = taskParameters;
-    }
 
     /**
      * Gets the context album reference set defines the context that may be used by Task Logic in
@@ -413,25 +368,6 @@ public class AxTask extends AxConcept {
         this.contextAlbumReferenceSet = contextAlbumReferences;
     }
 
-    /**
-     * Gets the task logic that performs the domain specific work of the task.
-     *
-     * @return the task logic that performs the domain specific work of the task
-     */
-    public AxTaskLogic getTaskLogic() {
-        return taskLogic;
-    }
-
-    /**
-     * Sets the task logic that performs the domain specific work of the task.
-     *
-     * @param taskLogic the task logic that performs the domain specific work of the task
-     */
-    public void setTaskLogic(final AxTaskLogic taskLogic) {
-        Assertions.argumentNotNull(taskLogic, "taskLogic may not be null");
-        this.taskLogic = taskLogic;
-    }
-
     /**
      * {@inheritDoc}.
      */
@@ -446,30 +382,12 @@ public class AxTask extends AxConcept {
 
         result = key.validate(result);
 
-        if (inputFields.size() == 0) {
-            result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
-                    "inputFields may not be empty"));
-        } else {
-            for (final Entry<String, AxInputField> inputFieldEntry : inputFields.entrySet()) {
-                result = validateField(inputFieldEntry.getKey(), inputFieldEntry.getValue(), "input", result);
-            }
-        }
-
-        if (outputFields.size() == 0) {
-            result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
-                    "outputFields may not be empty"));
-        } else {
-            for (final Entry<String, AxOutputField> outputFieldEntry : outputFields.entrySet()) {
-                result = validateField(outputFieldEntry.getKey(), outputFieldEntry.getValue(), "input", result);
-            }
-        }
-
         for (final Entry<String, AxTaskParameter> taskParameterEntry : taskParameters.entrySet()) {
-            result = vaildateTaskParameterEntry(taskParameterEntry, result);
+            result = validateTaskParameterEntry(taskParameterEntry, result);
         }
 
         for (final AxArtifactKey contextAlbumReference : contextAlbumReferenceSet) {
-            result = vaildateContextAlbumReference(contextAlbumReference, result);
+            result = validateContextAlbumReference(contextAlbumReference, result);
         }
 
         if (!taskLogic.getKey().getParentArtifactKey().equals(key)) {
@@ -480,32 +398,6 @@ public class AxTask extends AxConcept {
         return taskLogic.validate(result);
     }
 
-    /**
-     * Validate a field.
-     *
-     * @param fieldKey the key of the field to validate
-     * @param field the field to validate
-     * @param direction The direction of the field
-     * @param result The validation result to append to
-     * @return The result of the validation
-     */
-    private AxValidationResult validateField(final String fieldKey, final AxField field, final String direction,
-            AxValidationResult result) {
-        if (field == null) {
-            result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
-                    "null " + direction + " field value found on " + direction + " field " + fieldKey));
-        } else {
-            if (!field.getKey().getParentArtifactKey().equals(key)) {
-                result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
-                        "parent key on " + direction + " field " + fieldKey + DOES_NOT_EQUAL_TASK_KEY));
-            }
-
-            result = field.validate(result);
-        }
-
-        return result;
-    }
-
     /**
      * Validate a task parameter entry.
      *
@@ -513,7 +405,7 @@ public class AxTask extends AxConcept {
      * @param result The validation result to append to
      * @return The result of the validation
      */
-    private AxValidationResult vaildateTaskParameterEntry(final Entry<String, AxTaskParameter> taskParameterEntry,
+    private AxValidationResult validateTaskParameterEntry(final Entry<String, AxTaskParameter> taskParameterEntry,
             AxValidationResult result) {
         if (taskParameterEntry.getValue() == null) {
             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
@@ -537,7 +429,7 @@ public class AxTask extends AxConcept {
      * @param result The validation result to append to
      * @return The result of the validation
      */
-    private AxValidationResult vaildateContextAlbumReference(final AxArtifactKey contextAlbumReference,
+    private AxValidationResult validateContextAlbumReference(final AxArtifactKey contextAlbumReference,
             AxValidationResult result) {
         if (contextAlbumReference.equals(AxArtifactKey.getNullKey())) {
             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
index 4d076cf..3a4c36b 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -137,7 +138,7 @@ public class PolicyAnalyser {
         // Event usage by state
         result.getEventUsage().get(state.getTrigger()).add(state.getKey());
         for (final AxStateOutput stateOutput : state.getStateOutputs().values()) {
-            result.getEventUsage().get(stateOutput.getOutgingEvent()).add(state.getKey());
+            result.getEventUsage().get(stateOutput.getOutgoingEvent()).add(state.getKey());
         }
 
         // State Context Usage
index 86bbf3e..48022e8 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019-2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -335,7 +336,7 @@ public class PolicyModelTest {
         final AxStateOutput so = model.getPolicies().get("policy").getStateMap().get("state").getStateOutputs()
                         .get(savedStateOutputName);
 
-        final AxArtifactKey savedOutEvent = so.getOutgingEvent();
+        final AxArtifactKey savedOutEvent = so.getOutgoingEvent();
         so.setOutgoingEvent(new AxArtifactKey("NonExistantEvent", "0.0.1"));
         result = new AxValidationResult();
         result = model.validate(result);
index 8bd29fc..049783a 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019-2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -53,20 +54,20 @@ public class StateOutputTest {
         final AxArtifactKey eKey = new AxArtifactKey("EventName", "0.0.1");
 
         assertThatThrownBy(() -> so.setKey(null))
-            .hasMessage("key may not be null");
+            .hasMessage("key is marked non-null but is null");
         so.setKey(soKey);
         assertEquals("SOStateParent:0.0.1:SOState:SOName", so.getKey().getId());
         assertEquals("SOStateParent:0.0.1:SOState:SOName", so.getKeys().get(0).getId());
 
         assertThatThrownBy(() -> so.setNextState(null))
-            .hasMessage("nextState may not be null");
+            .hasMessage("nextState is marked non-null but is null");
         so.setNextState(nsKey);
         assertEquals(nsKey, so.getNextState());
 
         assertThatThrownBy(() -> so.setOutgoingEvent(null))
-            .hasMessage("outgoingEvent may not be null");
+            .hasMessage("outgoingEvent is marked non-null but is null");
         so.setOutgoingEvent(eKey);
-        assertEquals(eKey, so.getOutgingEvent());
+        assertEquals(eKey, so.getOutgoingEvent());
 
         AxValidationResult result = new AxValidationResult();
         result = so.validate(result);
index 100adb9..95266ac 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019-2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,6 +27,7 @@ import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import java.util.Map;
 import java.util.TreeMap;
 import java.util.TreeSet;
 import org.junit.Test;
@@ -33,6 +35,7 @@ import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
 import org.onap.policy.apex.model.eventmodel.concepts.AxField;
 import org.onap.policy.apex.model.eventmodel.concepts.AxInputField;
 import org.onap.policy.apex.model.eventmodel.concepts.AxOutputField;
@@ -91,7 +94,8 @@ public class TasksTest {
         assertEquals(ofMap, task.getOutputFields());
         assertTrue(task.getOutputFieldSet().contains(of0));
         assertTrue(task.getRawOutputFields().keySet().contains(of0.getKey().getLocalName()));
-
+        task.setInputEvent(new AxEvent());
+        task.setOutputEvents(Map.of("Event", new AxEvent()));
         final TreeMap<String, AxField> ifDupMap = new TreeMap<>();
         final TreeMap<String, AxField> ofDupMap = new TreeMap<>();
         ifDupMap.put(if1.getKey().getLocalName(), if1);
@@ -131,46 +135,6 @@ public class TasksTest {
         result = task.validate(result);
         assertEquals(ValidationResult.VALID, result.getValidationResult());
 
-        task.setInputFields(ifEmptyMap);
-        result = new AxValidationResult();
-        result = task.validate(result);
-        assertEquals(ValidationResult.INVALID, result.getValidationResult());
-
-        task.setInputFields(ifMap);
-        result = new AxValidationResult();
-        result = task.validate(result);
-        assertEquals(ValidationResult.VALID, result.getValidationResult());
-
-        ifMap.put("NullField", null);
-        result = new AxValidationResult();
-        result = task.validate(result);
-        assertEquals(ValidationResult.INVALID, result.getValidationResult());
-
-        ifMap.remove("NullField");
-        result = new AxValidationResult();
-        result = task.validate(result);
-        assertEquals(ValidationResult.VALID, result.getValidationResult());
-
-        task.setOutputFields(ofEmptyMap);
-        result = new AxValidationResult();
-        result = task.validate(result);
-        assertEquals(ValidationResult.INVALID, result.getValidationResult());
-
-        task.setOutputFields(ofMap);
-        result = new AxValidationResult();
-        result = task.validate(result);
-        assertEquals(ValidationResult.VALID, result.getValidationResult());
-
-        ofMap.put("NullField", null);
-        result = new AxValidationResult();
-        result = task.validate(result);
-        assertEquals(ValidationResult.INVALID, result.getValidationResult());
-
-        ofMap.remove("NullField");
-        result = new AxValidationResult();
-        result = task.validate(result);
-        assertEquals(ValidationResult.VALID, result.getValidationResult());
-
         // Empty task parameter map is OK
         task.setTaskParameters(tpEmptyMap);
         result = new AxValidationResult();
index 3fca397..ea2de86 100644 (file)
@@ -1,25 +1,27 @@
 /*-
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- * 
+ *
  * SPDX-License-Identifier: Apache-2.0
  * ============LICENSE_END=========================================================
  */
 
 package org.onap.policy.apex.model.policymodel.handling;
 
+import java.util.Map;
 import java.util.UUID;
 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
 import org.onap.policy.apex.model.basicmodel.concepts.AxKeyInfo;
@@ -52,7 +54,7 @@ import org.onap.policy.apex.model.policymodel.concepts.AxTasks;
 
 /**
  * Model creator for model tests.
- * 
+ *
  * @author Liam Fallon (liam.fallon@ericsson.com)
  */
 public class SupportApexPolicyModelCreator implements TestApexModelCreator<AxPolicyModel> {
@@ -136,6 +138,9 @@ public class SupportApexPolicyModelCreator implements TestApexModelCreator<AxPol
             task.getOutputFields().put(outputField.getKey().getLocalName(), outputField);
         }
 
+        task.setInputEvent(inEvent);
+        task.setOutputEvents(Map.of(outEvent0.getId(), outEvent0, outEvent1.getId(), outEvent1));
+
         final AxTaskParameter taskPar0 = new AxTaskParameter(new AxReferenceKey(task.getKey(), "taskParameter0"),
                         "Task parameter 0 value");
         final AxTaskParameter taskPar1 = new AxTaskParameter(new AxReferenceKey(task.getKey(), "taskParameter1"),
@@ -206,7 +211,7 @@ public class SupportApexPolicyModelCreator implements TestApexModelCreator<AxPol
 
     /**
      * Gets another policy model.
-     * 
+     *
      * @return the model
      */
     public AxPolicyModel getAnotherModel() {
@@ -287,6 +292,9 @@ public class SupportApexPolicyModelCreator implements TestApexModelCreator<AxPol
             task.getOutputFields().put(outputField.getKey().getLocalName(), outputField);
         }
 
+        task.setInputEvent(inEvent);
+        task.setOutputEvents(Map.of(outEvent0.getId(), outEvent0, outEvent1.getId(), outEvent1));
+
         final AxTaskParameter taskPar0 = new AxTaskParameter(new AxReferenceKey(task.getKey(), "taskParameterA0"),
                         "Task parameter 0 value");
         final AxTaskParameter taskPar1 = new AxTaskParameter(new AxReferenceKey(task.getKey(), "taskParameterA1"),
@@ -406,6 +414,8 @@ public class SupportApexPolicyModelCreator implements TestApexModelCreator<AxPol
             anotherTask.getOutputFields().put(outputField.getKey().getLocalName(), outputField);
         }
 
+        anotherTask.setInputEvent(inEvent);
+        anotherTask.setOutputEvents(Map.of(outEvent0.getId(), outEvent0));
         final AxTaskParameter taskPar0 = new AxTaskParameter(new AxReferenceKey(anotherTask.getKey(), "taskParameter0"),
                         "Task parameter 0 value");
         final AxTaskParameter taskPar1 = new AxTaskParameter(new AxReferenceKey(anotherTask.getKey(), "taskParameter1"),
index 2ccddcf..736249e 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -76,7 +77,7 @@ public class JavaTaskExecutor extends TaskExecutor {
      * @throws ContextException on context errors
      */
     @Override
-    public Map<String, Object> execute(final long executionId, final Properties executionProperties,
+    public Map<String, Map<String, Object>> execute(final long executionId, final Properties executionProperties,
             final Map<String, Object> incomingFields) throws StateMachineException, ContextException {
         // Do execution pre work
         executePre(executionId, executionProperties, incomingFields);
index 7f26324..96bc6bb 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2020 Nordix Foundation
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -28,6 +29,7 @@ import static org.junit.Assert.assertNotNull;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
+import java.util.TreeMap;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -38,6 +40,7 @@ import org.onap.policy.apex.context.parameters.LockManagerParameters;
 import org.onap.policy.apex.context.parameters.PersistorParameters;
 import org.onap.policy.apex.core.engine.context.ApexInternalContext;
 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
 import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
 import org.onap.policy.apex.model.policymodel.concepts.AxTask;
 import org.onap.policy.common.parameters.ParameterService;
@@ -83,7 +86,8 @@ public class JavaTaskExecutorTest {
         assertThatThrownBy(jte::prepare)
             .hasMessage("instantiation error on Java class \"\"");
         task.getTaskLogic().setLogic("java.lang.String");
-
+        task.setInputEvent(new AxEvent());
+        task.setOutputEvents(new TreeMap<>());
         jte.prepare();
 
         assertThatThrownBy(() -> jte.execute(-1, new Properties(), null))
@@ -96,7 +100,7 @@ public class JavaTaskExecutorTest {
         assertThatThrownBy(() -> jte.execute(-1, new Properties(), incomingParameters))
             .hasMessage("execute-post: task logic execution failure on task \"NULL\" in model NULL:0.0.0");
         jte.prepare();
-        Map<String, Object> returnMap = jte.execute(0, new Properties(), incomingParameters);
+        Map<String, Map<String, Object>> returnMap = jte.execute(0, new Properties(), incomingParameters);
         assertEquals(0, returnMap.size());
         jte.cleanUp();
 
index a25dca0..f88e3ef 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019-2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -66,7 +67,7 @@ public class JavascriptTaskExecutor extends TaskExecutor {
      * @throws ContextException on context errors
      */
     @Override
-    public Map<String, Object> execute(final long executionId, final Properties executionProperties,
+    public Map<String, Map<String, Object>> execute(final long executionId, final Properties executionProperties,
             final Map<String, Object> incomingFields) throws StateMachineException, ContextException {
         executePre(executionId, executionProperties, incomingFields);
         boolean result = javascriptExecutor.execute(getExecutionContext());
index 991c89b..fbf7db8 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2019-2020 Nordix Foundation.
  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,6 +30,7 @@ import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Properties;
+import java.util.TreeMap;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -47,6 +49,8 @@ import org.onap.policy.apex.model.basicmodel.service.ModelService;
 import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema;
 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchemas;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
+import org.onap.policy.apex.model.eventmodel.concepts.AxField;
 import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
 import org.onap.policy.apex.model.policymodel.concepts.AxTask;
 import org.onap.policy.common.parameters.ParameterService;
@@ -123,7 +127,8 @@ public class JavascriptTaskExecutorTest {
             jte.execute(-1, props, null);
         }).isInstanceOf(NullPointerException.class);
         jte.cleanUp();
-
+        task.setInputEvent(new AxEvent());
+        task.setOutputEvents(new TreeMap<>());
         task.getTaskLogic().setLogic("var returnValue = false;\nreturnValue;");
 
         Map<String, Object> incomingParameters = new HashMap<>();
@@ -138,13 +143,14 @@ public class JavascriptTaskExecutorTest {
         task.getTaskLogic().setLogic("var returnValue = true;\nreturnValue;");
 
         jte.prepare();
-        Map<String, Object> returnMap = jte.execute(0, new Properties(), incomingParameters);
+        Map<String, Map<String, Object>> returnMap = jte.execute(0, new Properties(), incomingParameters);
         assertEquals(0, returnMap.size());
         jte.cleanUp();
     }
 
     @Test
     public void testJavascriptTaskExecutorLogic() throws Exception {
+
         JavascriptTaskExecutor jte = new JavascriptTaskExecutor();
         assertNotNull(jte);
 
@@ -160,16 +166,25 @@ public class JavascriptTaskExecutorTest {
         internalContext.getContextAlbums().put(contextAlbum.getKey(), contextAlbum);
 
         task.getContextAlbumReferences().add(contextAlbum.getKey());
-        task.getOutputFields().put("par0", null);
-        task.getOutputFields().put("par1", null);
+        String parKey0 = "par0";
+        task.getOutputFields().put(parKey0, null);
+        String parKey1 = "par1";
+        task.getOutputFields().put(parKey1, null);
 
         jte.setContext(null, task, internalContext);
 
         Map<String, Object> incomingParameters = new HashMap<>();
-        incomingParameters.put("par0", "value0");
+        incomingParameters.put(parKey0, "value0");
 
-        task.getTaskLogic().setLogic(TextFileUtils.getTextFileAsString("src/test/resources/javascript/TestLogic00.js"));
+        AxEvent inEvent = new AxEvent();
+        inEvent.setParameterMap(Map.of(parKey0, new AxField()));
+        task.setInputEvent(inEvent);
+        AxEvent outEvent = new AxEvent();
+        outEvent.setParameterMap(Map.of(parKey0, new AxField(), parKey1, new AxField()));
+        final String eventName = "event1";
+        task.setOutputEvents(Map.of(eventName, outEvent));
 
+        task.getTaskLogic().setLogic(TextFileUtils.getTextFileAsString("src/test/resources/javascript/TestLogic00.js"));
         jte.prepare();
         jte.execute(-1, new Properties(), incomingParameters);
         jte.cleanUp();
@@ -177,11 +192,11 @@ public class JavascriptTaskExecutorTest {
         task.getTaskLogic().setLogic(TextFileUtils.getTextFileAsString("src/test/resources/javascript/TestLogic01.js"));
         jte.prepare();
 
-        Map<String, Object> outcomingParameters = jte.execute(-1, new Properties(), incomingParameters);
+        Map<String, Map<String, Object>> outcomingParameters = jte.execute(-1, new Properties(), incomingParameters);
         jte.cleanUp();
 
-        assertEquals("returnVal0", outcomingParameters.get("par0"));
-        assertEquals("returnVal1", outcomingParameters.get("par1"));
+        assertEquals("returnVal0", outcomingParameters.get(eventName).get(parKey0));
+        assertEquals("returnVal1", outcomingParameters.get(eventName).get(parKey1));
     }
 
     private ContextAlbum createTestContextAlbum() throws ContextException {
index 02504c6..aa57004 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -80,7 +81,7 @@ public class JrubyTaskExecutor extends TaskExecutor {
      * @throws ContextException on context errors
      */
     @Override
-    public Map<String, Object> execute(final long executionId, final Properties executionProperties,
+    public Map<String, Map<String, Object>> execute(final long executionId, final Properties executionProperties,
                     final Map<String, Object> incomingFields) throws StateMachineException, ContextException {
         // Do execution pre work
         executePre(executionId, executionProperties, incomingFields);
index e2785d8..0cc4764 100644 (file)
@@ -1,7 +1,7 @@
 /*-\r
  * ============LICENSE_START=======================================================\r
- *  Copyright (C) 2019 Nordix Foundation.\r
- *  Modifications Copyright (C) 2019-2020 Nordix Foundation.\r
+ *  Copyright (C) 2019-2020 Nordix Foundation.\r
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.\r
  * ================================================================================\r
  * Licensed under the Apache License, Version 2.0 (the "License");\r
  * you may not use this file except in compliance with the License.\r
@@ -29,6 +29,7 @@ import java.lang.reflect.Field;
 import java.util.HashMap;\r
 import java.util.Map;\r
 import java.util.Properties;\r
+import java.util.TreeMap;\r
 import org.junit.After;\r
 import org.junit.Before;\r
 import org.junit.Test;\r
@@ -39,6 +40,7 @@ import org.onap.policy.apex.context.parameters.LockManagerParameters;
 import org.onap.policy.apex.context.parameters.PersistorParameters;\r
 import org.onap.policy.apex.core.engine.context.ApexInternalContext;\r
 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;\r
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;\r
 import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;\r
 import org.onap.policy.apex.model.policymodel.concepts.AxTask;\r
 import org.onap.policy.common.parameters.ParameterService;\r
@@ -91,7 +93,8 @@ public class JrubyTaskExecutorTest {
         AxTask task = new AxTask();\r
         ApexInternalContext internalContext = null;\r
         internalContext = new ApexInternalContext(new AxPolicyModel());\r
-\r
+        task.setInputEvent(new AxEvent());\r
+        task.setOutputEvents(new TreeMap<>());\r
         jte.setContext(null, task, internalContext);\r
 \r
         jte.prepare();\r
@@ -102,14 +105,13 @@ public class JrubyTaskExecutorTest {
         final String jrubyLogic = "if executor.executionId == -1" + "\n return false" + "\n else " + "\n return true"\r
                         + "\n end";\r
         task.getTaskLogic().setLogic(jrubyLogic);\r
-\r
         jte.prepare();\r
-        Map<String, Object> returnMap = jte.execute(0, new Properties(), incomingParameters);\r
+        Map<String, Map<String, Object>> returnMap = jte.execute(0, new Properties(), incomingParameters);\r
         assertEquals(0, returnMap.size());\r
         jte.cleanUp();\r
 \r
         jte.prepare();\r
-        Map<String, Object> returnMap1 = jte.execute(0, new Properties(), incomingParameters);\r
+        Map<String, Map<String, Object>> returnMap1 = jte.execute(0, new Properties(), incomingParameters);\r
         assertEquals(0, returnMap1.size());\r
         jte.cleanUp();\r
     }\r
index 179462b..07a287f 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -77,7 +78,7 @@ public class MvelTaskExecutor extends TaskExecutor {
      * @throws ContextException on context errors
      */
     @Override
-    public Map<String, Object> execute(final long executionId, final Properties executionProperties,
+    public Map<String, Map<String, Object>> execute(final long executionId, final Properties executionProperties,
             final Map<String, Object> incomingFields) throws StateMachineException, ContextException {
         // Do execution pre work
         executePre(executionId, executionProperties, incomingFields);
index a4d2cbf..3d59c4b 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2019 Nordix Foundation.
  *  Modifications Copyright (C) 2020 Nordix Foundation
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -28,6 +29,7 @@ import static org.junit.Assert.assertNotNull;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
+import java.util.TreeMap;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -38,6 +40,7 @@ import org.onap.policy.apex.context.parameters.LockManagerParameters;
 import org.onap.policy.apex.context.parameters.PersistorParameters;
 import org.onap.policy.apex.core.engine.context.ApexInternalContext;
 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
+import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
 import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
 import org.onap.policy.apex.model.policymodel.concepts.AxTask;
 import org.onap.policy.common.parameters.ParameterService;
@@ -77,6 +80,8 @@ public class MvelTaskExecutorTest {
         AxTask task = new AxTask();
         ApexInternalContext internalContext = null;
         internalContext = new ApexInternalContext(new AxPolicyModel());
+        task.setInputEvent(new AxEvent());
+        task.setOutputEvents(new TreeMap<>());
         mte.setContext(null, task, internalContext);
 
         task.getTaskLogic().setLogic("x > 1 2 ()");
@@ -97,7 +102,7 @@ public class MvelTaskExecutorTest {
             .hasMessage("execute-post: task logic execution failure on task \"NULL\" in model NULL:0.0.0");
 
         mte.prepare();
-        Map<String, Object> returnMap = mte.execute(0, new Properties(), incomingParameters);
+        Map<String, Map<String, Object>> returnMap = mte.execute(0, new Properties(), incomingParameters);
         assertEquals(0, returnMap.size());
         mte.cleanUp();
     }
index fb2dea5..56f0af5 100644 (file)
@@ -1,6 +1,7 @@
 /*-
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2018 Ericsson. All rights reserved.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -43,11 +44,11 @@ public class DummyTaskExecutor extends TaskExecutor {
     }
 
     @Override
-    public Map<String, Object> execute(final long executionId, final Properties executorProperties,
+    public Map<String, Map<String, Object>> execute(final long executionId, final Properties executorProperties,
             final Map<String, Object> newIncomingFields) throws StateMachineException, ContextException {
 
         AxArtifactKey event0Key = new AxArtifactKey("Event0:0.0.1");
-        return new EnEvent(event0Key);
+        return Map.of(event0Key.getName(), new EnEvent(event0Key));
     }
 
     @Override
index d89fd2e..01f45a5 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -44,11 +45,11 @@ public class DummyTaskExecutor extends TaskExecutor {
     }
 
     @Override
-    public Map<String, Object> execute(final long executionId, final Properties executorProperties,
+    public Map<String, Map<String, Object>> execute(final long executionId, final Properties executorProperties,
             final Map<String, Object> newIncomingFields) throws StateMachineException, ContextException {
 
         AxArtifactKey event0Key = new AxArtifactKey("Event0:0.0.1");
-        return new EnEvent(event0Key);
+        return Map.of(event0Key.getName(), new EnEvent(event0Key));
     }
 
     @Override
index 321f649..81d8977 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2019 Samsung Electronics Co., Ltd.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -490,7 +491,7 @@ public class Model2Cli {
             final AxReferenceKey outkey = out.getKey();
 
             final ST val = cg.createPolicyStateOutput(kig.getPName(skey), kig.getPVersion(skey), kig.getLName(skey),
-                    kig.getLName(outkey), kig.getName(out.getOutgingEvent()), kig.getVersion(out.getOutgingEvent()),
+                    kig.getLName(outkey), kig.getName(out.getOutgoingEvent()), kig.getVersion(out.getOutgoingEvent()),
                     kig.getLName(out.getNextState()));
 
             ret.add(val);
index e48c233..ad0f3b6 100644 (file)
@@ -2,6 +2,7 @@
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
  *  Modifications Copyright (C) 2021 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -307,7 +308,7 @@ public class Model2JsonEventSchema {
         for (final AxState state : policy.getStateMap().values()) {
             if ("NULL".equals(state.getNextStateSet().iterator().next())) {
                 for (final AxStateOutput output : state.getStateOutputs().values()) {
-                    eventKeys.add(output.getOutgingEvent());
+                    eventKeys.add(output.getOutgoingEvent());
                 }
             }
         }
@@ -342,7 +343,7 @@ public class Model2JsonEventSchema {
             return;
         }
         for (final AxStateOutput output : state.getStateOutputs().values()) {
-            eventKeys.add(output.getOutgingEvent());
+            eventKeys.add(output.getOutgoingEvent());
         }
     }