added svcapi ui and camunda code
[it/otf.git] / otf-service-api / src / main / java / org / oran / otf / api / service / impl / TestInstanceServiceImpl.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.api.service.impl;\r
18 \r
19 import org.oran.otf.api.Utilities;\r
20 import org.oran.otf.api.Utilities.LogLevel;\r
21 import org.oran.otf.api.handler.CamundaProcessExecutionHandler;\r
22 import org.oran.otf.api.service.TestInstanceService;\r
23 import org.oran.otf.common.model.Group;\r
24 import org.oran.otf.common.model.TestDefinition;\r
25 import org.oran.otf.common.model.TestInstance;\r
26 import org.oran.otf.common.model.User;\r
27 import org.oran.otf.common.model.local.BpmnInstance;\r
28 import org.oran.otf.common.model.local.TestInstanceCreateRequest;\r
29 import org.oran.otf.common.model.local.WorkflowRequest;\r
30 import org.oran.otf.common.repository.GroupRepository;\r
31 import org.oran.otf.common.repository.TestDefinitionRepository;\r
32 import org.oran.otf.common.repository.TestInstanceRepository;\r
33 import org.oran.otf.common.repository.UserRepository;\r
34 import org.oran.otf.common.utility.Utility;\r
35 import org.oran.otf.common.utility.database.Generic;\r
36 import org.oran.otf.common.utility.http.ResponseUtility;\r
37 import org.oran.otf.common.utility.permissions.PermissionChecker;\r
38 import org.oran.otf.common.utility.permissions.UserPermission;\r
39 import com.google.common.base.Strings;\r
40 import org.bson.types.ObjectId;\r
41 import org.slf4j.Logger;\r
42 import org.slf4j.LoggerFactory;\r
43 import org.springframework.beans.factory.annotation.Autowired;\r
44 import org.springframework.stereotype.Service;\r
45 \r
46 import javax.ws.rs.core.MediaType;\r
47 import javax.ws.rs.core.Response;\r
48 import java.util.*;\r
49 \r
50 @Service\r
51 public class TestInstanceServiceImpl implements TestInstanceService {\r
52     @Autowired\r
53     CamundaProcessExecutionHandler camundaProcessExecutionHandler;\r
54     @Autowired\r
55     UserRepository userRepository;\r
56     @Autowired\r
57     TestInstanceRepository testInstanceRepository;\r
58     @Autowired\r
59     TestDefinitionRepository testDefinitionRepository;\r
60     @Autowired\r
61     GroupRepository groupRepository;\r
62 \r
63     private static final Logger logger = LoggerFactory.getLogger(TestInstanceServiceImpl.class);\r
64     private static final String logPrefix = Utility.getLoggerPrefix();\r
65 \r
66     @Override\r
67     public Response execute(String testInstanceId, String authorization, WorkflowRequest request) {\r
68         try {\r
69             if (request == null) {\r
70                 return ResponseUtility.Build.badRequestWithMessage("Request body is null.");\r
71             }\r
72 \r
73             // Check if the testInstanceId is a valid BSON ObjectI, otherwise return a bad request\r
74             // response.\r
75             if (!Utilities.isObjectIdValid(testInstanceId)) {\r
76                 String error =\r
77                         String.format(\r
78                                 "%sThe testInstanceId, %s, is not a valid ObjectId (BSON).",\r
79                                 logPrefix, testInstanceId);\r
80                 return ResponseUtility.Build.badRequestWithMessage(error);\r
81             }\r
82 \r
83             // Create an ObjectId now that we know the provided String was valid.\r
84             ObjectId oiTestInstanceId = new ObjectId(testInstanceId);\r
85             // Check if the testInstance exists, otherwise return a not found response.\r
86             TestInstance testInstance = Generic.findByIdGeneric(testInstanceRepository, oiTestInstanceId);\r
87             if (testInstance == null) {\r
88                 String error =\r
89                         String.format(\r
90                                 "%sThe testInstance with _id, %s, was not found.", logPrefix, testInstanceId);\r
91                 return ResponseUtility.Build.notFoundWithMessage(error);\r
92             }\r
93             // Check if the testDefinition exists.\r
94             TestDefinition testDefinition =\r
95                     Generic.findByIdGeneric(testDefinitionRepository, testInstance.getTestDefinitionId());\r
96             if (testDefinition == null) {\r
97                 String error =\r
98                         String.format(\r
99                                 "%sThe testDefinition with _id, %s, was not found.",\r
100                                 logPrefix, testInstance.getTestDefinitionId().toString());\r
101                 return ResponseUtility.Build.notFoundWithMessage(error);\r
102             }\r
103 \r
104             // Check if a user associated with the mechanizedId used in the authorization header exists in\r
105             // the database.\r
106             User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
107             if (mechanizedIdUser == null) {\r
108                 String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
109                 if (decodedAuth == null) {\r
110                     return ResponseUtility.Build.badRequestWithMessage(\r
111                             String.format("Unable to decode authorization header: %s", authorization));\r
112                 }\r
113                 String error =\r
114                         String.format(\r
115                                 "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
116                 return ResponseUtility.Build.unauthorizedWithMessage(error);\r
117             }\r
118 \r
119             // If the mechanizedId is not an OTF mechanizedId, check if the user is authorized to\r
120             // execute\r
121             // the test instance. This is required because the executorId only needs to be read from the\r
122             // otf-frontend component. The user/group system is not fully integrated with AAF, so this\r
123             // is\r
124             // required. A better way might be to use certificates to check identities.\r
125             Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));\r
126             // if we cant find the test instance group then we cant check the permission\r
127             if (testInstanceGroup == null) {\r
128                 return ResponseUtility.Build.\r
129                         badRequestWithMessage(\r
130                                 String.format("Can not find test instance group, id:%s", testInstance.getGroupId().toString()));\r
131             }\r
132             // If the mechanizedId is authorized, set the executorId in the WorkflowRequest to the\r
133             // mechanizedId's ObjectId to make sure that the executorId isn't spoofed. Only use the\r
134             // executorId sent with the request if it uses the OTF mechanizedId because we "trust" it.\r
135             if (isOtfMechanizedIdentifier(mechanizedIdUser.getEmail()) && request.getExecutorId() != null) {\r
136                 mechanizedIdUser = Utilities.resolveOptional(userRepository.findById(request.getExecutorId().toString()));\r
137             } else {\r
138                 request.setExecutorId(mechanizedIdUser.get_id());\r
139             }\r
140             if (!PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup, UserPermission.Permission.EXECUTE,groupRepository)) {\r
141                 String error =\r
142                         String.format(\r
143                                 "%sUnauthorized the execute test instance with _id, %s.",\r
144                                 logPrefix, testInstanceId);\r
145                 return ResponseUtility.Build.unauthorizedWithMessage(error);\r
146             }\r
147 \r
148             // Set the test instance _id after authorization.\r
149             request.setTestInstanceId(testInstance.get_id());\r
150 \r
151             // Check if the test instance is disabled.\r
152             if (testInstance.isDisabled()) {\r
153                 return ResponseUtility.Build.badRequestWithMessage(\r
154                         String.format("The test instance with identifier %s is disabled.", testInstanceId));\r
155             }\r
156             // Check if the test definition is disabled.\r
157             if (testDefinition.isDisabled()) {\r
158                 return ResponseUtility.Build.badRequestWithMessage(\r
159                         String.format(\r
160                                 "The test definition with identifier %s is disabled.",\r
161                                 testInstance.getTestDefinitionId().toString()));\r
162             }\r
163 \r
164             // Send the request to Camunda.\r
165             return camundaProcessExecutionHandler.startProcessInstance(request);\r
166         } catch (Exception e) {\r
167             Utilities.printStackTrace(e, LogLevel.ERROR);\r
168             return ResponseUtility.Build.internalServerError();\r
169         }\r
170     }\r
171 \r
172     @Override\r
173     public Response createByTestDefinitionId(\r
174             String testDefinitionId, String authorization, TestInstanceCreateRequest request) {\r
175         try {\r
176             // Check if a user associated with the mechanizedId used in the authorization header exists in\r
177             // the database.\r
178             User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
179             if (mechanizedIdUser == null) {\r
180                 String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
181                 if (decodedAuth == null) {\r
182                     return ResponseUtility.Build.badRequestWithMessage(\r
183                             String.format("Unable to decode authorization header: %s", authorization));\r
184                 }\r
185                 String error =\r
186                         String.format(\r
187                                 "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
188                 return ResponseUtility.Build.unauthorizedWithMessage(error);\r
189             }\r
190 \r
191             // Check if the String correctly parses as an ObjectId.\r
192             if (!Utilities.isObjectIdValid(testDefinitionId)) {\r
193                 return ResponseUtility.Build.badRequestWithMessage(\r
194                         String.format(\r
195                                 "The testDefinitionId %s is not a valid BSON ObjectId.", testDefinitionId));\r
196             }\r
197             ObjectId oiTestDefintionId = new ObjectId(testDefinitionId);\r
198 \r
199             // Find the testDefinition\r
200             TestDefinition testDefinition =\r
201                     Generic.findByIdGeneric(testDefinitionRepository, oiTestDefintionId);\r
202             if (testDefinition == null) {\r
203                 return ResponseUtility.Build.notFoundWithMessage(\r
204                         String.format("Test definition with id, %s, was not found.", testDefinitionId));\r
205             }\r
206             // Check if the mechanizedId has access to the test definition.\r
207             Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));\r
208             if (testDefGroup == null) {\r
209                 return ResponseUtility.Build.badRequestWithMessage(\r
210                         String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));\r
211             }\r
212 //            if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {\r
213 //                return ResponseUtility.Build.unauthorizedWithMessage(\r
214 //                        String.format(\r
215 //                                "MechanizedId, %s, does not have read access to test definition in group with name, %s",\r
216 //                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
217 //            }\r
218 //            if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {\r
219 //                return ResponseUtility.Build.unauthorizedWithMessage(\r
220 //                        String.format(\r
221 //                                "MechanizedId, %s, does not have write access to the group with name, %s",\r
222 //                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
223 //            }\r
224             if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,\r
225                     Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))\r
226             {\r
227                 return ResponseUtility.Build.unauthorizedWithMessage(\r
228                         String.format(\r
229                                 "MechanizedId, %s, does not have access (read/write) to the group with name, %s",\r
230                                 mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
231             }\r
232             // Get the latest version of the test definition to link it with the test instance\r
233             BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, Integer.MIN_VALUE, true);\r
234             if (bpmnInstance == null) {\r
235                 return ResponseUtility.Build.notFoundWithMessage(\r
236                         String.format(\r
237                                 "Test definition with id, %s, does not have any versions associated with it.",\r
238                                 testDefinitionId));\r
239             }\r
240 \r
241             TestInstance testInstance =\r
242                     new TestInstance(\r
243                             new ObjectId(),\r
244                             request.getTestInstanceName(),\r
245                             request.getTestInstanceDescription(),\r
246                             testDefinition.getGroupId(),\r
247                             testDefinition.get_id(),\r
248                             bpmnInstance.getProcessDefinitionId(),\r
249                             request.isUseLatestTestDefinition(),\r
250                             false,\r
251                             request.isSimulationMode(),\r
252                             request.getMaxExecutionTimeInMillis(),\r
253                             request.getPfloInput(),\r
254                             new HashMap<>(),\r
255                             request.getSimulationVthInput(),\r
256                             request.getTestData(),\r
257                             request.getVthInput(),\r
258                             new Date(System.currentTimeMillis()),\r
259                             new Date(System.currentTimeMillis()),\r
260                             mechanizedIdUser.get_id(),\r
261                             mechanizedIdUser.get_id());\r
262 \r
263             return Response.ok()\r
264                     .type(MediaType.APPLICATION_JSON_TYPE)\r
265                     .entity(testInstance.toString())\r
266                     .build();\r
267         } catch (Exception e) {\r
268             Utilities.printStackTrace(e, LogLevel.ERROR);\r
269             return ResponseUtility.Build.internalServerError();\r
270         }\r
271     }\r
272 \r
273     @Override\r
274     public Response createByTestDefinitionId(\r
275             String testDefinitionId,\r
276             int version,\r
277             String authorization,\r
278             TestInstanceCreateRequest request) {\r
279         try {\r
280             // Check if a user associated with the mechanizedId used in the authorization header exists in\r
281             // the database.\r
282             User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
283             if (mechanizedIdUser == null) {\r
284                 String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
285                 if (decodedAuth == null) {\r
286                     return ResponseUtility.Build.badRequestWithMessage(\r
287                             String.format("Unable to decode authorization header: %s", authorization));\r
288                 }\r
289                 String error =\r
290                         String.format(\r
291                                 "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
292                 return ResponseUtility.Build.unauthorizedWithMessage(error);\r
293             }\r
294 \r
295             // Check if the String correctly parses as an ObjectId.\r
296             if (!Utilities.isObjectIdValid(testDefinitionId)) {\r
297                 return ResponseUtility.Build.badRequestWithMessage(\r
298                         String.format(\r
299                                 "The testDefinitionId %s is not a valid BSON ObjectId.", testDefinitionId));\r
300             }\r
301             ObjectId oiTestDefintionId = new ObjectId(testDefinitionId);\r
302 \r
303             // Find the testDefinition\r
304             TestDefinition testDefinition =\r
305                     Generic.findByIdGeneric(testDefinitionRepository, oiTestDefintionId);\r
306             if (testDefinition == null) {\r
307                 return ResponseUtility.Build.notFoundWithMessage(\r
308                         String.format("Test definition with id, %s, was not found.", testDefinitionId));\r
309             }\r
310             // permission checking\r
311             Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));\r
312             if (testDefGroup == null) {\r
313                 return ResponseUtility.Build.badRequestWithMessage(\r
314                         String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));\r
315             }\r
316             // if not otf email and is not authorized\r
317 //            if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {\r
318 ////                return ResponseUtility.Build.unauthorizedWithMessage(\r
319 ////                        String.format(\r
320 ////                                "MechanizedId, %s, does not have read access to test definition in group with name, %s",\r
321 ////                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
322 ////            }\r
323 ////            if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {\r
324 ////                return ResponseUtility.Build.unauthorizedWithMessage(\r
325 ////                        String.format(\r
326 ////                                "MechanizedId, %s, does not have write access to the group with name, %s",\r
327 ////                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
328 ////            }\r
329             if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,\r
330                     Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))\r
331             {\r
332                 return ResponseUtility.Build.unauthorizedWithMessage(\r
333                         String.format(\r
334                                 "MechanizedId, %s, does not have access (read/write) to the group with name, %s",\r
335                                 mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
336             }\r
337             // Get the latest version of the test definition to link it with the test instance\r
338             BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, version, false);\r
339             if (bpmnInstance == null) {\r
340                 return ResponseUtility.Build.notFoundWithMessage(\r
341                         String.format(\r
342                                 "Test definition with id, %s, does not have any versions associated with it.",\r
343                                 testDefinitionId));\r
344             }\r
345 \r
346             TestInstance testInstance =\r
347                     new TestInstance(\r
348                             new ObjectId(),\r
349                             request.getTestInstanceName(),\r
350                             request.getTestInstanceDescription(),\r
351                             testDefinition.getGroupId(),\r
352                             testDefinition.get_id(),\r
353                             bpmnInstance.getProcessDefinitionId(),\r
354                             request.isUseLatestTestDefinition(),\r
355                             false,\r
356                             request.isSimulationMode(),\r
357                             request.getMaxExecutionTimeInMillis(),\r
358                             request.getPfloInput(),\r
359                             new HashMap<>(),\r
360                             request.getSimulationVthInput(),\r
361                             request.getTestData(),\r
362                             request.getVthInput(),\r
363                             new Date(System.currentTimeMillis()),\r
364                             new Date(System.currentTimeMillis()),\r
365                             mechanizedIdUser.get_id(),\r
366                             mechanizedIdUser.get_id());\r
367 \r
368             return Response.ok()\r
369                     .type(MediaType.APPLICATION_JSON_TYPE)\r
370                     .entity(testInstance.toString())\r
371                     .build();\r
372         } catch (Exception e) {\r
373             Utilities.printStackTrace(e, LogLevel.ERROR);\r
374             return ResponseUtility.Build.internalServerError();\r
375         }\r
376     }\r
377 \r
378     @Override\r
379     public Response createByProcessDefinitionKey(\r
380             String processDefinitionKey, String authorization, TestInstanceCreateRequest request) {\r
381         try {\r
382             // Check if a user associated with the mechanizedId used in the authorization header exists in\r
383             // the database.\r
384             User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
385             if (mechanizedIdUser == null) {\r
386                 String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
387                 if (decodedAuth == null) {\r
388                     return ResponseUtility.Build.badRequestWithMessage(\r
389                             String.format("Unable to decode authorization header: %s", authorization));\r
390                 }\r
391                 String error =\r
392                         String.format(\r
393                                 "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
394                 return ResponseUtility.Build.unauthorizedWithMessage(error);\r
395             }\r
396 \r
397             // Check if the String correctly parses as an ObjectId.\r
398             if (Strings.isNullOrEmpty(processDefinitionKey)) {\r
399                 return ResponseUtility.Build.badRequestWithMessage("The processDefinitionKey is required.");\r
400             }\r
401 \r
402             // Find the testDefinition\r
403             TestDefinition testDefinition =\r
404                     testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey).orElse(null);\r
405             if (testDefinition == null) {\r
406                 return ResponseUtility.Build.notFoundWithMessage(\r
407                         String.format(\r
408                                 "Test definition with processDefinitionKey, %s, was not found.",\r
409                                 processDefinitionKey));\r
410             }\r
411 \r
412             Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));\r
413             if (testDefGroup == null) {\r
414                 return ResponseUtility.Build.badRequestWithMessage(\r
415                         String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));\r
416             }\r
417             // if not otf email and is not authorized\r
418 //            if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {\r
419 //                return ResponseUtility.Build.unauthorizedWithMessage(\r
420 //                        String.format(\r
421 //                                "MechanizedId, %s, does not have read access to test definition in group with name, %s",\r
422 //                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
423 //            }\r
424 //            if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {\r
425 //                return ResponseUtility.Build.unauthorizedWithMessage(\r
426 //                        String.format(\r
427 //                                "MechanizedId, %s, does not have write access to the group with name, %s",\r
428 //                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
429 //            }\r
430             if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,\r
431                     Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))\r
432             {\r
433                 return ResponseUtility.Build.unauthorizedWithMessage(\r
434                         String.format(\r
435                                 "MechanizedId, %s, does not have access (read/write) to the group with name, %s",\r
436                                 mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
437             }\r
438             // Get the latest version of the test definition to link it with the test instance\r
439             BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, Integer.MIN_VALUE, false);\r
440             if (bpmnInstance == null) {\r
441                 return ResponseUtility.Build.notFoundWithMessage(\r
442                         String.format(\r
443                                 "Test definition with id, %s, does not have any versions associated with it.",\r
444                                 testDefinition.get_id().toString()));\r
445             }\r
446 \r
447             TestInstance testInstance =\r
448                     new TestInstance(\r
449                             new ObjectId(),\r
450                             request.getTestInstanceName(),\r
451                             request.getTestInstanceDescription(),\r
452                             testDefinition.getGroupId(),\r
453                             testDefinition.get_id(),\r
454                             bpmnInstance.getProcessDefinitionId(),\r
455                             request.isUseLatestTestDefinition(),\r
456                             false,\r
457                             request.isSimulationMode(),\r
458                             request.getMaxExecutionTimeInMillis(),\r
459                             request.getPfloInput(),\r
460                             new HashMap<>(),\r
461                             request.getSimulationVthInput(),\r
462                             request.getTestData(),\r
463                             request.getVthInput(),\r
464                             new Date(System.currentTimeMillis()),\r
465                             new Date(System.currentTimeMillis()),\r
466                             mechanizedIdUser.get_id(),\r
467                             mechanizedIdUser.get_id());\r
468 \r
469             return Response.ok()\r
470                     .type(MediaType.APPLICATION_JSON_TYPE)\r
471                     .entity(testInstance.toString())\r
472                     .build();\r
473         } catch (Exception e) {\r
474             Utilities.printStackTrace(e, LogLevel.ERROR);\r
475             return ResponseUtility.Build.internalServerError();\r
476         }\r
477     }\r
478 \r
479     @Override\r
480     public Response createByProcessDefinitionKey(\r
481             String processDefinitionKey,\r
482             int version,\r
483             String authorization,\r
484             TestInstanceCreateRequest request) {\r
485         try {\r
486             // Check if a user associated with the mechanizedId used in the authorization header exists in\r
487             // the database.\r
488             User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
489             if (mechanizedIdUser == null) {\r
490                 String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
491                 if (decodedAuth == null) {\r
492                     return ResponseUtility.Build.badRequestWithMessage(\r
493                             String.format("Unable to decode authorization header: %s", authorization));\r
494                 }\r
495                 String error =\r
496                         String.format(\r
497                                 "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
498                 return ResponseUtility.Build.unauthorizedWithMessage(error);\r
499             }\r
500 \r
501             // Check if the String correctly parses as an ObjectId.\r
502             if (Strings.isNullOrEmpty(processDefinitionKey)) {\r
503                 return ResponseUtility.Build.badRequestWithMessage("The processDefinitionKey is required.");\r
504             }\r
505 \r
506             // Find the testDefinition\r
507             TestDefinition testDefinition =\r
508                     testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey).orElse(null);\r
509             if (testDefinition == null) {\r
510                 return ResponseUtility.Build.notFoundWithMessage(\r
511                         String.format(\r
512                                 "Test definition with processDefinitionKey, %s, was not found.",\r
513                                 processDefinitionKey));\r
514             }\r
515 \r
516             Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));\r
517             if (testDefGroup == null) {\r
518                 return ResponseUtility.Build.badRequestWithMessage(\r
519                         String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));\r
520             }\r
521             // if not otf email and is not authorized\r
522 //            if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {\r
523 //                return ResponseUtility.Build.unauthorizedWithMessage(\r
524 //                        String.format(\r
525 //                                "MechanizedId, %s, does not have read access to test definition in group with name, %s",\r
526 //                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
527 //            }\r
528 //            if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {\r
529 //                return ResponseUtility.Build.unauthorizedWithMessage(\r
530 //                        String.format(\r
531 //                                "MechanizedId, %s, does not have write access to the group with name, %s",\r
532 //                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
533 //            }\r
534             if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,\r
535                     Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))\r
536             {\r
537                 return ResponseUtility.Build.unauthorizedWithMessage(\r
538                         String.format(\r
539                                 "MechanizedId, %s, does not have access (read/write) to the group with name, %s",\r
540                                 mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
541             }\r
542             // Get the latest version of the test definition to link it with the test instance\r
543             BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, version, false);\r
544             if (bpmnInstance == null) {\r
545                 return ResponseUtility.Build.notFoundWithMessage(\r
546                         String.format(\r
547                                 "Test definition with id, %s, does not have any versions associated with it.",\r
548                                 testDefinition.get_id().toString()));\r
549             }\r
550 \r
551             TestInstance testInstance =\r
552                     new TestInstance(\r
553                             new ObjectId(),\r
554                             request.getTestInstanceName(),\r
555                             request.getTestInstanceDescription(),\r
556                             testDefinition.getGroupId(),\r
557                             testDefinition.get_id(),\r
558                             bpmnInstance.getProcessDefinitionId(),\r
559                             request.isUseLatestTestDefinition(),\r
560                             false,\r
561                             request.isSimulationMode(),\r
562                             request.getMaxExecutionTimeInMillis(),\r
563                             request.getPfloInput(),\r
564                             new HashMap<>(),\r
565                             request.getSimulationVthInput(),\r
566                             request.getTestData(),\r
567                             request.getVthInput(),\r
568                             new Date(System.currentTimeMillis()),\r
569                             new Date(System.currentTimeMillis()),\r
570                             mechanizedIdUser.get_id(),\r
571                             mechanizedIdUser.get_id());\r
572 \r
573             return Response.ok()\r
574                     .type(MediaType.APPLICATION_JSON_TYPE)\r
575                     .entity(testInstance.toString())\r
576                     .build();\r
577         } catch (Exception e) {\r
578             Utilities.printStackTrace(e, LogLevel.ERROR);\r
579             return ResponseUtility.Build.internalServerError();\r
580         }\r
581     }\r
582 \r
583     @Override\r
584     public Response findById(String testInstanceId, String authorization) {\r
585         // Check if a user associated with the mechanizedId used in the authorization header exists in\r
586         // the database.\r
587         User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
588         if (mechanizedIdUser == null) {\r
589             String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
590             if (decodedAuth == null) {\r
591                 return ResponseUtility.Build.badRequestWithMessage(\r
592                         String.format("Unable to decode authorization header: %s", authorization));\r
593             }\r
594             String error =\r
595                     String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
596             return ResponseUtility.Build.unauthorizedWithMessage(error);\r
597         }\r
598 \r
599         // Check if the testInstanceId is a valid BSON ObjectI, otherwise return a bad request\r
600         // response.\r
601         if (!Utilities.isObjectIdValid(testInstanceId)) {\r
602             String error =\r
603                     String.format(\r
604                             "%sThe testInstanceId, %s, is not a valid ObjectId (BSON).",\r
605                             logPrefix, testInstanceId);\r
606             return ResponseUtility.Build.badRequestWithMessage(error);\r
607         }\r
608 \r
609         // Create an ObjectId now that we know the provided String was valid.\r
610         ObjectId oiTestInstanceId = new ObjectId(testInstanceId);\r
611         // Check if the testInstance exists, otherwise return a not found response.\r
612         TestInstance testInstance = Generic.findByIdGeneric(testInstanceRepository, oiTestInstanceId);\r
613         if (testInstance == null) {\r
614             String error =\r
615                     String.format(\r
616                             "%sThe testInstance with _id, %s, was not found.", logPrefix, testInstanceId);\r
617             return ResponseUtility.Build.notFoundWithMessage(error);\r
618         }\r
619 \r
620         Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));\r
621         if (testInstanceGroup == null) {\r
622             return ResponseUtility.Build.badRequestWithMessage(\r
623                     String.format("Can not find test instance's group, group name :%s", testInstance.get_id().toString()));\r
624         }\r
625         if (!PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) {\r
626             return ResponseUtility.Build.unauthorizedWithMessage(\r
627                     String.format(\r
628                             "User %s does not have read access to test instance group, group name: %s.",\r
629                             mechanizedIdUser.getEmail(), testInstanceGroup.getGroupName()));\r
630         }\r
631         return Response.ok(testInstance.toString(), MediaType.APPLICATION_JSON_TYPE).build();\r
632     }\r
633 \r
634     @Override\r
635     public Response findByProcessDefinitionKey(String processDefinitionKey, String authorization) {\r
636         // Check if a user associated with the mechanizedId used in the authorization header exists in\r
637         // the database.\r
638         User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
639         if (mechanizedIdUser == null) {\r
640             String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
641             if (decodedAuth == null) {\r
642                 return ResponseUtility.Build.badRequestWithMessage(\r
643                         String.format("Unable to decode authorization header: %s", authorization));\r
644             }\r
645             String error =\r
646                     String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
647             return ResponseUtility.Build.unauthorizedWithMessage(error);\r
648         }\r
649 \r
650         Optional<TestDefinition> optionalTestDefinition =\r
651                 testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey);\r
652         TestDefinition testDefinition = optionalTestDefinition.orElse(null);\r
653         if (testDefinition == null) {\r
654             return Utilities.Http.BuildResponse.badRequestWithMessage(\r
655                     String.format(\r
656                             "Cannot find test instance because a test"\r
657                                     + " definition with the process definition key (%s) does not exist.",\r
658                             processDefinitionKey));\r
659         }\r
660 \r
661         List<TestInstance> testInstances =\r
662                 testInstanceRepository.findAllByTestDefinitionId(testDefinition.get_id());\r
663         if (testInstances.isEmpty()) {\r
664             return Utilities.Http.BuildResponse.badRequestWithMessage(\r
665                     String.format(\r
666                             "No test instances found with process " + "definition key (%s).",\r
667                             processDefinitionKey));\r
668         }\r
669 \r
670         List<TestInstance> result = new ArrayList<>();\r
671         for (TestInstance testInstance : testInstances) {\r
672             Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));\r
673             if (testInstanceGroup != null && PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) {\r
674                 result.add(testInstance);\r
675             }\r
676         }\r
677 \r
678         return Response.ok(result.toString()).build();\r
679     }\r
680 \r
681     @Override\r
682     public Response findByProcessDefinitionKeyAndVersion(\r
683             String processDefinitionKey, String version, String authorization) {\r
684         // Check if a user associated with the mechanizedId used in the authorization header exists in\r
685         // the database.\r
686         User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
687         if (mechanizedIdUser == null) {\r
688             String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
689             if (decodedAuth == null) {\r
690                 return ResponseUtility.Build.badRequestWithMessage(\r
691                         String.format("Unable to decode authorization header: %s", authorization));\r
692             }\r
693             String error =\r
694                     String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
695             return ResponseUtility.Build.unauthorizedWithMessage(error);\r
696         }\r
697 \r
698         Optional<TestDefinition> optionalTestDefinition =\r
699                 testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey);\r
700         TestDefinition testDefinition = optionalTestDefinition.orElse(null);\r
701 \r
702         if (testDefinition == null) {\r
703             return Utilities.Http.BuildResponse.badRequestWithMessage(\r
704                     String.format(\r
705                             "Cannot find test instance because a test"\r
706                                     + " definition with the process definition key (%s) does not exist.",\r
707                             processDefinitionKey));\r
708         }\r
709 \r
710         int iVersion;\r
711         try {\r
712             iVersion = Integer.parseInt(version);\r
713         } catch (NumberFormatException nfe) {\r
714             return Utilities.Http.BuildResponse.badRequestWithMessage("Version must be a valid integer.");\r
715         }\r
716 \r
717         BpmnInstance bpmnInstance =\r
718                 testDefinition.getBpmnInstances().stream()\r
719                         .filter(_bpmnInstance -> _bpmnInstance.getVersion() == iVersion)\r
720                         .findAny()\r
721                         .orElse(null);\r
722 \r
723         if (bpmnInstance == null) {\r
724             return Utilities.Http.BuildResponse.badRequestWithMessage(\r
725                     String.format("Cannot find any test instances using " + "version %s.", version));\r
726         }\r
727 \r
728         List<TestInstance> testInstances =\r
729                 testInstanceRepository.findAllByTestDefinitionIdAndPDId(\r
730                         testDefinition.get_id(), bpmnInstance.getProcessDefinitionId());\r
731 \r
732         if (testInstances.isEmpty()) {\r
733             return Utilities.Http.BuildResponse.badRequestWithMessage(\r
734                     String.format(\r
735                             "No test instances found with process " + "definition key (%s).",\r
736                             processDefinitionKey));\r
737         }\r
738 \r
739         List<TestInstance> result = new ArrayList<>();\r
740         for (TestInstance testInstance : testInstances) {\r
741             Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));\r
742             if (testInstanceGroup != null && PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) {\r
743                 result.add(testInstance);\r
744             }\r
745         }\r
746 \r
747         return Response.ok(result.toString()).build();\r
748     }\r
749 \r
750     private boolean isOtfMechanizedIdentifier(String email) {\r
751         return email.equalsIgnoreCase("email@localhost")\r
752                 || email.equalsIgnoreCase("email@localhost")\r
753                 || email.equalsIgnoreCase("email@localhost")\r
754                 || email.equalsIgnoreCase("email@localhost")\r
755                 || email.equalsIgnoreCase("email@localhost");\r
756     }\r
757 \r
758     private BpmnInstance findBpmnInstance(TestDefinition testDefinition, int version, boolean latest)\r
759             throws Exception {\r
760         BpmnInstance bpmnInstance = null;\r
761         int maxVersion = Integer.MIN_VALUE;\r
762         // Check if the version exists\r
763         for (BpmnInstance bi : testDefinition.getBpmnInstances()) {\r
764             // If this field is null or empty, it means the bpmn hasn't been deployed, or there was a\r
765             // creation error on the Test Definition page (UI). Skip the field so the user isn't allowed\r
766             // to create a test instance based off this bpmn instance.\r
767             if (Strings.isNullOrEmpty(bi.getProcessDefinitionId())) {\r
768                 continue;\r
769             }\r
770 \r
771             // Split the processDefinitionId based on it's format:\r
772             // {processDefinitionKey}:{version}:{processDefinitionId}.\r
773             String processDefinitionId = bi.getProcessDefinitionId();\r
774             String[] processDefinitionIdSplit = processDefinitionId.split(":");\r
775             if (processDefinitionIdSplit.length != 3) {\r
776                 throw new Exception(\r
777                         String.format(\r
778                                 "testDefinition[%s].bpmnInstances.processDefinitionId[%s] is invalid.",\r
779                                 testDefinition.get_id().toString(), bi.getProcessDefinitionId()));\r
780             }\r
781 \r
782             String sVersion = processDefinitionIdSplit[1];\r
783             int currentVersion = Integer.parseInt(sVersion);\r
784             if (latest && currentVersion > maxVersion) {\r
785                 bpmnInstance = bi;\r
786             } else if (currentVersion == version) {\r
787                 bpmnInstance = bi;\r
788                 break;\r
789             }\r
790         }\r
791 \r
792         return bpmnInstance;\r
793     }\r
794 \r
795 //    private boolean isAuthorized(User user, Group group, String permission, GroupRepository groupRepository) {\r
796 //        if (isOtfMechanizedIdentifier(user.getEmail())) {\r
797 //            return true;\r
798 //        }\r
799 //        return PermissionChecker.isAuthorized(user, group, permission.toUpperCase(), groupRepository);\r
800 //    }\r
801 }\r
802 /*\r
803  PermissionChecker.hasReadPermission(mechanizedIdUser,testInstanceGroup,groupRepository)\r
804 \r
805   PermissionChecker.hasPermission(mechanizedIdUser,testInstanceGroup,groupRepository, [READ, WRITE])\r
806   PermissionsMAp = PermissionChecker.Build.hasRead\r
807  */