added svcapi ui and camunda code
[it/otf.git] / otf-camunda / src / main / java / org / oran / otf / camunda / workflow / utility / WorkflowUtility.java
1 /*  Copyright (c) 2019 AT&T Intellectual Property.                             #\r
2 #                                                                              #\r
3 #   Licensed under the Apache License, Version 2.0 (the "License");            #\r
4 #   you may not use this file except in compliance with the License.           #\r
5 #   You may obtain a copy of the License at                                    #\r
6 #                                                                              #\r
7 #       http://www.apache.org/licenses/LICENSE-2.0                             #\r
8 #                                                                              #\r
9 #   Unless required by applicable law or agreed to in writing, software        #\r
10 #   distributed under the License is distributed on an "AS IS" BASIS,          #\r
11 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #\r
12 #   See the License for the specific language governing permissions and        #\r
13 #   limitations under the License.                                             #\r
14 ##############################################################################*/\r
15 \r
16 \r
17 package org.oran.otf.camunda.workflow.utility;\r
18 \r
19 import static org.camunda.spin.Spin.JSON;\r
20 \r
21 import org.oran.otf.camunda.exception.TestExecutionException;\r
22 import org.oran.otf.camunda.model.ExecutionConstants;\r
23 import org.oran.otf.camunda.model.ExecutionConstants.ExecutionVariable;\r
24 import org.oran.otf.common.model.TestExecution;\r
25 import org.oran.otf.common.model.local.ParallelFlowInput;\r
26 import org.oran.otf.common.utility.Utility;\r
27 import java.util.ArrayList;\r
28 import java.util.HashMap;\r
29 import java.util.List;\r
30 import java.util.Map;\r
31 import org.bson.types.ObjectId;\r
32 import org.camunda.bpm.engine.delegate.DelegateExecution;\r
33 import org.camunda.spin.json.SpinJsonNode;\r
34 import org.slf4j.Logger;\r
35 import org.slf4j.LoggerFactory;\r
36 import org.springframework.beans.factory.annotation.Autowired;\r
37 import org.springframework.stereotype.Service;\r
38 \r
39 @Service\r
40 public class WorkflowUtility {\r
41 \r
42   private static Logger logger = LoggerFactory.getLogger(WorkflowUtility.class);\r
43   @Autowired\r
44   private RsaEncryptDecrypt rsaUtility;\r
45 \r
46   public boolean verifyTestExecutionChecksum(\r
47       DelegateExecution execution, TestExecution testExecution) {\r
48     try {\r
49       byte[] enc = (byte[]) execution.getVariable(ExecutionVariable.TEST_EXECUTION);\r
50 \r
51       String test = ""; // testExecution.createTestDescription();\r
52       String dec = new String(rsaUtility.decrypt(enc));\r
53       if (!dec.equals(test)) {\r
54         return false;\r
55         // throw new TestExecutionException("Modification Error: User modified platform data");\r
56       }\r
57     } catch (Exception e) {\r
58       logger.error(\r
59           execution.getCurrentActivityId()\r
60               + ": Failed to decrypt test execution. May have been tampered with.\n"\r
61               + e.getMessage());\r
62       return false;\r
63     }\r
64     return true;\r
65   }\r
66 \r
67   public <T> T getExecutionVariable(Map<String, Object> variables, String key, Class<T> type) {\r
68     Object obj = variables.get(key);\r
69     if (obj == null) {\r
70       logger.error(String.format("Failed to get variable because the key %s does not exist.", key));\r
71     }\r
72     // return spin json nodes as maps\r
73     if (obj instanceof SpinJsonNode) {\r
74       SpinJsonNode node = (SpinJsonNode) obj;\r
75       if (!node.isObject()) {\r
76         throw new TestExecutionException(\r
77             "Unable to retrieve variable as type Map from the execution. Variable was set to SpinJsonNode");\r
78       }\r
79       Map<String, Object> map = (Map<String, Object>) node.mapTo(HashMap.class);\r
80     }\r
81 \r
82     return type.isInstance(obj) ? type.cast(obj) : null;\r
83   }\r
84 \r
85 //  public boolean hasPermission(User user, TestInstance testInstance) {\r
86 //    // Groups that the user holds a membership in.\r
87 //    List<UserGroup> userGroups = user.getGroups();\r
88 //    // The groupId associated with the test instance.\r
89 //    ObjectId targetGroupId = testInstance.getGroupId();\r
90 //    // Check if any of the groups has access to the test instance.\r
91 //    UserGroup targetGroup =\r
92 //        userGroups.stream()\r
93 //            .filter(userGroup -> userGroup.getGroupId().equals(targetGroupId))\r
94 //            .findAny()\r
95 //            .orElse(null);\r
96 //\r
97 //    return targetGroup != null;\r
98 //  }\r
99 \r
100   public TestExecution getTestExecution(Map<String, Object> variables, String logPrefix)\r
101       throws TestExecutionException {\r
102     // Get the current test execution object.\r
103     TestExecution testExecution =\r
104         this.getExecutionVariable(variables, ExecutionVariable.TEST_EXECUTION, TestExecution.class);\r
105     // Perform a null-check to ensure it is available. It's critical to throw an exception if it\r
106     // is not available since the object is essential for results.\r
107     if (testExecution == null) {\r
108       logger.error(logPrefix + " Test execution is null.");\r
109       throw new TestExecutionException("The test execution was not found.");\r
110     }\r
111     return testExecution;\r
112   }\r
113 \r
114   public Map<String, Object> getTestData(Map<String, Object> variables, String logPrefix)\r
115       throws TestExecutionException {\r
116     // Get vthInput from the Camunda execution variable map.\r
117     @SuppressWarnings({"unchecked"})\r
118     Map<String, Object> testData =\r
119         (Map<String, Object>)\r
120             this.getExecutionVariable(variables, ExecutionVariable.TEST_DATA, Map.class);\r
121 \r
122     if (testData == null) {\r
123       throw new TestExecutionException(\r
124           "Unable to retrieve testData as type Map from the execution.");\r
125     }\r
126     return testData;\r
127   }\r
128 \r
129   public Object getTestDataByActivity(\r
130       Map<String, Object> variables, String currentActivityId, String logPrefix)\r
131       throws TestExecutionException, NullPointerException {\r
132     // Get vthInput from the Camunda execution variable map.\r
133     @SuppressWarnings({"unchecked"})\r
134     Map<String, Object> testData =\r
135         (Map<String, Object>)\r
136             this.getExecutionVariable(variables, ExecutionVariable.TEST_DATA, Map.class);\r
137 \r
138     if (testData == null) {\r
139       throw new TestExecutionException(\r
140           "Unable to retrieve testData as type Map from the execution.");\r
141     }\r
142     Object activityParameters = testData.get(currentActivityId);\r
143     if (activityParameters == null) {\r
144       throw new NullPointerException(\r
145           logPrefix\r
146               + String.format(\r
147               "A testData parameter was not found for the activityId, %s.", currentActivityId));\r
148     }\r
149     return activityParameters;\r
150   }\r
151 \r
152 \r
153   public Map<String, ParallelFlowInput> getPfloInputByActivity(\r
154       Map<String, Object> variables, String currentActivityId, String logPrefix)\r
155       throws TestExecutionException, NullPointerException {\r
156     // Get vthInput from the Camunda execution variable map.\r
157     @SuppressWarnings({"unchecked"})\r
158     Map<String, Object> pfloInput =\r
159         (Map<String, Object>)\r
160             this.getExecutionVariable(variables, ExecutionVariable.PFLO_INPUT, Map.class);\r
161 \r
162     if (pfloInput == null) {\r
163       throw new TestExecutionException(\r
164           "Unable to retrieve testData as type Map from the execution.");\r
165     }\r
166     Map<String, ParallelFlowInput> activityParameters =\r
167         (Map<String, ParallelFlowInput>) pfloInput.get(currentActivityId);\r
168     if (activityParameters == null) {\r
169       throw new NullPointerException(\r
170           logPrefix\r
171               + String.format(\r
172               "A plfoInput parameter was not found for the activityId, %s.",\r
173               currentActivityId));\r
174     }\r
175     return activityParameters;\r
176   }\r
177 \r
178   public List<Map<String, Object>> getVthInput(\r
179       Map<String, Object> variables, String currentActivityId, String logPrefix)\r
180       throws TestExecutionException, NullPointerException, IllegalArgumentException {\r
181     // Get vthInput from the Camunda execution variable map.\r
182     @SuppressWarnings({"unchecked"})\r
183     Map<String, Object> vthInput =\r
184         (Map<String, Object>)\r
185             this.getExecutionVariable(variables, ExecutionVariable.VTH_INPUT, Map.class);\r
186 \r
187     if (vthInput == null) {\r
188       throw new TestExecutionException(\r
189           "Unable to retrieve vthInput as type Map from the execution.");\r
190     }\r
191 \r
192     // Get the current activityId to use as a key to retrieve the vthInput for this task.\r
193     // vthInput is expected to be a JSON array of size [1, inf)\r
194     Object oActivityParameters = vthInput.get(currentActivityId);\r
195     // Throw an exception if no parameters were found for this activity.\r
196     if (oActivityParameters == null) {\r
197       throw new NullPointerException(\r
198           logPrefix\r
199               + String.format(\r
200               "A vthInput parameter was not found for the activityId, %s.", currentActivityId));\r
201     }\r
202 \r
203     List<Map<String, Object>> lActivityParameters;\r
204     // Legacy hack\r
205     try {\r
206       @SuppressWarnings("unchecked")\r
207       Map<String, Object> mActivityParameters = new HashMap<>();\r
208       mActivityParameters.put("method", "post");\r
209       mActivityParameters.put("payload", Utility.toMap(oActivityParameters));\r
210       Map<String, Object> headers = new HashMap<>();\r
211       headers.put("Content-Type", "application/json");\r
212       mActivityParameters.put("headers", headers);\r
213       lActivityParameters = new ArrayList();\r
214       lActivityParameters.add(mActivityParameters);\r
215     } catch (Exception e) {\r
216       try {\r
217         // Try to convert the parameters to an array of "vthInput(s)"\r
218         lActivityParameters = (List<Map<String, Object>>) Utility.toList(oActivityParameters);\r
219       } catch (Exception ee) {\r
220         throw new IllegalArgumentException(\r
221             String.format("Unable to parse the value for vthInput[%s].", currentActivityId));\r
222       }\r
223     }\r
224     return lActivityParameters;\r
225   }\r
226 \r
227   public String getTestResult(Map<String, Object> variables, String logPrefix) {\r
228     String testResult =\r
229         this.getExecutionVariable(variables, ExecutionVariable.TEST_RESULT, String.class);\r
230     // Set the test result to UNKNOWN\r
231     if (testResult == null) {\r
232       logger.debug(\r
233           logPrefix\r
234               + "Unable to retrieve test result as primitive type String. Setting result to unknown.");\r
235       testResult = ExecutionConstants.TestResult.UNKNOWN;\r
236     }\r
237     return testResult;\r
238   }\r
239 \r
240   public String getTestResultMessage(Map<String, Object> variables, String logPrefix) {\r
241     String testResultMessage =\r
242             this.getExecutionVariable(variables, ExecutionVariable.TEST_RESULT_MESSAGE, String.class);\r
243     // Set the test result to UNKNOWN\r
244     if (testResultMessage == null) {\r
245       testResultMessage = "";\r
246 //      logger.debug(\r
247 //              logPrefix\r
248 //                      + "Unable to retrieve test result message as primitive type String. Setting message to empty string.");\r
249 //      testResultMessage = "";\r
250     }\r
251     return testResultMessage;\r
252   }\r
253 \r
254   public Map<String, Object> getTestDetails(Map<String, Object> variables, String logPrefix)\r
255       throws TestExecutionException {\r
256     // Get test details as a String because it can be saved as one of many "JSON" types. Then try\r
257     // to convert it to a generic map.\r
258     String testDetailsString =\r
259         this.getExecutionVariable(variables, ExecutionVariable.TEST_DETAILS, String.class);\r
260     if (testDetailsString != null) {\r
261       // Use Spin to map the string to a Map.\r
262       @SuppressWarnings({"unchecked"})\r
263       Map<String, Object> mTestDetails;\r
264       try {\r
265         mTestDetails = JSON(testDetailsString).mapTo(HashMap.class);\r
266       } catch (Exception e) {\r
267         logger.error(\r
268             "Unable to convert testDetails to a map.\nError: "\r
269                 + e.getMessage()\r
270                 + "\ntestDetails: "\r
271                 + testDetailsString);\r
272         mTestDetails = new HashMap<>();\r
273       }\r
274       return mTestDetails;\r
275     }\r
276 \r
277     // get testDetails as a map.\r
278     @SuppressWarnings({"unchecked"})\r
279     Map<String, Object> testDetails =\r
280         (Map<String, Object>)\r
281             this.getExecutionVariable(variables, ExecutionVariable.TEST_DETAILS, Map.class);\r
282 \r
283     if (testDetails == null) {\r
284       logger.debug(\r
285           logPrefix\r
286               + "Unable to retrieve test details as primitive type String. Setting to an empty JSON.");\r
287       testDetails = new HashMap<>();\r
288     }\r
289     return testDetails;\r
290   }\r
291 }\r