2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.so.bpmn.common;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.fail;
25 import static org.onap.so.bpmn.core.json.JsonUtils.getJsonValue;
26 import static org.onap.so.bpmn.core.json.JsonUtils.updJsonValue;
28 import java.io.IOException;
29 import java.io.StringReader;
30 import java.lang.management.ManagementFactory;
31 import java.lang.management.RuntimeMXBean;
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
37 import java.util.UUID;
39 import javax.ws.rs.core.Response;
40 import javax.xml.bind.JAXBException;
41 import javax.xml.namespace.NamespaceContext;
42 import javax.xml.namespace.QName;
43 import javax.xml.parsers.DocumentBuilder;
44 import javax.xml.parsers.DocumentBuilderFactory;
45 import javax.xml.parsers.ParserConfigurationException;
46 import javax.xml.xpath.XPath;
47 import javax.xml.xpath.XPathConstants;
48 import javax.xml.xpath.XPathExpression;
49 import javax.xml.xpath.XPathExpressionException;
50 import javax.xml.xpath.XPathFactory;
52 import org.camunda.bpm.engine.HistoryService;
53 import org.camunda.bpm.engine.ProcessEngine;
54 import org.camunda.bpm.engine.ProcessEngineException;
55 import org.camunda.bpm.engine.RuntimeService;
56 import org.camunda.bpm.engine.history.HistoricProcessInstance;
57 import org.camunda.bpm.engine.history.HistoricVariableInstance;
58 import org.camunda.bpm.engine.runtime.ProcessInstance;
59 import org.camunda.bpm.engine.runtime.ProcessInstanceQuery;
60 import org.camunda.bpm.engine.test.ProcessEngineRule;
61 import org.camunda.bpm.engine.variable.impl.VariableMapImpl;
62 import org.custommonkey.xmlunit.DetailedDiff;
63 import org.custommonkey.xmlunit.XMLUnit;
64 import org.json.JSONArray;
65 import org.json.JSONObject;
66 import org.junit.Rule;
67 import org.onap.so.bpmn.common.adapter.sdnc.CallbackHeader;
68 import org.onap.so.bpmn.common.adapter.sdnc.SDNCAdapterCallbackRequest;
69 import org.onap.so.bpmn.common.adapter.sdnc.SDNCAdapterResponse;
70 import org.onap.so.bpmn.common.adapter.vnf.CreateVnfNotification;
71 import org.onap.so.bpmn.common.adapter.vnf.DeleteVnfNotification;
72 import org.onap.so.bpmn.common.adapter.vnf.MsoExceptionCategory;
73 import org.onap.so.bpmn.common.adapter.vnf.MsoRequest;
74 import org.onap.so.bpmn.common.adapter.vnf.UpdateVnfNotification;
75 import org.onap.so.bpmn.common.adapter.vnf.VnfRollback;
76 import org.onap.so.bpmn.common.workflow.context.WorkflowResponse;
77 import org.onap.so.bpmn.common.workflow.service.SDNCAdapterCallbackServiceImpl;
78 import org.onap.so.bpmn.common.workflow.service.VnfAdapterNotifyServiceImpl;
79 import org.onap.so.bpmn.common.workflow.service.WorkflowAsyncResource;
80 import org.onap.so.bpmn.common.workflow.service.WorkflowMessageResource;
81 import org.onap.so.bpmn.common.workflow.service.WorkflowResource;
82 import org.onap.so.bpmn.core.domain.Resource;
83 import org.onap.so.bpmn.core.domain.ServiceDecomposition;
84 import org.onap.so.logger.MsoLogger;
85 import org.springframework.beans.factory.annotation.Autowired;
86 import org.w3c.dom.Document;
87 import org.w3c.dom.Element;
88 import org.w3c.dom.Node;
89 import org.w3c.dom.NodeList;
90 import org.xml.sax.InputSource;
91 import org.xml.sax.SAXException;
96 * A base class for Workflow tests.
98 * WireMock response transformers may be specified by declaring public
99 * static fields with the @WorkflowTestTransformer annotation. For example:
101 * @WorkflowTestTransformer
102 * public static final ResponseTransformer sdncAdapterMockTransformer =
103 * new SDNCAdapterMockTransformer();
107 public abstract class WorkflowTest {
109 private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, WorkflowTest.class);
111 //TODO this is not used anymore, can maybe be removed
113 public ProcessEngineRule processEngineRule;
116 protected WorkflowResource workflowResourceSync;
119 protected ProcessEngine processEngine;
122 protected RuntimeService runtimeService;
125 protected HistoryService historyService;
128 private WorkflowAsyncResource workflowResource;
131 private WorkflowMessageResource workflowMessageResource;
134 SDNCAdapterCallbackServiceImpl callbackService;
136 * Content-Type for XML.
138 protected static final String XML = "application/xml";
141 * Content-Type for JSON.
143 protected static final String JSON = "application/json; charset=UTF-8";
145 private static final int timeout = 2000;
150 public WorkflowTest() throws RuntimeException {
154 * The current request ID. Normally set when an "invoke" method is called.
156 protected volatile String msoRequestId = null;
159 * The current service instance ID. Normally set when an "invoke" method
162 protected volatile String msoServiceInstanceId = null;
165 * Logs a test start method.
167 protected void logStart() {
168 msoLogger.debug("STARTED TEST");
172 * Logs a test end method.
174 protected void logEnd() {
175 msoLogger.debug("ENDED TEST");
179 * Invokes a subprocess.
180 * @param processKey the process key
181 * @param businessKey a unique key that will identify the process instance
182 * @param injectedVariables variables to inject into the process
184 protected void invokeSubProcess(String processKey, String businessKey, Map<String, Object> injectedVariables) {
185 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
186 List<String> arguments = runtimeMxBean.getInputArguments();
187 msoLogger.debug("JVM args = " + arguments);
189 msoRequestId = (String) injectedVariables.get("mso-request-id");
190 String requestId = (String) injectedVariables.get("msoRequestId");
192 if (msoRequestId == null && requestId == null) {
193 String msg = "mso-request-id variable was not provided";
194 msoLogger.debug(msg);
198 // Note: some scenarios don't have a service-instance-id, may be null
199 msoServiceInstanceId = (String) injectedVariables.get("mso-service-instance-id");
202 runtimeService.startProcessInstanceByKey(processKey, businessKey, injectedVariables);
205 protected String invokeSubProcess(String processKey, Map<String, Object> injectedVariables) {
206 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
207 List<String> arguments = runtimeMxBean.getInputArguments();
208 msoLogger.debug("JVM args = " + arguments);
210 msoRequestId = (String) injectedVariables.get("mso-request-id");
211 String requestId = (String) injectedVariables.get("msoRequestId");
213 if (msoRequestId == null && requestId == null) {
214 String msg = "mso-request-id variable was not provided";
215 msoLogger.debug(msg);
219 // Note: some scenarios don't have a service-instance-id, may be null
220 msoServiceInstanceId = (String) injectedVariables.get("mso-service-instance-id");
223 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey, msoRequestId, injectedVariables);
224 return processInstance.getId();
228 * Invokes an asynchronous process.
229 * Errors are handled with junit assertions and will cause the test to fail.
230 * @param processKey the process key
231 * @param schemaVersion the API schema version, e.g. "v1"
232 * @param businessKey a unique key that will identify the process instance
233 * @param request the request
234 * @return a TestAsyncResponse object associated with the test
235 * @throws InterruptedException
237 protected TestAsyncResponse invokeAsyncProcess(String processKey,
238 String schemaVersion, String businessKey, String request) throws InterruptedException {
239 return invokeAsyncProcess(processKey, schemaVersion, businessKey, request, null);
243 * Invokes an asynchronous process.
244 * Errors are handled with junit assertions and will cause the test to fail.
245 * @param processKey the process key
246 * @param schemaVersion the API schema version, e.g. "v1"
247 * @param businessKey a unique key that will identify the process instance
248 * @param request the request
249 * @param injectedVariables optional variables to inject into the process
250 * @return a TestAsyncResponse object associated with the test
251 * @throws InterruptedException
253 protected TestAsyncResponse invokeAsyncProcess(String processKey,
254 String schemaVersion, String businessKey, String request,
255 Map<String, Object> injectedVariables) {
257 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
258 List<String> arguments = runtimeMxBean.getInputArguments();
259 msoLogger.debug("JVM args = " + arguments);
261 Map<String, Object> variables = createVariables(schemaVersion, businessKey,
262 request, injectedVariables, false);
263 VariableMapImpl variableMapImpl = createVariableMapImpl(variables);
265 msoLogger.debug("Sending " + request + " to " + processKey + " process");
267 TestAsyncResponse asyncResponse = new TestAsyncResponse();
269 asyncResponse.setResponse(workflowResource.startProcessInstanceByKey( processKey, variableMapImpl));
271 return asyncResponse;
275 * Invokes an asynchronous process.
276 * Errors are handled with junit assertions and will cause the test to fail.
277 * @param processKey the process key
278 * @param schemaVersion the API schema version, e.g. "v1"
279 * @param businessKey a unique key that will identify the process instance
280 * @param request the request
281 * @param injectedVariables optional variables to inject into the process
282 * @param serviceInstantiationModel indicates whether this method is being
283 * invoked for a flow that is designed using the service instantiation model
284 * @return a TestAsyncResponse object associated with the test
285 * @throws InterruptedException
287 protected Response invokeAsyncProcess(String processKey,
288 String schemaVersion, String businessKey, String request,
289 Map<String, Object> injectedVariables, boolean serviceInstantiationModel) {
291 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
292 List<String> arguments = runtimeMxBean.getInputArguments();
293 msoLogger.debug("JVM args = " + arguments);
295 Map<String, Object> variables = createVariables(schemaVersion, businessKey,
296 request, injectedVariables, serviceInstantiationModel);
297 VariableMapImpl variableMapImpl = createVariableMapImpl(variables);
299 msoLogger.debug("Sending " + request + " to " + processKey + " process");
301 return workflowResource.startProcessInstanceByKey( processKey, variableMapImpl);
306 * Private helper method that creates a variable map for a request.
307 * Errors are handled with junit assertions and will cause the test to fail.
308 * @param schemaVersion the API schema version, e.g. "v1"
309 * @param businessKey a unique key that will identify the process instance
310 * @param request the request
311 * @param injectedVariables optional variables to inject into the process
312 * @param serviceInstantiationModel indicates whether this method is being
313 * invoked for a flow that is designed using the service instantiation model
314 * @return a variable map
316 private Map<String, Object> createVariables(String schemaVersion,
317 String businessKey, String request, Map<String, Object> injectedVariables,
318 boolean serviceInstantiationModel) {
320 Map<String, Object> variables = new HashMap<>();
322 // These variables may be overridded by injected variables.
323 variables.put("mso-service-request-timeout", "180");
324 variables.put("isDebugLogEnabled", "true");
326 // These variables may not be overridded by injected variables.
327 String[] notAllowed = new String[] {
328 "mso-schema-version",
332 "mso-service-instance-id"
335 if (injectedVariables != null) {
336 for (String key : injectedVariables.keySet()) {
337 for (String var : notAllowed) {
338 if (var.equals(key)) {
339 String msg = "Cannot specify " + var + " in injected variables";
340 msoLogger.debug(msg);
345 variables.put(key, injectedVariables.get(key));
349 variables.put("mso-schema-version", schemaVersion);
350 variables.put("mso-business-key", businessKey);
351 variables.put("bpmnRequest", request);
353 if (serviceInstantiationModel) {
356 * The request ID and the service instance ID are generated for flows
357 * that follow the service instantiation model unless "requestId" and
358 * "serviceInstanceId" are injected variables.
362 msoRequestId = (String) injectedVariables.get("requestId");
363 variables.put("mso-request-id", msoRequestId);
364 msoServiceInstanceId = (String) injectedVariables.get("serviceInstanceId");
365 variables.put("mso-service-instance-id", msoServiceInstanceId);
369 if (msoRequestId == null || msoRequestId.trim().equals("")) {
370 msoLogger.debug("No requestId element in injectedVariables");
371 variables.put("mso-request-id", UUID.randomUUID().toString());
373 if (msoServiceInstanceId == null || msoServiceInstanceId.trim().equals("")) {
374 msoLogger.debug("No seviceInstanceId element in injectedVariables");
375 variables.put("mso-service-instance-id", UUID.randomUUID().toString());
379 msoRequestId = getXMLTextElement(request, "request-id");
381 if (msoRequestId == null) {
382 //check in injected variables
384 msoRequestId = (String) injectedVariables.get("requestId");
388 if (msoRequestId == null || msoRequestId.trim().equals("")) {
389 String msg = "No request-id element in " + request;
390 msoLogger.debug(msg);
395 variables.put("mso-request-id", msoRequestId);
397 // Note: some request types don't have a service-instance-id
398 msoServiceInstanceId = getXMLTextElement(request, "service-instance-id");
400 if (msoServiceInstanceId != null) {
401 variables.put("mso-service-instance-id", msoServiceInstanceId);
409 * Private helper method that creates a camunda VariableMapImpl from a simple
411 * @param variables the simple variable map
412 * @return a VariableMap
414 private VariableMapImpl createVariableMapImpl(Map<String, Object> variables) {
415 Map<String, Object> wrappedVariables = new HashMap<>();
417 for (String key : variables.keySet()) {
418 Object value = variables.get(key);
419 wrappedVariables.put(key, wrapVariableValue(value));
422 VariableMapImpl variableMapImpl = new VariableMapImpl();
423 variableMapImpl.put("variables", wrappedVariables);
424 return variableMapImpl;
428 * Private helper method that wraps a variable value for inclusion in a
429 * camunda VariableMapImpl.
430 * @param value the variable value
431 * @return the wrapped variable
433 private Map<String, Object> wrapVariableValue(Object value) {
434 HashMap<String, Object> valueMap = new HashMap<>();
435 valueMap.put("value", value);
440 * Receives a response from an asynchronous process.
441 * Errors are handled with junit assertions and will cause the test to fail.
442 * @param businessKey the process business key
443 * @param asyncResponse the TestAsyncResponse object associated with the test
444 * @param timeout the timeout in milliseconds
445 * @return the WorkflowResponse
447 protected WorkflowResponse receiveResponse(String businessKey,
448 TestAsyncResponse asyncResponse, long timeout) {
449 msoLogger.debug("Waiting " + timeout + "ms for process with business key " + businessKey
450 + " to send a response");
452 long now = System.currentTimeMillis() + timeout;
453 long endTime = now + timeout;
455 while (now <= endTime) {
456 Response response = asyncResponse.getResponse();
458 if (response != null) {
459 msoLogger.debug("Received a response from process with business key " + businessKey);
461 Object entity = response.getEntity();
463 if (!(entity instanceof WorkflowResponse)) {
464 String msg = "Response entity is " +
465 (entity == null ? "null" : entity.getClass().getName()) +
466 ", expected WorkflowResponse";
467 msoLogger.debug(msg);
469 return null; // unreachable
472 return (WorkflowResponse) entity;
477 } catch (InterruptedException e) {
478 String msg = "Interrupted waiting for a response from process with business key " +
480 msoLogger.debug(msg);
482 return null; // unreachable
485 now = System.currentTimeMillis();
488 String msg = "No response received from process with business key " + businessKey +
489 " within " + timeout + "ms";
490 msoLogger.debug(msg);
491 fail("Process with business key " + businessKey + " did not end within 10000ms");
492 return null; // unreachable
496 * Runs a program to inject SDNC callback data into the test environment.
497 * A program is essentially just a list of keys that identify callback data
498 * to be injected, in sequence. An example program:
500 * reserve, assign, delete:ERR
502 * Errors are handled with junit assertions and will cause the test to fail.
503 * @param callbacks an object containing callback data for the program
504 * @param program the program to execute
506 protected void injectSDNCRestCallbacks(CallbackSet callbacks, String program) {
508 String[] cmds = program.replaceAll("\\s+", "").split(",");
510 for (String cmd : cmds) {
512 String modifier = "STD";
514 if (cmd.contains(":")) {
515 String[] parts = cmd.split(":");
520 String content = null;
521 String contentType = null;
523 if ("STD".equals(modifier)) {
524 CallbackData callbackData = callbacks.get(action);
526 if (callbackData == null) {
527 String msg = "No callback defined for '" + action + "' SDNC request";
528 msoLogger.debug(msg);
532 content = callbackData.getContent();
533 contentType = callbackData.getContentType();
534 } else if ("ERR".equals(modifier)) {
535 content = "{\"SDNCServiceError\":{\"sdncRequestId\":\"((REQUEST-ID))\",\"responseCode\":\"500\",\"responseMessage\":\"SIMULATED ERROR FROM SDNC ADAPTER\",\"ackFinalIndicator\":\"Y\"}}";
538 String msg = "Invalid SDNC program modifier: '" + modifier + "'";
539 msoLogger.debug(msg);
543 if (contentType == null) {
544 // Default for backward compatibility with existing tests.
548 if (!injectSDNCRestCallback(contentType, content, 10000)) {
549 fail("Failed to inject SDNC '" + action + "' callback");
554 } catch (InterruptedException e) {
555 fail("Interrupted after injection of SDNC '" + action + "' callback");
561 * Runs a program to inject SDNC events into the test environment.
562 * A program is essentially just a list of keys that identify event data
563 * to be injected, in sequence. An example program:
567 * NOTE: Each callback must have a message type associated with it, e.g.
569 * Errors are handled with junit assertions and will cause the test to fail.
570 * @param callbacks an object containing event data for the program
571 * @param program the program to execute
573 protected void injectSDNCEvents(CallbackSet callbacks, String program) {
574 injectWorkflowMessages(callbacks, program);
578 * Runs a program to inject SDNC callback data into the test environment.
579 * A program is essentially just a list of keys that identify callback data
580 * to be injected, in sequence. An example program:
582 * reserve, assign, delete:ERR
584 * Errors are handled with junit assertions and will cause the test to fail.
585 * Uses the static/default timeout value for backward compatibility.
586 * @param callbacks an object containing callback data for the program
587 * @param program the program to execute
589 protected void injectSDNCCallbacks(CallbackSet callbacks, String program) {
590 injectSDNCCallbacks(callbacks, program, timeout);
594 * Runs a program to inject SDNC callback data into the test environment.
595 * A program is essentially just a list of keys that identify callback data
596 * to be injected, in sequence. An example program:
598 * reserve, assign, delete:ERR
600 * Errors are handled with junit assertions and will cause the test to fail.
601 * @param callbacks an object containing callback data for the program
602 * @param program the program to execute
603 * @param timeout a timeout value to wait for the callback
605 protected void injectSDNCCallbacks(CallbackSet callbacks, String program, int timeout) {
607 String[] cmds = program.replaceAll("\\s+", "").split(",");
609 for (String cmd : cmds) {
611 String modifier = "STD";
613 if (cmd.contains(":")) {
614 String[] parts = cmd.split(":");
619 String content = null;
621 String respMsg = "OK";
623 if ("STD".equals(modifier)) {
624 CallbackData callbackData = callbacks.get(action);
626 if (callbackData == null) {
627 String msg = "No callback defined for '" + action + "' SDNC request";
628 msoLogger.debug(msg);
632 content = callbackData.getContent();
635 } else if ("CREATED".equals(modifier)) {
636 CallbackData callbackData = callbacks.get(action);
638 if (callbackData == null) {
639 String msg = "No callback defined for '" + action + "' SDNC request";
640 msoLogger.debug(msg);
644 content = callbackData.getContent();
647 } else if ("ERR".equals(modifier)) {
648 content = "<svc-request-id>((REQUEST-ID))</svc-request-id><response-code>500</response-code><response-message>SIMULATED ERROR FROM SDNC ADAPTER</response-message>";
650 respMsg = "SERVER ERROR";
652 String msg = "Invalid SDNC program modifier: '" + modifier + "'";
653 msoLogger.debug(msg);
657 if (!injectSDNCCallback(respCode, respMsg, content, 10000)) {
658 fail("Failed to inject SDNC '" + action + "' callback");
663 } catch (InterruptedException e) {
664 fail("Interrupted after injection of SDNC '" + action + "' callback");
670 * Runs a program to inject VNF adapter REST callback data into the test environment.
671 * A program is essentially just a list of keys that identify callback data
672 * to be injected, in sequence. An example program:
676 * Errors are handled with junit assertions and will cause the test to fail.
677 * @param callbacks an object containing callback data for the program
678 * @param program the program to execute
680 protected void injectVNFRestCallbacks(CallbackSet callbacks, String program) {
682 String[] cmds = program.replaceAll("\\s+", "").split(",");
684 for (String cmd : cmds) {
686 String modifier = "STD";
688 if (cmd.contains(":")) {
689 String[] parts = cmd.split(":");
694 String content = null;
695 String contentType = null;
697 if ("STD".equals(modifier)) {
698 CallbackData callbackData = callbacks.get(action);
700 if (callbackData == null) {
701 String msg = "No callback defined for '" + action + "' VNF REST request";
702 msoLogger.debug(msg);
706 content = callbackData.getContent();
707 contentType = callbackData.getContentType();
708 } else if ("ERR".equals(modifier)) {
709 content = "SIMULATED ERROR FROM VNF ADAPTER";
710 contentType = "text/plain";
712 String msg = "Invalid VNF REST program modifier: '" + modifier + "'";
713 msoLogger.debug(msg);
717 if (contentType == null) {
718 // Default for backward compatibility with existing tests.
722 if (!injectVnfAdapterRestCallback(contentType, content, 10000)) {
723 fail("Failed to inject VNF REST '" + action + "' callback");
728 } catch (InterruptedException e) {
729 fail("Interrupted after injection of VNF REST '" + action + "' callback");
735 * Runs a program to inject VNF callback data into the test environment.
736 * A program is essentially just a list of keys that identify callback data
737 * to be injected, in sequence. An example program:
739 * createVnf, deleteVnf
741 * Errors are handled with junit assertions and will cause the test to fail.
742 * @param callbacks an object containing callback data for the program
743 * @param program the program to execute
745 protected void injectVNFCallbacks(CallbackSet callbacks, String program) {
747 String[] cmds = program.replaceAll("\\s+", "").split(",");
749 for (String cmd : cmds) {
751 String modifier = "STD";
753 if (cmd.contains(":")) {
754 String[] parts = cmd.split(":");
759 String content = null;
761 if ("STD".equals(modifier)) {
762 CallbackData callbackData = callbacks.get(action);
764 if (callbackData == null) {
765 String msg = "No callback defined for '" + action + "' VNF request";
766 msoLogger.debug(msg);
770 content = callbackData.getContent();
771 } else if ("ERR".equals(modifier)) {
772 String msg = "Currently unsupported VNF program modifier: '" + modifier + "'";
773 msoLogger.debug(msg);
776 String msg = "Invalid VNF program modifier: '" + modifier + "'";
777 msoLogger.debug(msg);
781 boolean injected = false;
783 if (content.contains("createVnfNotification")) {
784 injected = injectCreateVNFCallback(content, 10000);
785 } else if (content.contains("deleteVnfNotification")) {
786 injected = injectDeleteVNFCallback(content, 10000);
787 } else if (content.contains("updateVnfNotification")) {
788 injected = injectUpdateVNFCallback(content, 10000);
792 String msg = "Failed to inject VNF '" + action + "' callback";
793 msoLogger.debug(msg);
799 } catch (InterruptedException e) {
800 fail("Interrupted after injection of VNF '" + action + "' callback");
806 * Waits for the number of running processes with the specified process
807 * definition key to equal a particular count.
808 * @param processKey the process definition key
809 * @param count the desired count
810 * @param timeout the timeout in milliseconds
812 protected void waitForRunningProcessCount(String processKey, int count, long timeout) {
813 msoLogger.debug("Waiting " + timeout + "ms for there to be " + count + " "
814 + processKey + " instances");
816 long now = System.currentTimeMillis() + timeout;
817 long endTime = now + timeout;
820 while (now <= endTime) {
821 int actual = runtimeService
822 .createProcessInstanceQuery()
823 .processDefinitionKey(processKey)
826 if (actual != last) {
827 msoLogger.debug("There are now " + actual + " "
828 + processKey + " instances");
832 if (actual == count) {
838 } catch (InterruptedException e) {
839 String msg = "Interrupted waiting for there to be " + count + " "
840 + processKey + " instances";
841 msoLogger.debug(msg);
845 now = System.currentTimeMillis();
848 String msg = "Timed out waiting for there to be " + count + " "
849 + processKey + " instances";
850 msoLogger.debug(msg);
855 * Waits for the specified process variable to be set.
856 * @param processKey the process definition key
857 * @param variable the variable name
858 * @param timeout the timeout in milliseconds
859 * @return the variable value, or null if it cannot be obtained
860 * in the specified time
862 protected Object getProcessVariable(String processKey, String variable,
865 msoLogger.debug("Waiting " + timeout + "ms for "
866 + processKey + "." + variable + " to be set");
868 long now = System.currentTimeMillis() + timeout;
869 long endTime = now + timeout;
871 ProcessInstance processInstance = null;
874 while (value == null) {
876 if (processInstance == null) {
877 msoLogger.debug("Timed out waiting for "
878 + processKey + " to start");
880 msoLogger.debug("Timed out waiting for "
881 + processKey + "[" + processInstance.getId()
882 + "]." + variable + " to be set");
888 ProcessInstanceQuery processInstanceQuery = null;
889 if (processInstance == null) {
890 processInstanceQuery = runtimeService
891 .createProcessInstanceQuery()
892 .processDefinitionKey(processKey);
895 if(processInstanceQuery.count() <= 1){
896 processInstance = processInstanceQuery.singleResult();
898 //TODO There shouldnt be more than one in the list but seems to be happening, need to figure out why happening and best way to get correct one from list
899 msoLogger.debug("Process Instance Query returned " + processInstanceQuery.count() + " instance. Getting the last instance in the list");
900 List<ProcessInstance> processList = processInstanceQuery.list();
901 processInstance = processList.get((processList.size() - 1));
904 if (processInstance != null) {
905 value = runtimeService
906 .getVariable(processInstance.getId(), variable);
911 } catch (InterruptedException e) {
912 msoLogger.debug("Interrupted waiting for "
913 + processKey + "." + variable + " to be set");
917 now = System.currentTimeMillis();
920 msoLogger.debug(processKey + "["
921 + processInstance.getId() + "]." + variable + "="
928 * Injects a single SDNC adapter callback request. The specified callback data
929 * may contain the placeholder string ((REQUEST-ID)) which is replaced with
930 * the actual SDNC request ID. Note: this is not the requestId in the original
932 * @param contentType the HTTP content type for the callback
933 * @param content the content of the callback
934 * @param timeout the timeout in milliseconds
935 * @return true if the callback could be injected, false otherwise
937 protected boolean injectSDNCRestCallback(String contentType, String content, long timeout) {
938 String sdncRequestId = (String) getProcessVariable("SDNCAdapterRestV1",
939 "SDNCAResponse_CORRELATOR", timeout);
941 if (sdncRequestId == null) {
942 sdncRequestId = (String) getProcessVariable("SDNCAdapterRestV2",
943 "SDNCAResponse_CORRELATOR", timeout);
946 if (sdncRequestId == null) {
950 content = content.replace("((REQUEST-ID))", sdncRequestId);
951 // Deprecated usage. All test code should switch to the (( ... )) syntax.
952 content = content.replace("{{REQUEST-ID}}", sdncRequestId);
954 msoLogger.debug("Injecting SDNC adapter callback");
956 Response response = workflowMessageResource.deliver(contentType, "SDNCAResponse", sdncRequestId, content);
957 msoLogger.debug("Workflow response to SDNC adapter callback: " + response);
962 * Injects a single SDNC adapter callback request. The specified callback data
963 * may contain the placeholder string ((REQUEST-ID)) which is replaced with
964 * the actual SDNC request ID. Note: this is not the requestId in the original
966 * @param content the content of the callback
967 * @param respCode the response code (normally 200)
968 * @param respMsg the response message (normally "OK")
969 * @param timeout the timeout in milliseconds
970 * @return true if the callback could be injected, false otherwise
972 protected boolean injectSDNCCallback(int respCode, String respMsg,
973 String content, long timeout) {
975 String sdncRequestId = (String) getProcessVariable("sdncAdapter",
976 "SDNCA_requestId", timeout);
978 if (sdncRequestId == null) {
982 content = content.replace("((REQUEST-ID))", sdncRequestId);
983 // Deprecated usage. All test code should switch to the (( ... )) syntax.
984 content = content.replace("{{REQUEST-ID}}", sdncRequestId);
986 // TODO this needs to be fixed. It is causing double tags and content
987 // Need to parse content before setting below since content includes not just RequestData or modify callback files to only contain RequestData contents.
989 msoLogger.debug("Injecting SDNC adapter callback");
990 CallbackHeader callbackHeader = new CallbackHeader();
991 callbackHeader.setRequestId(sdncRequestId);
992 callbackHeader.setResponseCode(String.valueOf(respCode));
993 callbackHeader.setResponseMessage(respMsg);
994 SDNCAdapterCallbackRequest sdncAdapterCallbackRequest = new SDNCAdapterCallbackRequest();
995 sdncAdapterCallbackRequest.setCallbackHeader(callbackHeader);
996 sdncAdapterCallbackRequest.setRequestData(content);
997 SDNCAdapterResponse sdncAdapterResponse = callbackService.sdncAdapterCallback(sdncAdapterCallbackRequest);
998 msoLogger.debug("Workflow response to SDNC adapter callback: " + sdncAdapterResponse);
1004 * Injects a single VNF adapter callback request. The specified callback data
1005 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
1006 * the actual message ID. Note: this is not the requestId in the original
1008 * @param contentType the HTTP content type for the callback
1009 * @param content the content of the callback
1010 * @param timeout the timeout in milliseconds
1011 * @return true if the callback could be injected, false otherwise
1013 protected boolean injectVnfAdapterRestCallback(String contentType, String content, long timeout) {
1014 String messageId = (String) getProcessVariable("vnfAdapterRestV1",
1015 "VNFAResponse_CORRELATOR", timeout);
1017 if (messageId == null) {
1021 content = content.replace("((MESSAGE-ID))", messageId);
1022 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1023 content = content.replace("{{MESSAGE-ID}}", messageId);
1025 msoLogger.debug("Injecting VNF adapter callback");
1027 Response response = workflowMessageResource.deliver(contentType, "VNFAResponse", messageId, content);
1028 msoLogger.debug("Workflow response to VNF adapter callback: " + response);
1033 * Injects a Create VNF adapter callback request. The specified callback data
1034 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
1035 * the actual message ID. It may also contain the placeholder string
1036 * ((REQUEST-ID)) which is replaced request ID of the original MSO request.
1037 * @param content the content of the callback
1038 * @param timeout the timeout in milliseconds
1039 * @return true if the callback could be injected, false otherwise
1040 * @throws JAXBException if the content does not adhere to the schema
1042 protected boolean injectCreateVNFCallback(String content, long timeout) {
1044 String messageId = (String) getProcessVariable("vnfAdapterCreateV1",
1045 "VNFC_messageId", timeout);
1047 if (messageId == null) {
1051 content = content.replace("((MESSAGE-ID))", messageId);
1052 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1053 content = content.replace("{{MESSAGE-ID}}", messageId);
1055 if(content.contains("((REQUEST-ID))")){
1056 content = content.replace("((REQUEST-ID))", msoRequestId);
1057 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1058 content = content.replace("{{REQUEST-ID}}", msoRequestId);
1061 msoLogger.debug("Injecting VNF adapter callback");
1063 // Is it possible to unmarshal this with JAXB? I couldn't.
1065 CreateVnfNotification createVnfNotification = new CreateVnfNotification();
1066 XPathTool xpathTool = new VnfNotifyXPathTool();
1067 xpathTool.setXML(content);
1070 String completed = xpathTool.evaluate(
1071 "/tns:createVnfNotification/tns:completed/text()");
1072 createVnfNotification.setCompleted("true".equals(completed));
1074 String vnfId = xpathTool.evaluate(
1075 "/tns:createVnfNotification/tns:vnfId/text()");
1076 createVnfNotification.setVnfId(vnfId);
1078 NodeList entries = (NodeList) xpathTool.evaluate(
1079 "/tns:createVnfNotification/tns:outputs/tns:entry",
1080 XPathConstants.NODESET);
1082 CreateVnfNotificationOutputs outputs = new CreateVnfNotificationOutputs();
1084 for (int i = 0; i < entries.getLength(); i++) {
1085 Node node = entries.item(i);
1087 if (node.getNodeType() == Node.ELEMENT_NODE) {
1088 Element entry = (Element) node;
1089 String key = entry.getElementsByTagNameNS("*", "key").item(0).getTextContent();
1090 String value = entry.getElementsByTagNameNS("*", "value").item(0).getTextContent();
1091 outputs.add(key, value);
1095 createVnfNotification.setOutputs(outputs);
1097 VnfRollback rollback = new VnfRollback();
1099 String cloudSiteId = xpathTool.evaluate(
1100 "/tns:createVnfNotification/tns:rollback/tns:cloudSiteId/text()");
1101 rollback.setCloudSiteId(cloudSiteId);
1103 String requestId = xpathTool.evaluate(
1104 "/tns:createVnfNotification/tns:rollback/tns:msoRequest/tns:requestId/text()");
1105 String serviceInstanceId = xpathTool.evaluate(
1106 "/tns:createVnfNotification/tns:rollback/tns:msoRequest/tns:serviceInstanceId/text()");
1108 if (requestId != null || serviceInstanceId != null) {
1109 MsoRequest msoRequest = new MsoRequest();
1110 msoRequest.setRequestId(requestId);
1111 msoRequest.setServiceInstanceId(serviceInstanceId);
1112 rollback.setMsoRequest(msoRequest);
1115 String tenantCreated = xpathTool.evaluate(
1116 "/tns:createVnfNotification/tns:rollback/tns:tenantCreated/text()");
1117 rollback.setTenantCreated("true".equals(tenantCreated));
1119 String tenantId = xpathTool.evaluate(
1120 "/tns:createVnfNotification/tns:rollback/tns:tenantId/text()");
1121 rollback.setTenantId(tenantId);
1123 String vnfCreated = xpathTool.evaluate(
1124 "/tns:createVnfNotification/tns:rollback/tns:vnfCreated/text()");
1125 rollback.setVnfCreated("true".equals(vnfCreated));
1127 String rollbackVnfId = xpathTool.evaluate(
1128 "/tns:createVnfNotification/tns:rollback/tns:vnfId/text()");
1129 rollback.setVnfId(rollbackVnfId);
1131 createVnfNotification.setRollback(rollback);
1133 } catch (Exception e) {
1134 msoLogger.debug("Failed to unmarshal VNF callback content:");
1135 msoLogger.debug(content);
1139 VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl();
1142 notifyService.createVnfNotification(
1144 createVnfNotification.isCompleted(),
1145 createVnfNotification.getException(),
1146 createVnfNotification.getErrorMessage(),
1147 createVnfNotification.getVnfId(),
1148 createVnfNotification.getOutputs(),
1149 createVnfNotification.getRollback());
1155 * Injects a Delete VNF adapter callback request. The specified callback data
1156 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
1157 * the actual message ID. It may also contain the placeholder string
1158 * ((REQUEST-ID)) which is replaced request ID of the original MSO request.
1159 * @param content the content of the callback
1160 * @param timeout the timeout in milliseconds
1161 * @return true if the callback could be injected, false otherwise
1162 * @throws JAXBException if the content does not adhere to the schema
1164 protected boolean injectDeleteVNFCallback(String content, long timeout) {
1166 String messageId = (String) getProcessVariable("vnfAdapterDeleteV1",
1167 "VNFDEL_uuid", timeout);
1169 if (messageId == null) {
1173 content = content.replace("((MESSAGE-ID))", messageId);
1174 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1175 content = content.replace("{{MESSAGE-ID}}", messageId);
1177 msoLogger.debug("Injecting VNF adapter delete callback");
1179 // Is it possible to unmarshal this with JAXB? I couldn't.
1181 DeleteVnfNotification deleteVnfNotification = new DeleteVnfNotification();
1182 XPathTool xpathTool = new VnfNotifyXPathTool();
1183 xpathTool.setXML(content);
1186 String completed = xpathTool.evaluate(
1187 "/tns:deleteVnfNotification/tns:completed/text()");
1188 deleteVnfNotification.setCompleted("true".equals(completed));
1189 // if notification failure, set the exception and error message
1190 if (deleteVnfNotification.isCompleted() == false) {
1191 deleteVnfNotification.setException(MsoExceptionCategory.INTERNAL);
1192 deleteVnfNotification.setErrorMessage(xpathTool.evaluate(
1193 "/tns:deleteVnfNotification/tns:errorMessage/text()")) ;
1196 } catch (Exception e) {
1197 msoLogger.debug("Failed to unmarshal VNF Delete callback content:");
1198 msoLogger.debug(content);
1202 VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl();
1205 notifyService.deleteVnfNotification(
1207 deleteVnfNotification.isCompleted(),
1208 deleteVnfNotification.getException(),
1209 deleteVnfNotification.getErrorMessage());
1215 * Injects a Update VNF adapter callback request. The specified callback data
1216 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
1217 * the actual message ID. It may also contain the placeholder string
1218 * ((REQUEST-ID)) which is replaced request ID of the original MSO request.
1219 * @param content the content of the callback
1220 * @param timeout the timeout in milliseconds
1221 * @return true if the callback could be injected, false otherwise
1222 * @throws JAXBException if the content does not adhere to the schema
1224 protected boolean injectUpdateVNFCallback(String content, long timeout) {
1226 String messageId = (String) getProcessVariable("vnfAdapterUpdate",
1227 "VNFU_messageId", timeout);
1229 if (messageId == null) {
1233 content = content.replace("((MESSAGE-ID))", messageId);
1234 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1235 content = content.replace("{{MESSAGE-ID}}", messageId);
1237 content = content.replace("((REQUEST-ID))", msoRequestId);
1238 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1239 content = content.replace("{{REQUEST-ID}}", msoRequestId);
1241 msoLogger.debug("Injecting VNF adapter callback");
1243 // Is it possible to unmarshal this with JAXB? I couldn't.
1245 UpdateVnfNotification updateVnfNotification = new UpdateVnfNotification();
1246 XPathTool xpathTool = new VnfNotifyXPathTool();
1247 xpathTool.setXML(content);
1250 String completed = xpathTool.evaluate(
1251 "/tns:updateVnfNotification/tns:completed/text()");
1252 updateVnfNotification.setCompleted("true".equals(completed));
1254 NodeList entries = (NodeList) xpathTool.evaluate(
1255 "/tns:updateVnfNotification/tns:outputs/tns:entry",
1256 XPathConstants.NODESET);
1258 UpdateVnfNotificationOutputs outputs = new UpdateVnfNotificationOutputs();
1260 for (int i = 0; i < entries.getLength(); i++) {
1261 Node node = entries.item(i);
1263 if (node.getNodeType() == Node.ELEMENT_NODE) {
1264 Element entry = (Element) node;
1265 String key = entry.getElementsByTagNameNS("*", "key").item(0).getTextContent();
1266 String value = entry.getElementsByTagNameNS("*", "value").item(0).getTextContent();
1267 outputs.add(key, value);
1271 updateVnfNotification.setOutputs(outputs);
1273 VnfRollback rollback = new VnfRollback();
1275 String cloudSiteId = xpathTool.evaluate(
1276 "/tns:updateVnfNotification/tns:rollback/tns:cloudSiteId/text()");
1277 rollback.setCloudSiteId(cloudSiteId);
1279 String requestId = xpathTool.evaluate(
1280 "/tns:updateVnfNotification/tns:rollback/tns:msoRequest/tns:requestId/text()");
1281 String serviceInstanceId = xpathTool.evaluate(
1282 "/tns:updateVnfNotification/tns:rollback/tns:msoRequest/tns:serviceInstanceId/text()");
1284 if (requestId != null || serviceInstanceId != null) {
1285 MsoRequest msoRequest = new MsoRequest();
1286 msoRequest.setRequestId(requestId);
1287 msoRequest.setServiceInstanceId(serviceInstanceId);
1288 rollback.setMsoRequest(msoRequest);
1291 String tenantCreated = xpathTool.evaluate(
1292 "/tns:updateVnfNotification/tns:rollback/tns:tenantCreated/text()");
1293 rollback.setTenantCreated("true".equals(tenantCreated));
1295 String tenantId = xpathTool.evaluate(
1296 "/tns:updateVnfNotification/tns:rollback/tns:tenantId/text()");
1297 rollback.setTenantId(tenantId);
1299 String vnfCreated = xpathTool.evaluate(
1300 "/tns:updateVnfNotification/tns:rollback/tns:vnfCreated/text()");
1301 rollback.setVnfCreated("true".equals(vnfCreated));
1303 String rollbackVnfId = xpathTool.evaluate(
1304 "/tns:updateVnfNotification/tns:rollback/tns:vnfId/text()");
1305 rollback.setVnfId(rollbackVnfId);
1307 updateVnfNotification.setRollback(rollback);
1309 } catch (Exception e) {
1310 msoLogger.debug("Failed to unmarshal VNF callback content:");
1311 msoLogger.debug(content);
1315 VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl();
1318 notifyService.updateVnfNotification(
1320 updateVnfNotification.isCompleted(),
1321 updateVnfNotification.getException(),
1322 updateVnfNotification.getErrorMessage(),
1323 updateVnfNotification.getOutputs(),
1324 updateVnfNotification.getRollback());
1330 * Runs a program to inject workflow messages into the test environment.
1331 * A program is essentially just a list of keys that identify event data
1332 * to be injected, in sequence. An example program:
1336 * Errors are handled with junit assertions and will cause the test to fail.
1337 * NOTE: Each callback must have a workflow message type associated with it.
1338 * @param callbacks an object containing event data for the program
1339 * @param program the program to execute
1341 protected void injectWorkflowMessages(CallbackSet callbacks, String program) {
1343 String[] cmds = program.replaceAll("\\s+", "").split(",");
1345 for (String cmd : cmds) {
1346 String action = cmd;
1347 String modifier = "STD";
1349 if (cmd.contains(":")) {
1350 String[] parts = cmd.split(":");
1352 modifier = parts[1];
1355 String messageType = null;
1356 String content = null;
1357 String contentType = null;
1359 if ("STD".equals(modifier)) {
1360 CallbackData callbackData = callbacks.get(action);
1362 if (callbackData == null) {
1363 String msg = "No '" + action + "' workflow message callback is defined";
1364 msoLogger.debug(msg);
1368 messageType = callbackData.getMessageType();
1370 if (messageType == null || messageType.trim().equals("")) {
1371 String msg = "No workflow message type is defined in the '" + action + "' callback";
1372 msoLogger.debug(msg);
1376 content = callbackData.getContent();
1377 contentType = callbackData.getContentType();
1379 String msg = "Invalid workflow message program modifier: '" + modifier + "'";
1380 msoLogger.debug(msg);
1384 if (!injectWorkflowMessage(contentType, messageType, content, 10000)) {
1385 fail("Failed to inject '" + action + "' workflow message");
1390 } catch (InterruptedException e) {
1391 fail("Interrupted after injection of '" + action + "' workflow message");
1397 * Injects a workflow message. The specified callback data may contain the
1398 * placeholder string ((CORRELATOR)) which is replaced with the actual
1400 * @param contentType the HTTP contentType for the message (possibly null)
1401 * @param messageType the message type
1402 * @param content the message content (possibly null)
1403 * @param timeout the timeout in milliseconds
1404 * @return true if the message could be injected, false otherwise
1406 protected boolean injectWorkflowMessage(String contentType, String messageType, String content, long timeout) {
1407 String correlator = (String) getProcessVariable("ReceiveWorkflowMessage",
1408 messageType + "_CORRELATOR", timeout);
1410 if (correlator == null) {
1414 if (content != null) {
1415 content = content.replace("((CORRELATOR))", correlator);
1418 msoLogger.debug("Injecting " + messageType + " message");
1420 Response response = workflowMessageResource.deliver(contentType, messageType, correlator, content);
1421 msoLogger.debug("Workflow response to " + messageType + " message: " + response);
1426 * Runs a program to inject sniro workflow messages into the test environment.
1427 * A program is essentially just a list of keys that identify event data
1428 * to be injected, in sequence. For more details, see
1429 * injectSNIROCallbacks(String contentType, String messageType, String content, long timeout)
1431 * Errors are handled with junit assertions and will cause the test to fail.
1432 * NOTE: Each callback must have a workflow message type associated with it.
1434 * @param callbacks an object containing event data for the program
1435 * @param program the program to execute
1437 protected void injectSNIROCallbacks(CallbackSet callbacks, String program) {
1439 String[] cmds = program.replaceAll("\\s+", "").split(",");
1441 for (String cmd : cmds) {
1442 String action = cmd;
1443 String modifier = "STD";
1445 if (cmd.contains(":")) {
1446 String[] parts = cmd.split(":");
1448 modifier = parts[1];
1451 String messageType = null;
1452 String content = null;
1453 String contentType = null;
1455 if ("STD".equals(modifier)) {
1456 CallbackData callbackData = callbacks.get(action);
1458 if (callbackData == null) {
1459 String msg = "No '" + action + "' workflow message callback is defined";
1460 msoLogger.debug(msg);
1464 messageType = callbackData.getMessageType();
1466 if (messageType == null || messageType.trim().equals("")) {
1467 String msg = "No workflow message type is defined in the '" + action + "' callback";
1468 msoLogger.debug(msg);
1472 content = callbackData.getContent();
1473 contentType = callbackData.getContentType();
1475 String msg = "Invalid workflow message program modifier: '" + modifier + "'";
1476 msoLogger.debug(msg);
1480 if (!injectSNIROCallbacks(contentType, messageType, content, 10000)) {
1481 fail("Failed to inject '" + action + "' workflow message");
1486 } catch (InterruptedException e) {
1487 fail("Interrupted after injection of '" + action + "' workflow message");
1493 * Injects a sniro workflow message. The specified callback response may
1494 * contain the placeholder strings ((CORRELATOR)) and ((SERVICE_RESOURCE_ID))
1495 * The ((CORRELATOR)) is replaced with the actual correlator value from the
1496 * request. The ((SERVICE_RESOURCE_ID)) is replaced with the actual serviceResourceId
1497 * value from the sniro request. Currently this only works with sniro request
1498 * that contain only 1 resource.
1500 * @param contentType the HTTP contentType for the message (possibly null)
1501 * @param messageType the message type
1502 * @param content the message content (possibly null)
1503 * @param timeout the timeout in milliseconds
1504 * @return true if the message could be injected, false otherwise
1506 protected boolean injectSNIROCallbacks(String contentType, String messageType, String content, long timeout) {
1507 String correlator = (String) getProcessVariable("ReceiveWorkflowMessage",
1508 messageType + "_CORRELATOR", timeout);
1510 if (correlator == null) {
1513 if (content != null) {
1514 content = content.replace("((CORRELATOR))", correlator);
1515 if(messageType.equalsIgnoreCase("SNIROResponse")){
1516 ServiceDecomposition decomp = (ServiceDecomposition) getProcessVariable("Homing", "serviceDecomposition", timeout);
1517 List<Resource> resourceList = decomp.getServiceResources();
1518 if(resourceList.size() == 1){
1519 String resourceId = "";
1520 for(Resource resource:resourceList){
1521 resourceId = resource.getResourceId();
1523 String homingList = getJsonValue(content, "solutionInfo.placementInfo");
1524 JSONArray placementArr = null;
1526 placementArr = new JSONArray(homingList);
1528 catch (Exception e) {
1531 if(placementArr.length() == 1){
1532 content = content.replace("((SERVICE_RESOURCE_ID))", resourceId);
1534 String licenseInfoList = getJsonValue(content, "solutionInfo.licenseInfo");
1535 JSONArray licenseArr = null;
1537 licenseArr = new JSONArray(licenseInfoList);
1539 catch (Exception e) {
1542 if(licenseArr.length() == 1){
1543 content = content.replace("((SERVICE_RESOURCE_ID))", resourceId);
1548 String homingList = getJsonValue(content, "solutionInfo.placementInfo");
1549 String licenseInfoList = getJsonValue(content, "solutionInfo.licenseInfo");
1550 JSONArray placementArr = new JSONArray(homingList);
1551 JSONArray licenseArr = new JSONArray(licenseInfoList);
1552 for (Resource resource: resourceList) {
1553 String resourceModuleName = resource.getModelInfo().getModelInstanceName();
1554 String resourceId = resource.getResourceId();
1556 for (int i=0; i<placementArr.length(); i++) {
1557 JSONObject placementObj = placementArr.getJSONObject(i);
1558 String placementModuleName = placementObj.getString("resourceModuleName");
1559 if (placementModuleName.equalsIgnoreCase(resourceModuleName)) {
1560 String placementString = placementObj.toString();
1561 placementString = placementString.replace("((SERVICE_RESOURCE_ID))", resourceId);
1562 JSONObject newPlacementObj = new JSONObject(placementString);
1563 placementArr.put(i, newPlacementObj);
1567 for (int i=0; i<licenseArr.length(); i++) {
1568 JSONObject licenseObj = licenseArr.getJSONObject(i);
1569 String licenseModuleName = licenseObj.getString("resourceModuleName");
1570 if (licenseModuleName.equalsIgnoreCase(resourceModuleName)) {
1571 String licenseString = licenseObj.toString();
1572 licenseString = licenseString.replace("((SERVICE_RESOURCE_ID))", resourceId);
1573 JSONObject newLicenseObj = new JSONObject(licenseString);
1574 licenseArr.put(i, newLicenseObj);
1578 String newPlacementInfos = placementArr.toString();
1579 String newLicenseInfos = licenseArr.toString();
1580 content = updJsonValue(content, "solutionInfo.placementInfo", newPlacementInfos);
1581 content = updJsonValue(content, "solutionInfo.licenseInfo", newLicenseInfos);
1583 catch(Exception e) {
1590 msoLogger.debug("Injecting " + messageType + " message");
1592 Response response = workflowMessageResource.deliver(contentType, messageType, correlator, content);
1593 msoLogger.debug("Workflow response to " + messageType + " message: " + response);
1599 * Wait for the process to end.
1600 * @param businessKey the process business key
1601 * @param timeout the amount of time to wait, in milliseconds
1603 protected void waitForProcessEnd(String businessKey, long timeout) {
1604 msoLogger.debug("Waiting " + timeout + "ms for process with business key " +
1605 businessKey + " to end");
1607 long now = System.currentTimeMillis() + timeout;
1608 long endTime = now + timeout;
1610 while (now <= endTime) {
1611 if (isProcessEnded(businessKey)) {
1612 msoLogger.debug("Process with business key " + businessKey + " has ended");
1618 } catch (InterruptedException e) {
1619 String msg = "Interrupted waiting for process with business key " +
1620 businessKey + " to end";
1621 msoLogger.debug(msg);
1625 now = System.currentTimeMillis();
1628 String msg = "Process with business key " + businessKey +
1629 " did not end within " + timeout + "ms";
1630 msoLogger.debug(msg);
1635 * Wait for the process to end. Must be used when multiple process instances exist with
1636 * this same business key such as when its passed to subflows or shared across multiple
1639 * @param businessKey the process business key
1640 * @param processName the process definition name
1641 * @param timeout the amount of time to wait, in milliseconds
1644 protected void waitForProcessEnd(String businessKey, String processName, long timeout) {
1645 msoLogger.debug("Waiting " + timeout + "ms for process with business key " +
1646 businessKey + " to end");
1648 long now = System.currentTimeMillis() + timeout;
1649 long endTime = now + timeout;
1651 while (now <= endTime) {
1652 if (isProcessEnded(businessKey, processName)) {
1653 msoLogger.debug("Process with business key " + businessKey + " has ended");
1659 } catch (InterruptedException e) {
1660 String msg = "Interrupted waiting for process with business key " +
1661 businessKey + " to end";
1662 msoLogger.debug(msg);
1666 now = System.currentTimeMillis();
1669 String msg = "Process with business key " + businessKey +
1670 " did not end within " + timeout + "ms";
1671 msoLogger.debug(msg);
1676 * Verifies that the specified historic process variable has the specified value.
1677 * If the variable does not have the specified value, the test is failed.
1679 * @param businessKey the process business key
1680 * @param variable the variable name
1681 * @param value the expected variable value
1683 protected void checkVariable(String businessKey, String variable, Object value) {
1684 if (!isProcessEnded(businessKey)) {
1685 fail("Cannot get historic variable " + variable + " because process with business key " +
1686 businessKey + " has not ended");
1689 Object variableValue = getVariableFromHistory(businessKey, variable);
1690 assertEquals(value, variableValue);
1694 * Checks to see if the specified process is ended.
1695 * @param businessKey the process business Key
1696 * @return true if the process is ended
1698 protected boolean isProcessEnded(String businessKey) {
1699 HistoricProcessInstance processInstance = historyService
1700 .createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
1701 return processInstance != null && processInstance.getEndTime() != null;
1705 * Checks to see if the specified process is ended.
1707 * @param processInstanceId the process Instance Id
1708 * @return true if the process is ended
1710 protected boolean isProcessEndedByProcessInstanceId(String processInstanceId) {
1711 HistoricProcessInstance processInstance = historyService
1712 .createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
1713 return processInstance != null && processInstance.getEndTime() != null;
1717 * Checks to see if the specified process is ended.
1721 //TODO combine into 1
1722 private boolean isProcessEnded(String businessKey, String processName) {
1723 HistoricProcessInstance processInstance = historyService
1724 .createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).processDefinitionName(processName).singleResult();
1725 return processInstance != null && processInstance.getEndTime() != null;
1729 * Gets a variable value from a historical process instance. The business key must be unique.
1731 * @param businessKey the process business key
1732 * @param variableName the variable name
1733 * @return the variable value or null if the variable does not exist
1735 protected Object getVariableFromHistory(String businessKey, String variableName) {
1737 HistoricProcessInstance processInstance = historyService
1738 .createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
1740 if (processInstance == null) {
1744 HistoricVariableInstance v = historyService
1745 .createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1746 .variableName(variableName).singleResult();
1747 return v == null ? null : v.getValue();
1748 } catch (Exception e) {
1749 msoLogger.debug("Error retrieving variable " + variableName +
1750 " from historical process with business key " + businessKey + ": " + e);
1756 * Gets a variable value from a process instance based on businessKey and process name.
1757 * Must be used when multiple instances exist with the same business key such as when
1758 * business key is passed to subflows or shared across multiple processes. This method
1759 * can obtain variables from mainflows and from subflows.
1761 * @param businessKey the process business key
1762 * @param processName the process definition name
1763 * @param variableName the variable name
1764 * @return the variable value or null if the variable does not exist
1767 protected Object getVariableFromHistory(String businessKey, String processName, String variableName){
1769 HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).processDefinitionName(processName)
1772 if(processInstance == null){
1775 HistoricVariableInstance variable = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId()).variableName(variableName).singleResult();
1777 return variable == null ? null : variable.getValue();
1778 }catch(ProcessEngineException e){
1779 msoLogger.debug("Multiple proccess instances exist with process name " + processName + " and business key " + businessKey + ". Must pass instance index as a parameter.");
1781 }catch(Exception e){
1782 msoLogger.debug("Error retrieving variable " + variableName + " from historical process for process " + processName + " with business key " + businessKey + ": " + e);
1788 * Gets the value of a process variable from x instance of y process. Must be used when
1789 * multiple instances exist with the same business key AND process name. This method
1790 * shall be used primarily for obtaining subflow variables when the business key is
1791 * passed to the subflow AND the subflow is called multiple times in a given flow.
1793 * @param businessKey the process business key
1794 * @param processName the name of the subflow that contains the variable
1795 * @param variableName the variable name
1796 * @param processInstanceIndex the instance in which the subprocess was called
1797 * @return the variable value or null if the variable does not exist
1800 protected Object getVariableFromHistory(String businessKey, int subflowInstanceIndex, String processName, String variableName){
1802 List<HistoricProcessInstance> processInstanceList = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).processDefinitionName(processName)
1805 if(processInstanceList == null){
1808 processInstanceList.sort((m1, m2) -> m1.getStartTime().compareTo(m2.getStartTime()));
1810 HistoricProcessInstance processInstance = processInstanceList.get(subflowInstanceIndex);
1811 HistoricVariableInstance variable = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1812 .variableName(variableName).singleResult();
1814 return variable == null ? null : variable.getValue();
1815 }catch(Exception e) {
1816 msoLogger.debug("Error retrieving variable " + variableName + " from historical process for process " + processName + " with business key " + businessKey + ": " + e);
1823 * Gets the value of a subflow variable from the specified subflow's
1824 * historical process instance.
1826 * DEPRECATED - Use method getVariableFromHistory(businessKey, processName, variableName) instead
1828 * @param subflowName - the name of the subflow that contains the variable
1829 * @param variableName the variable name
1831 * @return the variable value, or null if the variable could not be obtained
1835 protected Object getVariableFromSubflowHistory(String subflowName, String variableName) {
1837 List<HistoricProcessInstance> processInstanceList = historyService
1838 .createHistoricProcessInstanceQuery().processDefinitionName(subflowName).list();
1840 if (processInstanceList == null) {
1844 processInstanceList.sort((m1, m2) -> m1.getStartTime().compareTo(m2.getStartTime()));
1846 HistoricProcessInstance processInstance = processInstanceList.get(0);
1848 HistoricVariableInstance v = historyService
1849 .createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1850 .variableName(variableName).singleResult();
1851 return v == null ? null : v.getValue();
1852 } catch (Exception e) {
1853 msoLogger.debug("Error retrieving variable " + variableName +
1854 " from sub flow: " + subflowName + ", Exception is: " + e);
1860 * Gets the value of a subflow variable from the subflow's
1861 * historical process x instance.
1863 * DEPRECATED: Use method getVariableFromHistory(businessKey, processInstanceIndex, processName, variableName) instead
1865 * @param subflowName - the name of the subflow that contains the variable
1866 * @param variableName the variable name
1867 * @param subflowInstanceIndex - the instance of the subflow (use when same subflow is called more than once from mainflow)
1869 * @return the variable value, or null if the variable could not be obtained
1872 protected Object getVariableFromSubflowHistory(int subflowInstanceIndex, String subflowName, String variableName) {
1874 List<HistoricProcessInstance> processInstanceList = historyService.createHistoricProcessInstanceQuery().processDefinitionName(subflowName).list();
1876 if (processInstanceList == null) {
1880 processInstanceList.sort((m1, m2) -> m1.getStartTime().compareTo(m2.getStartTime()));
1882 HistoricProcessInstance processInstance = processInstanceList.get(subflowInstanceIndex);
1884 HistoricVariableInstance v = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1885 .variableName(variableName).singleResult();
1886 return v == null ? null : v.getValue();
1887 } catch (Exception e) {
1888 msoLogger.debug("Error retrieving variable " + variableName +
1889 " from " + subflowInstanceIndex + " instance index of sub flow: " + subflowName + ", Exception is: " + e);
1895 * Extracts text from an XML element. This method is not namespace aware
1896 * (namespaces are ignored). The first matching element is selected.
1897 * @param xml the XML document or fragment
1898 * @param tag the desired element, e.g. "<name>"
1899 * @return the element text, or null if the element was not found
1901 protected String getXMLTextElement(String xml, String tag) {
1902 xml = removeXMLNamespaces(xml);
1904 if (!tag.startsWith("<")) {
1905 tag = "<" + tag + ">";
1908 int start = xml.indexOf(tag);
1914 int end = xml.indexOf('<', start + tag.length());
1920 return xml.substring(start + tag.length(), end);
1924 * Removes namespace definitions and prefixes from XML, if any.
1926 private String removeXMLNamespaces(String xml) {
1927 // remove xmlns declaration
1928 xml = xml.replaceAll("xmlns.*?(\"|\').*?(\"|\')", "");
1930 // remove opening tag prefix
1931 xml = xml.replaceAll("(<)(\\w+:)(.*?>)", "$1$3");
1933 // remove closing tags prefix
1934 xml = xml.replaceAll("(</)(\\w+:)(.*?>)", "$1$3");
1936 // remove extra spaces left when xmlns declarations are removed
1937 xml = xml.replaceAll("\\s+>", ">");
1943 * Asserts that two XML documents are semantically equivalent. Differences
1944 * in whitespace or in namespace usage do not affect the comparison.
1945 * @param expected the expected XML
1946 * @param actual the XML to test
1947 * @throws SAXException
1948 * @throws IOException
1950 public static void assertXMLEquals(String expected, String actual)
1951 throws SAXException, IOException {
1952 XMLUnit.setIgnoreWhitespace(true);
1953 XMLUnit.setIgnoreAttributeOrder(true);
1954 DetailedDiff diff = new DetailedDiff(XMLUnit.compareXML(expected, actual));
1955 List<?> allDifferences = diff.getAllDifferences();
1956 assertEquals("Differences found: " + diff.toString(), 0, allDifferences.size());
1960 * A test implementation of AsynchronousResponse.
1962 public class TestAsyncResponse {
1963 Response response = null;
1968 public synchronized void setResponse(Response response) {
1969 this.response = response;
1973 * Gets the response.
1974 * @return the response, or null if none has been produced yet
1976 public synchronized Response getResponse() {
1982 * An object that contains callback data for a "program".
1984 public class CallbackSet {
1985 private final Map<String, CallbackData> map = new HashMap<>();
1988 * Add untyped callback data to the set.
1989 * @param action the action with which the data is associated
1990 * @param content the callback data
1992 public void put(String action, String content) {
1993 map.put(action, new CallbackData(null, null, content));
1997 * Add callback data to the set.
1998 * @param action the action with which the data is associated
1999 * @param messageType the callback message type
2000 * @param content the callback data
2002 public void put(String action, String messageType, String content) {
2003 map.put(action, new CallbackData(null, messageType, content));
2007 * Add callback data to the set.
2008 * @param action the action with which the data is associated
2009 * @param contentType the callback HTTP content type
2010 * @param messageType the callback message type
2011 * @param content the callback data
2013 public void put(String action, String contentType, String messageType, String content) {
2014 map.put(action, new CallbackData(contentType, messageType, content));
2018 * Retrieve callback data from the set.
2019 * @param action the action with which the data is associated
2020 * @return the callback data, or null if there is none for the specified operation
2022 public CallbackData get(String action) {
2023 return map.get(action);
2028 * Represents a callback data item.
2030 public class CallbackData {
2031 private final String contentType;
2032 private final String messageType;
2033 private final String content;
2037 * @param contentType the HTTP content type (optional)
2038 * @param messageType the callback message type (optional)
2039 * @param content the content
2041 public CallbackData(String contentType, String messageType, String content) {
2042 this.contentType = contentType;
2043 this.messageType = messageType;
2044 this.content = content;
2048 * Gets the callback HTTP content type, possibly null.
2050 public String getContentType() {
2055 * Gets the callback message type, possibly null.
2057 public String getMessageType() {
2062 * Gets the callback content.
2064 public String getContent() {
2070 * A tool for evaluating XPath expressions.
2072 protected class XPathTool {
2073 private final DocumentBuilderFactory factory;
2074 private final SimpleNamespaceContext context = new SimpleNamespaceContext();
2075 private final XPath xpath = XPathFactory.newInstance().newXPath();
2076 private String xml = null;
2077 private Document doc = null;
2082 public XPathTool() {
2083 factory = DocumentBuilderFactory.newInstance();
2084 factory.setNamespaceAware(true);
2085 xpath.setNamespaceContext(context);
2090 * @param prefix the namespace prefix
2091 * @param uri the namespace uri
2093 public synchronized void addNamespace(String prefix, String uri) {
2094 context.add(prefix, uri);
2098 * Sets the XML content to be operated on.
2099 * @param xml the XML content
2101 public synchronized void setXML(String xml) {
2107 * Returns the document object.
2108 * @return the document object, or null if XML has not been set
2109 * @throws SAXException
2110 * @throws IOException
2111 * @throws ParserConfigurationException
2113 public synchronized Document getDocument()
2114 throws ParserConfigurationException, IOException, SAXException {
2124 * Evaluates the specified XPath expression and returns a string result.
2125 * This method throws exceptions on error.
2126 * @param expression the expression
2127 * @return the result object
2128 * @throws ParserConfigurationException
2129 * @throws IOException
2130 * @throws SAXException
2131 * @throws XPathExpressionException on error
2133 public synchronized String evaluate(String expression)
2134 throws ParserConfigurationException, SAXException,
2135 IOException, XPathExpressionException {
2136 return (String) evaluate(expression, XPathConstants.STRING);
2140 * Evaluates the specified XPath expression.
2141 * This method throws exceptions on error.
2142 * @param expression the expression
2143 * @param returnType the return type
2144 * @return the result object
2145 * @throws ParserConfigurationException
2146 * @throws IOException
2147 * @throws SAXException
2148 * @throws XPathExpressionException on error
2150 public synchronized Object evaluate(String expression, QName returnType)
2151 throws ParserConfigurationException, SAXException,
2152 IOException, XPathExpressionException {
2155 XPathExpression expr = xpath.compile(expression);
2156 return expr.evaluate(doc, returnType);
2160 * Private helper method that builds the document object.
2161 * Assumes the calling method is synchronized.
2162 * @throws ParserConfigurationException
2163 * @throws IOException
2164 * @throws SAXException
2166 private void buildDocument() throws ParserConfigurationException,
2167 IOException, SAXException {
2170 throw new IOException("XML input is null");
2173 DocumentBuilder builder = factory.newDocumentBuilder();
2174 InputSource source = new InputSource(new StringReader(xml));
2175 doc = builder.parse(source);
2181 * A NamespaceContext class based on a Map.
2183 private class SimpleNamespaceContext implements NamespaceContext {
2184 private Map<String, String> prefixMap = new HashMap<>();
2185 private Map<String, String> uriMap = new HashMap<>();
2187 public synchronized void add(String prefix, String uri) {
2188 prefixMap.put(prefix, uri);
2189 uriMap.put(uri, prefix);
2193 public synchronized String getNamespaceURI(String prefix) {
2194 return prefixMap.get(prefix);
2198 public Iterator<String> getPrefixes(String uri) {
2199 List<String> list = new ArrayList<>();
2200 String prefix = uriMap.get(uri);
2201 if (prefix != null) {
2204 return list.iterator();
2208 public String getPrefix(String uri) {
2209 return uriMap.get(uri);
2214 * A VnfNotify XPathTool.
2216 protected class VnfNotifyXPathTool extends XPathTool {
2217 public VnfNotifyXPathTool() {
2218 addNamespace("tns", "http://org.onap.so/vnfNotify");
2223 * Helper class to make it easier to create this type.
2225 private static class CreateVnfNotificationOutputs
2226 extends CreateVnfNotification.Outputs {
2227 public void add(String key, String value) {
2228 Entry entry = new Entry();
2230 entry.setValue(value);
2231 getEntry().add(entry);
2236 * Helper class to make it easier to create this type.
2238 private static class UpdateVnfNotificationOutputs
2239 extends UpdateVnfNotification.Outputs {
2240 public void add(String key, String value) {
2241 Entry entry = new Entry();
2243 entry.setValue(value);
2244 getEntry().add(entry);