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