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.resource;
20  
21  import java.io.InputStream;
22  import java.net.URL;
23  import java.util.Iterator;
24  
25  import javax.faces.application.ProjectStage;
26  import javax.faces.application.ResourceHandler;
27  import javax.faces.application.ResourceVisitOption;
28  import javax.faces.context.FacesContext;
29  
30  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
31  import org.apache.myfaces.shared.resource.AliasResourceMetaImpl;
32  import org.apache.myfaces.shared.resource.ResourceLoader;
33  import org.apache.myfaces.shared.resource.ResourceMeta;
34  import org.apache.myfaces.shared.resource.ResourceMetaImpl;
35  import org.apache.myfaces.shared.util.ClassUtils;
36  import org.apache.myfaces.shared.util.WebConfigParamUtils;
37  import org.apache.myfaces.shared.renderkit.html.util.ResourceUtils;
38  import org.apache.myfaces.shared.resource.ClassLoaderResourceLoaderIterator;
39  
40  /**
41   * A resource loader implementation which loads resources from the thread ClassLoader.
42   */
43  public class InternalClassLoaderResourceLoader extends ResourceLoader
44  {
45  
46      /**
47       * If this param is true and the project stage is development mode,
48       * the source javascript files will be loaded separately instead have
49       * all in just one file, to preserve line numbers and make javascript
50       * debugging of the default jsf javascript file more simple.
51       */
52      @JSFWebConfigParam(since = "2.0.1", defaultValue = "false", expectedValues = "true,false", group = "render")
53      public static final String USE_MULTIPLE_JS_FILES_FOR_JSF_UNCOMPRESSED_JS
54              = "org.apache.myfaces.USE_MULTIPLE_JS_FILES_FOR_JSF_UNCOMPRESSED_JS";
55  
56      /**
57       * Define the mode used for jsf.js file:
58       * <ul>
59       * <li>normal : contains everything, including jsf-i18n.js, jsf-experimental.js and jsf-legacy.js</li>
60       * <li>minimal-modern : is the core jsf with a baseline of ie9+,
61       * without jsf-i18n.js, jsf-experimental.js and jsf-legacy.js</li>
62       * <li>minimal: which is the same with a baseline of ie6, without jsf-i18n.js, jsf-experimental.js</li>
63       * </ul>
64       * <p>If org.apache.myfaces.USE_MULTIPLE_JS_FILES_FOR_JSF_UNCOMPRESSED_JS param is set to true and project stage
65       * is Development, this param is ignored.</p>
66       */
67      @JSFWebConfigParam(since = "2.0.10,2.1.4", defaultValue = "normal",
68                         expectedValues = "normal, minimal-modern, minimal", group = "render")
69      public static final String MYFACES_JSF_MODE = "org.apache.myfaces.JSF_JS_MODE";
70      
71      private final boolean _useMultipleJsFilesForJsfUncompressedJs;
72      private final String _jsfMode;
73      private final boolean _developmentStage;
74  
75      public InternalClassLoaderResourceLoader(String prefix)
76      {
77          super(prefix);
78          _useMultipleJsFilesForJsfUncompressedJs
79                  = WebConfigParamUtils.getBooleanInitParameter(FacesContext.getCurrentInstance().getExternalContext(),
80                      USE_MULTIPLE_JS_FILES_FOR_JSF_UNCOMPRESSED_JS, false);
81  
82          _jsfMode = WebConfigParamUtils.getStringInitParameter(FacesContext.getCurrentInstance().getExternalContext(),
83                      MYFACES_JSF_MODE, ResourceUtils.JSF_MYFACES_JSFJS_NORMAL);
84          _developmentStage = FacesContext.getCurrentInstance().isProjectStage(ProjectStage.Development);
85      }
86  
87      @Override
88      public String getLibraryVersion(String path)
89      {
90          return null;
91      }
92  
93      @Override
94      public InputStream getResourceInputStream(ResourceMeta resourceMeta)
95      {
96          InputStream is;
97          if (getPrefix() != null && !"".equals(getPrefix()))
98          {
99              String name = getPrefix() + '/' + resourceMeta.getResourceIdentifier();
100             is = getClassLoader().getResourceAsStream(name);
101             if (is == null)
102             {
103                 is = this.getClass().getClassLoader().getResourceAsStream(name);
104             }
105             return is;
106         }
107         else
108         {
109             is = getClassLoader().getResourceAsStream(resourceMeta.getResourceIdentifier());
110             if (is == null)
111             {
112                 is = this.getClass().getClassLoader().getResourceAsStream(resourceMeta.getResourceIdentifier());
113             }
114             return is;
115         }
116     }
117 
118     public URL getResourceURL(String resourceId)
119     {
120         URL url;
121         if (getPrefix() != null && !"".equals(getPrefix()))
122         {
123             String name = getPrefix() + '/' + resourceId;
124             url = getClassLoader().getResource(name);
125             if (url == null)
126             {
127                 url = this.getClass().getClassLoader().getResource(name);
128             }
129             return url;
130         }
131         else
132         {
133             url = getClassLoader().getResource(resourceId);
134             if (url == null)
135             {
136                 url = this.getClass().getClassLoader().getResource(resourceId);
137             }
138             return url;
139         }
140     }
141     
142     @Override
143     public URL getResourceURL(ResourceMeta resourceMeta)
144     {
145         return getResourceURL(resourceMeta.getResourceIdentifier());
146     }
147 
148     @Override
149     public String getResourceVersion(String path)
150     {
151         return null;
152     }
153 
154     @Override
155     public ResourceMeta createResourceMeta(String prefix, String libraryName, String libraryVersion,
156                                            String resourceName, String resourceVersion)
157     {
158         //handle jsf.js
159         final boolean javaxFacesLib = libraryName != null &&
160                 ResourceHandler.JSF_SCRIPT_LIBRARY_NAME.equals(libraryName);
161         final boolean javaxFaces = javaxFacesLib &&
162                 ResourceHandler.JSF_SCRIPT_RESOURCE_NAME.equals(resourceName);
163 
164         if (javaxFaces)
165         {
166             if (_developmentStage)
167             {
168                 if (_useMultipleJsFilesForJsfUncompressedJs)
169                 {
170                     return new AliasResourceMetaImpl(prefix, libraryName, libraryVersion,
171                             resourceName, resourceVersion, ResourceUtils.JSF_UNCOMPRESSED_JS_RESOURCE_NAME, true);
172                 }
173                 else
174                 {
175                     //normall we would have to take care about the standard jsf.js case also
176                     //but our standard resource loader takes care of it,
177                     // because this part is only called in debugging mode
178                     //in production only in debugging
179                     return new AliasResourceMetaImpl(prefix, libraryName, libraryVersion, resourceName, resourceVersion,
180                                                      "jsf-uncompressed-full.js", false);
181                 }
182             }
183             else if (_jsfMode.equals(ResourceUtils.JSF_MYFACES_JSFJS_MINIMAL) )
184             {
185                 return new AliasResourceMetaImpl(prefix, libraryName, libraryVersion, resourceName, resourceVersion,
186                         ResourceUtils.JSF_MINIMAL_JS_RESOURCE_NAME, false);
187             }
188             else if (_jsfMode.equals(ResourceUtils.JSF_MYFACES_JSFJS_MINIMAL_MODERN) )
189             {
190                 return new AliasResourceMetaImpl(prefix, libraryName, libraryVersion, resourceName, resourceVersion,
191                         ResourceUtils.JSF_MINIMAL_MODERN_JS_RESOURCE_NAME, false);
192             }
193             else
194             {
195                 return null;
196             }
197         }
198         else if (javaxFacesLib && !_developmentStage && !_jsfMode.equals(ResourceUtils.JSF_MYFACES_JSFJS_NORMAL) &&
199                                    (ResourceUtils.JSF_MYFACES_JSFJS_I18N.equals(resourceName) ||
200                                    ResourceUtils.JSF_MYFACES_JSFJS_EXPERIMENTAL.equals(resourceName) ||
201                                    ResourceUtils.JSF_MYFACES_JSFJS_LEGACY.equals(resourceName)) )
202         {
203             return new ResourceMetaImpl(prefix, libraryName, libraryVersion, resourceName, resourceVersion);
204         }
205         else if (_developmentStage && libraryName != null &&
206                 ResourceUtils.MYFACES_LIBRARY_NAME.equals(libraryName) &&
207                 ResourceUtils.MYFACES_JS_RESOURCE_NAME.equals(resourceName))
208         {
209             //handle the oamSubmit.js
210             return new AliasResourceMetaImpl(prefix, libraryName, libraryVersion,
211                     resourceName, resourceVersion, ResourceUtils.MYFACES_JS_RESOURCE_NAME_UNCOMPRESSED, true);
212         }
213         else if (_developmentStage && libraryName != null && libraryName.startsWith("org.apache.myfaces.core"))
214         {
215             return new ResourceMetaImpl(prefix, libraryName, libraryVersion, resourceName, resourceVersion);
216         }
217         else
218         {
219             return null;
220         }
221     }
222 
223     /**
224      * Returns the ClassLoader to use when looking up resources under the top level package. By default, this is the
225      * context class loader.
226      *
227      * @return the ClassLoader used to lookup resources
228      */
229     protected ClassLoader getClassLoader()
230     {
231         return ClassUtils.getContextClassLoader();
232     }
233 
234     @Override
235     public boolean libraryExists(String libraryName)
236     {
237         if (getPrefix() != null && !"".equals(getPrefix()))
238         {
239             URL url = getClassLoader().getResource(getPrefix() + '/' + libraryName);
240             if (url == null)
241             {
242                 url = this.getClass().getClassLoader().getResource(getPrefix() + '/' + libraryName);
243             }
244             if (url != null)
245             {
246                 return true;
247             }
248         }
249         else
250         {
251             URL url = getClassLoader().getResource(libraryName);
252             if (url == null)
253             {
254                 url = this.getClass().getClassLoader().getResource(libraryName);
255             }
256             if (url != null)
257             {
258                 return true;
259             }
260         }
261         return false;
262     }
263 
264     @Override
265     public Iterator<String> iterator(FacesContext facesContext, String path, 
266             int maxDepth, ResourceVisitOption... options)
267     {
268         String basePath = path;
269         
270         if (getPrefix() != null)
271         {
272             basePath = getPrefix() + '/' + (path.startsWith("/") ? path.substring(1) : path);
273         }
274 
275         URL url = getClassLoader().getResource(basePath);
276 
277         return new ClassLoaderResourceLoaderIterator(url, basePath, maxDepth, options);
278     }
279 }