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;
25 import java.io.IOException;
27 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;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35 import org.xml.sax.Attributes;
36 import org.xml.sax.Locator;
37 import org.xml.sax.SAXException;
38 import org.xml.sax.SAXParseException;
39 import org.xml.sax.helpers.DefaultHandler;
45 public class SvcLogicParser {
47 static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
48 static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
49 static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
50 static final String JAXP_DYNAMIC_VALIDATION = "http://apache.org/xml/features/validation/dynamic";
51 static final String JAXP_SCHEMA_VALIDATION = "http://apache.org/xml/features/validation/schema";
53 private static final String LOAD_MESSAGE = "Getting SvcLogicGraph from database - {}";
54 private static final String LOAD_ERROR_MESSAGE = "SvcLogicGraph not found - {}";
55 private static final String ACTIVATION_ERROR_MESSAGE = "Could not activate SvcLogicGraph - {}";
56 private static final String PRINT_ERROR_MESSAGE = "Could not print SvcLogicGraph - {}";
57 private static final String SVC_LOGIC_STORE_ERROR = "Could not get service logic store";
59 private static final Logger LOGGER = LoggerFactory.getLogger(SvcLogicParser.class);
60 private static final String SLI_VALIDATING_PARSER = "org.onap.ccsdk.sli.parser.validate";
61 private static final String SVCLOGIC_XSD = "/svclogic.xsd";
63 private class SvcLogicHandler extends DefaultHandler {
64 private Locator locator = null;
65 private String module = null;
66 private String version = null;
67 private LinkedList<SvcLogicGraph> graphs = null;
68 private SvcLogicGraph curGraph = null;
69 private SvcLogicNode curNode = null;
70 private LinkedList<SvcLogicNode> nodeStack = null;
71 private int curNodeId = 0;
72 private String outcomeValue = null;
73 private LinkedList<String> outcomeStack = null;
75 public SvcLogicHandler(LinkedList<SvcLogicGraph> graphs) {
78 this.nodeStack = new LinkedList<>();
79 this.outcomeStack = new LinkedList<>();
81 this.outcomeValue = null;
85 public void setDocumentLocator(Locator locator) {
86 this.locator = locator;
90 public void startElement(String uri, String localName, String qName, Attributes attributes)
93 // Handle service-logic (graph) tag
94 if ("service-logic".equalsIgnoreCase(qName)) {
96 module = attributes.getValue("module");
97 if (module == null || module.length() == 0) {
98 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
99 + "Missing 'module' attribute from service-logic tag");
102 version = attributes.getValue("version");
103 if (version == null || version.length() == 0) {
104 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
105 + "Missing 'version' attribute from service-logic tag");
111 if ("method".equalsIgnoreCase(qName)) {
113 if (curGraph != null) {
114 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
115 + "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() + " "
126 + "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() + " "
133 + "Missing 'mode' attribute for method tag");
135 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()
152 + " " + "Cannot add outcome", e);
155 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
156 + "ref to unknown node " + refValue);
161 if (outcomeValue != null) {
162 outcomeStack.push(outcomeValue);
164 outcomeValue = attributes.getValue("value");
169 // Handle parameter tag
170 if ("parameter".equalsIgnoreCase(qName)) {
171 String parmName = attributes.getValue("name");
172 String parmValue = attributes.getValue("value");
174 if (parmName != null && parmName.length() > 0 && parmValue != null) {
177 curNode.mapParameter(parmName, parmValue);
178 } catch (Exception e) {
179 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
180 + " cannot set parameter " + parmName + " to " + parmValue + " [" + e.getMessage()
189 String nodeName = attributes.getValue("name");
190 SvcLogicNode thisNode;
194 if (nodeName != null && nodeName.length() > 0) {
195 thisNode = new SvcLogicNode(curNodeId++, qName, nodeName, curGraph);
197 thisNode = new SvcLogicNode(curNodeId++, qName, curGraph);
200 if (curGraph.getRootNode() == null) {
201 curGraph.setRootNode(thisNode);
203 } catch (SvcLogicException e) {
204 throw new SAXException(
205 "line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + e.getMessage());
209 int numAttributes = attributes.getLength();
211 for (int i = 0; i < numAttributes; i++) {
212 String attrName = attributes.getQName(i);
213 if (!"name".equalsIgnoreCase(attrName)) {
216 String attrValueStr = attributes.getValue(i);
217 SvcLogicExpression attrValue;
218 if (attrValueStr.trim().startsWith("`")) {
219 int lastParen = attrValueStr.lastIndexOf('`');
220 String evalExpr = attrValueStr.trim().substring(1, lastParen);
221 attrValue = SvcLogicExpressionFactory.parse(evalExpr);
224 if (Character.isDigit(attrValueStr.charAt(0))) {
225 attrValue = new SvcLogicAtom("NUMBER", attrValueStr);
227 attrValue = new SvcLogicAtom("STRING", attrValueStr);
230 thisNode.setAttribute(attrName, attrValue);
231 } catch (Exception e) {
232 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " "
233 + "Cannot set attribute " + attrName, e);
238 if (curNode != null) {
240 if ("block".equalsIgnoreCase(curNode.getNodeType()) || "for".equalsIgnoreCase(curNode.getNodeType())
241 || "while".equalsIgnoreCase(curNode.getNodeType())) {
242 curNode.addOutcome(Integer.toString(curNode.getNumOutcomes() + 1), thisNode);
244 if (outcomeValue == null) {
245 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber()
246 + " " + curNode.getNodeType() + " node expects outcome, instead found "
247 + thisNode.getNodeType());
249 curNode.addOutcome(outcomeValue, thisNode);
251 } catch (SvcLogicException e) {
252 throw new SAXException(
253 "line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + e.getMessage());
255 nodeStack.push(curNode);
262 public void endElement(String uri, String localName, String qName) throws SAXException {
264 // Handle close of service-logic tag
265 if ("service-logic".equalsIgnoreCase(qName)) {
266 // Nothing more to do
270 // Handle close of method tag
271 if ("method".equalsIgnoreCase(qName)) {
272 graphs.add(curGraph);
277 // Handle close of outcome tag
278 if ("outcome".equalsIgnoreCase(qName)) {
279 // Finished this outcome - pop the outcome stack
280 if (outcomeStack.isEmpty()) {
283 outcomeValue = outcomeStack.pop();
288 // Handle close of parameter tag - do nothing
289 if ("parameter".equalsIgnoreCase(qName)) {
293 // Handle close of a node tag
294 if (nodeStack.isEmpty()) {
297 curNode = nodeStack.pop();
302 public void error(SAXParseException arg0) throws SAXException {
303 throw new SAXException(
304 "line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + arg0.getMessage());
309 public LinkedList<SvcLogicGraph> parse(String fileName) throws SvcLogicException {
310 LinkedList<SvcLogicGraph> graphs;
313 Schema schema = null;
314 String validateSchema = System.getProperty(SLI_VALIDATING_PARSER, "true");
316 if ("true".equalsIgnoreCase(validateSchema)) {
317 xsdUrl = getClass().getResource(SVCLOGIC_XSD);
320 if (xsdUrl != null) {
322 SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
323 schema = schemaFactory.newSchema(xsdUrl);
324 LOGGER.info("Schema path {}", xsdUrl.getPath());
325 } catch (Exception e) {
326 LOGGER.warn("Could not validate using schema {}", xsdUrl.getPath(), e);
329 LOGGER.warn("Could not find resource {}", SVCLOGIC_XSD);
333 SAXParserFactory factory = SAXParserFactory.newInstance();
335 if (schema != null) {
336 factory.setNamespaceAware(true);
337 factory.setSchema(schema);
339 SAXParser saxParser = factory.newSAXParser();
341 if (saxParser.isValidating()) {
342 LOGGER.info("Parser configured to validate XML {}", (xsdUrl != null ? xsdUrl.getPath() : null));
345 graphs = new LinkedList<>();
347 saxParser.parse(fileName, new SvcLogicHandler(graphs));
350 for (SvcLogicGraph graph : graphs) {
351 graph.setMd5sum(CheckSumHelper.md5SumFromFile(fileName));
353 } catch (Exception exc) {
354 LOGGER.error("Couldn't set md5sum on graphs", exc);
357 } catch (Exception e) {
358 LOGGER.error("Parsing failed ", e);
359 String msg = e.getMessage();
361 throw new SvcLogicException("Compiler error: " + fileName + " @ " + msg);
363 throw new SvcLogicException("Compiler error: " + fileName, e);
370 public static void main(String argv[]) {
372 if (argv.length == 0) {
373 SvcLogicParser.usage();
376 if ("load".equalsIgnoreCase(argv[0])) {
377 if (argv.length == 3) {
378 String xmlfile = argv[1];
379 String propfile = argv[2];
381 SvcLogicStore store = SvcLogicParser.getStore(propfile);
383 SvcLogicParser.load(xmlfile, store);
384 } catch (Exception e) {
385 LOGGER.error("Load failed ", e);
388 SvcLogicParser.usage();
390 } else if ("print".equalsIgnoreCase(argv[0])) {
391 String version = null;
392 String propfile = null;
394 switch (argv.length) {
399 if (propfile == null) {
402 SvcLogicStore store = SvcLogicParser.getStore(propfile);
403 SvcLogicParser.print(argv[1], argv[2], argv[3], version, store);
406 SvcLogicParser.usage();
408 } else if ("get-source".equalsIgnoreCase(argv[0])) {
410 if (argv.length == 6) {
411 SvcLogicStore store = SvcLogicParser.getStore(argv[5]);
412 SvcLogicParser.getSource(argv[1], argv[2], argv[3], argv[4], store);
414 SvcLogicParser.usage();
416 } else if ("activate".equalsIgnoreCase(argv[0])) {
417 if (argv.length == 6) {
418 SvcLogicStore store = SvcLogicParser.getStore(argv[5]);
419 SvcLogicParser.activate(argv[1], argv[2], argv[3], argv[4], store);
421 SvcLogicParser.usage();
423 } else if ("validate".equalsIgnoreCase(argv[0])) {
424 if (argv.length == 3) {
425 String xmlfile = argv[1];
426 String propfile = argv[2];
428 System.setProperty(SLI_VALIDATING_PARSER, "true");
429 SvcLogicStore store = SvcLogicParser.getStore(propfile);
431 SvcLogicParser.validate(xmlfile, store);
432 } catch (Exception e) {
433 LOGGER.error("Validate failed", e);
436 SvcLogicParser.usage();
438 } else if ("install".equalsIgnoreCase(argv[0])) {
439 if (argv.length == 3) {
440 SvcLogicLoader loader = new SvcLogicLoader(argv[1], argv[2]);
442 loader.loadAndActivate();
443 } catch (IOException e) {
444 LOGGER.error(e.getMessage(), e);
447 SvcLogicParser.usage();
454 protected static SvcLogicStore getStore(String propfile) {
456 SvcLogicStore store = null;
459 store = SvcLogicStoreFactory.getSvcLogicStore(propfile);
460 } catch (Exception e) {
461 LOGGER.error(SVC_LOGIC_STORE_ERROR, e);
469 public static void load(String xmlfile, SvcLogicStore store) throws SvcLogicException {
470 File xmlFile = new File(xmlfile);
471 if (!xmlFile.canRead()) {
472 throw new ConfigurationException("Cannot read xml file (" + xmlfile + ")");
475 SvcLogicParser parser = new SvcLogicParser();
476 LinkedList<SvcLogicGraph> graphs;
478 LOGGER.info("Loading {}", xmlfile);
479 graphs = parser.parse(xmlfile);
480 } catch (Exception e) {
481 throw new SvcLogicException(e.getMessage(), e);
484 if (graphs == null) {
485 throw new SvcLogicException("Could not parse " + xmlfile);
488 for (SvcLogicGraph graph : graphs) {
490 String module = graph.getModule();
491 String rpc = graph.getRpc();
492 String version = graph.getVersion();
493 String mode = graph.getMode();
495 LOGGER.info("Saving SvcLogicGraph to database (module:{},rpc:{},mode:{},version:{})", module, rpc, mode,
498 } catch (Exception e) {
499 throw new SvcLogicException(e.getMessage(), e);
506 public static void validate(String xmlfile, SvcLogicStore store) throws SvcLogicException {
507 File xmlFile = new File(xmlfile);
508 if (!xmlFile.canRead()) {
509 throw new ConfigurationException("Cannot read xml file (" + xmlfile + ")");
512 SvcLogicParser parser = new SvcLogicParser();
513 LinkedList<SvcLogicGraph> graphs;
515 LOGGER.info("Validating {}", xmlfile);
516 graphs = parser.parse(xmlfile);
517 } catch (Exception e) {
518 throw new SvcLogicException(e.getMessage(), e);
521 if (graphs == null) {
522 throw new SvcLogicException("Could not parse " + xmlfile);
524 LOGGER.info("Compilation successful for {}", xmlfile);
529 private static void print(String module, String rpc, String mode, String version, SvcLogicStore store) {
530 String details = "(module:" + module + ", rpc:" + rpc + ", version:" + version + ", mode:" + mode + ")";
533 LOGGER.info(LOAD_MESSAGE, details);
535 SvcLogicGraph graph = store.fetch(module, rpc, version, mode);
537 LOGGER.error(LOAD_ERROR_MESSAGE, details);
540 graph.printAsGv(System.out);
541 } catch (Exception e) {
542 LOGGER.error(PRINT_ERROR_MESSAGE, details, e);
548 private static void getSource(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.printAsXml(System.out);
560 } catch (Exception e) {
561 LOGGER.error(PRINT_ERROR_MESSAGE, details, e);
567 private static void activate(String module, String rpc, String version, String mode, 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 store.activate(graph);
579 } catch (Exception e) {
580 LOGGER.error(ACTIVATION_ERROR_MESSAGE, details, e);
586 private static void usage() {
587 System.err.println("Usage: SvcLogicParser load <xml-file> <prop-file>");
588 System.err.println(" OR SvcLogicParser print <module> <rpc> <mode> [<version>] <prop-file>");
589 System.err.println(" OR SvcLogicParser get-source <module> <rpc> <mode> <version> <prop-file>");
590 System.err.println(" OR SvcLogicParser activate <module> <rpc> <version> <mode>");
591 System.err.println(" OR SvcLogicParser validate <file path to graph> <prop-file>");
592 System.err.println(" OR SvcLogicParser install <service-logic directory path> <prop-file>");