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.IOException;
22  import java.io.InputStream;
23  import java.net.URL;
24  import java.net.URLConnection;
25  import javax.faces.context.ExternalContext;
26  import javax.xml.parsers.ParserConfigurationException;
27  import javax.xml.parsers.SAXParser;
28  import javax.xml.parsers.SAXParserFactory;
29  import org.apache.myfaces.config.ConfigFilesXmlValidationUtils;
30  import org.apache.myfaces.config.element.facelets.FaceletTagLibrary;
31  import org.apache.myfaces.config.impl.digester.elements.facelets.FaceletBehaviorTagImpl;
32  import org.apache.myfaces.config.impl.digester.elements.facelets.FaceletComponentTagImpl;
33  import org.apache.myfaces.config.impl.digester.elements.facelets.FaceletConverterTagImpl;
34  import org.apache.myfaces.config.impl.digester.elements.facelets.FaceletFunctionImpl;
35  import org.apache.myfaces.config.impl.digester.elements.facelets.FaceletHandlerTagImpl;
36  import org.apache.myfaces.config.impl.digester.elements.facelets.FaceletSourceTagImpl;
37  import org.apache.myfaces.config.impl.digester.elements.facelets.FaceletTagImpl;
38  import org.apache.myfaces.config.impl.digester.elements.facelets.FaceletTagLibraryImpl;
39  import org.apache.myfaces.config.impl.digester.elements.facelets.FaceletValidatorTagImpl;
40  import org.apache.myfaces.shared.config.MyfacesConfig;
41  import org.apache.myfaces.shared.util.ClassUtils;
42  import org.xml.sax.Attributes;
43  import org.xml.sax.InputSource;
44  import org.xml.sax.Locator;
45  import org.xml.sax.SAXException;
46  import org.xml.sax.SAXParseException;
47  import org.xml.sax.XMLReader;
48  import org.xml.sax.helpers.DefaultHandler;
49  
50  /**
51   *
52   */
53  public class TagLibraryConfigUnmarshallerImpl
54  {
55      
56      public static FaceletTagLibrary create(ExternalContext externalContext, URL url) throws IOException
57      {
58          InputStream is = null;
59          FaceletTagLibrary t = null;
60          URLConnection conn = null;
61          try
62          {
63              boolean schemaValidating = false;
64  
65              // validate XML
66              if (MyfacesConfig.getCurrentInstance(externalContext).isValidateXML())
67              {
68                  String version = ConfigFilesXmlValidationUtils.getFaceletTagLibVersion(url);
69                  schemaValidating = "2.0".equals(version);
70                  if (schemaValidating)
71                  {
72                      ConfigFilesXmlValidationUtils.validateFaceletTagLibFile(url, externalContext, version);
73                  }
74              }
75              
76              // parse file
77              LibraryHandler handler = new LibraryHandler(url);
78              SAXParser parser = createSAXParser(handler, externalContext, schemaValidating);
79              conn = url.openConnection();
80              conn.setUseCaches(false);
81              is = conn.getInputStream();
82              parser.parse(is, handler);
83              t = handler.getLibrary();
84          }
85          catch (SAXException e)
86          {
87              IOException ioe = new IOException("Error parsing [" + url + "]: ");
88              ioe.initCause(e);
89              throw ioe;
90          }
91          catch (ParserConfigurationException e)
92          {
93              IOException ioe = new IOException("Error parsing [" + url + "]: ");
94              ioe.initCause(e);
95              throw ioe;
96          }
97          finally
98          {
99              if (is != null)
100             {
101                 is.close();
102             }
103         }
104         return t;
105     }    
106     
107     private static final SAXParser createSAXParser(LibraryHandler handler, ExternalContext externalContext,
108                                                    boolean schemaValidating)
109             throws SAXException, ParserConfigurationException
110     {
111         SAXParserFactory factory = SAXParserFactory.newInstance();
112 
113         if (MyfacesConfig.getCurrentInstance(externalContext).isValidateXML() && !schemaValidating)
114         {
115             // DTD validating
116             factory.setNamespaceAware(false);
117             factory.setFeature("http://xml.org/sax/features/validation", true);
118             factory.setValidating(true);
119         }
120         else
121         {
122             //Just parse it and do not validate, because it is not necessary.
123             factory.setNamespaceAware(true);
124             factory.setFeature("http://xml.org/sax/features/validation", false);
125             factory.setValidating(false);
126         }
127 
128         SAXParser parser = factory.newSAXParser();
129         XMLReader reader = parser.getXMLReader();
130         reader.setErrorHandler(handler);
131         reader.setEntityResolver(handler);
132         return parser;
133     }
134 
135     private static class LibraryHandler extends DefaultHandler
136     {
137         private final URL source;
138         
139         private FaceletTagLibraryImpl library;
140 
141         private final StringBuffer buffer;
142 
143         private Locator locator;
144 
145         private String tagName;
146 
147         private String converterId;
148 
149         private String validatorId;
150         
151         private String behaviorId;
152 
153         private String componentType;
154 
155         private String rendererType;
156 
157         private String functionName;
158 
159         //private Class<? extends TagHandler> handlerClass;
160         private String handlerClass;
161 
162         //private Class<?> functionClass;
163         private String functionClass;
164 
165         private String functionSignature;
166         
167         private String resourceId;
168        
169         public LibraryHandler(URL source)
170         {
171             this.source = source;
172             this.buffer = new StringBuffer(64);
173         }
174 
175         public FaceletTagLibrary getLibrary()
176         {
177             return this.library;
178         }
179         
180         private FaceletTagLibraryImpl getLibraryImpl()
181         {
182             if (this.library == null)
183             {
184                 this.library = new FaceletTagLibraryImpl();
185             }
186             return this.library;
187         }
188 
189         public void endElement(String uri, String localName, String qName) throws SAXException
190         {
191             try
192             {
193                 if ("facelet-taglib".equals(qName))
194                 {
195                     // Nothing to do
196                 }                
197                 else if ("library-class".equals(qName))
198                 {
199                     getLibraryImpl().setLibraryClass(this.captureBuffer());
200                 }
201                 else if ("short-name".equals(qName))
202                 {
203                     getLibraryImpl().setShortName(this.captureBuffer());
204                 }
205                 else if ("namespace".equals(qName))
206                 {
207                     getLibraryImpl().setNamespace(this.captureBuffer());
208                 }
209                 else if ("composite-library-name".equals(qName))
210                 {
211                     getLibraryImpl().setCompositeLibraryName(this.captureBuffer());
212                 }
213                 else if ("component-type".equals(qName))
214                 {
215                     this.componentType = this.captureBuffer();
216                 }
217                 else if ("renderer-type".equals(qName))
218                 {
219                     this.rendererType = this.captureBufferEmptyNull();
220                 }
221                 else if ("tag-name".equals(qName))
222                 {
223                     this.tagName = this.captureBuffer();
224                 }
225                 else if ("function-name".equals(qName))
226                 {
227                     this.functionName = this.captureBuffer();
228                 }
229                 else if ("function-class".equals(qName))
230                 {
231                     //String className = this.captureBuffer();
232                     //this.functionClass = createClass(Object.class, className);
233                     this.functionClass = this.captureBuffer();
234                 }
235                 else if ("description".equals(qName))
236                 {
237                     //Not used
238                 }
239                 else if ("display-name".equals(qName))
240                 {
241                     //Not used
242                 }
243                 else if ("icon".equals(qName))
244                 {
245                     //Not used
246                 }                
247                 else if ("resource-id".equals(qName))
248                 {
249                     this.resourceId = this.captureBuffer();
250                 }
251                 else
252                 {
253                     // Make sure there we've seen a namespace element
254                     // before trying any of the following elements to avoid
255                     // obscure NPEs
256                     if (this.library == null)
257                     {
258                         throw new IllegalStateException("No <namespace> element");
259                     }
260                     else if (this.library.getNamespace() == null)
261                     {
262                         throw new IllegalStateException("No <namespace> element");
263                     }
264 
265                     //TagLibraryImpl impl = (TagLibraryImpl) this.library;
266 
267                     if ("tag".equals(qName))
268                     {
269                         if (this.handlerClass != null)
270                         {
271                             //impl.putTagHandler(this.tagName, this.handlerClass);
272                             getLibraryImpl().addTag(
273                                 new FaceletTagImpl(this.tagName, 
274                                     new FaceletHandlerTagImpl(this.handlerClass)) );
275                             this.handlerClass = null;
276                         }
277                     }
278                     else if ("handler-class".equals(qName))
279                     {
280                         //String cName = this.captureBuffer();
281                         //this.handlerClass = createClass(TagHandler.class, cName);
282                         this.handlerClass = this.captureBufferEmptyNull();
283                     }
284                     else if ("component".equals(qName))
285                     {
286                         if (this.handlerClass != null)
287                         {
288                             //impl.putComponent(this.tagName, this.componentType, this.rendererType, this.handlerClass);
289                             getLibraryImpl().addTag(new FaceletTagImpl(this.tagName,
290                                 new FaceletComponentTagImpl(this.componentType, this.rendererType, 
291                                     this.handlerClass, null)));
292                             this.handlerClass = null;
293                         }
294                         else if (this.resourceId != null)
295                         {
296                             //impl.putComponentFromResourceId(this.tagName, this.resourceId);
297                             getLibraryImpl().addTag(new FaceletTagImpl(this.tagName,
298                                 new FaceletComponentTagImpl(null, null, null, this.resourceId)));
299                             this.resourceId = null;
300                             this.handlerClass = null;
301                         }
302                         else
303                         {
304                             getLibraryImpl().addTag(new FaceletTagImpl(this.tagName,
305                                 new FaceletComponentTagImpl(this.componentType, this.rendererType, null, null)));
306                             this.handlerClass = null;
307                             //impl.putComponent(this.tagName, this.componentType, this.rendererType);
308                         }
309                     }
310                     else if ("converter-id".equals(qName))
311                     {
312                         this.converterId = this.captureBuffer();
313                     }
314                     else if ("converter".equals(qName))
315                     {
316                         if (this.handlerClass != null)
317                         {
318                             //impl.putConverter(this.tagName, this.converterId, handlerClass);
319                             getLibraryImpl().addTag(new FaceletTagImpl(this.tagName,
320                                 new FaceletConverterTagImpl(this.converterId, this.handlerClass)));
321                             this.handlerClass = null;
322                         }
323                         else
324                         {
325                             //impl.putConverter(this.tagName, this.converterId);
326                             getLibraryImpl().addTag(new FaceletTagImpl(this.tagName,
327                                 new FaceletConverterTagImpl(this.converterId)));
328                         }
329                         this.converterId = null;
330                     }
331                     else if ("validator-id".equals(qName))
332                     {
333                         this.validatorId = this.captureBuffer();
334                     }
335                     else if ("validator".equals(qName))
336                     {
337                         if (this.handlerClass != null)
338                         {
339                             //impl.putValidator(this.tagName, this.validatorId, handlerClass);
340                             getLibraryImpl().addTag(new FaceletTagImpl(this.tagName,
341                                 new FaceletValidatorTagImpl(this.validatorId, this.handlerClass)));
342                             this.handlerClass = null;
343                         }
344                         else
345                         {
346                             //impl.putValidator(this.tagName, this.validatorId);
347                             getLibraryImpl().addTag(new FaceletTagImpl(this.tagName,
348                                 new FaceletValidatorTagImpl(this.validatorId)));
349                         }
350                         this.validatorId = null;
351                     }
352                     else if ("behavior-id".equals(qName))
353                     {
354                         this.behaviorId = this.captureBuffer();
355                     }
356                     else if ("behavior".equals(qName))
357                     {
358                         if (this.handlerClass != null)
359                         {
360                             //impl.putBehavior(this.tagName, this.behaviorId, handlerClass);
361                             getLibraryImpl().addTag(new FaceletTagImpl(this.tagName,
362                                 new FaceletBehaviorTagImpl(this.behaviorId, this.handlerClass)));
363                             this.handlerClass = null;
364                         }
365                         else
366                         {
367                             //impl.putBehavior(this.tagName, this.behaviorId);
368                             getLibraryImpl().addTag(new FaceletTagImpl(this.tagName,
369                                 new FaceletBehaviorTagImpl(this.behaviorId)));
370                         }
371                         this.behaviorId = null;
372                     }
373                     else if ("source".equals(qName))
374                     {
375                         String path = this.captureBuffer();
376                         URL url = new URL(this.source, path);
377                         //impl.putUserTag(this.tagName, url);
378                         getLibraryImpl().addTag(new FaceletTagImpl(this.tagName,
379                             new FaceletSourceTagImpl(url.toString())));
380                     }
381                     else if ("function-signature".equals(qName))
382                     {
383                         this.functionSignature = this.captureBuffer();
384                         getLibraryImpl().addFunction(
385                             new FaceletFunctionImpl(this.functionName, this.functionClass, functionSignature));
386                         //Method m = createMethod(this.functionClass, this.functionSignature);
387                         //impl.putFunction(this.functionName, m);
388                     }
389                 }
390             }
391             catch (Exception e)
392             {
393                 throw new SAXParseException("Error Handling [" + this.source + "@" + this.locator.getLineNumber()
394                         + "," + this.locator.getColumnNumber() + "] <" + qName + ">", locator, e);
395             }
396         }
397 
398         private String captureBuffer() throws Exception
399         {
400             String s = this.buffer.toString().trim();
401             if (s.length() == 0)
402             {
403                 throw new Exception("Value Cannot be Empty");
404             }
405             this.buffer.setLength(0);
406             return s;
407         }
408         
409         private String captureBufferEmptyNull() throws Exception
410         {
411             String s = this.buffer.toString().trim();
412             if (s.length() == 0)
413             {
414                 //if is "" just set null instead
415                 s = null;
416             }
417             this.buffer.setLength(0);
418             return s;
419         }        
420 
421         public InputSource resolveEntity(String publicId, String systemId) throws SAXException
422         {
423             if ("-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN".equals(publicId))
424             {
425                 URL url = ClassUtils.getResource("org/apache/myfaces/resource/facelet-taglib_1_0.dtd");
426                 return new InputSource(url.toExternalForm());
427             }
428             return null;
429         }
430 
431         public void characters(char[] ch, int start, int length) throws SAXException
432         {
433             this.buffer.append(ch, start, length);
434         }
435 
436         public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
437         {
438             this.buffer.setLength(0);
439             if ("tag".equals(qName))
440             {
441                 this.handlerClass = null;
442                 this.componentType = null;
443                 this.rendererType = null;
444                 this.tagName = null;
445             }
446             else if ("function".equals(qName))
447             {
448                 this.functionName = null;
449                 this.functionClass = null;
450                 this.functionSignature = null;
451             }
452         }
453 
454         public void error(SAXParseException e) throws SAXException
455         {
456             throw new SAXException(
457                     "Error Handling [" + this.source + "@" + e.getLineNumber() + "," + e.getColumnNumber() + "]", e);
458         }
459 
460         public void setDocumentLocator(Locator locator)
461         {
462             this.locator = locator;
463         }
464 
465         public void fatalError(SAXParseException e) throws SAXException
466         {
467             throw e;
468         }
469 
470         public void warning(SAXParseException e) throws SAXException
471         {
472             throw e;
473         }
474     }
475 
476 }