[MSO-8] Update the maven dependency
[so.git] / bpmn / MSOCoreBPMN / src / main / java / org / openecomp / mso / bpmn / core / XQueryScriptTask.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * OPENECOMP - MSO
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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=========================================================
19  */
20
21 package org.openecomp.mso.bpmn.core;
22
23 import java.io.ByteArrayInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.math.BigDecimal;
27 import java.net.URI;
28 import java.util.Iterator;
29
30 import javax.xml.transform.stream.StreamSource;
31
32 import org.camunda.bpm.engine.ProcessEngineException;
33 import org.camunda.bpm.engine.delegate.DelegateExecution;
34 //import java.util.logging.Logger;
35 import org.camunda.bpm.engine.delegate.Expression;
36
37 import org.openecomp.mso.logger.MessageEnum;
38 import org.openecomp.mso.logger.MsoLogger;
39
40 import net.sf.saxon.Configuration;
41 import net.sf.saxon.s9api.DocumentBuilder;
42 import net.sf.saxon.s9api.Processor;
43 import net.sf.saxon.s9api.QName;
44 import net.sf.saxon.s9api.XQueryCompiler;
45 import net.sf.saxon.s9api.XQueryEvaluator;
46 import net.sf.saxon.s9api.XQueryExecutable;
47 import net.sf.saxon.s9api.XdmAtomicValue;
48 import net.sf.saxon.s9api.XdmItem;
49 import net.sf.saxon.s9api.XdmNode;
50
51 /**
52  * Executes an XQuery script.
53  * <p>
54  * Required fields:<br/><br/>
55  * &nbsp;&nbsp;&nbsp;&nbsp;scriptFile: the XQuery script file path<br/>
56  * &nbsp;&nbsp;&nbsp;&nbsp;outputVariable: the output variable name<br/>
57  * <p>
58  * Optional fields:<br/><br/>
59  * &nbsp;&nbsp;&nbsp;&nbsp;xmlInputVariables: CSV list of variables containing
60  *              XML data to be injected into the script<br/>
61  * &nbsp;&nbsp;&nbsp;&nbsp;atomicInputVariables: CSV list of variables containing
62  *              atomic data to be injected into the script<br/>
63  */
64 public class XQueryScriptTask extends BaseTask {
65         
66         private static MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL);
67
68         private Expression scriptFile;
69         private Expression xmlInputVariables;
70         private Expression atomicInputVariables;
71         private Expression outputVariable;
72
73         public void execute(DelegateExecution execution) throws Exception {
74                 if (msoLogger.isDebugEnabled()) {
75                         msoLogger.debug("Started Executing " + getTaskName());
76                 }
77
78                 String theScriptFile =
79                         getStringField(scriptFile, execution, "scriptFile");
80                 String theXmlInputVariables =
81                         getOptionalStringField(xmlInputVariables, execution, "xmlInputVariables");
82                 String theAtomicInputVariables =
83                         getOptionalStringField(atomicInputVariables, execution, "atomicInputVariables");
84                 String theOutputVariable =
85                         getStringField(outputVariable, execution, "outputVariable");
86
87                 if (msoLogger.isDebugEnabled()) {
88                         System.out.println("scriptFile = " + theScriptFile
89                                 + " xmlInputVariables = " + theXmlInputVariables
90                                 + " atomicInputVariables = " + theAtomicInputVariables
91                                 + "outputVariable = " + theOutputVariable);
92                 }
93
94                 String[] xmlInputVariableArray = (theXmlInputVariables == null)
95                         ? new String[0] : theXmlInputVariables.split(",[ ]*");
96
97                 String[] atomicInputVariableArray = (theAtomicInputVariables == null)
98                         ? new String[0] : theAtomicInputVariables.split(",[ ]*");
99
100                 Boolean shouldFail = (Boolean) execution.getVariable("shouldFail");
101
102                 if (shouldFail != null && shouldFail) {
103                         throw new ProcessEngineException(getClass().getSimpleName() + " Failed");
104                 }
105
106                 // The script could be compiled once and reused, but we are reading it
107                 // and compiling it every time.
108                 Configuration configuration = new Configuration();
109                 Processor processor = new Processor(configuration);
110                 XQueryCompiler compiler = processor.newXQueryCompiler();
111                 XQueryExecutable executable = compile(compiler, theScriptFile);
112
113                 // The evaluator must not be shared by multiple threads.  Here is where
114                 // the initial context may be set, as well as values of external variables.
115                 XQueryEvaluator evaluator = executable.load();
116
117                 // Convert XML string variable content to document-node objects and inject
118                 // these into the evaluator.  Note: the script must accept the document-node
119                 // type.  Most MSO scripts today expect element() input, not document-node
120                 // input.  TODO: figure out how to pass the variable data as element() types.
121
122                 for (String xmlInputVariable : xmlInputVariableArray) {
123                         if (msoLogger.isDebugEnabled()) {
124                                 msoLogger.debug("Injecting XML variable '" + xmlInputVariable + "'");
125                                 msoLogger.debug("printing the variable content>>'" + execution.getVariable(xmlInputVariable) +"'");
126                         }
127
128                         String xml = (String) execution.getVariable(xmlInputVariable);
129                         DocumentBuilder documentBuilder = processor.newDocumentBuilder();
130                         StreamSource source = new StreamSource(new ByteArrayInputStream(xml.getBytes("UTF-8")));
131                         XdmNode xdmNode = documentBuilder.build(source);
132
133                         // Inject the document-node object into the XQueryEvaluator.
134                         // TODO: transform it to an element()
135                         QName variable = new QName(xmlInputVariable);
136                         evaluator.setExternalVariable(variable, xdmNode);
137                 }
138
139                 // Inject atomic variables into the evaluator.
140
141                 for (String atomicInputVariable : atomicInputVariableArray) {
142                         
143                         if (msoLogger.isDebugEnabled()) {
144                                 System.out.println("Injecting object variable '"
145                                         + atomicInputVariable + "'");
146                         }
147
148                         QName variable = new QName(atomicInputVariable);
149                         Object value = execution.getVariable(atomicInputVariable);
150
151                         if (value == null) {
152                                 // The variable value is null, so we have no way to know what
153                                 // type it is.  I don't know how to deal with this, so for
154                                 // now, just skip it.
155                                 
156                                 msoLogger.warn (MessageEnum.BPMN_VARIABLE_NULL, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.DataError, atomicInputVariable);
157                                 
158                                 continue;
159                         }
160
161                         // There might be a better way to do this...
162                         if (value instanceof BigDecimal) {
163                                 evaluator.setExternalVariable(variable,
164                                         new XdmAtomicValue((BigDecimal) value));
165                         } else if (value instanceof Boolean) {
166                                 evaluator.setExternalVariable(variable,
167                                         new XdmAtomicValue((Boolean) value));
168                         } else if (value instanceof Double) {
169                                 evaluator.setExternalVariable(variable,
170                                         new XdmAtomicValue((Double) value));
171                         } else if (value instanceof Float) {
172                                 evaluator.setExternalVariable(variable,
173                                         new XdmAtomicValue((Float) value));
174                         } else if (value instanceof Long) {
175                                 evaluator.setExternalVariable(variable,
176                                         new XdmAtomicValue((Long) value));
177                         } else if (value instanceof String) {
178                                 evaluator.setExternalVariable(variable,
179                                         new XdmAtomicValue((String) value));
180                         } else if (value instanceof URI) {
181                                 evaluator.setExternalVariable(variable,
182                                         new XdmAtomicValue((URI) value));
183                         } else {
184                                 throw new BadInjectedFieldException(
185                                         "atomicInputVariables", getTaskName(),
186                                         "'" + atomicInputVariable + "' type is not supported: "
187                                                 + value.getClass());
188                         }
189                 }
190
191                 // Evaluate the query and collect the output.
192                 StringBuilder output = new StringBuilder();
193                 Iterator<XdmItem> xdmItems = evaluator.iterator();
194                 while (xdmItems.hasNext()) {
195                         XdmItem item = xdmItems.next();
196                         
197                         if (msoLogger.isDebugEnabled()) {
198                                 msoLogger.debug("XQuery result item = " + item);
199                         }
200
201                         output.append(item.toString());
202                 }
203
204                 // Set the output variable.
205                 execution.setVariable(theOutputVariable, output.toString());
206
207                 if (msoLogger.isDebugEnabled()) {
208                         msoLogger.debug("Done Executing " + getTaskName());
209                 }
210         }
211         
212         /**
213          * Compiles an XQuery script contained in a resource (file).
214          * @param compiler the XQueryCompiler
215          * @param resource the resource path
216          * @return an XQueryExecutable
217          * @throws Exception on error
218          */
219         private XQueryExecutable compile(XQueryCompiler compiler, String resource)
220                         throws Exception {
221                 InputStream xqStream = null;
222                 try {
223                         xqStream = getClass().getResourceAsStream(resource);
224
225                         if (xqStream == null) {
226                                 throw new IOException("Resource not found: " + resource);
227                         }
228
229                         XQueryExecutable executable = compiler.compile(xqStream);
230                         xqStream.close();
231                         xqStream = null;
232                         return executable;
233                 } finally {
234                         if (xqStream != null) {
235                                 try {
236                                         xqStream.close();
237                                 } catch (Exception e) {
238                                         // Do nothing
239                                 }
240                         }
241                 }
242         }
243 }