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.commons.resourcehandler;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.Locale;
26  import java.util.Map;
27  
28  import javax.el.ELContext;
29  import javax.el.ELResolver;
30  import javax.el.FunctionMapper;
31  import javax.el.ValueExpression;
32  import javax.el.VariableMapper;
33  import javax.faces.application.ResourceHandler;
34  import javax.faces.context.FacesContext;
35  
36  import org.apache.myfaces.commons.resourcehandler.config.element.Library;
37  import org.apache.myfaces.commons.resourcehandler.resource.ResourceImpl;
38  import org.apache.myfaces.commons.resourcehandler.resource.ResourceLoader;
39  import org.apache.myfaces.commons.resourcehandler.resource.ValueExpressionFilterInputStream;
40  
41  /**
42   * 
43   * @author Leonardo Uribe
44   *
45   */
46  public class ExtendedResourceImpl extends ResourceImpl
47  {
48      private String _expectedLocalePrefix;
49      
50      private ExtendedResourceMeta _extendedResourceMeta;
51      
52      private ExtendedDefaultResourceHandlerSupport _extendedDefaultResourceHandlerSupport;
53      
54      public ExtendedResourceImpl(ExtendedResourceMeta resourceMeta,
55              ResourceLoader resourceLoader, ExtendedDefaultResourceHandlerSupport support,
56              String contentType, String expectedLocalePrefix, String expectedLibraryName)
57      {
58          super(resourceMeta, resourceLoader, support, contentType);
59          _extendedResourceMeta = resourceMeta;
60          _expectedLocalePrefix = expectedLocalePrefix;
61          _extendedDefaultResourceHandlerSupport = support;
62          if (expectedLibraryName != null)
63          {
64              setLibraryName(expectedLibraryName);
65          }
66      }
67      
68      @Override
69      public InputStream getInputStream() throws IOException
70      {
71          if ( getExtendedDefaultResourceHandlerSupport().isGzipResourcesEnabled() &&
72               getExtendedDefaultResourceHandlerSupport().isCacheDiskGzipResources() &&
73               getExtendedDefaultResourceHandlerSupport().isCompressable(this) &&
74               getExtendedDefaultResourceHandlerSupport().userAgentSupportsCompression(FacesContext.getCurrentInstance()))
75          {
76              //GZIPResourceLoader will take care of resources containing ValueExpressions 
77              return getResourceLoader().getResourceInputStream(getResourceMeta());
78          }
79          else
80          {
81              return super.getInputStream();
82          }
83      }
84  
85      @Override
86      public String getRequestPath()
87      {
88          String mapping = getResourceHandlerSupport().getMapping() != null ?
89                  getResourceHandlerSupport().getMapping() :
90                  "" ;
91  
92          Library library = getExtendedDefaultResourceHandlerSupport().getMyFacesResourcesConfig().
93              getLibrary(getLibraryName());
94              
95          if (library.getRequestPath() == null)
96          {
97              String localePrefix = getResourceMeta().getLocalePrefix() != null ?  
98                      getResourceMeta().getLocalePrefix() : _expectedLocalePrefix;
99              if (localePrefix == null)
100             {
101                 // calculate current localePrefix (could be different from the one requested, e.g. on locale change)
102                 localePrefix = getRequestLocalePrefix();
103             }
104             String path = null;
105             if (!getResourceHandlerSupport().isExtensionMapping())
106             {
107                 path = mapping + getResourceHandlerSupport().getResourceIdentifier() + "/$/" + 
108                                 localePrefix + '/' + 
109                                 getLibraryName() + '/' + 
110                                 getResourceName();
111             }
112             else
113             {
114                 path = getResourceHandlerSupport().getResourceIdentifier() + "/$/" + 
115                 localePrefix + '/' + 
116                 getLibraryName() + '/' + 
117                 getResourceName() + mapping;
118             }
119             
120             FacesContext facesContext = FacesContext.getCurrentInstance();
121             return facesContext.getApplication().getViewHandler().getResourceURL(facesContext, path);
122         }
123         else
124         {
125             //Redirect url assume prefix mapping.
126             FacesContext facesContext = FacesContext.getCurrentInstance();
127             return facesContext.getApplication().getViewHandler().getResourceURL(facesContext, 
128                     calculateRequestPath(facesContext, library.getRequestPath()));
129         }
130     }
131     
132     public String getLocalePrefix()
133     {
134         String localePrefix = getResourceMeta().getLocalePrefix() != null ?  
135                 getResourceMeta().getLocalePrefix() : _expectedLocalePrefix;
136         if (localePrefix == null)
137         {
138             // calculate current localePrefix (could be different from the one requested, e.g. on locale change)
139             localePrefix = getRequestLocalePrefix();
140         }
141         return localePrefix;
142     }
143     
144     private String calculateRequestPath(FacesContext context, String expression)
145     {
146         ValueExpression requestPath = getExtendedResourceMeta().getRequestPathExpression(); 
147         if (requestPath == null)
148         {
149             ELContext elContext = new ELContextWrapper(context.getELContext(), context, this);
150             requestPath = context.getApplication().getExpressionFactory().createValueExpression(
151                     elContext, expression, String.class);
152             getExtendedResourceMeta().setRequestPathExpression(requestPath);
153         }
154         return (String) requestPath.getValue(context.getELContext());
155     }
156     
157     protected ExtendedResourceMeta getExtendedResourceMeta()
158     {
159         return _extendedResourceMeta;
160     }
161     
162     protected ExtendedDefaultResourceHandlerSupport getExtendedDefaultResourceHandlerSupport()
163     {
164         return _extendedDefaultResourceHandlerSupport;
165     }
166     
167     @Override
168     public Map<String, String> getResponseHeaders()
169     {
170         FacesContext facesContext = FacesContext.getCurrentInstance();
171         
172         if (facesContext.getApplication().getResourceHandler().isResourceRequest(facesContext))
173         {
174             Map<String, String> headers = super.getResponseHeaders();
175             
176             if (getExtendedDefaultResourceHandlerSupport().isGzipResourcesEnabled() && 
177                 getExtendedDefaultResourceHandlerSupport().userAgentSupportsCompression(facesContext) && 
178                 getExtendedDefaultResourceHandlerSupport().isCompressable(this))
179                 {
180                     headers.put("Content-Encoding", "gzip");
181                 }
182             
183             return headers; 
184         }
185         else
186         {
187             //No need to return headers 
188             return Collections.emptyMap();
189         }
190     }
191     
192     /**
193      * Returns the String representation of the current locale for the use in the request path.
194      *
195      * @return
196      */
197     private static String getRequestLocalePrefix()
198     {
199         FacesContext facesContext = FacesContext.getCurrentInstance();
200         Locale locale = facesContext.getViewRoot().getLocale();
201         if (locale == null)
202         {
203             // fallback to default locale
204             locale = Locale.getDefault();
205         }
206         
207         String language = locale.getLanguage();
208         String country = locale.getCountry();
209         
210         if (country != null)
211         {
212             // de_AT
213             return language + "_" + country;
214         }
215         else
216         {
217             // de
218             return language;
219         }
220     }
221     
222     private static class ELContextWrapper extends ELContext
223     {
224         private ELContext _delegate;
225         private VariableMapper _mapper;
226         
227         
228         private ELContextWrapper(ELContext delegate, FacesContext context, ExtendedResourceImpl resource)
229         {
230             this._delegate = delegate;
231             this._mapper = new VariableMapperWrapper(delegate.getVariableMapper(), context, resource);
232         }
233 
234         public void setPropertyResolved(boolean resolved)
235         {
236             _delegate.setPropertyResolved(resolved);
237         }
238 
239         public boolean isPropertyResolved()
240         {
241             return _delegate.isPropertyResolved();
242         }
243 
244         public void putContext(Class key, Object contextObject)
245         {
246             _delegate.putContext(key, contextObject);
247         }
248 
249         public Object getContext(Class key)
250         {
251             return _delegate.getContext(key);
252         }
253 
254         public ELResolver getELResolver()
255         {
256             return _delegate.getELResolver();
257         }
258 
259         public FunctionMapper getFunctionMapper()
260         {
261             return _delegate.getFunctionMapper();
262         }
263 
264         public Locale getLocale()
265         {
266             return _delegate.getLocale();
267         }
268 
269         public void setLocale(Locale locale)
270         {
271             _delegate.setLocale(locale);
272         }
273 
274         public VariableMapper getVariableMapper()
275         {
276             return _mapper;
277         }
278     }
279     
280     private static class VariableMapperWrapper extends VariableMapper
281     {
282         private VariableMapper delegate;
283         
284         private Map<String, ValueExpression> map; 
285         
286         private VariableMapperWrapper(VariableMapper delegate, FacesContext context, ExtendedResourceImpl resource)
287         {
288             this.delegate = delegate;
289             map = new HashMap<String, ValueExpression>(4,1);
290             map.put("localePrefix", context.getApplication().getExpressionFactory().createValueExpression(resource.getLocalePrefix(), String.class));
291             map.put("libraryName", context.getApplication().getExpressionFactory().createValueExpression(resource.getLibraryName(), String.class));
292             map.put("resourceName", context.getApplication().getExpressionFactory().createValueExpression(resource.getResourceName(), String.class));
293             map.put("mapping", context.getApplication().getExpressionFactory().createValueExpression(
294                     resource.getExtendedDefaultResourceHandlerSupport().getMapping(), String.class));
295             map.put("extensionMapping", context.getApplication().getExpressionFactory().createValueExpression(
296                     resource.getExtendedDefaultResourceHandlerSupport().isExtensionMapping(), Boolean.class));
297         }
298 
299         public ValueExpression resolveVariable(String variable)
300         {
301             ValueExpression value = map.get(variable);
302             if (value != null)
303             {
304                 return value;
305             }
306             if (delegate != null)
307             {
308                 return delegate.resolveVariable(variable);
309             }
310             return null;
311         }
312 
313         public ValueExpression setVariable(String variable,
314                 ValueExpression expression)
315         {
316             if (delegate != null)
317             {
318                 return delegate.setVariable(variable, expression);
319             }
320             return null;
321         }
322     }
323 }