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