View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
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  import java.security.AccessController;
28  import java.security.PrivilegedExceptionAction;
29  import java.security.PrivilegedActionException;
30  
31  import javax.el.ELException;
32  import javax.faces.FacesException;
33  import javax.faces.view.Location;
34  import javax.faces.view.facelets.FaceletException;
35  import javax.faces.view.facelets.FaceletHandler;
36  import javax.faces.view.facelets.Tag;
37  import javax.faces.view.facelets.TagAttribute;
38  import javax.faces.view.facelets.TagAttributes;
39  import javax.xml.parsers.ParserConfigurationException;
40  import javax.xml.parsers.SAXParser;
41  import javax.xml.parsers.SAXParserFactory;
42  
43  import org.apache.myfaces.config.element.FaceletsProcessing;
44  import org.apache.myfaces.shared.util.ClassUtils;
45  import org.apache.myfaces.view.facelets.tag.TagAttributeImpl;
46  import org.apache.myfaces.view.facelets.tag.TagAttributesImpl;
47  import org.apache.myfaces.view.facelets.tag.composite.CompositeLibrary;
48  import org.apache.myfaces.view.facelets.tag.composite.ImplementationHandler;
49  import org.apache.myfaces.view.facelets.tag.composite.InterfaceHandler;
50  import org.apache.myfaces.view.facelets.tag.jsf.core.CoreLibrary;
51  import org.xml.sax.Attributes;
52  import org.xml.sax.InputSource;
53  import org.xml.sax.Locator;
54  import org.xml.sax.SAXException;
55  import org.xml.sax.SAXParseException;
56  import org.xml.sax.XMLReader;
57  import org.xml.sax.ext.LexicalHandler;
58  import org.xml.sax.helpers.DefaultHandler;
59  
60  /**
61   * Compiler implementation that uses SAX
62   * 
63   * @see org.apache.myfaces.view.facelets.compiler.Compiler
64   * 
65   * @author Jacob Hookom
66   * @version $Id: SAXCompiler.java 1390212 2012-09-25 23:17:29Z lu4242 $
67   */
68  public final class SAXCompiler extends Compiler
69  {
70  
71      private final static Pattern XML_DECLARATION = Pattern
72              .compile("^<\\?xml.+?version=['\"](.+?)['\"](.+?encoding=['\"]((.+?))['\"])?.*?\\?>");
73  
74      private static class CompilationHandler extends DefaultHandler implements LexicalHandler
75      {
76  
77          private final String alias;
78  
79          private boolean inDocument = false;
80  
81          private Locator locator;
82  
83          private final CompilationManager unit;
84          
85          private boolean consumingCDATA = false;
86          private boolean swallowCDATAContent = false;
87  
88          public CompilationHandler(CompilationManager unit, String alias)
89          {
90              this.unit = unit;
91              this.alias = alias;
92          }
93  
94          public void characters(char[] ch, int start, int length) throws SAXException
95          {
96              if (this.inDocument && (!consumingCDATA || (consumingCDATA && !swallowCDATAContent)))
97              {
98                  this.unit.writeText(new String(ch, start, length));
99              }
100         }
101 
102         public void comment(char[] ch, int start, int length) throws SAXException
103         {
104             if (this.inDocument && !unit.getFaceletsProcessingInstructions().isConsumeXMLComments())
105             {
106                 this.unit.writeComment(new String(ch, start, length));
107             }
108         }
109 
110         protected TagAttributes createAttributes(Attributes attrs)
111         {
112             int len = attrs.getLength();
113             TagAttribute[] ta = new TagAttribute[len];
114             for (int i = 0; i < len; i++)
115             {
116                 ta[i] = new TagAttributeImpl(this.createLocation(), attrs.getURI(i), attrs.getLocalName(i), attrs
117                         .getQName(i), attrs.getValue(i));
118             }
119             return new TagAttributesImpl(ta);
120         }
121 
122         protected Location createLocation()
123         {
124             return new Location(this.alias, this.locator.getLineNumber(), this.locator.getColumnNumber());
125         }
126 
127         public void endCDATA() throws SAXException
128         {
129             if (this.inDocument)
130             {
131                 if (!this.unit.getFaceletsProcessingInstructions().isConsumeCDataSections())
132                 {
133                     this.unit.writeInstruction("]]>");
134                 }
135                 else
136                 {
137                     this.consumingCDATA = false;
138                     this.swallowCDATAContent = false;
139                 }
140             }
141         }
142 
143         public void endDocument() throws SAXException
144         {
145             super.endDocument();
146         }
147 
148         public void endDTD() throws SAXException
149         {
150             this.inDocument = true;
151         }
152 
153         public void endElement(String uri, String localName, String qName) throws SAXException
154         {
155             this.unit.popTag();
156         }
157 
158         public void endEntity(String name) throws SAXException
159         {
160         }
161 
162         public void endPrefixMapping(String prefix) throws SAXException
163         {
164             this.unit.popNamespace(prefix);
165         }
166 
167         public void fatalError(SAXParseException e) throws SAXException
168         {
169             if (this.locator != null)
170             {
171                 throw new SAXException("Error Traced[line: " + this.locator.getLineNumber() + "] " + e.getMessage());
172             }
173             else
174             {
175                 throw e;
176             }
177         }
178 
179         public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
180         {
181             if (this.inDocument)
182             {
183                 this.unit.writeWhitespace(new String(ch, start, length));
184             }
185         }
186 
187         public InputSource resolveEntity(String publicId, String systemId) throws SAXException
188         {
189             String dtd = "org/apache/myfaces/resource/default.dtd";
190             /*
191              * if ("-//W3C//DTD XHTML 1.0 Transitional//EN".equals(publicId)) { dtd = "xhtml1-transitional.dtd"; } else
192              * if (systemId != null && systemId.startsWith("file:/")) { return new InputSource(systemId); }
193              */
194             URL url = ClassUtils.getResource(dtd);
195             return new InputSource(url.toString());
196         }
197 
198         public void setDocumentLocator(Locator locator)
199         {
200             this.locator = locator;
201         }
202 
203         public void startCDATA() throws SAXException
204         {
205             if (this.inDocument)
206             {
207                 if (!this.unit.getFaceletsProcessingInstructions().isConsumeCDataSections())
208                 {
209                     this.unit.writeInstruction("<![CDATA[");
210                 }
211                 else
212                 {
213                     this.consumingCDATA = true;
214                     this.swallowCDATAContent = this.unit.getFaceletsProcessingInstructions().isSwallowCDataContent();
215                 }
216             }
217         }
218 
219         public void startDocument() throws SAXException
220         {
221             this.inDocument = true;
222         }
223 
224         public void startDTD(String name, String publicId, String systemId) throws SAXException
225         {
226             if (this.inDocument && !unit.getFaceletsProcessingInstructions().isConsumeXmlDocType())
227             {
228                 StringBuffer sb = new StringBuffer(64);
229                 sb.append("<!DOCTYPE ").append(name);
230                 if (publicId != null)
231                 {
232                     sb.append(" PUBLIC \"").append(publicId).append("\"");
233                     if (systemId != null)
234                     {
235                         sb.append(" \"").append(systemId).append("\"");
236                     }
237                 }
238                 else if (systemId != null)
239                 {
240                     sb.append(" SYSTEM \"").append(systemId).append("\"");
241                 }
242                 sb.append(" >\n");
243                 this.unit.writeInstruction(sb.toString());
244             }
245             this.inDocument = false;
246         }
247 
248         public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
249         {
250             this.unit.pushTag(new Tag(this.createLocation(), uri, localName, qName, this.createAttributes(attributes)));
251         }
252 
253         public void startEntity(String name) throws SAXException
254         {
255         }
256 
257         public void startPrefixMapping(String prefix, String uri) throws SAXException
258         {
259             this.unit.pushNamespace(prefix, uri);
260         }
261 
262         public void processingInstruction(String target, String data) throws SAXException
263         {
264             if (this.inDocument && !this.unit.getFaceletsProcessingInstructions().isConsumeProcessingInstructions())
265             {
266                 StringBuffer sb = new StringBuffer(64);
267                 sb.append("<?").append(target).append(' ').append(data).append("?>\n");
268                 this.unit.writeInstruction(sb.toString());
269             }
270         }
271     }
272     
273     /**
274      * Like CompilationHandler but does not take into account everything outside f:metadata tag 
275      * 
276      * @since 2.0
277      */
278     private static class ViewMetadataHandler extends DefaultHandler implements LexicalHandler
279     {
280 
281         private final String alias;
282 
283         private boolean inDocument = false;
284 
285         private Locator locator;
286 
287         private final CompilationManager unit;
288         
289         private boolean inMetadata = false;
290         
291         private boolean consumingCDATA = false;
292         private boolean swallowCDATAContent = false;
293 
294         public ViewMetadataHandler(CompilationManager unit, String alias)
295         {
296             this.unit = unit;
297             this.alias = alias;
298         }
299 
300         public void characters(char[] ch, int start, int length) throws SAXException
301         {
302             if (this.inDocument && inMetadata && (!consumingCDATA || (consumingCDATA && !swallowCDATAContent)))
303             {
304                 this.unit.writeText(new String(ch, start, length));
305             }
306         }
307 
308         public void comment(char[] ch, int start, int length) throws SAXException
309         {
310             if (this.inDocument && inMetadata && !unit.getFaceletsProcessingInstructions().isConsumeXMLComments())
311             {
312                 this.unit.writeComment(new String(ch, start, length));
313             }
314         }
315 
316         protected TagAttributes createAttributes(Attributes attrs)
317         {
318             int len = attrs.getLength();
319             TagAttribute[] ta = new TagAttribute[len];
320             for (int i = 0; i < len; i++)
321             {
322                 ta[i] = new TagAttributeImpl(this.createLocation(), attrs.getURI(i), attrs.getLocalName(i), attrs
323                         .getQName(i), attrs.getValue(i));
324             }
325             return new TagAttributesImpl(ta);
326         }
327 
328         protected Location createLocation()
329         {
330             return new Location(this.alias, this.locator.getLineNumber(), this.locator.getColumnNumber());
331         }
332 
333         public void endCDATA() throws SAXException
334         {
335             if (this.inDocument && inMetadata)
336             {
337                 if (!this.unit.getFaceletsProcessingInstructions().isConsumeCDataSections())
338                 {
339                     this.unit.writeInstruction("]]>");
340                 }
341                 else
342                 {
343                     this.consumingCDATA = false;
344                     this.swallowCDATAContent = false;
345                 }
346             }
347         }
348 
349         public void endDocument() throws SAXException
350         {
351             super.endDocument();
352         }
353 
354         public void endDTD() throws SAXException
355         {
356             this.inDocument = true;
357         }
358 
359         public void endElement(String uri, String localName, String qName) throws SAXException
360         {
361             if (inMetadata)
362             {
363                 this.unit.popTag();
364             }
365             if (CoreLibrary.NAMESPACE.equals(uri) && "metadata".equals(localName))
366             {
367                 this.inMetadata=false;
368             }            
369         }
370 
371         public void endEntity(String name) throws SAXException
372         {
373         }
374 
375         public void endPrefixMapping(String prefix) throws SAXException
376         {
377             this.unit.popNamespace(prefix);
378         }
379 
380         public void fatalError(SAXParseException e) throws SAXException
381         {
382             if (this.locator != null)
383             {
384                 throw new SAXException("Error Traced[line: " + this.locator.getLineNumber() + "] " + e.getMessage());
385             }
386             else
387             {
388                 throw e;
389             }
390         }
391 
392         public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
393         {
394             if (this.inDocument && inMetadata)
395             {
396                 this.unit.writeWhitespace(new String(ch, start, length));
397             }
398         }
399 
400         public InputSource resolveEntity(String publicId, String systemId) throws SAXException
401         {
402             String dtd = "org/apache/myfaces/resource/default.dtd";
403             /*
404              * if ("-//W3C//DTD XHTML 1.0 Transitional//EN".equals(publicId)) { dtd = "xhtml1-transitional.dtd"; } else
405              * if (systemId != null && systemId.startsWith("file:/")) { return new InputSource(systemId); }
406              */
407             URL url = ClassUtils.getResource(dtd);
408             return new InputSource(url.toString());
409         }
410 
411         public void setDocumentLocator(Locator locator)
412         {
413             this.locator = locator;
414         }
415 
416         public void startCDATA() throws SAXException
417         {
418             if (this.inDocument && inMetadata)
419             {
420                 if (!this.unit.getFaceletsProcessingInstructions().isConsumeCDataSections())
421                 {
422                     this.unit.writeInstruction("<![CDATA[");
423                 }
424                 else
425                 {
426                     this.consumingCDATA = true;
427                     this.swallowCDATAContent = this.unit.getFaceletsProcessingInstructions().isSwallowCDataContent();
428                 }
429             }
430         }
431 
432         public void startDocument() throws SAXException
433         {
434             this.inDocument = true;
435         }
436 
437         public void startDTD(String name, String publicId, String systemId) throws SAXException
438         {
439             // metadata does not require output doctype
440             this.inDocument = false;
441         }
442 
443         public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
444         {
445             if (CoreLibrary.NAMESPACE.equals(uri) && "metadata".equals(localName))
446             {
447                 this.inMetadata=true;
448             }
449             if (inMetadata)
450             {
451                 this.unit.pushTag(new Tag(createLocation(), uri, localName, qName, createAttributes(attributes)));
452             }
453         }
454 
455         public void startEntity(String name) throws SAXException
456         {
457         }
458 
459         public void startPrefixMapping(String prefix, String uri) throws SAXException
460         {
461             this.unit.pushNamespace(prefix, uri);
462         }
463 
464         public void processingInstruction(String target, String data) throws SAXException
465         {
466             if (inDocument && inMetadata && !unit.getFaceletsProcessingInstructions().isConsumeProcessingInstructions())
467             {
468                 StringBuffer sb = new StringBuffer(64);
469                 sb.append("<?").append(target).append(' ').append(data).append("?>\n");
470                 unit.writeInstruction(sb.toString());
471             }
472         }        
473     }
474     
475     /**
476      * Like CompilationHandler but does not take into account everything outside cc:interface or cc:implementation tag.
477      *  
478      * Note inside cc:implementation it only takes into account cc:insertChildren, cc:insertFacet and cc:renderFacet,
479      * all other tags, comments or text are just skipped.
480      * 
481      * @since 2.0.1
482      */
483     private static class CompositeComponentMetadataHandler extends DefaultHandler implements LexicalHandler
484     {
485 
486         private final String alias;
487 
488         private boolean inDocument = false;
489 
490         private Locator locator;
491 
492         private final CompilationManager unit;
493         
494         private boolean inCompositeInterface = false;
495         
496         private boolean inCompositeImplementation = false;
497 
498         private boolean consumingCDATA = false;
499         private boolean swallowCDATAContent = false;
500 
501         public CompositeComponentMetadataHandler(CompilationManager unit, String alias)
502         {
503             this.unit = unit;
504             this.alias = alias;
505         }
506 
507         public void characters(char[] ch, int start, int length) throws SAXException
508         {
509             if (this.inDocument && inCompositeInterface && 
510                     (!consumingCDATA || (consumingCDATA && !swallowCDATAContent)))
511             {
512                 this.unit.writeText(new String(ch, start, length));
513             }
514         }
515 
516         public void comment(char[] ch, int start, int length) throws SAXException
517         {
518             if (inDocument && inCompositeInterface && 
519                     !unit.getFaceletsProcessingInstructions().isConsumeXMLComments())
520             {
521                 this.unit.writeComment(new String(ch, start, length));
522             }
523         }
524 
525         protected TagAttributes createAttributes(Attributes attrs)
526         {
527             int len = attrs.getLength();
528             TagAttribute[] ta = new TagAttribute[len];
529             for (int i = 0; i < len; i++)
530             {
531                 ta[i] = new TagAttributeImpl(this.createLocation(), attrs.getURI(i), attrs.getLocalName(i), attrs
532                         .getQName(i), attrs.getValue(i));
533             }
534             return new TagAttributesImpl(ta);
535         }
536 
537         protected Location createLocation()
538         {
539             return new Location(this.alias, this.locator.getLineNumber(), this.locator.getColumnNumber());
540         }
541 
542         public void endCDATA() throws SAXException
543         {
544             if (this.inDocument && inCompositeInterface)
545             {
546                 if (!this.unit.getFaceletsProcessingInstructions().isConsumeCDataSections())
547                 {
548                     this.unit.writeInstruction("]]>");
549                 }
550                 else
551                 {
552                     this.consumingCDATA = false;
553                     this.swallowCDATAContent = false;
554                 }
555             }
556         }
557 
558         public void endDocument() throws SAXException
559         {
560             super.endDocument();
561         }
562 
563         public void endDTD() throws SAXException
564         {
565             this.inDocument = true;
566         }
567 
568         public void endElement(String uri, String localName, String qName) throws SAXException
569         {
570             if (inCompositeInterface)
571             {
572                 this.unit.popTag();
573             }
574             else if (inCompositeImplementation && CompositeLibrary.NAMESPACE.equals(uri))
575             {
576                 if ( "insertFacet".equals(localName) ||
577                      "renderFacet".equals(localName) ||
578                      "insertChildren".equals(localName) || 
579                      ImplementationHandler.NAME.equals(localName))
580                 {
581                     this.unit.popTag();
582                 }
583             }
584             
585             if (CompositeLibrary.NAMESPACE.equals(uri))
586             {
587                 if (InterfaceHandler.NAME.equals(localName))
588                 {
589                     this.inCompositeInterface=false;
590                 }
591                 else if (ImplementationHandler.NAME.equals(localName))
592                 {
593                     this.inCompositeImplementation=false;
594                 }
595             }
596         }
597 
598         public void endEntity(String name) throws SAXException
599         {
600         }
601 
602         public void endPrefixMapping(String prefix) throws SAXException
603         {
604             this.unit.popNamespace(prefix);
605         }
606 
607         public void fatalError(SAXParseException e) throws SAXException
608         {
609             if (this.locator != null)
610             {
611                 throw new SAXException("Error Traced[line: " + this.locator.getLineNumber() + "] " + e.getMessage());
612             }
613             else
614             {
615                 throw e;
616             }
617         }
618 
619         public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
620         {
621             if (this.inDocument && inCompositeInterface)
622             {
623                 this.unit.writeWhitespace(new String(ch, start, length));
624             }
625         }
626 
627         public InputSource resolveEntity(String publicId, String systemId) throws SAXException
628         {
629             String dtd = "org/apache/myfaces/resource/default.dtd";
630             /*
631              * if ("-//W3C//DTD XHTML 1.0 Transitional//EN".equals(publicId)) { dtd = "xhtml1-transitional.dtd"; } else
632              * if (systemId != null && systemId.startsWith("file:/")) { return new InputSource(systemId); }
633              */
634             URL url = ClassUtils.getResource(dtd);
635             return new InputSource(url.toString());
636         }
637 
638         public void setDocumentLocator(Locator locator)
639         {
640             this.locator = locator;
641         }
642 
643         public void startCDATA() throws SAXException
644         {
645             if (this.inDocument && inCompositeInterface)
646             {
647                 if (!this.unit.getFaceletsProcessingInstructions().isConsumeCDataSections())
648                 {
649                     this.unit.writeInstruction("<![CDATA[");
650                 }
651                 else
652                 {
653                     this.consumingCDATA = true;
654                     this.swallowCDATAContent = this.unit.getFaceletsProcessingInstructions().isSwallowCDataContent();
655                 }
656             }
657         }
658 
659         public void startDocument() throws SAXException
660         {
661             this.inDocument = true;
662         }
663 
664         public void startDTD(String name, String publicId, String systemId) throws SAXException
665         {
666             // metadata does not require output doctype
667             this.inDocument = false;
668         }
669 
670         public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
671         {
672             if (CompositeLibrary.NAMESPACE.equals(uri))
673             {
674                 if (InterfaceHandler.NAME.equals(localName))
675                 {
676                     this.inCompositeInterface=true;
677                 }
678                 else if (ImplementationHandler.NAME.equals(localName))
679                 {
680                     this.inCompositeImplementation=true;
681                 }
682             }
683             
684             if (inCompositeInterface)
685             {
686                 this.unit.pushTag(new Tag(createLocation(), uri, localName, qName, createAttributes(attributes)));
687             }
688             else if (inCompositeImplementation && CompositeLibrary.NAMESPACE.equals(uri))
689             {
690                 if ("insertFacet".equals(localName)    ||
691                     "renderFacet".equals(localName)    ||
692                     "insertChildren".equals(localName) ||
693                     ImplementationHandler.NAME.equals(localName)   )
694                 {
695                     this.unit.pushTag(new Tag(createLocation(), uri, localName, qName, createAttributes(attributes)));
696                 }
697             }
698         }
699 
700         public void startEntity(String name) throws SAXException
701         {
702         }
703 
704         public void startPrefixMapping(String prefix, String uri) throws SAXException
705         {
706             this.unit.pushNamespace(prefix, uri);
707         }
708 
709         public void processingInstruction(String target, String data) throws SAXException
710         {
711             if (inDocument && inCompositeInterface
712                 && !unit.getFaceletsProcessingInstructions().isConsumeProcessingInstructions())
713             {
714                 StringBuffer sb = new StringBuffer(64);
715                 sb.append("<?").append(target).append(' ').append(data).append("?>\n");
716                 this.unit.writeInstruction(sb.toString());
717             }
718         }        
719     }
720 
721     public SAXCompiler()
722     {
723         super();
724     }
725 
726     public FaceletHandler doCompile(URL src, String alias)
727             throws IOException, FaceletException, ELException, FacesException
728     {
729         CompilationManager mngr = null;
730         InputStream is = null;
731         String encoding = null;
732         try
733         {
734             is = new BufferedInputStream(src.openStream(), 1024);
735             mngr = new CompilationManager(alias, this, getFaceletsProcessingInstructions(src, alias));
736             encoding = writeXmlDecl(is, mngr);
737             CompilationHandler handler = new CompilationHandler(mngr, alias);
738             SAXParser parser = this.createSAXParser(handler);
739             parser.parse(is, handler);
740         }
741         catch (SAXException e)
742         {
743             throw new FaceletException("Error Parsing " + alias + ": " + e.getMessage(), e.getCause());
744         }
745         catch (ParserConfigurationException e)
746         {
747             throw new FaceletException("Error Configuring Parser " + alias + ": " + e.getMessage(), e.getCause());
748         }
749         finally
750         {
751             if (is != null)
752             {
753                 is.close();
754             }
755         }
756         return new EncodingHandler(mngr.createFaceletHandler(), encoding);
757     }
758 
759     /**
760      * @since 2.0
761      */
762     @Override
763     protected FaceletHandler doCompileViewMetadata(URL src, String alias)
764             throws IOException, FaceletException, ELException, FacesException
765     {
766         CompilationManager mngr = null;
767         InputStream is = null;
768         String encoding = null;
769         try
770         {
771             is = new BufferedInputStream(src.openStream(), 1024);
772             mngr = new CompilationManager(alias, this, getFaceletsProcessingInstructions(src, alias));
773             encoding = getXmlDecl(is, mngr);
774             final ViewMetadataHandler handler = new ViewMetadataHandler(mngr, alias);
775             final SAXParser parser = this.createSAXParser(handler);
776             
777             if (System.getSecurityManager() != null)
778             {
779                 try
780                 {
781                     final InputStream finalInputStream = is;
782                     AccessController.doPrivileged(new PrivilegedExceptionAction() 
783                     {
784                         public Object run() throws SAXException, IOException 
785                         {
786                             parser.parse(finalInputStream, handler);
787                             return null; 
788                         }
789                     });
790                 }
791                 catch (PrivilegedActionException pae)
792                 {
793                     Exception e = pae.getException();
794                     if(e instanceof SAXException)
795                     {
796                         throw new FaceletException("Error Parsing " + alias + ": " + e.getMessage(), e.getCause());
797                     } 
798                     else if(e instanceof IOException)
799                     {
800                         throw (IOException)e;
801                     }
802                 }
803             }
804             else
805             {
806                 parser.parse(is, handler);
807             }
808         }
809         catch (SAXException e)
810         {
811             throw new FaceletException("Error Parsing " + alias + ": " + e.getMessage(), e.getCause());
812         }
813         catch (ParserConfigurationException e)
814         {
815             throw new FaceletException("Error Configuring Parser " + alias + ": " + e.getMessage(), e.getCause());
816         }
817         finally
818         {
819             if (is != null)
820             {
821                 is.close();
822             }
823         }
824         return new EncodingHandler(mngr.createFaceletHandler(), encoding);
825     }
826 
827     /**
828      * @since 2.0.1
829      */
830     @Override
831     protected FaceletHandler doCompileCompositeComponentMetadata(URL src, String alias)
832             throws IOException, FaceletException, ELException, FacesException
833     {
834         CompilationManager mngr = null;
835         InputStream is = null;
836         String encoding = null;
837         try
838         {
839             is = new BufferedInputStream(src.openStream(), 1024);
840             mngr = new CompilationManager(alias, this, getFaceletsProcessingInstructions(src, alias));
841             encoding = getXmlDecl(is, mngr);
842             CompositeComponentMetadataHandler handler = new CompositeComponentMetadataHandler(mngr, alias);
843             SAXParser parser = this.createSAXParser(handler);
844             parser.parse(is, handler);
845         }
846         catch (SAXException e)
847         {
848             throw new FaceletException("Error Parsing " + alias + ": " + e.getMessage(), e.getCause());
849         }
850         catch (ParserConfigurationException e)
851         {
852             throw new FaceletException("Error Configuring Parser " + alias + ": " + e.getMessage(), e.getCause());
853         }
854         finally
855         {
856             if (is != null)
857             {
858                 is.close();
859             }
860         }
861         return new EncodingHandler(mngr.createFaceletHandler(), encoding);
862     }
863     
864     protected FaceletsProcessingInstructions getFaceletsProcessingInstructions(URL src, String alias)
865     {
866         String processAs = null;
867         boolean compressSpaces = false;
868         for (FaceletsProcessing entry : getFaceletsProcessingConfigurations())
869         {
870             if (src.getPath().endsWith(entry.getFileExtension()))
871             {
872                 processAs = entry.getProcessAs();
873                 compressSpaces = Boolean.valueOf(entry.getOamCompressSpaces());
874                 break;
875             }
876         }
877         return FaceletsProcessingInstructions.getProcessingInstructions(processAs, compressSpaces);
878     }
879 
880     protected static final String writeXmlDecl(InputStream is, CompilationManager mngr) throws IOException
881     {
882         is.mark(128);
883         String encoding = null;
884         try
885         {
886             byte[] b = new byte[128];
887             if (is.read(b) > 0)
888             {
889                 String r = new String(b);
890                 Matcher m = XML_DECLARATION.matcher(r);
891                 if (m.find())
892                 {
893                     if (!mngr.getFaceletsProcessingInstructions().isConsumeXmlDeclaration())
894                     {
895                         mngr.writeInstruction(m.group(0) + "\n");
896                     }
897                     if (m.group(3) != null)
898                     {
899                         encoding = m.group(3);
900                     }
901                 }
902             }
903         }
904         finally
905         {
906             is.reset();
907         }
908         return encoding;
909     }
910     
911     protected static final String getXmlDecl(InputStream is, CompilationManager mngr) throws IOException
912     {
913         is.mark(128);
914         String encoding = null;
915         try
916         {
917             byte[] b = new byte[128];
918             if (is.read(b) > 0)
919             {
920                 String r = new String(b);
921                 Matcher m = XML_DECLARATION.matcher(r);
922                 if (m.find())
923                 {
924                     //mngr.writeInstruction(m.group(0) + "\n");
925                     if (m.group(3) != null)
926                     {
927                         encoding = m.group(3);
928                     }
929                 }
930             }
931         }
932         finally
933         {
934             is.reset();
935         }
936         return encoding;
937     }
938 
939     private final SAXParser createSAXParser(DefaultHandler handler) throws SAXException,
940             ParserConfigurationException
941     {
942         SAXParserFactory factory = SAXParserFactory.newInstance();
943         factory.setNamespaceAware(true);
944         factory.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
945         factory.setFeature("http://xml.org/sax/features/validation", this.isValidating());
946         factory.setValidating(this.isValidating());
947         SAXParser parser = factory.newSAXParser();
948         XMLReader reader = parser.getXMLReader();
949         reader.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
950         reader.setErrorHandler(handler);
951         reader.setEntityResolver(handler);
952         return parser;
953     }
954 
955 }