2 * ============LICENSE_START=======================================================
\r
4 * ================================================================================
\r
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * ================================================================================
\r
7 * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * you may not use this file except in compliance with the License.
\r
9 * You may obtain a copy of the License at
\r
11 * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * Unless required by applicable law or agreed to in writing, software
\r
14 * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * See the License for the specific language governing permissions and
\r
17 * limitations under the License.
\r
18 * ============LICENSE_END=========================================================
\r
21 package org.openecomp.mso.bpmn.core;
\r
23 import java.io.ByteArrayInputStream;
\r
24 import java.io.IOException;
\r
25 import java.io.InputStream;
\r
26 import java.math.BigDecimal;
\r
27 import java.net.URI;
\r
29 import javax.xml.transform.stream.StreamSource;
\r
31 import org.camunda.bpm.engine.ProcessEngineException;
\r
32 import org.camunda.bpm.engine.delegate.DelegateExecution;
\r
33 //import java.util.logging.Logger;
\r
34 import org.camunda.bpm.engine.delegate.Expression;
\r
35 import org.openecomp.mso.logger.MessageEnum;
\r
36 import org.openecomp.mso.logger.MsoLogger;
\r
38 import net.sf.saxon.Configuration;
\r
39 import net.sf.saxon.s9api.DocumentBuilder;
\r
40 import net.sf.saxon.s9api.Processor;
\r
41 import net.sf.saxon.s9api.QName;
\r
42 import net.sf.saxon.s9api.XQueryCompiler;
\r
43 import net.sf.saxon.s9api.XQueryEvaluator;
\r
44 import net.sf.saxon.s9api.XQueryExecutable;
\r
45 import net.sf.saxon.s9api.XdmAtomicValue;
\r
46 import net.sf.saxon.s9api.XdmItem;
\r
47 import net.sf.saxon.s9api.XdmNode;
\r
50 * Executes an XQuery script.
\r
52 * Required fields:<br/><br/>
\r
53 * scriptFile: the XQuery script file path<br/>
\r
54 * outputVariable: the output variable name<br/>
\r
56 * Optional fields:<br/><br/>
\r
57 * xmlInputVariables: CSV list of variables containing
\r
58 * XML data to be injected into the script<br/>
\r
59 * atomicInputVariables: CSV list of variables containing
\r
60 * atomic data to be injected into the script<br/>
\r
62 public class XQueryScriptTask extends BaseTask {
\r
64 private static MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL);
\r
66 private Expression scriptFile;
\r
67 private Expression xmlInputVariables;
\r
68 private Expression atomicInputVariables;
\r
69 private Expression outputVariable;
\r
71 public void execute(DelegateExecution execution) throws Exception {
\r
72 if (msoLogger.isDebugEnabled()) {
\r
73 msoLogger.debug("Started Executing " + getTaskName());
\r
76 String theScriptFile =
\r
77 getStringField(scriptFile, execution, "scriptFile");
\r
78 String theXmlInputVariables =
\r
79 getOptionalStringField(xmlInputVariables, execution, "xmlInputVariables");
\r
80 String theAtomicInputVariables =
\r
81 getOptionalStringField(atomicInputVariables, execution, "atomicInputVariables");
\r
82 String theOutputVariable =
\r
83 getStringField(outputVariable, execution, "outputVariable");
\r
85 if (msoLogger.isDebugEnabled()) {
\r
86 System.out.println("scriptFile = " + theScriptFile
\r
87 + " xmlInputVariables = " + theXmlInputVariables
\r
88 + " atomicInputVariables = " + theAtomicInputVariables
\r
89 + "outputVariable = " + theOutputVariable);
\r
92 String[] xmlInputVariableArray = (theXmlInputVariables == null)
\r
93 ? new String[0] : theXmlInputVariables.split(",[ ]*");
\r
95 String[] atomicInputVariableArray = (theAtomicInputVariables == null)
\r
96 ? new String[0] : theAtomicInputVariables.split(",[ ]*");
\r
98 if (shouldFail(execution)) {
\r
99 throw new ProcessEngineException(getTaskName() + " Failed");
\r
102 // The script could be compiled once and reused, but we are reading it
\r
103 // and compiling it every time.
\r
104 Configuration configuration = new Configuration();
\r
105 Processor processor = new Processor(configuration);
\r
106 XQueryCompiler compiler = processor.newXQueryCompiler();
\r
107 XQueryExecutable executable = compile(compiler, theScriptFile);
\r
109 // The evaluator must not be shared by multiple threads. Here is where
\r
110 // the initial context may be set, as well as values of external variables.
\r
111 XQueryEvaluator evaluator = executable.load();
\r
113 // Convert XML string variable content to document-node objects and inject
\r
114 // these into the evaluator. Note: the script must accept the document-node
\r
115 // type. Most MSO scripts today expect element() input, not document-node
\r
116 // input. TODO: figure out how to pass the variable data as element() types.
\r
118 for (String xmlInputVariable : xmlInputVariableArray) {
\r
119 if (msoLogger.isDebugEnabled()) {
\r
120 msoLogger.debug("Injecting XML variable '" + xmlInputVariable + "'");
\r
121 msoLogger.debug("printing the variable content>>'" + execution.getVariable(xmlInputVariable) +"'");
\r
124 String xml = (String) execution.getVariable(xmlInputVariable);
\r
125 DocumentBuilder documentBuilder = processor.newDocumentBuilder();
\r
126 StreamSource source = new StreamSource(new ByteArrayInputStream(xml.getBytes("UTF-8")));
\r
127 XdmNode xdmNode = documentBuilder.build(source);
\r
129 // Inject the document-node object into the XQueryEvaluator.
\r
130 // TODO: transform it to an element()
\r
131 QName variable = new QName(xmlInputVariable);
\r
132 evaluator.setExternalVariable(variable, xdmNode);
\r
135 // Inject atomic variables into the evaluator.
\r
137 for (String atomicInputVariable : atomicInputVariableArray) {
\r
139 if (msoLogger.isDebugEnabled()) {
\r
140 System.out.println("Injecting object variable '"
\r
141 + atomicInputVariable + "'");
\r
144 QName variable = new QName(atomicInputVariable);
\r
145 Object value = execution.getVariable(atomicInputVariable);
\r
147 if (value == null) {
\r
148 // The variable value is null, so we have no way to know what
\r
149 // type it is. I don't know how to deal with this, so for
\r
150 // now, just skip it.
\r
152 msoLogger.warn (MessageEnum.BPMN_VARIABLE_NULL, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.DataError, atomicInputVariable);
\r
157 // There might be a better way to do this...
\r
158 if (value instanceof BigDecimal) {
\r
159 evaluator.setExternalVariable(variable,
\r
160 new XdmAtomicValue((BigDecimal) value));
\r
161 } else if (value instanceof Boolean) {
\r
162 evaluator.setExternalVariable(variable,
\r
163 new XdmAtomicValue((Boolean) value));
\r
164 } else if (value instanceof Double) {
\r
165 evaluator.setExternalVariable(variable,
\r
166 new XdmAtomicValue((Double) value));
\r
167 } else if (value instanceof Float) {
\r
168 evaluator.setExternalVariable(variable,
\r
169 new XdmAtomicValue((Float) value));
\r
170 } else if (value instanceof Long) {
\r
171 evaluator.setExternalVariable(variable,
\r
172 new XdmAtomicValue((Long) value));
\r
173 } else if (value instanceof String) {
\r
174 evaluator.setExternalVariable(variable,
\r
175 new XdmAtomicValue((String) value));
\r
176 } else if (value instanceof URI) {
\r
177 evaluator.setExternalVariable(variable,
\r
178 new XdmAtomicValue((URI) value));
\r
180 throw new BadInjectedFieldException(
\r
181 "atomicInputVariables", getTaskName(),
\r
182 "'" + atomicInputVariable + "' type is not supported: "
\r
183 + value.getClass());
\r
187 // Evaluate the query and collect the output.
\r
188 StringBuilder output = new StringBuilder();
\r
189 for(XdmItem item : evaluator) {
\r
191 if (msoLogger.isDebugEnabled()) {
\r
192 msoLogger.debug("XQuery result item = " + item);
\r
195 output.append(item.toString());
\r
198 // Set the output variable.
\r
199 execution.setVariable(theOutputVariable, output.toString());
\r
201 if (msoLogger.isDebugEnabled()) {
\r
202 msoLogger.debug("Done Executing " + getTaskName());
\r
207 * Compiles an XQuery script contained in a resource (file).
\r
208 * @param compiler the XQueryCompiler
\r
209 * @param resource the resource path
\r
210 * @return an XQueryExecutable
\r
211 * @throws Exception on error
\r
213 private XQueryExecutable compile(XQueryCompiler compiler, String resource)
\r
215 try(InputStream xqStream = getClass().getResourceAsStream(resource)) {
\r
217 if (xqStream == null) {
\r
218 throw new IOException("Resource not found: " + resource);
\r
221 return compiler.compile(xqStream);
\r