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.openecomp.mso.bpmn.core;
23 import org.camunda.bpm.engine.delegate.DelegateExecution;
26 * Used in the output variable mapping configuration of subflow call activity
27 * tasks to normalize subflow responses. The output mapping is normally set up
28 * as follows. Note that the order of these mappings is important!
32 * SOURCE EXPRESSION TARGET
33 * ${ResponseBuilder.buildWorkflowException(execution)} WorkflowException
34 * ${ResponseBuilder.buildWorkflowResponse(execution)} SomeResponseVariable
37 public class ResponseBuilder implements java.io.Serializable {
38 private static final long serialVersionUID = 1L;
41 * Creates a WorkflowException using data from the execution variables.
42 * If the variables do not indicate that there was an error, null
44 * @param execution the execution
46 public WorkflowException buildWorkflowException(DelegateExecution execution) {
48 String method = getClass().getSimpleName() + ".buildWorkflowException(" +
49 "execution=" + execution.getId() +
51 String isDebugLogEnabled = (String) execution.getVariable("isDebugLogEnabled");
52 logDebug("Entered " + method, isDebugLogEnabled);
54 String prefix = (String) execution.getVariable("prefix");
55 String processKey = getProcessKey(execution);
57 logDebug("processKey=" + processKey, isDebugLogEnabled);
59 // See if there"s already a WorkflowException object in the execution.
60 WorkflowException theException = (WorkflowException) execution.getVariable("WorkflowException");
62 if (theException != null) {
63 logDebug("Exited " + method + " - propagated " + theException, isDebugLogEnabled);
67 // Look in the legacy variables: ErrorResponse and ResponseCode
69 String errorResponse = trimString(execution.getVariable(prefix + "ErrorResponse"), null);
70 String responseCode = trimString(execution.getVariable(prefix + "ResponseCode"), null);
71 logDebug("errorResponse=" + errorResponse, isDebugLogEnabled);
72 logDebug("responseCode=" + responseCode, isDebugLogEnabled);
73 if (errorResponse != null || !isOneOf(responseCode, null, "0", "200", "201", "202", "204")) {
74 // This is an error condition. We need to return a WorkflowExcpetion
76 if (errorResponse == null) {
77 // No errorResponse string. See if there"s something in the Response variable
78 String response = trimString(execution.getVariable(processKey + "Response"), null);
79 if (response == null) {
80 errorResponse = "Received response code " + responseCode + " from " + processKey;
82 errorResponse = response;
86 // Some subflows may try to return a WorkflowException as XML in the
87 // errorResponse. If provided, use the errorCode and errorMessage
90 String maybeXML = removeXMLNamespaces(errorResponse);
92 String xmlErrorMessage = trimString(getXMLTextElement(maybeXML, "ErrorMessage"), null);
93 String xmlErrorCode = trimString(getXMLTextElement(maybeXML, "ErrorCode"), null);
95 if (xmlErrorMessage != null || xmlErrorCode != null) {
96 logDebug("xmlErrorMessage=" + xmlErrorMessage, isDebugLogEnabled);
97 logDebug("xmlErrorCode=" + xmlErrorCode, isDebugLogEnabled);
99 if (xmlErrorMessage == null) {
100 errorResponse = "Received error code " + xmlErrorCode + " from " + processKey;
102 errorResponse = xmlErrorMessage;
105 if (xmlErrorCode != null) {
106 responseCode = xmlErrorCode;
110 // Convert the responseCode to an integer
115 intResponseCode = Integer.valueOf(responseCode);
116 } catch (NumberFormatException e) {
118 intResponseCode = 2000;
121 // Convert 3-digit HTTP response codes (we should not be using them here)
122 // to appropriate 4-digit response codes
124 if (intResponseCode < 1000) {
125 if (intResponseCode >= 400 && intResponseCode <= 499) {
127 intResponseCode = 1002;
130 intResponseCode = 2000;
134 // Create a new WorkflowException object
136 theException = new WorkflowException(processKey, intResponseCode, errorResponse);
137 execution.setVariable("WorkflowException", theException);
138 logDebug("Exited " + method + " - created " + theException, isDebugLogEnabled);
142 logDebug("Exited " + method + " - no WorkflowException", isDebugLogEnabled);
147 * Returns the "Response" variable, unless the execution variables
148 * indicate there was an error. In that case, null is returned.
149 * @param execution the execution
151 public Object buildWorkflowResponse(DelegateExecution execution) {
153 String method = getClass().getSimpleName() + ".buildWorkflowResponse(" +
154 "execution=" + execution.getId() +
156 String isDebugLogEnabled = (String) execution.getVariable("isDebugLogEnabled");
157 logDebug("Entered " + method, isDebugLogEnabled);
159 String prefix = (String) execution.getVariable("prefix");
160 String processKey = getProcessKey(execution);
162 Object theResponse = null;
164 WorkflowException theException = (WorkflowException) execution.getVariable("WorkflowException");
165 String errorResponse = trimString(execution.getVariable(prefix + "ErrorResponse"), null);
166 String responseCode = trimString(execution.getVariable(prefix + "ResponseCode"), null);
168 if (theException == null && errorResponse == null &&
169 isOneOf(responseCode, null, "0", "200", "201", "202", "204")) {
171 theResponse = execution.getVariable("WorkflowResponse");
173 if (theResponse == null) {
174 theResponse = execution.getVariable(processKey + "Response");
178 logDebug("Exited " + method, isDebugLogEnabled);
183 * Checks if the specified item is one of the specified values.
184 * @param item the item
185 * @param values the list of values
186 * @return true if the item is in the list of values
188 private boolean isOneOf(Object item, Object ... values) {
189 if (values == null) {
193 for (Object value : values) {
199 if (value.equals(item)) {
209 * Creates a string value of the specified object, trimming whitespace in
210 * the process. If the result is null or empty, the specified empty string
211 * value is returned. Otherwise the trimmed value is returned. This method
212 * helps ensure consistent treatment of empty and null strings.
213 * @param object the object to convert (possibly null)
214 * @param emptyStringValue the desired value for empty results
216 private String trimString(Object object, String emptyStringValue) {
217 if (object == null) {
218 return emptyStringValue;
221 String s = String.valueOf(object).trim();
222 return s.equals("") ? emptyStringValue : s;
226 * Returns the process definition key (i.e. the process name) from the
228 * @param execution the execution
230 private String getProcessKey(DelegateExecution execution) {
231 Object testKey = execution.getVariable("testProcessKey");
233 if (testKey instanceof String) {
234 return (String) testKey;
237 return execution.getProcessEngineServices().getRepositoryService()
238 .getProcessDefinition(execution.getProcessDefinitionId()).getKey();
242 * Logs a message at the DEBUG level.
243 * @param message the message
244 * @param isDebugLogEnabled a flag indicating if DEBUG level is enabled
246 private void logDebug(String message, String isDebugLogEnabled) {
247 BPMNLogger.debug(isDebugLogEnabled, message);
251 * Removes namespace definitions and prefixes from XML, if any.
253 private String removeXMLNamespaces(String xml) {
254 // remove xmlns declaration
255 xml = xml.replaceAll("xmlns.*?(\"|\').*?(\"|\')", "");
257 // remove opening tag prefix
258 xml = xml.replaceAll("(<)(\\w+:)(.*?>)", "$1$3");
260 // remove closing tags prefix
261 xml = xml.replaceAll("(</)(\\w+:)(.*?>)", "$1$3");
263 // remove extra spaces left when xmlns declarations are removed
264 xml = xml.replaceAll("\\s+>", ">");
270 * Extracts text from an XML element. This method is not namespace aware
271 * (namespaces are ignored). The first matching element is selected.
272 * @param xml the XML document or fragment
273 * @param tag the desired element, e.g. "<name>"
274 * @return the element text, or null if the element was not found
276 private String getXMLTextElement(String xml, String tag) {
277 xml = removeXMLNamespaces(xml);
279 if (!tag.startsWith("<")) {
280 tag = "<" + tag + ">";
283 int start = xml.indexOf(tag);
289 int end = xml.indexOf('<', start + tag.length());
295 return xml.substring(start + tag.length(), end);