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.onap.ccsdk.sli.core.sli;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26 import org.xml.sax.Attributes;
27 import org.xml.sax.Locator;
28 import org.xml.sax.SAXException;
29 import org.xml.sax.SAXNotRecognizedException;
30 import org.xml.sax.SAXParseException;
31 import org.xml.sax.helpers.DefaultHandler;
33 import javax.xml.XMLConstants;
34 import javax.xml.parsers.SAXParser;
35 import javax.xml.parsers.SAXParserFactory;
36 import javax.xml.validation.Schema;
37 import javax.xml.validation.SchemaFactory;
39 import java.io.InputStream;
41 import java.util.LinkedList;
47 public class SvcLogicParser {
49 private 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.onap.ccsdk.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() + " "
104 + "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() + " "
110 + "Missing 'version' attribute from service-logic tag");
116 if ("method".equalsIgnoreCase(qName)) {
118 if (curGraph != null) {
119 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
120 + "Cannot nest module tags");
123 curGraph = new SvcLogicGraph();
124 curGraph.setModule(module);
125 curGraph.setVersion(version);
128 String attrValue = attributes.getValue("rpc");
129 if (attrValue == null || attrValue.length() == 0) {
130 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
131 + "Missing 'rpc' attribute for method tag");
133 curGraph.setRpc(attrValue);
135 attrValue = attributes.getValue("mode");
136 if (attrValue == null || attrValue.length() == 0) {
137 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
138 + "Missing 'mode' attribute for method tag");
140 curGraph.setMode(attrValue);
145 // Handle outcome (edge) tag
146 if ("outcome".equalsIgnoreCase(qName)) {
147 String refValue = attributes.getValue("ref");
149 if (refValue != null) {
150 SvcLogicNode refNode = curGraph.getNamedNode(refValue);
152 if (refNode != null) {
154 curNode.addOutcome(attributes.getValue("value"), refNode);
155 } catch (SvcLogicException e) {
156 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
157 + "Cannot add outcome", e);
160 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
161 + "ref to unknown node " + refValue);
166 if (outcomeValue != null) {
167 outcomeStack.push(outcomeValue);
169 outcomeValue = attributes.getValue("value");
174 // Handle parameter tag
175 if ("parameter".equalsIgnoreCase(qName)) {
176 String parmName = attributes.getValue("name");
177 String parmValue = attributes.getValue("value");
179 if (parmName != null && parmName.length() > 0 && parmValue != null) {
182 curNode.mapParameter(parmName, parmValue);
183 } catch (Exception e) {
184 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
185 + " cannot set parameter " + parmName + " to " + parmValue + " [" + e.getMessage() + "]");
193 String nodeName = attributes.getValue("name");
194 SvcLogicNode thisNode;
197 if (!svcLogicStore.isValidNodeType(qName)) {
198 throw new SAXNotRecognizedException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber()
199 + " " + "Unknown tag " + qName);
201 } catch (Exception e) {
202 throw new SAXNotRecognizedException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber()
203 + " " + "Cannot validate node type " + qName);
207 if (nodeName != null && nodeName.length() > 0) {
208 thisNode = new SvcLogicNode(curNodeId++, qName, nodeName, curGraph);
210 thisNode = new SvcLogicNode(curNodeId++, qName, curGraph);
213 if (curGraph.getRootNode() == null) {
214 curGraph.setRootNode(thisNode);
216 } catch (SvcLogicException e) {
217 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
222 int numAttributes = attributes.getLength();
224 for (int i = 0; i < numAttributes; i++) {
225 String attrName = attributes.getQName(i);
226 if (!"name".equalsIgnoreCase(attrName)) {
229 String attrValueStr = attributes.getValue(i);
230 SvcLogicExpression attrValue;
231 if (attrValueStr.trim().startsWith("`")) {
232 int lastParen = attrValueStr.lastIndexOf('`');
233 String evalExpr = attrValueStr.trim().substring(1, lastParen);
234 attrValue = SvcLogicExpressionFactory.parse(evalExpr);
237 if (Character.isDigit(attrValueStr.charAt(0))) {
238 attrValue = new SvcLogicAtom("NUMBER", attrValueStr);
240 attrValue = new SvcLogicAtom("STRING", attrValueStr);
243 thisNode.setAttribute(attrName, attrValue);
244 } catch (Exception e) {
245 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
246 + "Cannot set attribute " + attrName, e);
251 if (curNode != null) {
253 if ("block".equalsIgnoreCase(curNode.getNodeType()) || "for".equalsIgnoreCase(curNode.getNodeType())
254 || "while".equalsIgnoreCase(curNode.getNodeType())) {
255 curNode.addOutcome(Integer.toString(curNode.getNumOutcomes() + 1), thisNode);
257 if (outcomeValue == null) {
258 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
259 + curNode.getNodeType() + " node expects outcome, instead found " + thisNode.getNodeType());
261 curNode.addOutcome(outcomeValue, thisNode);
263 } catch (SvcLogicException e) {
264 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
267 nodeStack.push(curNode);
274 public void endElement(String uri, String localName, String qName) throws SAXException {
276 // Handle close of service-logic tag
277 if ("service-logic".equalsIgnoreCase(qName)) {
278 // Nothing more to do
282 // Handle close of method tag
283 if ("method".equalsIgnoreCase(qName)) {
284 graphs.add(curGraph);
289 // Handle close of outcome tag
290 if ("outcome".equalsIgnoreCase(qName)) {
291 // Finished this outcome - pop the outcome stack
292 if (outcomeStack.isEmpty()) {
295 outcomeValue = outcomeStack.pop();
300 // Handle close of parameter tag - do nothing
301 if ("parameter".equalsIgnoreCase(qName)) {
305 // Handle close of a node tag
306 if (nodeStack.isEmpty()) {
309 curNode = nodeStack.pop();
314 public void error(SAXParseException arg0) throws SAXException {
315 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
316 + arg0.getMessage());
321 public SvcLogicParser(SvcLogicStore store) {
325 public SvcLogicParser(String propFile) {
328 this.store = SvcLogicStoreFactory.getSvcLogicStore(propFile);
329 } catch (Exception e) {
330 LOGGER.error(SVC_LOGIC_STORE_ERROR, e);
336 public SvcLogicParser(InputStream propStr) {
339 this.store = SvcLogicStoreFactory.getSvcLogicStore(propStr);
340 } catch (Exception e) {
341 LOGGER.error(SVC_LOGIC_STORE_ERROR, e);
347 public LinkedList<SvcLogicGraph> parse(String fileName) throws SvcLogicException {
348 LinkedList<SvcLogicGraph> graphs;
351 Schema schema = null;
352 String validateSchema = System.getProperty(SLI_VALIDATING_PARSER, "true");
354 if ("true".equalsIgnoreCase(validateSchema)) {
355 xsdUrl = getClass().getResource(SVCLOGIC_XSD);
358 if (xsdUrl != null) {
360 SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
361 schema = schemaFactory.newSchema(xsdUrl);
362 LOGGER.info("Schema path {}", xsdUrl.getPath());
363 } catch (Exception e) {
364 LOGGER.warn("Could not validate using schema {}", xsdUrl.getPath(), e);
367 LOGGER.warn("Could not find resource {}", SVCLOGIC_XSD);
371 SAXParserFactory factory = SAXParserFactory.newInstance();
373 if (schema != null) {
374 factory.setNamespaceAware(true);
375 factory.setSchema(schema);
377 SAXParser saxParser = factory.newSAXParser();
379 if (saxParser.isValidating()) {
380 LOGGER.info("Parser configured to validate XML {}", (xsdUrl != null ? xsdUrl.getPath() : null));
383 graphs = new LinkedList<>();
385 saxParser.parse(fileName, new SvcLogicHandler(graphs, store));
387 } catch (Exception e) {
388 LOGGER.error("Parsing failed {}", e);
389 String msg = e.getMessage();
391 throw new SvcLogicException("Compiler error: " + fileName + " @ " + msg);
393 throw new SvcLogicException("Compiler error: " + fileName, e);
400 public static void main(String argv[]) {
402 if (argv.length == 0) {
403 SvcLogicParser.usage();
406 if ("load".equalsIgnoreCase(argv[0])) {
407 if (argv.length == 3) {
408 String xmlfile = argv[1];
409 String propfile = argv[2];
411 SvcLogicStore store = SvcLogicParser.getStore(propfile);
413 SvcLogicParser.load(xmlfile, store);
414 } catch (Exception e) {
415 LOGGER.error("Load failed {}", e);
418 SvcLogicParser.usage();
420 } else if ("print".equalsIgnoreCase(argv[0])) {
421 String version = null;
422 String propfile = null;
424 switch (argv.length) {
429 if (propfile == null) {
432 SvcLogicStore store = SvcLogicParser.getStore(propfile);
433 SvcLogicParser.print(argv[1], argv[2], argv[3], version, store);
436 SvcLogicParser.usage();
438 } else if ("get-source".equalsIgnoreCase(argv[0])) {
440 if (argv.length == 6) {
441 SvcLogicStore store = SvcLogicParser.getStore(argv[5]);
442 SvcLogicParser.getSource(argv[1], argv[2], argv[3], argv[4], store);
444 SvcLogicParser.usage();
446 } else if ("activate".equalsIgnoreCase(argv[0])) {
447 if (argv.length == 6) {
448 SvcLogicStore store = SvcLogicParser.getStore(argv[5]);
449 SvcLogicParser.activate(argv[1], argv[2], argv[3], argv[4], store);
451 SvcLogicParser.usage();
453 } else if ("validate".equalsIgnoreCase(argv[0])) {
454 if (argv.length == 3) {
455 String xmlfile = argv[1];
456 String propfile = argv[2];
458 System.setProperty(SLI_VALIDATING_PARSER, "true");
459 SvcLogicStore store = SvcLogicParser.getStore(propfile);
461 SvcLogicParser.validate(xmlfile, store);
462 } catch (Exception e) {
463 LOGGER.error("Validate failed", e);
466 SvcLogicParser.usage();
473 private static SvcLogicStore getStore(String propfile) {
475 SvcLogicStore store = null;
478 store = SvcLogicStoreFactory.getSvcLogicStore(propfile);
479 } catch (Exception e) {
480 LOGGER.error(SVC_LOGIC_STORE_ERROR, e);
488 public static void load(String xmlfile, SvcLogicStore store) throws SvcLogicException {
489 File xmlFile = new File(xmlfile);
490 if (!xmlFile.canRead()) {
491 throw new ConfigurationException("Cannot read xml file (" + xmlfile + ")");
494 SvcLogicParser parser = new SvcLogicParser(store);
495 LinkedList<SvcLogicGraph> graphs;
497 LOGGER.info("Loading {}", xmlfile);
498 graphs = parser.parse(xmlfile);
499 } catch (Exception e) {
500 throw new SvcLogicException(e.getMessage(), e);
503 if (graphs == null) {
504 throw new SvcLogicException("Could not parse " + xmlfile);
507 for (SvcLogicGraph graph : graphs) {
509 String module = graph.getModule();
510 String rpc = graph.getRpc();
511 String version = graph.getVersion();
512 String mode = graph.getMode();
514 LOGGER.info("Saving SvcLogicGraph to database (module:{},rpc:{},mode:{},version:{})", module, rpc,
517 } catch (Exception e) {
518 throw new SvcLogicException(e.getMessage(), e);
525 public static void validate(String xmlfile, SvcLogicStore store) throws SvcLogicException {
526 File xmlFile = new File(xmlfile);
527 if (!xmlFile.canRead()) {
528 throw new ConfigurationException("Cannot read xml file (" + xmlfile + ")");
531 SvcLogicParser parser = new SvcLogicParser(store);
532 LinkedList<SvcLogicGraph> graphs;
534 LOGGER.info("Validating {}", xmlfile);
535 graphs = parser.parse(xmlfile);
536 } catch (Exception e) {
537 throw new SvcLogicException(e.getMessage(), e);
540 if (graphs == null) {
541 throw new SvcLogicException("Could not parse " + xmlfile);
543 LOGGER.info("Compilation successful for {}", xmlfile);
548 private static void print(String module, String rpc, String mode, String version, SvcLogicStore store) {
549 String details = "(module:" + module + ", rpc:" + rpc + ", version:" + version + ", mode:" + mode + ")";
552 LOGGER.info(LOAD_MESSAGE, details);
554 SvcLogicGraph graph = store.fetch(module, rpc, version, mode);
556 LOGGER.error(LOAD_ERROR_MESSAGE, details);
559 graph.printAsGv(System.out);
560 } catch (Exception e) {
561 LOGGER.error(PRINT_ERROR_MESSAGE, details, e);
567 private static void getSource(String module, String rpc, String mode, String version, SvcLogicStore store) {
568 String details = "(module:" + module + ", rpc:" + rpc + ", version:" + version + ", mode:" + mode + ")";
571 LOGGER.info(LOAD_MESSAGE, details);
573 SvcLogicGraph graph = store.fetch(module, rpc, version, mode);
575 LOGGER.error(LOAD_ERROR_MESSAGE, details);
578 graph.printAsXml(System.out);
579 } catch (Exception e) {
580 LOGGER.error(PRINT_ERROR_MESSAGE, details, e);
586 private static void activate(String module, String rpc, String version, String mode, SvcLogicStore store) {
587 String details = "(module:" + module + ", rpc:" + rpc + ", version:" + version + ", mode:" + mode + ")";
590 LOGGER.info(LOAD_MESSAGE, details);
592 SvcLogicGraph graph = store.fetch(module, rpc, version, mode);
594 LOGGER.error(LOAD_ERROR_MESSAGE, details);
597 store.activate(graph);
598 } catch (Exception e) {
599 LOGGER.error(ACTIVATION_ERROR_MESSAGE, details, e);
605 private static void usage() {
606 System.err.println("Usage: SvcLogicParser load <xml-file> <prop-file>");
607 System.err.println(" OR SvcLogicParser print <module> <rpc> <mode> [<version>] <prop-file>");
608 System.err.println(" OR SvcLogicParser get-source <module> <rpc> <mode> <version> <prop-file>");
609 System.err.println(" OR SvcLogicParser activate <module> <rpc> <version> <mode>");