1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package name.angoca.zemucan.grammarReader.impl.xml;
30
31 import java.io.File;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.util.ArrayList;
35 import java.util.List;
36
37 import javax.xml.XMLConstants;
38 import javax.xml.parsers.DocumentBuilder;
39 import javax.xml.parsers.DocumentBuilderFactory;
40 import javax.xml.parsers.ParserConfigurationException;
41 import javax.xml.transform.Source;
42 import javax.xml.transform.stream.StreamSource;
43 import javax.xml.validation.Schema;
44 import javax.xml.validation.SchemaFactory;
45 import javax.xml.validation.Validator;
46
47 import name.angoca.zemucan.AbstractZemucanException;
48 import name.angoca.zemucan.ParameterNullException;
49 import name.angoca.zemucan.core.graph.model.Graph;
50 import name.angoca.zemucan.core.graph.model.StartingNode;
51 import name.angoca.zemucan.grammarReader.api.AbstractGrammarFileReaderException;
52 import name.angoca.zemucan.grammarReader.api.AbstractGrammarReaderException;
53 import name.angoca.zemucan.grammarReader.api.AbstractTwoPhaseGrammarReader;
54 import name.angoca.zemucan.grammarReader.api.DelimitersIncorrectlyDefinedException;
55 import name.angoca.zemucan.grammarReader.api.GeneralGrammarFileProblemException;
56 import name.angoca.zemucan.grammarReader.api.GrammarFileNotDefinedException;
57 import name.angoca.zemucan.grammarReader.api.GrammarReaderController;
58 import name.angoca.zemucan.tools.Constants;
59 import name.angoca.zemucan.tools.configurator.Configurator;
60 import name.angoca.zemucan.tools.file.FileReader;
61
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64 import org.w3c.dom.Attr;
65 import org.w3c.dom.Document;
66 import org.w3c.dom.Element;
67 import org.w3c.dom.NodeList;
68 import org.xml.sax.ErrorHandler;
69 import org.xml.sax.InputSource;
70 import org.xml.sax.SAXException;
71 import org.xml.sax.SAXParseException;
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 class Handler implements ErrorHandler {
90
91
92
93
94 private static final Logger LOGGER = LoggerFactory.getLogger(Handler.class);
95
96
97
98
99
100
101
102
103
104
105 private String
106 final SAXParseException
107 String message = "There was " + level + " at the line "
108 + exception.getLineNumber() + " column "
109 + exception.getColumnNumber();
110 final String filename = exception.getSystemId();
111 if (filename != null) {
112 message += " of file " + exception.getSystemId();
113 } else {
114 message += " from the input";
115 }
116 return message + ": " + exception.getMessage();
117 }
118
119
120
121
122
123
124 @Override
125 public void error(final SAXParseException
126 throws SAXException {
127 final String message = this.createMessage("an error", exception);
128 Handler.LOGGER.error(message);
129 }
130
131
132
133
134
135
136 @Override
137 public void fatalError(final SAXParseException exception)
138 throws SAXException {
139 final String message = this.createMessage("a problem", exception);
140 Handler.LOGGER.error(message);
141 }
142
143
144
145
146
147
148 @Override
149 public void warning(final SAXParseException exception) throws SAXException {
150 final String message = this.createMessage("an alert", exception);
151 Handler.LOGGER.warn(message);
152 }
153 }
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201 public final class ImplementationXMLGrammarReader extends
202 AbstractTwoPhaseGrammarReader {
203
204
205
206
207 private static final String DELIMITERS = "delimiters";
208
209
210
211
212 private static final Logger LOGGER = LoggerFactory
213 .getLogger(ImplementationXMLGrammarReader.class);
214
215
216
217
218 private static final String NODE_ID = "id";
219
220
221
222 private static final String NODE_NAME = "name";
223
224
225
226 private static final String TOKEN = "token";
227
228
229
230 private static final String TOKEN_ID_TOKEN = "idToken";
231
232
233
234
235 private static final String TOKEN_RESERVED = "reserved";
236
237
238
239 private static final String TRUE = "true";
240
241
242
243 private static final String VALIDATE_GRAMMAR_PROPERTY = "ValidateGrammar";
244
245
246
247
248
249
250
251
252
253
254 private static InputSource
255 throws AbstractGrammarReaderException,
256 AbstractGrammarFileReaderException {
257 if (fileName == null) {
258 throw new GrammarFileNotDefinedException();
259 }
260
261 InputStream inputStream = null;
262 try {
263 inputStream = FileReader.getStream(fileName);
264 } catch (final AbstractZemucanException e) {
265 throw new GeneralGrammarFileProblemException(e);
266 }
267 final InputSource content = new InputSource(inputStream);
268
269 assert content != null;
270 return content;
271 }
272
273
274
275
276 private InputSource contentToParse;
277
278
279
280
281 private InputSource contentToValidate;
282
283
284
285
286 private Document dom;
287
288
289
290 private Graph graph;
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306 ImplementationXMLGrammarReader(final Graph
307 final InputSource
308 final InputSource
309 throws AbstractZemucanException {
310 super();
311
312 if (contentToBeParsed == null) {
313 throw new ParameterNullException("contentToParse");
314 }
315 if (contentToBeValidated == null) {
316 throw new ParameterNullException("contentToValidate");
317 }
318 if (graphToFill == null) {
319 throw new ParameterNullException("graph");
320 }
321 ImplementationXMLGrammarReader.LOGGER
322 .debug("Creating the grammar reader");
323
324 this.contentToParse = contentToBeParsed;
325 this.contentToValidate = contentToBeValidated;
326 this.graph = graphToFill;
327 this.dom = null;
328 }
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343 public ImplementationXMLGrammarReader(final Graph
344 final String
345 super();
346
347 if (graphToFill == null) {
348 throw new ParameterNullException("graphToFill");
349 }
350 if (fileName == null) {
351 throw new ParameterNullException("fileDescriptor");
352 }
353
354 this.graph = graphToFill;
355 this.fileDescriptor = fileName;
356 this.contentToParse = null;
357 this.contentToValidate = null;
358 this.dom = null;
359 }
360
361
362
363
364
365
366
367
368
369
370
371 protected final void firstPhase() throws AbstractZemucanException {
372
373
374 final Element docEle = this.dom.getDocumentElement();
375
376
377 final NodeList nodelist = docEle
378 .getElementsByTagName(ImplementationXMLGrammarReader.TOKEN);
379
380 final int size = nodelist.getLength();
381 ImplementationXMLGrammarReader.LOGGER.debug(
382 "Processing {} nodes", Integer.toString(size));
383 if (size > 0) {
384 for (int i = 0; i < size; i += 1) {
385
386 final Element eleNode = (Element) nodelist.item(i);
387
388
389 this.readAndAddNode(eleNode);
390 }
391 }
392 }
393
394
395
396
397
398
399
400
401 @Override
402 public Graph
403 if ((this.contentToParse == null) && (this.contentToValidate == null)) {
404 final String[] files = this.getFileNamesFromDescriptor();
405
406 if (files.length <= 0) {
407 this.contentToParse = ImplementationXMLGrammarReader
408 .readSource(this.fileDescriptor);
409 this.contentToValidate = ImplementationXMLGrammarReader
410 .readSource(this.fileDescriptor);
411 } else {
412
413 final List<Graph> graphs = new ArrayList<Graph>(files.length);
414 final List<String> delimiters = new ArrayList<String>(
415 files.length);
416 for (int i = 0; i < files.length; i++) {
417 final String filename = files[i];
418 final boolean extraNodes = !Boolean.parseBoolean(System
419 .getProperty(Constants.WITHOUT_EXTRA_NODES));
420 final Graph newGraph = new Graph(this.fileDescriptor + "/"
421 + filename, extraNodes);
422 graphs.add(newGraph);
423 final ImplementationXMLGrammarReader grammar = new ImplementationXMLGrammarReader(
424 newGraph, this.fileDescriptor + File.separatorChar
425 + filename);
426 grammar.generateGraph();
427 grammar.getStartingNode();
428 delimiters.add(grammar.getDelimiters());
429 }
430 this.graph = GrammarReaderController.mergeGraphs(graphs
431 .toArray(new Graph[0]));
432 super.setDelimiters(GrammarReaderController
433 .processDelimiters(delimiters));
434
435 }
436 }
437
438
439 if ((this.contentToParse != null) && (this.contentToValidate != null)) {
440
441 this.validation(this.contentToValidate);
442
443
444 this.dom = this.parseXmlFile();
445
446 super.setStartingNode(this.readGraph());
447
448 super.setDelimiters(this.readDelimiters());
449 }
450 super.setGrammarProcessed(true);
451 return this.graph;
452 }
453
454
455
456
457
458
459
460
461
462
463
464
465 private void getChildren(final Element
466 throws AbstractZemucanException {
467 assert eleNode != null;
468
469
470 final String nodeId = this.getTextValue(eleNode,
471 ImplementationXMLGrammarReader.NODE_ID);
472
473
474 if (nodeId != null) {
475
476 final NodeList childList = eleNode
477 .getElementsByTagName(ImplementationXMLGrammarReader.TOKEN_ID_TOKEN);
478
479 final int size = childList.getLength();
480 if (size > 0) {
481 for (int i = 0; i < size; i += 1) {
482
483 final Element childElement = (Element) childList.item(i);
484
485
486 final String childId = childElement.getFirstChild()
487 .getNodeValue();
488
489
490 this.graph.addRelation(nodeId, childId);
491 }
492 }
493 }
494 }
495
496
497
498
499
500
501
502
503
504
505
506 private String
507 final String
508 assert element != null;
509 assert tagName != null;
510
511 String textValue = null;
512 final NodeList nodelist = element.getElementsByTagName(tagName);
513 if (nodelist.getLength() > 0) {
514 final Element elem = (Element) nodelist.item(0);
515 textValue = elem.getFirstChild().getNodeValue();
516 }
517
518 return textValue;
519 }
520
521
522
523
524
525
526
527
528
529 private Document
530 throws AbstractGrammarFileReaderException {
531 assert this.contentToParse != null;
532
533 ImplementationXMLGrammarReader.LOGGER.debug("Parsing the XML file");
534
535 DocumentBuilder parser = null;
536 Document document = null;
537
538
539 try {
540 parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
541
542 parser.setErrorHandler(new Handler());
543
544 document = parser.parse(this.contentToParse);
545 } catch (final ParserConfigurationException e) {
546
547 throw new XMLProblemException(e);
548 } catch (final SAXException exception) {
549 throw new XMLProblemException(exception);
550 } catch (final IOException exception) {
551
552 throw new GeneralGrammarFileProblemException(exception);
553 }
554
555 assert document != null;
556 return document;
557 }
558
559
560
561
562
563
564
565
566
567
568
569 private void readAndAddNode(final Element
570 throws AbstractZemucanException {
571 assert eleNode != null;
572
573
574 final String nodeId = this.getTextValue(eleNode,
575 ImplementationXMLGrammarReader.NODE_ID);
576 final String name = this.getTextValue(eleNode,
577 ImplementationXMLGrammarReader.NODE_NAME);
578 final NodeList nodelist = eleNode
579 .getElementsByTagName(ImplementationXMLGrammarReader.TOKEN_RESERVED);
580 boolean reserved = false;
581 if (nodelist.getLength() > 0) {
582 reserved = true;
583 }
584 if (nodeId == null) {
585 if (name == null) {
586 throw new NoIdNoNameDefinedInNodeException();
587 }
588
589 throw new NoIdDefinedInNodeException(name);
590 } else if (name == null) {
591
592 throw new NoNameDefinedInNodeException(nodeId);
593 }
594 this.graph.addNode(nodeId, name, reserved);
595 }
596
597
598
599
600
601
602
603
604
605
606 private String
607 throws DelimitersIncorrectlyDefinedException {
608 ImplementationXMLGrammarReader.LOGGER.debug("Reading the delimiters");
609
610 String delimitersRead = null;
611
612 final Element docEle = this.dom.getDocumentElement();
613
614
615 final Attr attributes = docEle
616 .getAttributeNode(ImplementationXMLGrammarReader.DELIMITERS);
617
618 try {
619 delimitersRead = attributes.getValue();
620 } catch (final NullPointerException exception) {
621 throw new DelimitersIncorrectlyDefinedException();
622 }
623 if ((delimitersRead == null) || delimitersRead.equals("")) {
624 throw new DelimitersIncorrectlyDefinedException();
625 }
626
627 assert delimitersRead != null;
628 return delimitersRead;
629 }
630
631
632
633
634
635
636
637
638
639 private StartingNode
640
641
642 this.firstPhase();
643
644 this.graph.firstPhaseFinished();
645
646
647 this.secondPhase();
648
649 final StartingNode node = this.graph.secondPhaseFinished();
650
651 assert node != null;
652 return node;
653 }
654
655
656
657
658
659
660
661
662
663 protected final void secondPhase() throws AbstractZemucanException {
664
665
666 final Element docEle = this.dom.getDocumentElement();
667
668
669 final NodeList nodeList = docEle
670 .getElementsByTagName(ImplementationXMLGrammarReader.TOKEN);
671
672
673
674 final int size = nodeList.getLength();
675 if (size > 0) {
676 for (int i = 0; i < size; i += 1) {
677
678
679 final Element eleNode = (Element) nodeList.item(i);
680
681
682 this.getChildren(eleNode);
683 }
684 }
685 }
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701 private void validation(final InputSource input)
702 throws GeneralGrammarFileProblemException, XMLProblemException,
703 GrammarFileNotDefinedException {
704 final String validate = Configurator.getInstance().getProperty(
705 ImplementationXMLGrammarReader.VALIDATE_GRAMMAR_PROPERTY);
706 if ((validate != null)
707 && validate.equals(ImplementationXMLGrammarReader.TRUE)) {
708 Schema schema = null;
709
710
711 final SchemaFactory schemaFactory = SchemaFactory
712 .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
713 StreamSource schemaSource;
714 try {
715 schemaSource = new StreamSource(
716 FileReader.getStream("grammar.xsd"));
717 } catch (final AbstractZemucanException e) {
718 throw new GeneralGrammarFileProblemException(e);
719 }
720 try {
721 schema = schemaFactory.newSchema(schemaSource);
722 } catch (final SAXException exception) {
723 throw new XMLProblemException(exception);
724 }
725
726 final Validator validator = schema.newValidator();
727 validator.setErrorHandler(new Handler());
728
729
730
731 final Source source = new StreamSource(input.getByteStream());
732 try {
733 validator.validate(source);
734 } catch (final SAXException exception) {
735 throw new XMLProblemException(exception);
736 } catch (final IOException exception) {
737
738 throw new GeneralGrammarFileProblemException(exception);
739 }
740 }
741 }
742 }