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