2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 ONAP
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.ccsdk.sli.core.sli;
24 import java.io.InputStream;
26 import java.util.LinkedList;
28 import javax.xml.XMLConstants;
29 import javax.xml.parsers.SAXParser;
30 import javax.xml.parsers.SAXParserFactory;
31 import javax.xml.validation.Schema;
32 import javax.xml.validation.SchemaFactory;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36 import org.xml.sax.Attributes;
37 import org.xml.sax.Locator;
38 import org.xml.sax.SAXException;
39 import org.xml.sax.SAXNotRecognizedException;
40 import org.xml.sax.SAXParseException;
41 import org.xml.sax.helpers.DefaultHandler;
47 public class SvcLogicParser {
49 SvcLogicStore store = null;
50 static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
51 static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
52 static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
53 static final String JAXP_DYNAMIC_VALIDATION = "http://apache.org/xml/features/validation/dynamic";
54 static final String JAXP_SCHEMA_VALIDATION = "http://apache.org/xml/features/validation/schema";
56 private static final String LOAD_MESSAGE = "Getting SvcLogicGraph from database - ";
57 private static final String LOAD_ERROR_MESSAGE = "SvcLogicGraph not found - ";
58 private static final String ACTIVATION_ERROR_MESSAGE = "Could not activate SvcLogicGraph - ";
59 private static final String PRINT_ERROR_MESSAGE = "Could not print SvcLogicGraph - ";
60 private static final String SVC_LOGIC_STORE_ERROR = "Could not get service logic store";
62 private static final Logger LOGGER = LoggerFactory.getLogger(SvcLogicParser.class);
63 private static final String SLI_VALIDATING_PARSER = "org.openecomp.sdnc.sli.parser.validate";
64 private static final String SVCLOGIC_XSD = "/svclogic.xsd";
66 private class SvcLogicHandler extends DefaultHandler {
67 private Locator locator = null;
68 private String module = null;
69 private String version = null;
70 private LinkedList<SvcLogicGraph> graphs = null;
71 private SvcLogicGraph curGraph = null;
72 private SvcLogicNode curNode = null;
73 private LinkedList<SvcLogicNode> nodeStack = null;
74 private int curNodeId = 0;
75 private String outcomeValue = null;
76 private LinkedList<String> outcomeStack = null;
77 private SvcLogicStore svcLogicStore = null;
79 public SvcLogicHandler(LinkedList<SvcLogicGraph> graphs, SvcLogicStore store) {
82 this.nodeStack = new LinkedList<>();
83 this.outcomeStack = new LinkedList<>();
85 this.outcomeValue = null;
86 this.svcLogicStore = store;
91 public void setDocumentLocator(Locator locator) {
92 this.locator = locator;
96 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
98 // Handle service-logic (graph) tag
99 if ("service-logic".equalsIgnoreCase(qName)) {
101 module = attributes.getValue("module");
102 if (module == null || module.length() == 0) {
103 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Missing 'module' attribute from service-logic tag");
106 version = attributes.getValue("version");
107 if (version == null || version.length() == 0) {
108 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Missing 'version' attribute from service-logic tag");
114 if ("method".equalsIgnoreCase(qName)) {
115 if (curGraph != null) {
116 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Cannot nest module tags");
118 curGraph = new SvcLogicGraph();
119 curGraph.setModule(module);
120 curGraph.setVersion(version);
123 String attrValue = attributes.getValue("rpc");
124 if (attrValue == null || attrValue.length() == 0) {
125 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Missing 'rpc' attribute for method tag");
127 curGraph.setRpc(attrValue);
129 attrValue = attributes.getValue("mode");
130 if (attrValue == null || attrValue.length() == 0) {
131 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Missing 'mode' attribute for method tag");
133 curGraph.setMode(attrValue);
139 // Handle outcome (edge) tag
140 if ("outcome".equalsIgnoreCase(qName)) {
141 String refValue = attributes.getValue("ref");
143 if (refValue != null) {
144 SvcLogicNode refNode = curGraph.getNamedNode(refValue);
146 if (refNode != null) {
148 curNode.addOutcome(attributes.getValue("value"), refNode);
149 } catch (SvcLogicException e) {
150 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Cannot add outcome", e);
153 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "ref to unknown node " + refValue);
158 if (outcomeValue != null) {
159 outcomeStack.push(outcomeValue);
161 outcomeValue = attributes.getValue("value");
166 // Handle parameter tag
167 if ("parameter".equalsIgnoreCase(qName)) {
168 String parmName = attributes.getValue("name");
169 String parmValue = attributes.getValue("value");
171 if (parmName != null && parmName.length() > 0 && parmValue != null) {
174 curNode.mapParameter(parmName, parmValue);
175 } catch (Exception e) {
176 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + " cannot set parameter " + parmName + " to " + parmValue + " [" + e.getMessage() + "]");
185 String nodeName = attributes.getValue("name");
186 SvcLogicNode thisNode = null;
189 if (!svcLogicStore.isValidNodeType(qName)) {
190 throw new SAXNotRecognizedException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Unknown tag " + qName);
192 } catch (Exception e) {
193 throw new SAXNotRecognizedException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Cannot validate node type " + qName);
197 if (nodeName != null && nodeName.length() > 0) {
198 thisNode = new SvcLogicNode(curNodeId++, qName, nodeName, curGraph);
200 thisNode = new SvcLogicNode(curNodeId++, qName, curGraph);
203 if (curGraph.getRootNode() == null) {
204 curGraph.setRootNode(thisNode);
206 } catch (SvcLogicException e) {
207 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + e.getMessage());
211 int numAttributes = attributes.getLength();
213 for (int i = 0; i < numAttributes; i++) {
214 String attrName = attributes.getQName(i);
215 if (!"name".equalsIgnoreCase(attrName)) {
218 String attrValueStr = attributes.getValue(i);
219 SvcLogicExpression attrValue = null;
220 if (attrValueStr.trim().startsWith("`")) {
221 int lastParen = attrValueStr.lastIndexOf("`");
222 String evalExpr = attrValueStr.trim().substring(1, lastParen);
223 attrValue = SvcLogicExpressionFactory.parse(evalExpr);
226 if (Character.isDigit(attrValueStr.charAt(0))) {
227 attrValue = new SvcLogicAtom("NUMBER", attrValueStr);
229 attrValue = new SvcLogicAtom("STRING", attrValueStr);
232 thisNode.setAttribute(attrName, attrValue);
233 } catch (Exception e) {
234 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Cannot set attribute " + attrName, e);
239 if (curNode != null) {
241 if ("block".equalsIgnoreCase(curNode.getNodeType()) || "for".equalsIgnoreCase(curNode.getNodeType()) || "while".equalsIgnoreCase(curNode.getNodeType())) {
242 curNode.addOutcome("" + (curNode.getNumOutcomes() + 1), thisNode);
244 if (outcomeValue == null) {
245 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + curNode.getNodeType() + " node expects outcome, instead found " + thisNode.getNodeType());
247 curNode.addOutcome(outcomeValue, thisNode);
249 } catch (SvcLogicException e) {
250 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + e.getMessage());
252 nodeStack.push(curNode);
259 public void endElement(String uri, String localName, String qName) throws SAXException {
261 // Handle close of service-logic tag
262 if ("service-logic".equalsIgnoreCase(qName)) {
263 // Nothing more to do
267 // Handle close of method tag
268 if ("method".equalsIgnoreCase(qName)) {
269 graphs.add(curGraph);
274 // Handle close of outcome tag
275 if ("outcome".equalsIgnoreCase(qName)) {
276 // Finished this outcome - pop the outcome stack
277 if (outcomeStack.isEmpty()) {
280 outcomeValue = outcomeStack.pop();
285 // Handle close of parameter tag - do nothing
286 if ("parameter".equalsIgnoreCase(qName)) {
290 // Handle close of a node tag
291 if (nodeStack.isEmpty()) {
294 curNode = nodeStack.pop();
299 public void error(SAXParseException arg0) throws SAXException {
300 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + arg0.getMessage());
305 public SvcLogicParser(SvcLogicStore store) {
309 public SvcLogicParser(String propFile) {
312 this.store = SvcLogicStoreFactory.getSvcLogicStore(propFile);
313 } catch (Exception e) {
314 LOGGER.error(SVC_LOGIC_STORE_ERROR, e);
320 public SvcLogicParser(InputStream propStr) {
323 this.store = SvcLogicStoreFactory.getSvcLogicStore(propStr);
324 } catch (Exception e) {
325 LOGGER.error(SVC_LOGIC_STORE_ERROR, e);
331 public LinkedList<SvcLogicGraph> parse(String fileName) throws SvcLogicException {
332 LinkedList<SvcLogicGraph> graphs = null;
335 Schema schema = null;
336 String validateSchema = System.getProperty(SLI_VALIDATING_PARSER, "true");
338 if (validateSchema != null || validateSchema.equalsIgnoreCase("true")) {
339 xsdUrl = getClass().getResource(SVCLOGIC_XSD);
343 if (xsdUrl != null) {
345 SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
346 schema = schemaFactory.newSchema(xsdUrl);
347 } catch (Exception e) {
348 LOGGER.warn("Could not validate using schema " + xsdUrl.getPath(), e);
351 LOGGER.warn("Could not find resource " + SVCLOGIC_XSD);
355 SAXParserFactory factory = SAXParserFactory.newInstance();
357 if (schema != null) {
358 factory.setNamespaceAware(true);
359 factory.setSchema(schema);
361 SAXParser saxParser = factory.newSAXParser();
363 if (saxParser.isValidating()) {
364 LOGGER.info("Validating against schema " + xsdUrl.getPath());
366 graphs = new LinkedList<>();
368 saxParser.parse(fileName, new SvcLogicHandler(graphs, store));
370 } catch (Exception e) {
371 String msg = e.getMessage();
374 throw new SvcLogicException("Compiler error: " + fileName + " @ " + msg);
376 LOGGER.info("Caught exception parsing " + fileName, e);
377 throw new SvcLogicException("Compiler error: " + fileName, e);
384 public static void main(String argv[]) {
386 if (argv.length == 0) {
387 SvcLogicParser.usage();
390 if ("load".equalsIgnoreCase(argv[0])) {
391 if (argv.length == 3) {
392 String xmlfile = argv[1];
393 String propfile = argv[2];
395 SvcLogicStore store = SvcLogicParser.getStore(propfile);
397 SvcLogicParser.load(xmlfile, store);
398 } catch (Exception e) {
399 LOGGER.error(e.getMessage(), e);
402 SvcLogicParser.usage();
404 } else if ("print".equalsIgnoreCase(argv[0])) {
405 String version = null;
406 String propfile = null;
408 switch (argv.length) {
413 if (propfile == null) {
416 SvcLogicStore store = SvcLogicParser.getStore(propfile);
417 SvcLogicParser.print(argv[1], argv[2], argv[3], version, store);
420 SvcLogicParser.usage();
422 } else if ("get-source".equalsIgnoreCase(argv[0])) {
424 switch (argv.length) {
426 SvcLogicStore store = SvcLogicParser.getStore(argv[5]);
427 SvcLogicParser.getSource(argv[1], argv[2], argv[3], argv[4], store);
430 SvcLogicParser.usage();
432 } else if ("activate".equalsIgnoreCase(argv[0])) {
433 if (argv.length == 6) {
434 SvcLogicStore store = SvcLogicParser.getStore(argv[5]);
435 SvcLogicParser.activate(argv[1], argv[2], argv[3], argv[4], store);
437 SvcLogicParser.usage();
439 } else if ("validate".equalsIgnoreCase(argv[0])) {
440 if (argv.length == 3) {
441 String xmlfile = argv[1];
442 String propfile = argv[2];
444 System.setProperty(SLI_VALIDATING_PARSER, "true");
445 SvcLogicStore store = SvcLogicParser.getStore(propfile);
447 SvcLogicParser.validate(xmlfile, store);
448 } catch (Exception e) {
449 LOGGER.error(e.getMessage(), e);
452 SvcLogicParser.usage();
459 private static SvcLogicStore getStore(String propfile) {
461 SvcLogicStore store = null;
464 store = SvcLogicStoreFactory.getSvcLogicStore(propfile);
465 } catch (Exception e) {
466 LOGGER.error(SVC_LOGIC_STORE_ERROR, e);
474 public static void load(String xmlfile, SvcLogicStore store) throws SvcLogicException {
475 File xmlFile = new File(xmlfile);
476 if (!xmlFile.canRead()) {
477 throw new ConfigurationException("Cannot read xml file (" + xmlfile + ")");
480 SvcLogicParser parser = new SvcLogicParser(store);
481 LinkedList<SvcLogicGraph> graphs = null;
483 graphs = parser.parse(xmlfile);
484 } catch (Exception e) {
485 throw new SvcLogicException(e.getMessage(), e);
488 if (graphs == null) {
489 throw new SvcLogicException("Could not parse " + xmlfile);
492 for (SvcLogicGraph graph : graphs) {
494 String module = graph.getModule();
495 String rpc = graph.getRpc();
496 String version = graph.getVersion();
497 String mode = graph.getMode();
499 LOGGER.info("Saving SvcLogicGraph to database (module:" + module + ",rpc:" + rpc + ",version:" + version + ",mode:" + mode + ")");
501 } catch (Exception e) {
502 throw new SvcLogicException(e.getMessage(), e);
509 public static void validate(String xmlfile, SvcLogicStore store) throws SvcLogicException {
510 File xmlFile = new File(xmlfile);
511 if (!xmlFile.canRead()) {
512 throw new ConfigurationException("Cannot read xml file (" + xmlfile + ")");
515 SvcLogicParser parser = new SvcLogicParser(store);
516 LinkedList<SvcLogicGraph> graphs = null;
518 LOGGER.info("Validating " + xmlfile);
519 graphs = parser.parse(xmlfile);
520 } catch (Exception e) {
521 throw new SvcLogicException(e.getMessage(), e);
524 if (graphs == null) {
525 throw new SvcLogicException("Could not parse " + xmlfile);
527 LOGGER.info("Compilation successful for " + xmlfile);
532 private static void print(String module, String rpc, String mode, String version, SvcLogicStore store) {
533 String details = "(module:" + module + ", rpc:" + rpc + ", version:" + version + ", mode:" + mode + ")";
536 LOGGER.info(LOAD_MESSAGE + details);
538 SvcLogicGraph graph = store.fetch(module, rpc, version, mode);
540 LOGGER.error(LOAD_ERROR_MESSAGE + details);
543 graph.printAsGv(System.out);
544 } catch (Exception e) {
545 LOGGER.error(PRINT_ERROR_MESSAGE + details, e);
551 private static void getSource(String module, String rpc, String mode, String version, SvcLogicStore store) {
552 String details = "(module:" + module + ", rpc:" + rpc + ", version:" + version + ", mode:" + mode + ")";
555 LOGGER.info(LOAD_MESSAGE + details);
557 SvcLogicGraph graph = store.fetch(module, rpc, version, mode);
559 LOGGER.error(LOAD_ERROR_MESSAGE + details);
562 graph.printAsXml(System.out);
563 } catch (Exception e) {
564 LOGGER.error(PRINT_ERROR_MESSAGE + details, e);
570 private static void activate(String module, String rpc, String version, String mode, SvcLogicStore store) {
571 String details = "(module:" + module + ", rpc:" + rpc + ", version:" + version + ", mode:" + mode + ")";
574 LOGGER.info(LOAD_MESSAGE + details);
576 SvcLogicGraph graph = store.fetch(module, rpc, version, mode);
578 LOGGER.error(LOAD_ERROR_MESSAGE + details);
581 store.activate(graph);
582 } catch (Exception e) {
583 LOGGER.error(ACTIVATION_ERROR_MESSAGE + details, e);
589 private static void usage() {
590 System.err.println("Usage: SvcLogicParser load <xml-file> <prop-file>");
591 System.err.println(" OR SvcLogicParser print <module> <rpc> <mode> [<version>] <prop-file>");
592 System.err.println(" OR SvcLogicParser get-source <module> <rpc> <mode> <version> <prop-file>");
593 System.err.println(" OR SvcLogicParser activate <module> <rpc> <version> <mode>");