1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.view.facelets.compiler;
20
21 import java.io.BufferedInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.URL;
25 import java.util.regex.Matcher;
26 import java.util.regex.Pattern;
27
28 import javax.el.ELException;
29 import javax.faces.FacesException;
30 import javax.faces.view.Location;
31 import javax.faces.view.facelets.FaceletException;
32 import javax.faces.view.facelets.FaceletHandler;
33 import javax.faces.view.facelets.Tag;
34 import javax.faces.view.facelets.TagAttribute;
35 import javax.faces.view.facelets.TagAttributes;
36 import javax.xml.parsers.ParserConfigurationException;
37 import javax.xml.parsers.SAXParser;
38 import javax.xml.parsers.SAXParserFactory;
39
40 import org.apache.myfaces.shared.util.ClassUtils;
41 import org.apache.myfaces.view.facelets.tag.TagAttributeImpl;
42 import org.apache.myfaces.view.facelets.tag.TagAttributesImpl;
43 import org.apache.myfaces.view.facelets.tag.composite.CompositeLibrary;
44 import org.apache.myfaces.view.facelets.tag.composite.ImplementationHandler;
45 import org.apache.myfaces.view.facelets.tag.composite.InterfaceHandler;
46 import org.apache.myfaces.view.facelets.tag.jsf.core.CoreLibrary;
47 import org.xml.sax.Attributes;
48 import org.xml.sax.InputSource;
49 import org.xml.sax.Locator;
50 import org.xml.sax.SAXException;
51 import org.xml.sax.SAXParseException;
52 import org.xml.sax.XMLReader;
53 import org.xml.sax.ext.LexicalHandler;
54 import org.xml.sax.helpers.DefaultHandler;
55
56
57
58
59
60
61
62
63
64 public final class SAXCompiler extends Compiler
65 {
66
67 private final static Pattern XmlDeclaration = Pattern
68 .compile("^<\\?xml.+?version=['\"](.+?)['\"](.+?encoding=['\"]((.+?))['\"])?.*?\\?>");
69
70 private static class CompilationHandler extends DefaultHandler implements LexicalHandler
71 {
72
73 private final String alias;
74
75 private boolean inDocument = false;
76
77 private Locator locator;
78
79 private final CompilationManager unit;
80
81 public CompilationHandler(CompilationManager unit, String alias)
82 {
83 this.unit = unit;
84 this.alias = alias;
85 }
86
87 public void characters(char[] ch, int start, int length) throws SAXException
88 {
89 if (this.inDocument)
90 {
91 this.unit.writeText(new String(ch, start, length));
92 }
93 }
94
95 public void comment(char[] ch, int start, int length) throws SAXException
96 {
97 if (this.inDocument)
98 {
99 this.unit.writeComment(new String(ch, start, length));
100 }
101 }
102
103 protected TagAttributes createAttributes(Attributes attrs)
104 {
105 int len = attrs.getLength();
106 TagAttribute[] ta = new TagAttribute[len];
107 for (int i = 0; i < len; i++)
108 {
109 ta[i] = new TagAttributeImpl(this.createLocation(), attrs.getURI(i), attrs.getLocalName(i), attrs
110 .getQName(i), attrs.getValue(i));
111 }
112 return new TagAttributesImpl(ta);
113 }
114
115 protected Location createLocation()
116 {
117 return new Location(this.alias, this.locator.getLineNumber(), this.locator.getColumnNumber());
118 }
119
120 public void endCDATA() throws SAXException
121 {
122 if (this.inDocument)
123 {
124 this.unit.writeInstruction("]]>");
125 }
126 }
127
128 public void endDocument() throws SAXException
129 {
130 super.endDocument();
131 }
132
133 public void endDTD() throws SAXException
134 {
135 this.inDocument = true;
136 }
137
138 public void endElement(String uri, String localName, String qName) throws SAXException
139 {
140 this.unit.popTag();
141 }
142
143 public void endEntity(String name) throws SAXException
144 {
145 }
146
147 public void endPrefixMapping(String prefix) throws SAXException
148 {
149 this.unit.popNamespace(prefix);
150 }
151
152 public void fatalError(SAXParseException e) throws SAXException
153 {
154 if (this.locator != null)
155 {
156 throw new SAXException("Error Traced[line: " + this.locator.getLineNumber() + "] " + e.getMessage());
157 }
158 else
159 {
160 throw e;
161 }
162 }
163
164 public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
165 {
166 if (this.inDocument)
167 {
168 this.unit.writeWhitespace(new String(ch, start, length));
169 }
170 }
171
172 public InputSource resolveEntity(String publicId, String systemId) throws SAXException
173 {
174 String dtd = "org/apache/myfaces/resource/default.dtd";
175
176
177
178
179 URL url = ClassUtils.getResource(dtd);
180 return new InputSource(url.toString());
181 }
182
183 public void setDocumentLocator(Locator locator)
184 {
185 this.locator = locator;
186 }
187
188 public void startCDATA() throws SAXException
189 {
190 if (this.inDocument)
191 {
192 this.unit.writeInstruction("<![CDATA[");
193 }
194 }
195
196 public void startDocument() throws SAXException
197 {
198 this.inDocument = true;
199 }
200
201 public void startDTD(String name, String publicId, String systemId) throws SAXException
202 {
203 if (this.inDocument)
204 {
205 StringBuffer sb = new StringBuffer(64);
206 sb.append("<!DOCTYPE ").append(name);
207 if (publicId != null)
208 {
209 sb.append(" PUBLIC \"").append(publicId).append("\"");
210 if (systemId != null)
211 {
212 sb.append(" \"").append(systemId).append("\"");
213 }
214 }
215 else if (systemId != null)
216 {
217 sb.append(" SYSTEM \"").append(systemId).append("\"");
218 }
219 sb.append(" >\n");
220 this.unit.writeInstruction(sb.toString());
221 }
222 this.inDocument = false;
223 }
224
225 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
226 {
227 this.unit.pushTag(new Tag(this.createLocation(), uri, localName, qName, this.createAttributes(attributes)));
228 }
229
230 public void startEntity(String name) throws SAXException
231 {
232 }
233
234 public void startPrefixMapping(String prefix, String uri) throws SAXException
235 {
236 this.unit.pushNamespace(prefix, uri);
237 }
238
239 public void processingInstruction(String target, String data) throws SAXException
240 {
241 if (this.inDocument)
242 {
243 StringBuffer sb = new StringBuffer(64);
244 sb.append("<?").append(target).append(' ').append(data).append("?>\n");
245 this.unit.writeInstruction(sb.toString());
246 }
247 }
248 }
249
250
251
252
253
254
255 private static class ViewMetadataHandler extends DefaultHandler implements LexicalHandler
256 {
257
258 private final String alias;
259
260 private boolean inDocument = false;
261
262 private Locator locator;
263
264 private final CompilationManager unit;
265
266 private boolean inMetadata = false;
267
268 public ViewMetadataHandler(CompilationManager unit, String alias)
269 {
270 this.unit = unit;
271 this.alias = alias;
272 }
273
274 public void characters(char[] ch, int start, int length) throws SAXException
275 {
276 if (this.inDocument && inMetadata)
277 {
278 this.unit.writeText(new String(ch, start, length));
279 }
280 }
281
282 public void comment(char[] ch, int start, int length) throws SAXException
283 {
284 if (this.inDocument && inMetadata)
285 {
286 this.unit.writeComment(new String(ch, start, length));
287 }
288 }
289
290 protected TagAttributes createAttributes(Attributes attrs)
291 {
292 int len = attrs.getLength();
293 TagAttribute[] ta = new TagAttribute[len];
294 for (int i = 0; i < len; i++)
295 {
296 ta[i] = new TagAttributeImpl(this.createLocation(), attrs.getURI(i), attrs.getLocalName(i), attrs
297 .getQName(i), attrs.getValue(i));
298 }
299 return new TagAttributesImpl(ta);
300 }
301
302 protected Location createLocation()
303 {
304 return new Location(this.alias, this.locator.getLineNumber(), this.locator.getColumnNumber());
305 }
306
307 public void endCDATA() throws SAXException
308 {
309 if (this.inDocument && inMetadata)
310 {
311 this.unit.writeInstruction("]]>");
312 }
313 }
314
315 public void endDocument() throws SAXException
316 {
317 super.endDocument();
318 }
319
320 public void endDTD() throws SAXException
321 {
322 this.inDocument = true;
323 }
324
325 public void endElement(String uri, String localName, String qName) throws SAXException
326 {
327 if (inMetadata)
328 {
329 this.unit.popTag();
330 }
331 if (CoreLibrary.Namespace.equals(uri) && "metadata".equals(localName))
332 {
333 this.inMetadata=false;
334 }
335 }
336
337 public void endEntity(String name) throws SAXException
338 {
339 }
340
341 public void endPrefixMapping(String prefix) throws SAXException
342 {
343 this.unit.popNamespace(prefix);
344 }
345
346 public void fatalError(SAXParseException e) throws SAXException
347 {
348 if (this.locator != null)
349 {
350 throw new SAXException("Error Traced[line: " + this.locator.getLineNumber() + "] " + e.getMessage());
351 }
352 else
353 {
354 throw e;
355 }
356 }
357
358 public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
359 {
360 if (this.inDocument && inMetadata)
361 {
362 this.unit.writeWhitespace(new String(ch, start, length));
363 }
364 }
365
366 public InputSource resolveEntity(String publicId, String systemId) throws SAXException
367 {
368 String dtd = "org/apache/myfaces/resource/default.dtd";
369
370
371
372
373 URL url = ClassUtils.getResource(dtd);
374 return new InputSource(url.toString());
375 }
376
377 public void setDocumentLocator(Locator locator)
378 {
379 this.locator = locator;
380 }
381
382 public void startCDATA() throws SAXException
383 {
384 if (this.inDocument && inMetadata)
385 {
386 this.unit.writeInstruction("<![CDATA[");
387 }
388 }
389
390 public void startDocument() throws SAXException
391 {
392 this.inDocument = true;
393 }
394
395 public void startDTD(String name, String publicId, String systemId) throws SAXException
396 {
397
398 this.inDocument = false;
399 }
400
401 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
402 {
403 if (CoreLibrary.Namespace.equals(uri) && "metadata".equals(localName))
404 {
405 this.inMetadata=true;
406 }
407 if (inMetadata)
408 {
409 this.unit.pushTag(new Tag(this.createLocation(), uri, localName, qName, this.createAttributes(attributes)));
410 }
411 }
412
413 public void startEntity(String name) throws SAXException
414 {
415 }
416
417 public void startPrefixMapping(String prefix, String uri) throws SAXException
418 {
419 this.unit.pushNamespace(prefix, uri);
420 }
421
422 public void processingInstruction(String target, String data) throws SAXException
423 {
424 if (this.inDocument && inMetadata)
425 {
426 StringBuffer sb = new StringBuffer(64);
427 sb.append("<?").append(target).append(' ').append(data).append("?>\n");
428 this.unit.writeInstruction(sb.toString());
429 }
430 }
431 }
432
433
434
435
436
437
438
439
440
441 private static class CompositeComponentMetadataHandler extends DefaultHandler implements LexicalHandler
442 {
443
444 private final String alias;
445
446 private boolean inDocument = false;
447
448 private Locator locator;
449
450 private final CompilationManager unit;
451
452 private boolean inCompositeInterface = false;
453
454 private boolean inCompositeImplementation = false;
455
456 public CompositeComponentMetadataHandler(CompilationManager unit, String alias)
457 {
458 this.unit = unit;
459 this.alias = alias;
460 }
461
462 public void characters(char[] ch, int start, int length) throws SAXException
463 {
464 if (this.inDocument && inCompositeInterface)
465 {
466 this.unit.writeText(new String(ch, start, length));
467 }
468 }
469
470 public void comment(char[] ch, int start, int length) throws SAXException
471 {
472 if (this.inDocument && inCompositeInterface)
473 {
474 this.unit.writeComment(new String(ch, start, length));
475 }
476 }
477
478 protected TagAttributes createAttributes(Attributes attrs)
479 {
480 int len = attrs.getLength();
481 TagAttribute[] ta = new TagAttribute[len];
482 for (int i = 0; i < len; i++)
483 {
484 ta[i] = new TagAttributeImpl(this.createLocation(), attrs.getURI(i), attrs.getLocalName(i), attrs
485 .getQName(i), attrs.getValue(i));
486 }
487 return new TagAttributesImpl(ta);
488 }
489
490 protected Location createLocation()
491 {
492 return new Location(this.alias, this.locator.getLineNumber(), this.locator.getColumnNumber());
493 }
494
495 public void endCDATA() throws SAXException
496 {
497 if (this.inDocument && inCompositeInterface)
498 {
499 this.unit.writeInstruction("]]>");
500 }
501 }
502
503 public void endDocument() throws SAXException
504 {
505 super.endDocument();
506 }
507
508 public void endDTD() throws SAXException
509 {
510 this.inDocument = true;
511 }
512
513 public void endElement(String uri, String localName, String qName) throws SAXException
514 {
515 if (inCompositeInterface)
516 {
517 this.unit.popTag();
518 }
519 else if (inCompositeImplementation && CompositeLibrary.NAMESPACE.equals(uri))
520 {
521 if ( "insertFacet".equals(localName) ||
522 "renderFacet".equals(localName) ||
523 "insertChildren".equals(localName) ||
524 ImplementationHandler.NAME.equals(localName))
525 {
526 this.unit.popTag();
527 }
528 }
529
530 if (CompositeLibrary.NAMESPACE.equals(uri))
531 {
532 if (InterfaceHandler.NAME.equals(localName))
533 {
534 this.inCompositeInterface=false;
535 }
536 else if (ImplementationHandler.NAME.equals(localName))
537 {
538 this.inCompositeImplementation=false;
539 }
540 }
541 }
542
543 public void endEntity(String name) throws SAXException
544 {
545 }
546
547 public void endPrefixMapping(String prefix) throws SAXException
548 {
549 this.unit.popNamespace(prefix);
550 }
551
552 public void fatalError(SAXParseException e) throws SAXException
553 {
554 if (this.locator != null)
555 {
556 throw new SAXException("Error Traced[line: " + this.locator.getLineNumber() + "] " + e.getMessage());
557 }
558 else
559 {
560 throw e;
561 }
562 }
563
564 public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
565 {
566 if (this.inDocument && inCompositeInterface)
567 {
568 this.unit.writeWhitespace(new String(ch, start, length));
569 }
570 }
571
572 public InputSource resolveEntity(String publicId, String systemId) throws SAXException
573 {
574 String dtd = "org/apache/myfaces/resource/default.dtd";
575
576
577
578
579 URL url = ClassUtils.getResource(dtd);
580 return new InputSource(url.toString());
581 }
582
583 public void setDocumentLocator(Locator locator)
584 {
585 this.locator = locator;
586 }
587
588 public void startCDATA() throws SAXException
589 {
590 if (this.inDocument && inCompositeInterface)
591 {
592 this.unit.writeInstruction("<![CDATA[");
593 }
594 }
595
596 public void startDocument() throws SAXException
597 {
598 this.inDocument = true;
599 }
600
601 public void startDTD(String name, String publicId, String systemId) throws SAXException
602 {
603
604 this.inDocument = false;
605 }
606
607 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
608 {
609 if (CompositeLibrary.NAMESPACE.equals(uri))
610 {
611 if (InterfaceHandler.NAME.equals(localName))
612 {
613 this.inCompositeInterface=true;
614 }
615 else if (ImplementationHandler.NAME.equals(localName))
616 {
617 this.inCompositeImplementation=true;
618 }
619 }
620
621 if (inCompositeInterface)
622 {
623 this.unit.pushTag(new Tag(this.createLocation(), uri, localName, qName, this.createAttributes(attributes)));
624 }
625 else if (inCompositeImplementation && CompositeLibrary.NAMESPACE.equals(uri))
626 {
627 if ("insertFacet".equals(localName) ||
628 "renderFacet".equals(localName) ||
629 "insertChildren".equals(localName) ||
630 ImplementationHandler.NAME.equals(localName) )
631 {
632 this.unit.pushTag(new Tag(this.createLocation(), uri, localName, qName, this.createAttributes(attributes)));
633 }
634 }
635 }
636
637 public void startEntity(String name) throws SAXException
638 {
639 }
640
641 public void startPrefixMapping(String prefix, String uri) throws SAXException
642 {
643 this.unit.pushNamespace(prefix, uri);
644 }
645
646 public void processingInstruction(String target, String data) throws SAXException
647 {
648 if (this.inDocument && inCompositeInterface)
649 {
650 StringBuffer sb = new StringBuffer(64);
651 sb.append("<?").append(target).append(' ').append(data).append("?>\n");
652 this.unit.writeInstruction(sb.toString());
653 }
654 }
655 }
656
657 public SAXCompiler()
658 {
659 super();
660 }
661
662 public FaceletHandler doCompile(URL src, String alias) throws IOException, FaceletException, ELException,
663 FacesException
664 {
665 CompilationManager mngr = null;
666 InputStream is = null;
667 String encoding = null;
668 try
669 {
670 is = new BufferedInputStream(src.openStream(), 1024);
671 mngr = new CompilationManager(alias, this);
672 encoding = writeXmlDecl(is, mngr);
673 CompilationHandler handler = new CompilationHandler(mngr, alias);
674 SAXParser parser = this.createSAXParser(handler);
675 parser.parse(is, handler);
676 }
677 catch (SAXException e)
678 {
679 throw new FaceletException("Error Parsing " + alias + ": " + e.getMessage(), e.getCause());
680 }
681 catch (ParserConfigurationException e)
682 {
683 throw new FaceletException("Error Configuring Parser " + alias + ": " + e.getMessage(), e.getCause());
684 }
685 finally
686 {
687 if (is != null)
688 {
689 is.close();
690 }
691 }
692 return new EncodingHandler(mngr.createFaceletHandler(), encoding);
693 }
694
695
696
697
698 @Override
699 protected FaceletHandler doCompileViewMetadata(URL src, String alias)
700 throws IOException, FaceletException, ELException, FacesException
701 {
702 CompilationManager mngr = null;
703 InputStream is = null;
704 String encoding = null;
705 try
706 {
707 is = new BufferedInputStream(src.openStream(), 1024);
708 mngr = new CompilationManager(alias, this);
709 encoding = getXmlDecl(is, mngr);
710 ViewMetadataHandler handler = new ViewMetadataHandler(mngr, alias);
711 SAXParser parser = this.createSAXParser(handler);
712 parser.parse(is, handler);
713 }
714 catch (SAXException e)
715 {
716 throw new FaceletException("Error Parsing " + alias + ": " + e.getMessage(), e.getCause());
717 }
718 catch (ParserConfigurationException e)
719 {
720 throw new FaceletException("Error Configuring Parser " + alias + ": " + e.getMessage(), e.getCause());
721 }
722 finally
723 {
724 if (is != null)
725 {
726 is.close();
727 }
728 }
729 return new EncodingHandler(mngr.createFaceletHandler(), encoding);
730 }
731
732
733
734
735 @Override
736 protected FaceletHandler doCompileCompositeComponentMetadata(URL src, String alias)
737 throws IOException, FaceletException, ELException, FacesException
738 {
739 CompilationManager mngr = null;
740 InputStream is = null;
741 String encoding = null;
742 try
743 {
744 is = new BufferedInputStream(src.openStream(), 1024);
745 mngr = new CompilationManager(alias, this);
746 encoding = getXmlDecl(is, mngr);
747 CompositeComponentMetadataHandler handler = new CompositeComponentMetadataHandler(mngr, alias);
748 SAXParser parser = this.createSAXParser(handler);
749 parser.parse(is, handler);
750 }
751 catch (SAXException e)
752 {
753 throw new FaceletException("Error Parsing " + alias + ": " + e.getMessage(), e.getCause());
754 }
755 catch (ParserConfigurationException e)
756 {
757 throw new FaceletException("Error Configuring Parser " + alias + ": " + e.getMessage(), e.getCause());
758 }
759 finally
760 {
761 if (is != null)
762 {
763 is.close();
764 }
765 }
766 return new EncodingHandler(mngr.createFaceletHandler(), encoding);
767 }
768
769 protected static final String writeXmlDecl(InputStream is, CompilationManager mngr) throws IOException
770 {
771 is.mark(128);
772 String encoding = null;
773 try
774 {
775 byte[] b = new byte[128];
776 if (is.read(b) > 0)
777 {
778 String r = new String(b);
779 Matcher m = XmlDeclaration.matcher(r);
780 if (m.find())
781 {
782 mngr.writeInstruction(m.group(0) + "\n");
783 if (m.group(3) != null)
784 {
785 encoding = m.group(3);
786 }
787 }
788 }
789 }
790 finally
791 {
792 is.reset();
793 }
794 return encoding;
795 }
796
797 protected static final String getXmlDecl(InputStream is, CompilationManager mngr) throws IOException
798 {
799 is.mark(128);
800 String encoding = null;
801 try
802 {
803 byte[] b = new byte[128];
804 if (is.read(b) > 0)
805 {
806 String r = new String(b);
807 Matcher m = XmlDeclaration.matcher(r);
808 if (m.find())
809 {
810
811 if (m.group(3) != null)
812 {
813 encoding = m.group(3);
814 }
815 }
816 }
817 }
818 finally
819 {
820 is.reset();
821 }
822 return encoding;
823 }
824
825 private final SAXParser createSAXParser(DefaultHandler handler) throws SAXException,
826 ParserConfigurationException
827 {
828 SAXParserFactory factory = SAXParserFactory.newInstance();
829 factory.setNamespaceAware(true);
830 factory.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
831 factory.setFeature("http://xml.org/sax/features/validation", this.isValidating());
832 factory.setValidating(this.isValidating());
833 SAXParser parser = factory.newSAXParser();
834 XMLReader reader = parser.getXMLReader();
835 reader.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
836 reader.setErrorHandler(handler);
837 reader.setEntityResolver(handler);
838 return parser;
839 }
840
841 }