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