Coverage Report - org.apache.myfaces.shared.resource.ResourceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
ResourceImpl
0%
0/91
0%
0/56
3.692
 
 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.shared.resource;
 20  
 
 21  
 import java.io.IOException;
 22  
 import java.io.InputStream;
 23  
 import java.net.URL;
 24  
 import java.util.Collections;
 25  
 import java.util.HashMap;
 26  
 import java.util.Map;
 27  
 
 28  
 import javax.faces.application.ProjectStage;
 29  
 import javax.faces.application.Resource;
 30  
 import javax.faces.context.FacesContext;
 31  
 
 32  
 /**
 33  
  * Default implementation for resources
 34  
  */
 35  
 public class ResourceImpl extends Resource implements ContractResource
 36  
 {
 37  
     protected final static String JAVAX_FACES_LIBRARY_NAME = "javax.faces";
 38  
     protected final static String JSF_JS_RESOURCE_NAME = "jsf.js";
 39  
 
 40  
 
 41  
     private ResourceMeta _resourceMeta;
 42  
     private ResourceLoader _resourceLoader;
 43  
     private ResourceHandlerSupport _resourceHandlerSupport;
 44  
     
 45  
     private URL _url;
 46  
     private String _requestPath;
 47  
     
 48  
     public ResourceImpl(ResourceMeta resourceMeta, 
 49  
             ResourceLoader resourceLoader, ResourceHandlerSupport support, String contentType)
 50  0
     {
 51  0
         _resourceMeta = resourceMeta;
 52  0
         _resourceLoader = resourceLoader;
 53  0
         _resourceHandlerSupport = support;
 54  0
         setLibraryName(resourceMeta.getLibraryName());
 55  0
         setResourceName(resourceMeta.getResourceName());
 56  0
         setContentType(contentType);
 57  0
     }
 58  
     
 59  
     public ResourceImpl(ResourceMeta resourceMeta, 
 60  
             ResourceLoader resourceLoader, ResourceHandlerSupport support, String contentType,
 61  
             URL url, String requestPath)
 62  0
     {
 63  
         
 64  0
         _resourceMeta = resourceMeta;
 65  0
         _resourceLoader = resourceLoader;
 66  0
         _resourceHandlerSupport = support;
 67  0
         _url = url;
 68  0
         _requestPath = requestPath;
 69  0
         setLibraryName(resourceMeta.getLibraryName());
 70  0
         setResourceName(resourceMeta.getResourceName());
 71  0
         setContentType(contentType);
 72  0
     }
 73  
     
 74  
     public ResourceLoader getResourceLoader()
 75  
     {
 76  0
         return _resourceLoader;
 77  
     }    
 78  
     
 79  
     @Override
 80  
     public InputStream getInputStream() throws IOException
 81  
     {
 82  0
         if (couldResourceContainValueExpressions())
 83  
         {
 84  0
             return new ValueExpressionFilterInputStream(
 85  
                     getResourceLoader().getResourceInputStream(_resourceMeta), getLibraryName(), getResourceName()); 
 86  
         }
 87  
         else
 88  
         {
 89  0
             return getResourceLoader().getResourceInputStream(_resourceMeta);            
 90  
         }
 91  
     }
 92  
     
 93  
     private boolean couldResourceContainValueExpressions()
 94  
     {
 95  0
         if (_resourceMeta.couldResourceContainValueExpressions())
 96  
         {
 97  0
             return true;
 98  
         }
 99  
         else
 100  
         {
 101  
             //By default only css resource contain value expressions
 102  0
             String contentType = getContentType();
 103  
     
 104  0
             return ("text/css".equals(contentType));
 105  
         }
 106  
     }
 107  
 
 108  
     @Override
 109  
     public String getRequestPath()
 110  
     {
 111  0
         if (_requestPath == null)
 112  
         {
 113  
             String path;
 114  0
             if (_resourceHandlerSupport.isExtensionMapping())
 115  
             {
 116  0
                 path = _resourceHandlerSupport.getResourceIdentifier() + '/' + 
 117  
                     getResourceName() + _resourceHandlerSupport.getMapping();
 118  
             }
 119  
             else
 120  
             {
 121  0
                 String mapping = _resourceHandlerSupport.getMapping(); 
 122  0
                 path = _resourceHandlerSupport.getResourceIdentifier() + '/' + getResourceName();
 123  0
                 path = (mapping == null) ? path : mapping + path;
 124  
             }
 125  
 
 126  0
             FacesContext facesContext = FacesContext.getCurrentInstance();
 127  0
             String metadata = null;
 128  0
             boolean useAmp = false;
 129  0
             if (getLibraryName() != null)
 130  
             {
 131  0
                 metadata = "?ln=" + getLibraryName();
 132  0
                 path = path + metadata;
 133  0
                 useAmp = true;
 134  
 
 135  0
                 if (!facesContext.isProjectStage(ProjectStage.Production)
 136  
                         && JSF_JS_RESOURCE_NAME.equals(getResourceName()) 
 137  
                         && JAVAX_FACES_LIBRARY_NAME.equals(getLibraryName()))
 138  
                 {
 139  
                     // append &stage=?? for all ProjectStages except Production
 140  0
                     path = path + "&stage=" + facesContext.getApplication().getProjectStage().toString();
 141  
                 }
 142  
             }
 143  0
             if (_resourceMeta.getLocalePrefix() != null)
 144  
             {
 145  0
                 path = path + (useAmp ? '&' : '?') + "loc=" + _resourceMeta.getLocalePrefix();
 146  0
                 useAmp = true;
 147  
             }
 148  0
             if (_resourceMeta.getContractName() != null)
 149  
             {
 150  0
                 path = path + (useAmp ? '&' : '?') + "con=" + _resourceMeta.getContractName();
 151  0
                 useAmp = true;
 152  
             }
 153  0
             _requestPath = facesContext.getApplication().getViewHandler().getResourceURL(facesContext, path);
 154  
         }
 155  0
         return _requestPath;
 156  
     }
 157  
 
 158  
     @Override
 159  
     public Map<String, String> getResponseHeaders()
 160  
     {
 161  0
         FacesContext facesContext = FacesContext.getCurrentInstance();
 162  
         
 163  0
         if (facesContext.getApplication().getResourceHandler().isResourceRequest(facesContext))
 164  
         {
 165  0
             Map<String, String> headers = new HashMap<String, String>();
 166  
             
 167  
             long lastModified;
 168  
             try
 169  
             {
 170  0
                 lastModified = ResourceLoaderUtils.getResourceLastModified(this.getURL());
 171  
             }
 172  0
             catch (IOException e)
 173  
             {
 174  0
                 lastModified = -1;
 175  0
             }
 176  
             
 177  
             // Here we have two cases: If the file could contain EL Expressions
 178  
             // the last modified time is the greatest value between application startup and
 179  
             // the value from file.
 180  0
             if (this.couldResourceContainValueExpressions() &&
 181  
                     lastModified < _resourceHandlerSupport.getStartupTime())
 182  
             {
 183  0
                 lastModified = _resourceHandlerSupport.getStartupTime();
 184  
             }            
 185  0
             else if (_resourceMeta instanceof AliasResourceMetaImpl &&
 186  
                 lastModified < _resourceHandlerSupport.getStartupTime())
 187  
             {
 188  
                 // If the resource meta is aliased, the last modified time is the greatest 
 189  
                 // value between application startup and the value from file.
 190  0
                 lastModified = _resourceHandlerSupport.getStartupTime();
 191  
             }
 192  
 
 193  0
             if (lastModified >= 0)
 194  
             {
 195  0
                 headers.put("Last-Modified", ResourceLoaderUtils.formatDateHeader(lastModified));
 196  
                 
 197  
                 long expires;
 198  0
                 if (facesContext.isProjectStage(ProjectStage.Development))
 199  
                 {
 200  
                     // Force to expire now to prevent caching on development time.
 201  0
                     expires = System.currentTimeMillis();
 202  
                 }
 203  
                 else
 204  
                 {
 205  0
                     expires = System.currentTimeMillis() + _resourceHandlerSupport.getMaxTimeExpires();
 206  
                 }
 207  0
                 headers.put("Expires", ResourceLoaderUtils.formatDateHeader(expires));
 208  
             }
 209  
             
 210  0
             return headers;
 211  
         }
 212  
         else
 213  
         {
 214  
             //No need to return headers 
 215  0
             return Collections.emptyMap();
 216  
         }
 217  
     }
 218  
 
 219  
     @Override
 220  
     public URL getURL()
 221  
     {
 222  
         // For the default algorithm, it is safe to assume the resource
 223  
         // URL will not change over resource lifetime. See MYFACES-3458
 224  0
         if (_url == null)
 225  
         {
 226  0
             _url = getResourceLoader().getResourceURL(_resourceMeta);
 227  
         }
 228  0
         return _url;
 229  
     }
 230  
 
 231  
     @Override
 232  
     public boolean userAgentNeedsUpdate(FacesContext context)
 233  
     {
 234  
         // RFC2616 says related to If-Modified-Since header the following:
 235  
         //
 236  
         // "... The If-Modified-Since request-header field is used with a method to 
 237  
         // make it conditional: if the requested variant has not been modified since 
 238  
         // the time specified in this field, an entity will not be returned from 
 239  
         // the server; instead, a 304 (not modified) response will be returned 
 240  
         // without any message-body..."
 241  
         // 
 242  
         // This method is called from ResourceHandlerImpl.handleResourceRequest and if
 243  
         // returns false send a 304 Not Modified response.
 244  
         
 245  0
         String ifModifiedSinceString = context.getExternalContext().getRequestHeaderMap().get("If-Modified-Since");
 246  
         
 247  0
         if (ifModifiedSinceString == null)
 248  
         {
 249  0
             return true;
 250  
         }
 251  
         
 252  0
         Long ifModifiedSince = ResourceLoaderUtils.parseDateHeader(ifModifiedSinceString);
 253  
         
 254  0
         if (ifModifiedSince == null)
 255  
         {
 256  0
             return true;
 257  
         }
 258  
         
 259  
         Long lastModified;
 260  
         try
 261  
         {
 262  0
             lastModified = ResourceLoaderUtils.getResourceLastModified(this.getURL());
 263  
         }
 264  0
         catch (IOException exception)
 265  
         {
 266  0
             lastModified = -1L;
 267  0
         }
 268  
         
 269  0
         if (lastModified >= 0)
 270  
         {
 271  0
             if (this.couldResourceContainValueExpressions() &&
 272  
                     lastModified < _resourceHandlerSupport.getStartupTime())
 273  
             {
 274  0
                 lastModified = _resourceHandlerSupport.getStartupTime();
 275  
             }
 276  
             
 277  
             // If the lastModified date is lower or equal than ifModifiedSince,
 278  
             // the agent does not need to update.
 279  
             // Note the lastModified time is set at milisecond precision, but when 
 280  
             // the date is parsed and sent on ifModifiedSince, the exceding miliseconds
 281  
             // are trimmed. So, we have to compare trimming this from the calculated
 282  
             // lastModified time.
 283  0
             if ( (lastModified-(lastModified % 1000)) <= ifModifiedSince)
 284  
             {
 285  0
                 return false;
 286  
             }
 287  
         }
 288  
         
 289  0
         return true;
 290  
     }
 291  
     
 292  
     protected ResourceHandlerSupport getResourceHandlerSupport()
 293  
     {
 294  0
         return _resourceHandlerSupport;
 295  
     }
 296  
     
 297  
     protected ResourceMeta getResourceMeta()
 298  
     {
 299  0
         return _resourceMeta;
 300  
     }
 301  
 
 302  
     public boolean isContractResource()
 303  
     {
 304  0
         return _resourceMeta.getContractName() != null;
 305  
     }
 306  
     
 307  
     public String getContractName()
 308  
     {
 309  0
         return _resourceMeta.getContractName();
 310  
     }
 311  
 }