398c28de723c242efbe2e031615a692434697fa2
[ccsdk/sli/core.git] / sli / common / src / main / java / org / openecomp / sdnc / sli / SvcLogicParser.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                                              reserved.
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
11  * 
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  * 
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=========================================================
20  */
21
22 package org.openecomp.sdnc.sli;
23
24 import java.io.File;
25 import java.io.InputStream;
26 import java.net.URL;
27 import java.util.LinkedList;
28
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;
34
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;
43
44 /**
45  * @author dt5972
46  *
47  */
48 public class SvcLogicParser {
49
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";
56
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";
62
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";
66
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;
79
80     public SvcLogicHandler(LinkedList<SvcLogicGraph> graphs, SvcLogicStore store) {
81         this.graphs = graphs;
82         this.curNode = null;
83         this.nodeStack = new LinkedList<>();
84         this.outcomeStack = new LinkedList<>();
85         this.curNodeId = 1;
86         this.outcomeValue = null;
87         this.svcLogicStore = store;
88
89     }
90
91     @Override
92         public void setDocumentLocator(Locator locator) {
93         this.locator = locator;
94     }
95
96     @Override
97     public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
98
99         // Handle service-logic (graph) tag
100         if ("service-logic".equalsIgnoreCase(qName)) {
101
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");
105         }
106
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");
110         }
111
112         return;
113         }
114
115         if ("method".equalsIgnoreCase(qName)) {
116         if (curGraph != null) {
117             throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Cannot nest module tags");
118         }
119         curGraph = new SvcLogicGraph();
120         curGraph.setModule(module);
121         curGraph.setVersion(version);
122         this.curNodeId = 1;
123
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");
127         }
128         curGraph.setRpc(attrValue);
129
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");
133         }
134         curGraph.setMode(attrValue);
135
136         return;
137
138         }
139
140         // Handle outcome (edge) tag
141         if ("outcome".equalsIgnoreCase(qName)) {
142         String refValue = attributes.getValue("ref");
143
144         if (refValue != null) {
145             SvcLogicNode refNode = curGraph.getNamedNode(refValue);
146
147             if (refNode != null) {
148             try {
149                 curNode.addOutcome(attributes.getValue("value"), refNode);
150             } catch (SvcLogicException e) {
151                 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Cannot add outcome", e);
152             }
153             } else {
154             throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "ref to unknown node " + refValue);
155             }
156             return;
157         }
158
159         if (outcomeValue != null) {
160             outcomeStack.push(outcomeValue);
161         }
162         outcomeValue = attributes.getValue("value");
163
164         return;
165         }
166
167         // Handle parameter tag
168         if ("parameter".equalsIgnoreCase(qName)) {
169         String parmName = attributes.getValue("name");
170         String parmValue = attributes.getValue("value");
171
172         if (parmName != null && parmName.length() > 0 && parmValue != null) {
173             try {
174
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() + "]");
178             }
179         }
180
181         return;
182         }
183
184         // Handle node tags
185
186         String nodeName = attributes.getValue("name");
187         SvcLogicNode thisNode = null;
188
189         try {
190         if (!svcLogicStore.isValidNodeType(qName)) {
191             throw new SAXNotRecognizedException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Unknown tag " + qName);
192         }
193         } catch (Exception e) {
194         throw new SAXNotRecognizedException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Cannot validate node type " + qName);
195         }
196
197         try {
198         if (nodeName != null && nodeName.length() > 0) {
199             thisNode = new SvcLogicNode(curNodeId++, qName, nodeName, curGraph);
200         } else {
201             thisNode = new SvcLogicNode(curNodeId++, qName, curGraph);
202         }
203
204         if (curGraph.getRootNode() == null) {
205             curGraph.setRootNode(thisNode);
206         }
207         } catch (SvcLogicException e) {
208         throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + e.getMessage());
209
210         }
211
212         int numAttributes = attributes.getLength();
213
214         for (int i = 0; i < numAttributes; i++) {
215         String attrName = attributes.getQName(i);
216         if (!"name".equalsIgnoreCase(attrName)) {
217             try {
218
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);
225
226             } else {
227                 if (Character.isDigit(attrValueStr.charAt(0))) {
228                 attrValue = new SvcLogicAtom("NUMBER", attrValueStr);
229                 } else {
230                 attrValue = new SvcLogicAtom("STRING", attrValueStr);
231                 }
232             }
233             thisNode.setAttribute(attrName, attrValue);
234             } catch (Exception e) {
235             throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + "Cannot set attribute " + attrName, e);
236             }
237         }
238         }
239
240         if (curNode != null) {
241         try {
242             if ("block".equalsIgnoreCase(curNode.getNodeType()) || "for".equalsIgnoreCase(curNode.getNodeType()) || "while".equalsIgnoreCase(curNode.getNodeType())) {
243             curNode.addOutcome("" + (curNode.getNumOutcomes() + 1), thisNode);
244             } else {
245             if (outcomeValue == null) {
246                 throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + curNode.getNodeType() + " node expects outcome, instead found " + thisNode.getNodeType());
247             }
248             curNode.addOutcome(outcomeValue, thisNode);
249             }
250         } catch (SvcLogicException e) {
251             throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + e.getMessage());
252         }
253         nodeStack.push(curNode);
254         }
255         curNode = thisNode;
256
257     }
258
259     @Override
260     public void endElement(String uri, String localName, String qName) throws SAXException {
261
262         // Handle close of service-logic tag
263         if ("service-logic".equalsIgnoreCase(qName)) {
264         // Nothing more to do
265         return;
266         }
267
268         // Handle close of method tag
269         if ("method".equalsIgnoreCase(qName)) {
270         graphs.add(curGraph);
271         curGraph = null;
272         return;
273         }
274
275         // Handle close of outcome tag
276         if ("outcome".equalsIgnoreCase(qName)) {
277         // Finished this outcome - pop the outcome stack
278         if (outcomeStack.isEmpty()) {
279             outcomeValue = null;
280         } else {
281             outcomeValue = outcomeStack.pop();
282         }
283         return;
284         }
285
286         // Handle close of parameter tag - do nothing
287         if ("parameter".equalsIgnoreCase(qName)) {
288         return;
289         }
290
291         // Handle close of a node tag
292         if (nodeStack.isEmpty()) {
293         curNode = null;
294         } else {
295         curNode = nodeStack.pop();
296         }
297     }
298
299     @Override
300     public void error(SAXParseException arg0) throws SAXException {
301         throw new SAXException("line " + locator.getLineNumber() + ":" + locator.getColumnNumber() + " " + arg0.getMessage());
302     }
303
304     }
305
306     public SvcLogicParser(SvcLogicStore store) {
307     this.store = store;
308     }
309
310     public SvcLogicParser(String propFile) {
311
312     try {
313         this.store = SvcLogicStoreFactory.getSvcLogicStore(propFile);
314     } catch (Exception e) {
315         LOGGER.error(SVC_LOGIC_STORE_ERROR, e);
316
317     }
318
319     }
320
321     public SvcLogicParser(InputStream propStr) {
322
323     try {
324         this.store = SvcLogicStoreFactory.getSvcLogicStore(propStr);
325     } catch (Exception e) {
326         LOGGER.error(SVC_LOGIC_STORE_ERROR, e);
327
328     }
329
330     }
331
332     public LinkedList<SvcLogicGraph> parse(String fileName) throws SvcLogicException {
333     LinkedList<SvcLogicGraph> graphs = null;
334
335     URL xsdUrl = null;
336     Schema schema = null;
337     String validateSchema = System.getProperty(SLI_VALIDATING_PARSER, "true");
338
339     if (validateSchema != null || validateSchema.equalsIgnoreCase("true")) {
340         xsdUrl = getClass().getResource(SVCLOGIC_XSD);
341
342     }
343
344     if (xsdUrl != null) {
345         try {
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);
350         }
351     } else {
352         LOGGER.warn("Could not find resource " + SVCLOGIC_XSD);
353     }
354
355     try {
356         SAXParserFactory factory = SAXParserFactory.newInstance();
357
358         if (schema != null) {
359         factory.setNamespaceAware(true);
360         factory.setSchema(schema);
361         }
362         SAXParser saxParser = factory.newSAXParser();
363
364         if (saxParser.isValidating()) {
365         LOGGER.info("Validating against schema " + xsdUrl.getPath());
366         }
367         graphs = new LinkedList<>();
368
369         saxParser.parse(fileName, new SvcLogicHandler(graphs, store));
370
371     } catch (Exception e) {
372         String msg = e.getMessage();
373         if (msg != null) {
374         LOGGER.error(msg);
375         throw new SvcLogicException("Compiler error: " + fileName + " @ " + msg);
376         } else {
377         LOGGER.info("Caught exception parsing " + fileName, e);
378         throw new SvcLogicException("Compiler error: " + fileName, e);
379         }
380     }
381
382     return graphs;
383     }
384
385     public static void main(String argv[]) {
386
387     if (argv.length == 0) {
388         SvcLogicParser.usage();
389     }
390
391     if ("load".equalsIgnoreCase(argv[0])) {
392         if (argv.length == 3) {
393         String xmlfile = argv[1];
394         String propfile = argv[2];
395
396         SvcLogicStore store = SvcLogicParser.getStore(propfile);
397         try {
398             SvcLogicParser.load(xmlfile, store);
399         } catch (Exception e) {
400             LOGGER.error(e.getMessage(), e);
401         }
402         } else {
403         SvcLogicParser.usage();
404         }
405     } else if ("print".equalsIgnoreCase(argv[0])) {
406         String version = null;
407         String propfile = null;
408
409         switch (argv.length) {
410         case 6:
411         version = argv[4];
412         propfile = argv[5];
413         case 5:
414         if (propfile == null) {
415             propfile = argv[4];
416         }
417         SvcLogicStore store = SvcLogicParser.getStore(propfile);
418         SvcLogicParser.print(argv[1], argv[2], argv[3], version, store);
419         break;
420         default:
421         SvcLogicParser.usage();
422         }
423     } else if ("get-source".equalsIgnoreCase(argv[0])) {
424
425         switch (argv.length) {
426         case 6:
427         SvcLogicStore store = SvcLogicParser.getStore(argv[5]);
428         SvcLogicParser.getSource(argv[1], argv[2], argv[3], argv[4], store);
429         break;
430         default:
431         SvcLogicParser.usage();
432         }
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);
437         } else {
438         SvcLogicParser.usage();
439         }
440     } else if ("validate".equalsIgnoreCase(argv[0])) {
441         if (argv.length == 3) {
442         String xmlfile = argv[1];
443         String propfile = argv[2];
444
445         System.setProperty(SLI_VALIDATING_PARSER, "true");
446         SvcLogicStore store = SvcLogicParser.getStore(propfile);
447         try {
448             SvcLogicParser.validate(xmlfile, store);
449         } catch (Exception e) {
450             LOGGER.error(e.getMessage(), e);
451         }
452         } else {
453         SvcLogicParser.usage();
454         }
455     }
456
457     System.exit(0);
458     }
459
460     private static SvcLogicStore getStore(String propfile) {
461
462     SvcLogicStore store = null;
463
464     try {
465         store = SvcLogicStoreFactory.getSvcLogicStore(propfile);
466     } catch (Exception e) {
467         LOGGER.error(SVC_LOGIC_STORE_ERROR, e);
468         System.exit(1);
469     }
470
471     return store;
472
473     }
474
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 + ")");
479     }
480
481     SvcLogicParser parser = new SvcLogicParser(store);
482     LinkedList<SvcLogicGraph> graphs = null;
483     try {
484         graphs = parser.parse(xmlfile);
485     } catch (Exception e) {
486         throw new SvcLogicException(e.getMessage(), e);
487     }
488
489     if (graphs == null) {
490         throw new SvcLogicException("Could not parse " + xmlfile);
491     }
492
493     for (SvcLogicGraph graph : graphs) {
494
495         String module = graph.getModule();
496         String rpc = graph.getRpc();
497         String version = graph.getVersion();
498         String mode = graph.getMode();
499         try {
500         LOGGER.info("Saving SvcLogicGraph to database (module:" + module + ",rpc:" + rpc + ",version:" + version + ",mode:" + mode + ")");
501         store.store(graph);
502         } catch (Exception e) {
503         throw new SvcLogicException(e.getMessage(), e);
504         }
505
506     }
507
508     }
509
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 + ")");
514     }
515
516     SvcLogicParser parser = new SvcLogicParser(store);
517     LinkedList<SvcLogicGraph> graphs = null;
518     try {
519         LOGGER.info("Validating " + xmlfile);
520         graphs = parser.parse(xmlfile);
521     } catch (Exception e) {
522         throw new SvcLogicException(e.getMessage(), e);
523     }
524
525     if (graphs == null) {
526         throw new SvcLogicException("Could not parse " + xmlfile);
527     } else {
528         LOGGER.info("Compilation successful for " + xmlfile);
529     }
530
531     }
532
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 + ")";
535
536     try {
537         LOGGER.info(LOAD_MESSAGE + details);
538
539         SvcLogicGraph graph = store.fetch(module, rpc, version, mode);
540         if (graph == null) {
541         LOGGER.error(LOAD_ERROR_MESSAGE + details);
542         System.exit(1);
543         }
544         graph.printAsGv(System.out);
545     } catch (Exception e) {
546         LOGGER.error(PRINT_ERROR_MESSAGE + details, e);
547         System.exit(1);
548     }
549
550     }
551
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 + ")";
554
555     try {
556         LOGGER.info(LOAD_MESSAGE + details);
557
558         SvcLogicGraph graph = store.fetch(module, rpc, version, mode);
559         if (graph == null) {
560         LOGGER.error(LOAD_ERROR_MESSAGE + details);
561         System.exit(1);
562         }
563         graph.printAsXml(System.out);
564     } catch (Exception e) {
565         LOGGER.error(PRINT_ERROR_MESSAGE + details, e);
566         System.exit(1);
567     }
568
569     }
570
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 + ")";
573
574     try {
575         LOGGER.info(LOAD_MESSAGE + details);
576
577         SvcLogicGraph graph = store.fetch(module, rpc, version, mode);
578         if (graph == null) {
579         LOGGER.error(LOAD_ERROR_MESSAGE + details);
580         System.exit(1);
581         }
582         store.activate(graph);
583     } catch (Exception e) {
584         LOGGER.error(ACTIVATION_ERROR_MESSAGE + details, e);
585         System.exit(1);
586     }
587
588     }
589
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>");
595     System.exit(1);
596     }
597
598 }