2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights
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.sdnc.sli;
25 import java.io.InputStream;
27 import java.util.LinkedList;
29 import javax.xml.XMLConstants;
30 import javax.xml.parsers.SAXParser;
31 import javax.xml.parsers.SAXParserFactory;
32 import javax.xml.validation.Schema;
33 import javax.xml.validation.SchemaFactory;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37 import org.xml.sax.Attributes;
38 import org.xml.sax.Locator;
39 import org.xml.sax.SAXException;
40 import org.xml.sax.SAXNotRecognizedException;
41 import org.xml.sax.SAXParseException;
42 import org.xml.sax.helpers.DefaultHandler;
48 public class SvcLogicParser {
50 SvcLogicStore store = null;
51 static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
52 static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
53 static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
54 static final String JAXP_DYNAMIC_VALIDATION = "http://apache.org/xml/features/validation/dynamic";
55 static final String JAXP_SCHEMA_VALIDATION = "http://apache.org/xml/features/validation/schema";
57 private static final String LOAD_MESSAGE = "Getting SvcLogicGraph from database - ";
58 private static final String LOAD_ERROR_MESSAGE = "SvcLogicGraph not found - ";
59 private static final String ACTIVATION_ERROR_MESSAGE = "Could not activate SvcLogicGraph - ";
60 private static final String PRINT_ERROR_MESSAGE = "Could not print SvcLogicGraph - ";
61 private static final String SVC_LOGIC_STORE_ERROR = "Could not get service logic store";
63 private static final Logger LOGGER = LoggerFactory.getLogger(SvcLogicParser.class);
64 private static final String SLI_VALIDATING_PARSER = "org.openecomp.sdnc.sli.parser.validate";
65 private static final String SVCLOGIC_XSD = "/svclogic.xsd";
67 private class SvcLogicHandler extends DefaultHandler {
68 private Locator locator = null;
69 private String module = null;
70 private String version = null;
71 private LinkedList<SvcLogicGraph> graphs = null;
72 private SvcLogicGraph curGraph = null;
73 private SvcLogicNode curNode = null;
74 private LinkedList<SvcLogicNode> nodeStack = null;
75 private int curNodeId = 0;
76 private String outcomeValue = null;
77 private LinkedList<String> outcomeStack = null;
78 private SvcLogicStore svcLogicStore = null;
80 public SvcLogicHandler(LinkedList<SvcLogicGraph> graphs, SvcLogicStore store) {
83 this.nodeStack = new LinkedList<>();
84 this.outcomeStack = new LinkedList<>();
86 this.outcomeValue = null;
87 this.svcLogicStore = store;
92 public void setDocumentLocator(Locator locator) {
93 this.locator = locator;
97 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
99 // Handle service-logic (graph) tag
100 if ("service-logic".equalsIgnoreCase(qName)) {
102 module = attributes.getValue("module");
103 if (module == null || module.length() == 0) {
104 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Missing 'module' attribute from service-logic tag");
107 version = attributes.getValue("version");
108 if (version == null || version.length() == 0) {
109 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Missing 'version' attribute from service-logic tag");
115 if ("method".equalsIgnoreCase(qName)) {
116 if (curGraph != null) {
117 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Cannot nest module tags");
119 curGraph = new SvcLogicGraph();
120 curGraph.setModule(module);
121 curGraph.setVersion(version);
124 String attrValue = attributes.getValue("rpc");
125 if (attrValue == null || attrValue.length() == 0) {
126 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Missing 'rpc' attribute for method tag");
128 curGraph.setRpc(attrValue);
130 attrValue = attributes.getValue("mode");
131 if (attrValue == null || attrValue.length() == 0) {
132 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Missing 'mode' attribute for method tag");
134 curGraph.setMode(attrValue);
140 // Handle outcome (edge) tag
141 if ("outcome".equalsIgnoreCase(qName)) {
142 String refValue = attributes.getValue("ref");
144 if (refValue != null) {
145 SvcLogicNode refNode = curGraph.getNamedNode(refValue);
147 if (refNode != null) {
149 curNode.addOutcome(attributes.getValue("value"), refNode);
150 } catch (SvcLogicException e) {
151 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Cannot add outcome", e);
154 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "ref to unknown node " + refValue);
159 if (outcomeValue != null) {
160 outcomeStack.push(outcomeValue);
162 outcomeValue = attributes.getValue("value");
167 // Handle parameter tag
168 if ("parameter".equalsIgnoreCase(qName)) {
169 String parmName = attributes.getValue("name");
170 String parmValue = attributes.getValue("value");
172 if (parmName != null && parmName.length() > 0 && parmValue != null) {
175 curNode.mapParameter(parmName, parmValue);
176 } catch (Exception e) {
177 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + " cannot set parameter " + parmName + " to " + parmValue + " [" + e.getMessage() + "]");
186 String nodeName = attributes.getValue("name");
187 SvcLogicNode thisNode = null;
190 if (!svcLogicStore.isValidNodeType(qName)) {
191 throw new SAXNotRecognizedException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Unknown tag " + qName);
193 } catch (Exception e) {
194 throw new SAXNotRecognizedException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Cannot validate node type " + qName);
198 if (nodeName != null && nodeName.length() > 0) {
199 thisNode = new SvcLogicNode(curNodeId++, qName, nodeName, curGraph);
201 thisNode = new SvcLogicNode(curNodeId++, qName, curGraph);
204 if (curGraph.getRootNode() == null) {
205 curGraph.setRootNode(thisNode);
207 } catch (SvcLogicException e) {
208 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + e.getMessage());
212 int numAttributes = attributes.getLength();
214 for (int i = 0; i < numAttributes; i++) {
215 String attrName = attributes.getQName(i);
216 if (!"name".equalsIgnoreCase(attrName)) {
219 String attrValueStr = attributes.getValue(i);
220 SvcLogicExpression attrValue = null;
221 if (attrValueStr.trim().startsWith("`")) {
222 int lastParen = attrValueStr.lastIndexOf("`");
223 String evalExpr = attrValueStr.trim().substring(1, lastParen);
224 attrValue = SvcLogicExpressionFactory.parse(evalExpr);
227 if (Character.isDigit(attrValueStr.charAt(0))) {
228 attrValue = new SvcLogicAtom("NUMBER", attrValueStr);
230 attrValue = new SvcLogicAtom("STRING", attrValueStr);
233 thisNode.setAttribute(attrName, attrValue);
234 } catch (Exception e) {
235 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Cannot set attribute " + attrName, e);
240 if (curNode != null) {
242 if ("block".equalsIgnoreCase(curNode.getNodeType()) || "for".equalsIgnoreCase(curNode.getNodeType()) || "while".equalsIgnoreCase(curNode.getNodeType())) {
243 curNode.addOutcome("" + (curNode.getNumOutcomes() + 1), thisNode);
245 if (outcomeValue == null) {
246 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + curNode.getNodeType() + " node expects outcome, instead found " + thisNode.getNodeType());
248 curNode.addOutcome(outcomeValue, thisNode);
250 } catch (SvcLogicException e) {
251 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + e.getMessage());
253 nodeStack.push(curNode);
260 public void endElement(String uri, String localName, String qName) throws SAXException {
262 // Handle close of service-logic tag
263 if ("service-logic".equalsIgnoreCase(qName)) {
264 // Nothing more to do
268 // Handle close of method tag
269 if ("method".equalsIgnoreCase(qName)) {
270 graphs.add(curGraph);
275 // Handle close of outcome tag
276 if ("outcome".equalsIgnoreCase(qName)) {
277 // Finished this outcome - pop the outcome stack
278 if (outcomeStack.isEmpty()) {
281 outcomeValue = outcomeStack.pop();
286 // Handle close of parameter tag - do nothing
287 if ("parameter".equalsIgnoreCase(qName)) {
291 // Handle close of a node tag
292 if (nodeStack.isEmpty()) {
295 curNode = nodeStack.pop();
300 public void error(SAXParseException arg0) throws SAXException {
301 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + arg0.getMessage());
306 public SvcLogicParser(SvcLogicStore store) {
310 public SvcLogicParser(String propFile) {
313 this.store = SvcLogicStoreFactory.getSvcLogicStore(propFile);
314 } catch (Exception e) {
315 LOGGER.error(SVC_LOGIC_STORE_ERROR, e);
321 public SvcLogicParser(InputStream propStr) {
324 this.store = SvcLogicStoreFactory.getSvcLogicStore(propStr);
325 } catch (Exception e) {
326 LOGGER.error(SVC_LOGIC_STORE_ERROR, e);
332 public LinkedList<SvcLogicGraph> parse(String fileName) throws SvcLogicException {
333 LinkedList<SvcLogicGraph> graphs = null;
336 Schema schema = null;
337 String validateSchema = System.getProperty(SLI_VALIDATING_PARSER, "true");
339 if (validateSchema != null || validateSchema.equalsIgnoreCase("true")) {
340 xsdUrl = getClass().getResource(SVCLOGIC_XSD);
344 if (xsdUrl != null) {
346 SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
347 schema = schemaFactory.newSchema(xsdUrl);
348 } catch (Exception e) {
349 LOGGER.warn("Could not validate using schema " + xsdUrl.getPath(), e);
352 LOGGER.warn("Could not find resource " + SVCLOGIC_XSD);
356 SAXParserFactory factory = SAXParserFactory.newInstance();
358 if (schema != null) {
359 factory.setNamespaceAware(true);
360 factory.setSchema(schema);
362 SAXParser saxParser = factory.newSAXParser();
364 if (saxParser.isValidating()) {
365 LOGGER.info("Validating against schema " + xsdUrl.getPath());
367 graphs = new LinkedList<>();
369 saxParser.parse(fileName, new SvcLogicHandler(graphs, store));
371 } catch (Exception e) {
372 String msg = e.getMessage();
375 throw new SvcLogicException("Compiler error: " + fileName + " @ " + msg);
377 LOGGER.info("Caught exception parsing " + fileName, e);
378 throw new SvcLogicException("Compiler error: " + fileName, e);
385 public static void main(String argv[]) {
387 if (argv.length == 0) {
388 SvcLogicParser.usage();
391 if ("load".equalsIgnoreCase(argv[0])) {
392 if (argv.length == 3) {
393 String xmlfile = argv[1];
394 String propfile = argv[2];
396 SvcLogicStore store = SvcLogicParser.getStore(propfile);
398 SvcLogicParser.load(xmlfile, store);
399 } catch (Exception e) {
400 LOGGER.error(e.getMessage(), e);
403 SvcLogicParser.usage();
405 } else if ("print".equalsIgnoreCase(argv[0])) {
406 String version = null;
407 String propfile = null;
409 switch (argv.length) {
414 if (propfile == null) {
417 SvcLogicStore store = SvcLogicParser.getStore(propfile);
418 SvcLogicParser.print(argv[1], argv[2], argv[3], version, store);
421 SvcLogicParser.usage();
423 } else if ("get-source".equalsIgnoreCase(argv[0])) {
425 switch (argv.length) {
427 SvcLogicStore store = SvcLogicParser.getStore(argv[5]);
428 SvcLogicParser.getSource(argv[1], argv[2], argv[3], argv[4], store);
431 SvcLogicParser.usage();
433 } else if ("activate".equalsIgnoreCase(argv[0])) {
434 if (argv.length == 6) {
435 SvcLogicStore store = SvcLogicParser.getStore(argv[5]);
436 SvcLogicParser.activate(argv[1], argv[2], argv[3], argv[4], store);
438 SvcLogicParser.usage();
440 } else if ("validate".equalsIgnoreCase(argv[0])) {
441 if (argv.length == 3) {
442 String xmlfile = argv[1];
443 String propfile = argv[2];
445 System.setProperty(SLI_VALIDATING_PARSER, "true");
446 SvcLogicStore store = SvcLogicParser.getStore(propfile);
448 SvcLogicParser.validate(xmlfile, store);
449 } catch (Exception e) {
450 LOGGER.error(e.getMessage(), e);
453 SvcLogicParser.usage();
460 private static SvcLogicStore getStore(String propfile) {
462 SvcLogicStore store = null;
465 store = SvcLogicStoreFactory.getSvcLogicStore(propfile);
466 } catch (Exception e) {
467 LOGGER.error(SVC_LOGIC_STORE_ERROR, e);
475 public static void load(String xmlfile, SvcLogicStore store) throws SvcLogicException {
476 File xmlFile = new File(xmlfile);
477 if (!xmlFile.canRead()) {
478 throw new ConfigurationException("Cannot read xml file (" + xmlfile + ")");
481 SvcLogicParser parser = new SvcLogicParser(store);
482 LinkedList<SvcLogicGraph> graphs = null;
484 graphs = parser.parse(xmlfile);
485 } catch (Exception e) {
486 throw new SvcLogicException(e.getMessage(), e);
489 if (graphs == null) {
490 throw new SvcLogicException("Could not parse " + xmlfile);
493 for (SvcLogicGraph graph : graphs) {
495 String module = graph.getModule();
496 String rpc = graph.getRpc();
497 String version = graph.getVersion();
498 String mode = graph.getMode();
500 LOGGER.info("Saving SvcLogicGraph to database (module:" + module + ",rpc:" + rpc + ",version:" + version + ",mode:" + mode + ")");
502 } catch (Exception e) {
503 throw new SvcLogicException(e.getMessage(), e);
510 public static void validate(String xmlfile, SvcLogicStore store) throws SvcLogicException {
511 File xmlFile = new File(xmlfile);
512 if (!xmlFile.canRead()) {
513 throw new ConfigurationException("Cannot read xml file (" + xmlfile + ")");
516 SvcLogicParser parser = new SvcLogicParser(store);
517 LinkedList<SvcLogicGraph> graphs = null;
519 LOGGER.info("Validating " + xmlfile);
520 graphs = parser.parse(xmlfile);
521 } catch (Exception e) {
522 throw new SvcLogicException(e.getMessage(), e);
525 if (graphs == null) {
526 throw new SvcLogicException("Could not parse " + xmlfile);
528 LOGGER.info("Compilation successful for " + xmlfile);
533 private static void print(String module, String rpc, String mode, String version, SvcLogicStore store) {
534 String details = "(module:" + module + ", rpc:" + rpc + ", version:" + version + ", mode:" + mode + ")";
537 LOGGER.info(LOAD_MESSAGE + details);
539 SvcLogicGraph graph = store.fetch(module, rpc, version, mode);
541 LOGGER.error(LOAD_ERROR_MESSAGE + details);
544 graph.printAsGv(System.out);
545 } catch (Exception e) {
546 LOGGER.error(PRINT_ERROR_MESSAGE + details, e);
552 private static void getSource(String module, String rpc, String mode, String version, SvcLogicStore store) {
553 String details = "(module:" + module + ", rpc:" + rpc + ", version:" + version + ", mode:" + mode + ")";
556 LOGGER.info(LOAD_MESSAGE + details);
558 SvcLogicGraph graph = store.fetch(module, rpc, version, mode);
560 LOGGER.error(LOAD_ERROR_MESSAGE + details);
563 graph.printAsXml(System.out);
564 } catch (Exception e) {
565 LOGGER.error(PRINT_ERROR_MESSAGE + details, e);
571 private static void activate(String module, String rpc, String version, String mode, SvcLogicStore store) {
572 String details = "(module:" + module + ", rpc:" + rpc + ", version:" + version + ", mode:" + mode + ")";
575 LOGGER.info(LOAD_MESSAGE + details);
577 SvcLogicGraph graph = store.fetch(module, rpc, version, mode);
579 LOGGER.error(LOAD_ERROR_MESSAGE + details);
582 store.activate(graph);
583 } catch (Exception e) {
584 LOGGER.error(ACTIVATION_ERROR_MESSAGE + details, e);
590 private static void usage() {
591 System.err.println("Usage: SvcLogicParser load <xml-file> <prop-file>");
592 System.err.println(" OR SvcLogicParser print <module> <rpc> <mode> [<version>] <prop-file>");
593 System.err.println(" OR SvcLogicParser get-source <module> <rpc> <mode> <version> <prop-file>");
594 System.err.println(" OR SvcLogicParser activate <module> <rpc> <version> <mode>");