2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.openecomp.mso.bpmn.core;
24 import java.io.ByteArrayInputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.math.BigDecimal;
29 import java.util.Iterator;
31 import javax.xml.transform.stream.StreamSource;
33 import org.camunda.bpm.engine.ProcessEngineException;
34 import org.camunda.bpm.engine.delegate.DelegateExecution;
35 //import java.util.logging.Logger;
36 import org.camunda.bpm.engine.delegate.Expression;
38 import org.openecomp.mso.logger.MessageEnum;
39 import org.openecomp.mso.logger.MsoLogger;
41 import net.sf.saxon.Configuration;
42 import net.sf.saxon.s9api.DocumentBuilder;
43 import net.sf.saxon.s9api.Processor;
44 import net.sf.saxon.s9api.QName;
45 import net.sf.saxon.s9api.XQueryCompiler;
46 import net.sf.saxon.s9api.XQueryEvaluator;
47 import net.sf.saxon.s9api.XQueryExecutable;
48 import net.sf.saxon.s9api.XdmAtomicValue;
49 import net.sf.saxon.s9api.XdmItem;
50 import net.sf.saxon.s9api.XdmNode;
53 * Executes an XQuery script.
55 * Required fields:<br/><br/>
56 * scriptFile: the XQuery script file path<br/>
57 * outputVariable: the output variable name<br/>
59 * Optional fields:<br/><br/>
60 * xmlInputVariables: CSV list of variables containing
61 * XML data to be injected into the script<br/>
62 * atomicInputVariables: CSV list of variables containing
63 * atomic data to be injected into the script<br/>
65 public class XQueryScriptTask extends BaseTask {
67 private static MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL);
69 private Expression scriptFile;
70 private Expression xmlInputVariables;
71 private Expression atomicInputVariables;
72 private Expression outputVariable;
75 public void execute(DelegateExecution execution) throws Exception {
76 if (msoLogger.isDebugEnabled()) {
77 msoLogger.debug("Started Executing " + getTaskName());
80 String theScriptFile =
81 getStringField(scriptFile, execution, "scriptFile");
82 String theXmlInputVariables =
83 getOptionalStringField(xmlInputVariables, execution, "xmlInputVariables");
84 String theAtomicInputVariables =
85 getOptionalStringField(atomicInputVariables, execution, "atomicInputVariables");
86 String theOutputVariable =
87 getStringField(outputVariable, execution, "outputVariable");
89 if (msoLogger.isDebugEnabled()) {
90 msoLogger.debug ("scriptFile = " + theScriptFile
91 + " xmlInputVariables = " + theXmlInputVariables
92 + " atomicInputVariables = " + theAtomicInputVariables
93 + "outputVariable = " + theOutputVariable);
96 String[] xmlInputVariableArray = (theXmlInputVariables == null)
97 ? new String[0] : theXmlInputVariables.split(",[ ]*");
99 String[] atomicInputVariableArray = (theAtomicInputVariables == null)
100 ? new String[0] : theAtomicInputVariables.split(",[ ]*");
102 Boolean shouldFail = (Boolean) execution.getVariable("shouldFail");
104 if (shouldFail != null && shouldFail) {
105 throw new ProcessEngineException(getClass().getSimpleName() + " Failed");
108 // The script could be compiled once and reused, but we are reading it
109 // and compiling it every time.
110 Configuration configuration = new Configuration();
111 Processor processor = new Processor(configuration);
112 XQueryCompiler compiler = processor.newXQueryCompiler();
113 XQueryExecutable executable = compile(compiler, theScriptFile);
114 if (executable == null) {
115 throw new ProcessEngineException(getClass().getSimpleName() + " Failed");
118 // The evaluator must not be shared by multiple threads. Here is where
119 // the initial context may be set, as well as values of external variables.
120 XQueryEvaluator evaluator = executable.load();
122 // Convert XML string variable content to document-node objects and inject
123 // these into the evaluator. Note: the script must accept the document-node
124 // type. Most MSO scripts today expect element() input, not document-node
125 // input. TODO: figure out how to pass the variable data as element() types.
127 for (String xmlInputVariable : xmlInputVariableArray) {
128 if (msoLogger.isDebugEnabled()) {
129 msoLogger.debug("Injecting XML variable '" + xmlInputVariable + "'");
130 msoLogger.debug("printing the variable content>>'" + execution.getVariable(xmlInputVariable) +"'");
133 String xml = (String) execution.getVariable(xmlInputVariable);
134 DocumentBuilder documentBuilder = processor.newDocumentBuilder();
135 StreamSource source = new StreamSource(new ByteArrayInputStream(xml.getBytes("UTF-8")));
136 XdmNode xdmNode = documentBuilder.build(source);
138 // Inject the document-node object into the XQueryEvaluator.
139 // TODO: transform it to an element()
140 QName variable = new QName(xmlInputVariable);
141 evaluator.setExternalVariable(variable, xdmNode);
144 // Inject atomic variables into the evaluator.
146 for (String atomicInputVariable : atomicInputVariableArray) {
148 if (msoLogger.isDebugEnabled()) {
149 msoLogger.debug ("Injecting object variable '"
150 + atomicInputVariable + "'");
153 QName variable = new QName(atomicInputVariable);
154 Object value = execution.getVariable(atomicInputVariable);
157 // The variable value is null, so we have no way to know what
158 // type it is. I don't know how to deal with this, so for
159 // now, just skip it.
161 msoLogger.warn (MessageEnum.BPMN_VARIABLE_NULL, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.DataError, atomicInputVariable);
166 // There might be a better way to do this...
167 if (value instanceof BigDecimal) {
168 evaluator.setExternalVariable(variable,
169 new XdmAtomicValue((BigDecimal) value));
170 } else if (value instanceof Boolean) {
171 evaluator.setExternalVariable(variable,
172 new XdmAtomicValue((Boolean) value));
173 } else if (value instanceof Double) {
174 evaluator.setExternalVariable(variable,
175 new XdmAtomicValue((Double) value));
176 } else if (value instanceof Float) {
177 evaluator.setExternalVariable(variable,
178 new XdmAtomicValue((Float) value));
179 } else if (value instanceof Long) {
180 evaluator.setExternalVariable(variable,
181 new XdmAtomicValue((Long) value));
182 } else if (value instanceof String) {
183 evaluator.setExternalVariable(variable,
184 new XdmAtomicValue((String) value));
185 } else if (value instanceof URI) {
186 evaluator.setExternalVariable(variable,
187 new XdmAtomicValue((URI) value));
189 throw new BadInjectedFieldException(
190 "atomicInputVariables", getTaskName(),
191 "'" + atomicInputVariable + "' type is not supported: "
196 // Evaluate the query and collect the output.
197 StringBuilder output = new StringBuilder();
198 Iterator<XdmItem> xdmItems = evaluator.iterator();
199 while (xdmItems.hasNext()) {
200 XdmItem item = xdmItems.next();
202 if (msoLogger.isDebugEnabled()) {
203 msoLogger.debug("XQuery result item = " + item);
206 output.append(item.toString());
209 // Set the output variable.
210 execution.setVariable(theOutputVariable, output.toString());
212 if (msoLogger.isDebugEnabled()) {
213 msoLogger.debug("Done Executing " + getTaskName());
218 * Compiles an XQuery script contained in a resource (file).
219 * @param compiler the XQueryCompiler
220 * @param resource the resource path
221 * @return an XQueryExecutable
222 * @throws Exception on error
224 private XQueryExecutable compile(XQueryCompiler compiler, String resource)
226 try (InputStream xqStream = getClass().getResourceAsStream(resource)) {
227 return compiler.compile(xqStream);
228 } catch (Exception e) {
229 msoLogger.debug ("Exception at resourceFile stream:", e);