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.tag.composite;
20  
21  import java.lang.reflect.Method;
22  import java.net.URL;
23  import java.util.regex.Pattern;
24  
25  import javax.faces.FacesException;
26  import javax.faces.application.Resource;
27  import javax.faces.application.ResourceHandler;
28  import javax.faces.application.ViewHandler;
29  import javax.faces.context.ExternalContext;
30  import javax.faces.context.FacesContext;
31  import javax.faces.view.facelets.ComponentConfig;
32  import javax.faces.view.facelets.FaceletHandler;
33  import javax.faces.view.facelets.Tag;
34  import javax.faces.view.facelets.TagConfig;
35  import javax.faces.view.facelets.TagHandler;
36  
37  import org.apache.myfaces.shared.util.ArrayUtils;
38  import org.apache.myfaces.shared.util.StringUtils;
39  import org.apache.myfaces.shared.util.WebConfigParamUtils;
40  import org.apache.myfaces.view.facelets.tag.TagLibrary;
41  
42  /**
43   * This class create composite component tag handlers for "http://java.sun.com/jsf/composite/"
44   * namespace. Note that the class that create composite component tag handlers using its own 
45   * namespace defined in facelet taglib .xml file see TagLibraryConfig.TagLibraryImpl
46   * 
47   * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
48   * @version $Revision: 1300255 $ $Date: 2012-03-13 12:38:54 -0500 (Tue, 13 Mar 2012) $
49   */
50  public class CompositeResourceLibrary implements TagLibrary
51  {
52      public final static String NAMESPACE_PREFIX = "http://java.sun.com/jsf/composite/";
53      
54      private final ResourceHandler _resourceHandler;
55      private Pattern _acceptPatterns;
56      private String _extension;
57      private String[] _defaultSuffixesArray;
58      
59      public CompositeResourceLibrary(FacesContext facesContext)
60      {
61          super();
62          _resourceHandler = facesContext.getApplication().getResourceHandler();
63  
64          ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
65          
66          _acceptPatterns = loadAcceptPattern(externalContext);
67  
68          _extension = loadFaceletExtension(externalContext);
69          
70          String defaultSuffixes = WebConfigParamUtils.getStringInitParameter(externalContext,
71                  ViewHandler.DEFAULT_SUFFIX_PARAM_NAME, ViewHandler.DEFAULT_SUFFIX );
72          
73          _defaultSuffixesArray = StringUtils.splitShortString(defaultSuffixes, ' ');
74          
75          boolean faceletsExtensionFound = false;
76          for (String ext : _defaultSuffixesArray)
77          {
78              if (_extension.equals(ext))
79              {
80                  faceletsExtensionFound = true;
81                  break;
82              }
83          }
84          if (!faceletsExtensionFound)
85          {
86              _defaultSuffixesArray = (String[]) ArrayUtils.concat(_defaultSuffixesArray, new String[]{_extension});
87          }
88      }
89      
90      /**
91       * Load and compile a regular expression pattern built from the Facelet view mapping parameters.
92       * 
93       * @param context
94       *            the application's external context
95       * 
96       * @return the compiled regular expression
97       */
98      private Pattern loadAcceptPattern(ExternalContext context)
99      {
100         assert context != null;
101 
102         String mappings = context.getInitParameter(ViewHandler.FACELETS_VIEW_MAPPINGS_PARAM_NAME);
103         if (mappings == null)
104         {
105             return null;
106         }
107 
108         // Make sure the mappings contain something
109         mappings = mappings.trim();
110         if (mappings.length() == 0)
111         {
112             return null;
113         }
114 
115         return Pattern.compile(toRegex(mappings));
116     }
117 
118     private String loadFaceletExtension(ExternalContext context)
119     {
120         assert context != null;
121 
122         String suffix = context.getInitParameter(ViewHandler.FACELETS_SUFFIX_PARAM_NAME);
123         if (suffix == null)
124         {
125             suffix = ViewHandler.DEFAULT_FACELETS_SUFFIX;
126         }
127         else
128         {
129             suffix = suffix.trim();
130             if (suffix.length() == 0)
131             {
132                 suffix = ViewHandler.DEFAULT_FACELETS_SUFFIX;
133             }
134         }
135 
136         return suffix;
137     }
138     
139     /**
140      * Convert the specified mapping string to an equivalent regular expression.
141      * 
142      * @param mappings
143      *            le mapping string
144      * 
145      * @return an uncompiled regular expression representing the mappings
146      */
147     private String toRegex(String mappings)
148     {
149         assert mappings != null;
150 
151         // Get rid of spaces
152         mappings = mappings.replaceAll("\\s", "");
153 
154         // Escape '.'
155         mappings = mappings.replaceAll("\\.", "\\\\.");
156 
157         // Change '*' to '.*' to represent any match
158         mappings = mappings.replaceAll("\\*", ".*");
159 
160         // Split the mappings by changing ';' to '|'
161         mappings = mappings.replaceAll(";", "|");
162 
163         return mappings;
164     }
165     
166     public boolean handles(String resourceName)
167     {
168         if (resourceName == null)
169         {
170             return false;
171         }
172         // Check extension first as it's faster than mappings
173         if (resourceName.endsWith(_extension))
174         {
175             // If the extension matches, it's a Facelet viewId.
176             return true;
177         }
178 
179         // Otherwise, try to match the view identifier with the facelet mappings
180         return _acceptPatterns != null && _acceptPatterns.matcher(resourceName).matches();
181     }
182 
183     public boolean containsFunction(String ns, String name)
184     {
185         // Composite component tag library does not suport functions
186         return false;
187     }
188 
189     public boolean containsNamespace(String ns)
190     {
191         if (ns != null && ns.startsWith(NAMESPACE_PREFIX))
192         {
193             if (ns.length() > NAMESPACE_PREFIX.length())
194             {
195                 String libraryName = ns.substring(NAMESPACE_PREFIX.length());
196                 return _resourceHandler.libraryExists(libraryName);
197             }
198         }        
199         return false;
200     }
201 
202     public boolean containsTagHandler(String ns, String localName)
203     {
204         if (ns != null && ns.startsWith(NAMESPACE_PREFIX))
205         {
206             if (ns.length() > NAMESPACE_PREFIX.length())
207             {
208                 String libraryName = ns.substring(NAMESPACE_PREFIX.length());
209                 
210                 for (String defaultSuffix : _defaultSuffixesArray)
211                 {
212                     String resourceName = localName + defaultSuffix;
213                     if (handles(resourceName))
214                     {
215                         Resource compositeComponentResource = 
216                             _resourceHandler.createResource(resourceName, libraryName);
217                         if (compositeComponentResource != null)
218                         {
219                             URL url = compositeComponentResource.getURL();
220                             return (url != null);
221                         }
222                     }
223                 }
224             }
225         }
226         return false;
227     }
228 
229     public Method createFunction(String ns, String name)
230     {
231         // Composite component tag library does not suport functions
232         return null;
233     }
234 
235     public TagHandler createTagHandler(String ns, String localName,
236             TagConfig tag) throws FacesException
237     {
238         if (ns != null && ns.startsWith(NAMESPACE_PREFIX))
239         {
240             if (ns.length() > NAMESPACE_PREFIX.length())
241             {
242                 String libraryName = ns.substring(NAMESPACE_PREFIX.length());
243                 for (String defaultSuffix : _defaultSuffixesArray)
244                 {
245                     String resourceName = localName + defaultSuffix;
246                     if (handles(resourceName))
247                     {
248                         // MYFACES-3308 If a composite component exists, it requires to 
249                         // be always resolved. In other words, it should always exists a default.
250                         // The call here for resourceHandler.createResource, just try to get
251                         // the Resource and if it does not exists, it just returns null.
252                         // The intention of this code is just create an instance and pass to
253                         // CompositeComponentResourceTagHandler. Then, its values 
254                         // (resourceName, libraryName) will be used to derive the real instance
255                         // to use in a view, based on the locale used.
256                         Resource compositeComponentResourceWrapped
257                                 = _resourceHandler.createResource(resourceName, libraryName);
258                         if (compositeComponentResourceWrapped != null)
259                         {
260                             Resource compositeComponentResource
261                                     = new CompositeResouceWrapper(compositeComponentResourceWrapped);
262                             ComponentConfig componentConfig = new ComponentConfigWrapper(tag,
263                                     "javax.faces.NamingContainer", null);
264 
265                             return new CompositeComponentResourceTagHandler(componentConfig,
266                                                                             compositeComponentResource);
267                         }
268                     }
269                 }
270             }
271         }
272         return null;
273     }
274 
275     private static class ComponentConfigWrapper implements ComponentConfig
276     {
277 
278         protected final TagConfig parent;
279 
280         protected final String componentType;
281 
282         protected final String rendererType;
283 
284         public ComponentConfigWrapper(TagConfig parent, String componentType,
285                                       String rendererType)
286         {
287             this.parent = parent;
288             this.componentType = componentType;
289             this.rendererType = rendererType;
290         }
291 
292         public String getComponentType()
293         {
294             return this.componentType;
295         }
296 
297         public String getRendererType()
298         {
299             return this.rendererType;
300         }
301 
302         public FaceletHandler getNextHandler()
303         {
304             return this.parent.getNextHandler();
305         }
306 
307         public Tag getTag()
308         {
309             return this.parent.getTag();
310         }
311 
312         public String getTagId()
313         {
314             return this.parent.getTagId();
315         }
316     }
317 }