myfaces-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lu4...@apache.org
Subject svn commit: r1138272 - in /myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler: ./ src/main/java/org/apache/myfaces/commons/resourcehandler/ src/main/java/org/apache/myfaces/commons/resourcehandler/config/ src/main/java/org/apache/myfaces/c...
Date Wed, 22 Jun 2011 01:26:26 GMT
Author: lu4242
Date: Wed Jun 22 01:26:26 2011
New Revision: 1138272

URL: http://svn.apache.org/viewvc?rev=1138272&view=rev
Log:
MFCOMMONS-33 Extended ResourceHandler implementation (add GZIP compression)

Added:
    myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/GZIPResourceLoader.java
    myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/resource/ResourceLoaderWrapper.java
Modified:
    myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/pom.xml
    myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedDefaultResourceHandlerSupport.java
    myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedResourceHandlerImpl.java
    myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedResourceImpl.java
    myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/config/AdvancedResourceHandlerConfig.java
    myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/config/AdvancedResourceHandlerConfigParser.java
    myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/resource/ResourceLoader.java

Modified: myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/pom.xml
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/pom.xml?rev=1138272&r1=1138271&r2=1138272&view=diff
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/pom.xml (original)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/pom.xml Wed Jun 22 01:26:26
2011
@@ -65,9 +65,27 @@
             <scope>provided</scope>
         </dependency>
 
+        <!-- Servlet 2.5 -->
         <dependency>
-            <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-servlet_2.5_spec</artifactId>
+            <version>1.2</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- JSP 2.1 -->
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-jsp_2.1_spec</artifactId>
+            <version>1.0.1</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- el 2.2 (javax.el.*) -->
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-el_2.2_spec</artifactId>
+            <version>1.0.1</version>
             <scope>provided</scope>
         </dependency>
 

Modified: myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedDefaultResourceHandlerSupport.java
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedDefaultResourceHandlerSupport.java?rev=1138272&r1=1138271&r2=1138272&view=diff
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedDefaultResourceHandlerSupport.java
(original)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedDefaultResourceHandlerSupport.java
Wed Jun 22 01:26:26 2011
@@ -21,16 +21,21 @@ package org.apache.myfaces.commons.resou
 import java.util.Map;
 
 import javax.faces.FacesException;
+import javax.faces.application.ProjectStage;
+import javax.faces.application.Resource;
 import javax.faces.application.ResourceHandler;
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
 import org.apache.myfaces.commons.resourcehandler.application.FacesServletMapping;
 import org.apache.myfaces.commons.resourcehandler.filter.ExtendedResourceHandlerFilter;
 import org.apache.myfaces.commons.resourcehandler.resource.BaseResourceHandlerSupport;
 import org.apache.myfaces.commons.resourcehandler.resource.ClassLoaderResourceLoader;
 import org.apache.myfaces.commons.resourcehandler.resource.ExternalContextResourceLoader;
 import org.apache.myfaces.commons.resourcehandler.resource.ResourceLoader;
+import org.apache.myfaces.commons.resourcehandler.resource.ResourceMeta;
+import org.apache.myfaces.commons.util.StringUtils;
 import org.apache.myfaces.commons.util.WebConfigParamUtils;
 
 public class ExtendedDefaultResourceHandlerSupport extends BaseResourceHandlerSupport
@@ -38,13 +43,125 @@ public class ExtendedDefaultResourceHand
     protected static final String CACHED_SERVLET_MAPPING =
         ExtendedDefaultResourceHandlerSupport.class.getName() + ".CACHED_SERVLET_MAPPING";
     
+    /**
+     * Enable or disable gzip compressions for resources served by this extended resource
handler. By default is disabled (false).
+     */
+    @JSFWebConfigParam(defaultValue="false")
+    public static final String INIT_PARAM_GZIP_RESOURCES_ENABLED = "org.apache.myfaces.commons.GZIP_RESOURCES_ENABLED";
+    
+    /**
+     * Indicate the suffix used to recognize resources that should be compressed. By default
is ".css .js".
+     */
+    @JSFWebConfigParam(defaultValue=".css, .js")
+    public static final String INIT_PARAM_GZIP_RESOURCES_SUFFIX = "org.apache.myfaces.commons.GZIP_RESOURCES_SUFFIX";
+    public static final String INIT_PARAM_GZIP_RESOURCES_EXTENSIONS_DEFAULT = ".css .js";
+    
+    /**
+     * Indicate if gzipped files are stored on a temporal directory to serve them later.
By default is true. If this is
+     * disable, the files are compressed when they are served. 
+     */
+    @JSFWebConfigParam(defaultValue="true")
+    public static final String INIT_PARAM_CACHE_DISK_GZIP_RESOURCES = "org.apache.myfaces.commons.CACHE_DISK_GZIP_RESOURCES";
+    
+    /**
+     * Accept-Encoding HTTP header field.
+     */
+    private static final String ACCEPT_ENCODING_HEADER = "Accept-Encoding";
+    
     private ResourceLoader[] _resourceLoaders;
     
+    private final boolean _gzipResourcesEnabled;
+    
+    private final String[] _gzipResourcesSuffix;
+    
+    private final boolean _cacheDiskGzipResources;
+    
+    private final boolean _developmentStage;
+    
     public ExtendedDefaultResourceHandlerSupport()
     {
         super();
+        FacesContext context = FacesContext.getCurrentInstance();
+        
+        _gzipResourcesEnabled = WebConfigParamUtils.getBooleanInitParameter(context.getExternalContext(),

+                INIT_PARAM_GZIP_RESOURCES_ENABLED, false);
+        _gzipResourcesSuffix = StringUtils.splitShortString(
+                WebConfigParamUtils.getStringInitParameter(context.getExternalContext(),
+                        INIT_PARAM_GZIP_RESOURCES_SUFFIX, INIT_PARAM_GZIP_RESOURCES_EXTENSIONS_DEFAULT),
' ');
+        _cacheDiskGzipResources = WebConfigParamUtils.getBooleanInitParameter(context.getExternalContext(),

+                INIT_PARAM_CACHE_DISK_GZIP_RESOURCES, true);
+        _developmentStage = context.isProjectStage(ProjectStage.Development);
+    }
+    
+    public String[] getGzipResourcesSuffixes()
+    {
+        return _gzipResourcesSuffix;
+    }
+    
+    public boolean isGzipResourcesEnabled()
+    {
+        return _gzipResourcesEnabled;
+    }
+    
+    public boolean isCacheDiskGzipResources()
+    {
+        return _cacheDiskGzipResources;
+    }
+    
+    public boolean isCompressable(ResourceMeta resourceMeta)
+    {
+        if (getGzipResourcesSuffixes() != null)
+        {
+            boolean compressable = false;            
+            for (int i = 0; i < getGzipResourcesSuffixes().length; i++)
+            {
+                if (getGzipResourcesSuffixes()[i] != null && 
+                    getGzipResourcesSuffixes()[i].length() > 0 &&
+                    resourceMeta.getResourceName().endsWith(getGzipResourcesSuffixes()[i]))
+                {
+                    compressable = true;
+                    break;
+                }
+            }
+            return compressable;
+        }
+        else
+        {
+            return true;
+        }
     }
     
+    public boolean isCompressable(Resource resource)
+    {
+        if (getGzipResourcesSuffixes() != null)
+        {
+            boolean compressable = false;            
+            for (int i = 0; i < getGzipResourcesSuffixes().length; i++)
+            {
+                if (getGzipResourcesSuffixes()[i] != null && 
+                    getGzipResourcesSuffixes()[i].length() > 0 &&
+                    resource.getResourceName().endsWith(getGzipResourcesSuffixes()[i]))
+                {
+                    compressable = true;
+                    break;
+                }
+            }
+            return compressable;
+        }
+        else
+        {
+            return true;
+        }
+    }
+
+    public boolean userAgentSupportsCompression(FacesContext facesContext)
+    {
+        String acceptEncodingHeader = facesContext.getExternalContext()
+                .getRequestHeaderMap().get(ACCEPT_ENCODING_HEADER);
+
+        return isGZIPEncodingAccepted(acceptEncodingHeader);
+    }
+
     public String calculateResourceBasePath(FacesContext facesContext)
     {        
         FacesServletMapping mapping = getFacesServletMapping(facesContext);
@@ -145,25 +262,99 @@ public class ExtendedDefaultResourceHand
     {
         if (_resourceLoaders == null)
         {
-            //The ExternalContextResourceLoader has precedence over
-            //ClassLoaderResourceLoader, so it goes first.
-            //if (FacesContext.getCurrentInstance().isProjectStage(ProjectStage.Development))
-            //{
-            //    _resourceLoaders = new ResourceLoader[] {
-            //            new ExternalContextResourceLoader("/resources"),
-            //            new ClassLoaderResourceLoader("META-INF/resources"),
-            //            new InternalClassLoaderResourceLoader("META-INF/internal-resources")
-            //    };
-            //}
-            //else
-            //{
+            // we should serve a compressed version of the resource, if
+            //   - ProjectStage != Development
+            //   - a compressed version is available (created in constructor)
+            //   - the user agent supports compresssion
+            if (!_developmentStage && isGzipResourcesEnabled() && isCacheDiskGzipResources())
+            {
+                _resourceLoaders = new ResourceLoader[] {
+                        new GZIPResourceLoader(new ExternalContextResourceLoader("/resources"),
this),
+                        new GZIPResourceLoader(new ClassLoaderResourceLoader("META-INF/resources"),
this)
+                };
+            }
+            else
+            {
                 _resourceLoaders = new ResourceLoader[] {
                         new ExternalContextResourceLoader("/resources"),
                         new ClassLoaderResourceLoader("META-INF/resources")
                 };
-            //}
+            }
         }
         return _resourceLoaders;
     }
+    
+    
+    /**
+     * Checks if the user agent supports GZIP compression on basis of the "Accept-Encoding"
header field. 
+     * Created according to RFC2616, section 14.3 Accept-Encoding.
+     *
+     * Some examples of Accept-Encoding:
+     *
+     *     Accept-Encoding: gzip, deflate
+     *     Accept-Encoding:
+     *     Accept-Encoding: *
+     *     Accept-Encoding: compress;q=0.5, gzip;q=1.0
+     *     Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0 
+     *
+     * @param acceptEncodingHeader
+     * @return
+     */
+    private static boolean isGZIPEncodingAccepted(String acceptEncodingHeader)
+    {
+        int gzipIndex = acceptEncodingHeader.indexOf("gzip");
+        if (gzipIndex != -1)
+        {
+            // "gzip" appears in the header
+            // --> check if banned via q=0
+            return !isEncodingQValueZero(acceptEncodingHeader, gzipIndex);
+        }
 
+        // no "gzip" in header --> check for "*"
+        int starIndex = acceptEncodingHeader.indexOf('*');
+        if (starIndex != -1)
+        {
+            // "*" appears in the header
+            // --> check if banned via q=0
+            return !isEncodingQValueZero(acceptEncodingHeader, starIndex);
+        }
+
+        // neither "gzip" nor "*" in header
+        return false;
+    }
+
+    private static boolean isEncodingQValueZero(String acceptEncodingHeader, int startIndex)
+    {
+        // remove any precending definitions
+        String encodingSubstring = acceptEncodingHeader.substring(startIndex);
+
+        // remove any subsequent definitions (separated via ,)
+        int commaIndex = encodingSubstring.indexOf(',');
+        if (commaIndex != -1)
+        {
+            encodingSubstring = encodingSubstring.substring(0, commaIndex);
+        }
+
+        int qZeroIndex = encodingSubstring.indexOf("q=0");
+        if (qZeroIndex != -1)
+        {
+            String qZeroSubstring = encodingSubstring.substring(qZeroIndex).trim();
+            if (qZeroSubstring.matches("q=0(\\.(0){0,3})?"))
+            {
+                // "q=0" or "q=0." or "q=0.0" or "q=0.00" or "q=0.000" found
+                // NOTE that there MUST NOT be more than 3 digits after the decimal point
(per RFC section 3.9)
+                return true;
+            }
+            else
+            {
+                // q=0.xyz" found with any of xyz being != 0
+                return false;
+            }
+        }
+        else
+        {
+            // "q=0" not found
+            return false;
+        }
+    }
 }

Modified: myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedResourceHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedResourceHandlerImpl.java?rev=1138272&r1=1138271&r2=1138272&view=diff
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedResourceHandlerImpl.java
(original)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedResourceHandlerImpl.java
Wed Jun 22 01:26:26 2011
@@ -21,15 +21,16 @@ package org.apache.myfaces.commons.resou
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.net.URL;
 import java.util.Locale;
 import java.util.Map;
 import java.util.MissingResourceException;
 import java.util.ResourceBundle;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import java.util.zip.GZIPOutputStream;
 
 import javax.faces.FacesException;
+import javax.faces.application.ProjectStage;
 import javax.faces.application.Resource;
 import javax.faces.application.ResourceHandler;
 import javax.faces.application.ResourceHandlerWrapper;
@@ -43,7 +44,6 @@ import org.apache.myfaces.commons.resour
 import org.apache.myfaces.commons.resourcehandler.filter.ExtendedResourceHandlerFilter;
 import org.apache.myfaces.commons.resourcehandler.resource.ResourceHandlerCache;
 import org.apache.myfaces.commons.resourcehandler.resource.ResourceHandlerCache.ResourceValue;
-import org.apache.myfaces.commons.resourcehandler.resource.ResourceHandlerSupport;
 import org.apache.myfaces.commons.resourcehandler.resource.ResourceLoader;
 import org.apache.myfaces.commons.resourcehandler.resource.ResourceMeta;
 import org.apache.myfaces.commons.util.ClassUtils;
@@ -63,7 +63,7 @@ public class ExtendedResourceHandlerImpl
     
     private static final String RESOURCE_LOCALE = "org.apache.myfaces.commons.RESOURCE_LOCALE";
 
-    private ResourceHandlerSupport _resourceHandlerSupport;
+    private ExtendedDefaultResourceHandlerSupport _resourceHandlerSupport;
 
     private ResourceHandlerCache _resourceHandlerCache;
 
@@ -231,8 +231,7 @@ public class ExtendedResourceHandlerImpl
 
             if (resourceId != null)
             {
-                URL url = resourceLoader.getResourceURL(resourceId);
-                if (url == null)
+                if (!resourceLoader.resourceExists(resourceId))
                 {
                     resourceId = null;
                 }
@@ -281,8 +280,7 @@ public class ExtendedResourceHandlerImpl
 
             if (resourceId != null)
             {
-                URL url = resourceLoader.getResourceURL(resourceId);
-                if (url == null)
+                if (!resourceLoader.resourceExists(resourceId))
                 {
                     resourceId = null;
                 }
@@ -436,29 +434,65 @@ public class ExtendedResourceHandlerImpl
             {
                 httpServletResponse.setHeader(entry.getKey(), entry.getValue());
             }
-    
+            
             //serve up the bytes (taken from trinidad ResourceServlet)
             try
             {
-                InputStream in = resource.getInputStream();
-                OutputStream out = httpServletResponse.getOutputStream();
-                byte[] buffer = new byte[_BUFFER_SIZE];
-    
-                try
-                {
-                    int count = pipeBytes(in, out, buffer);
-                    //set the content lenght
-                    httpServletResponse.setContentLength(count);
+                // we should serve a compressed version of the resource, if
+                //   - ProjectStage != Development
+                //   - a compressed version is available (created in constructor)
+                //   - the user agent supports compresssion
+                // and if there is no caching on disk, do compression here!
+                if (!facesContext.isProjectStage(ProjectStage.Development) &&
+                    getResourceHandlerSupport().isGzipResourcesEnabled() && 
+                    !getResourceHandlerSupport().isCacheDiskGzipResources() && 
+                    getResourceHandlerSupport().userAgentSupportsCompression(facesContext)
&& 
+                    getResourceHandlerSupport().isCompressable(resource))
+                {
+                    InputStream in = resource.getInputStream();
+                    OutputStream out = new GZIPOutputStream(httpServletResponse.getOutputStream(),
_BUFFER_SIZE);
+                    byte[] buffer = new byte[_BUFFER_SIZE];
+        
+                    try
+                    {
+                        int count = pipeBytes(in, out, buffer);
+                        //set the content lenght
+                        httpServletResponse.setContentLength(count);
+                    }
+                    finally
+                    {
+                        try
+                        {
+                            in.close();
+                        }
+                        finally
+                        {
+                            out.close();
+                        }
+                    }
                 }
-                finally
+                else
                 {
+                    InputStream in = resource.getInputStream();
+                    OutputStream out = httpServletResponse.getOutputStream();
+                    byte[] buffer = new byte[_BUFFER_SIZE];
+        
                     try
                     {
-                        in.close();
+                        int count = pipeBytes(in, out, buffer);
+                        //set the content lenght
+                        httpServletResponse.setContentLength(count);
                     }
                     finally
                     {
-                        out.close();
+                        try
+                        {
+                            in.close();
+                        }
+                        finally
+                        {
+                            out.close();
+                        }
                     }
                 }
             }
@@ -644,7 +678,7 @@ public class ExtendedResourceHandlerImpl
      *            the resourceHandlerSupport to set
      */
     public void setResourceHandlerSupport(
-            ResourceHandlerSupport resourceHandlerSupport)
+            ExtendedDefaultResourceHandlerSupport resourceHandlerSupport)
     {
         _resourceHandlerSupport = resourceHandlerSupport;
     }
@@ -652,7 +686,7 @@ public class ExtendedResourceHandlerImpl
     /**
      * @return the resourceHandlerSupport
      */
-    protected ResourceHandlerSupport getResourceHandlerSupport()
+    protected ExtendedDefaultResourceHandlerSupport getResourceHandlerSupport()
     {
         if (_resourceHandlerSupport == null)
         {

Modified: myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedResourceImpl.java
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedResourceImpl.java?rev=1138272&r1=1138271&r2=1138272&view=diff
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedResourceImpl.java
(original)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/ExtendedResourceImpl.java
Wed Jun 22 01:26:26 2011
@@ -18,10 +18,13 @@
  */
 package org.apache.myfaces.commons.resourcehandler;
 
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Map;
+
 import javax.faces.application.ResourceHandler;
 import javax.faces.context.FacesContext;
 
-import org.apache.myfaces.commons.resourcehandler.resource.ResourceHandlerSupport;
 import org.apache.myfaces.commons.resourcehandler.resource.ResourceImpl;
 import org.apache.myfaces.commons.resourcehandler.resource.ResourceLoader;
 import org.apache.myfaces.commons.resourcehandler.resource.ResourceMeta;
@@ -36,7 +39,7 @@ public class ExtendedResourceImpl extend
     private String _expectedLocalePrefix;
 
     public ExtendedResourceImpl(ResourceMeta resourceMeta,
-            ResourceLoader resourceLoader, ResourceHandlerSupport support,
+            ResourceLoader resourceLoader, ExtendedDefaultResourceHandlerSupport support,
             String contentType, String expectedLocalePrefix)
     {
         super(resourceMeta, resourceLoader, support, contentType);
@@ -54,7 +57,7 @@ public class ExtendedResourceImpl extend
         if (localePrefix == null)
         {
             // calculate current localePrefix (could be different from the one requested,
e.g. on locale change)
-            localePrefix = ResourceUtils.getRequestLocalePrefix();
+            localePrefix = getRequestLocalePrefix();
         }
         String path = null;
         if (!getResourceHandlerSupport().isExtensionMapping())
@@ -75,4 +78,64 @@ public class ExtendedResourceImpl extend
         FacesContext facesContext = FacesContext.getCurrentInstance();
         return facesContext.getApplication().getViewHandler().getResourceURL(facesContext,
path);
     }
+
+    protected ExtendedDefaultResourceHandlerSupport getExtendedDefaultResourceHandlerSupport()
+    {
+        return (ExtendedDefaultResourceHandlerSupport) getResourceHandlerSupport();
+    }
+    
+    @Override
+    public Map<String, String> getResponseHeaders()
+    {
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        
+        if (facesContext.getApplication().getResourceHandler().isResourceRequest(facesContext))
+        {
+            Map<String, String> headers = super.getResponseHeaders();
+            
+            if (getExtendedDefaultResourceHandlerSupport().isGzipResourcesEnabled() &&

+                getExtendedDefaultResourceHandlerSupport().userAgentSupportsCompression(facesContext)
&& 
+                getExtendedDefaultResourceHandlerSupport().isCompressable(this))
+                {
+                    headers.put("Content-Encoding", "gzip");
+                }
+            
+            return headers; 
+        }
+        else
+        {
+            //No need to return headers 
+            return Collections.emptyMap();
+        }
+    }
+    
+    /**
+     * Returns the String representation of the current locale for the use in the request
path.
+     *
+     * @return
+     */
+    private static String getRequestLocalePrefix()
+    {
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        Locale locale = facesContext.getViewRoot().getLocale();
+        if (locale == null)
+        {
+            // fallback to default locale
+            locale = Locale.getDefault();
+        }
+        
+        String language = locale.getLanguage();
+        String country = locale.getCountry();
+        
+        if (country != null)
+        {
+            // de_AT
+            return language + "_" + country;
+        }
+        else
+        {
+            // de
+            return language;
+        }
+    }    
 }

Added: myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/GZIPResourceLoader.java
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/GZIPResourceLoader.java?rev=1138272&view=auto
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/GZIPResourceLoader.java
(added)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/GZIPResourceLoader.java
Wed Jun 22 01:26:26 2011
@@ -0,0 +1,308 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.commons.resourcehandler;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.zip.GZIPOutputStream;
+
+import javax.faces.FacesException;
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.commons.resourcehandler.resource.ResourceLoader;
+import org.apache.myfaces.commons.resourcehandler.resource.ResourceLoaderWrapper;
+import org.apache.myfaces.commons.resourcehandler.resource.ResourceMeta;
+
+/**
+ * 
+ * @author Leonardo Uribe
+ * @author Jakob Korherr
+ *
+ */
+public class GZIPResourceLoader extends ResourceLoaderWrapper
+{
+    
+    public final static String COMPRESSED_FILES_MAP = "oam.commons.COMPRESSED_FILES_MAP";
+    
+    /**
+     * Subdir of the ServletContext tmp dir to store compressed resources.
+     */
+    private static final String COMPRESSION_BASE_DIR = "oam-resourcehandler-cache/";
+
+    /**
+     * Suffix for compressed files.
+     */
+    private static final String COMPRESSED_FILE_SUFFIX = ".gzip";
+    
+    /**
+     * Size of the byte array buffer.
+     */
+    private static final int BUFFER_SIZE = 2048;
+    
+    private ResourceLoader delegate;
+    
+    private volatile File _tempDir;
+    
+    private final ExtendedDefaultResourceHandlerSupport _extendedDefaultResourceHandlerSupport;
+    
+    public GZIPResourceLoader(ResourceLoader delegate, ExtendedDefaultResourceHandlerSupport
extendedDefaultResourceHandlerSupport)
+    {
+        this.delegate = delegate;
+        _extendedDefaultResourceHandlerSupport = extendedDefaultResourceHandlerSupport;
+        initialize();
+    }
+    
+    protected void initialize()
+    {
+        //Get startup FacesContext
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+    
+        //1. Create temporal directory for compressed resources
+        Map<String, Object> applicationMap = facesContext.getExternalContext().getApplicationMap();
+        File tempdir = (File) applicationMap.get("javax.servlet.context.tempdir");
+        File imagesDir = new File(tempdir, COMPRESSION_BASE_DIR);
+        if (!imagesDir.exists())
+        {
+            imagesDir.mkdirs();
+        }
+        _tempDir = imagesDir;
+
+        //2. Create map for register compressed resources
+        Map<String, FileProducer> compressedFilesMap = new ConcurrentHashMap<String,
FileProducer>();
+        facesContext.getExternalContext().getApplicationMap().put(COMPRESSED_FILES_MAP, compressedFilesMap);
+    }    
+    
+    @Override
+    public URL getResourceURL(ResourceMeta resourceMeta)
+    {
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+
+        if (!_extendedDefaultResourceHandlerSupport.isCompressable(resourceMeta) || !_extendedDefaultResourceHandlerSupport.userAgentSupportsCompression(facesContext))
+        {
+            return super.getResourceURL(resourceMeta);
+        }
+        
+        if (resourceExists(resourceMeta))
+        {
+            File file = createOrGetCompressedFile(facesContext, resourceMeta);
+            
+            try
+            {
+                return file.toURL();
+            }
+            catch (MalformedURLException e)
+            {
+                throw new FacesException(e);
+            }
+        }
+        else
+        {
+            return null;
+        }
+    }    
+    
+    @Override
+    public InputStream getResourceInputStream(ResourceMeta resourceMeta)
+    {
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+
+        if (!_extendedDefaultResourceHandlerSupport.isCompressable(resourceMeta) || !_extendedDefaultResourceHandlerSupport.userAgentSupportsCompression(facesContext))
+        {
+            return super.getResourceInputStream(resourceMeta);
+        }
+            
+        if (resourceExists(resourceMeta))
+        {
+            File file = createOrGetCompressedFile(facesContext, resourceMeta);
+            
+            try
+            {
+                return new BufferedInputStream(new FileInputStream(file));
+            }
+            catch (FileNotFoundException e)
+            {
+                throw new FacesException(e);
+            }
+        }
+        else
+        {
+            return null;
+        }
+    }
+    
+    @Override
+    public boolean resourceExists(ResourceMeta resourceMeta)
+    {
+        return super.resourceExists(resourceMeta);
+    }
+
+    @SuppressWarnings("unchecked")
+    private File createOrGetCompressedFile(FacesContext facesContext, ResourceMeta resourceMeta)
+    {
+        String identifier = resourceMeta.toString();
+        File file = getCompressedFile(resourceMeta);
+        if (!file.exists())
+        {
+            Map<String, FileProducer> map = (Map<String, FileProducer>) 
+                facesContext.getExternalContext().getApplicationMap().get(COMPRESSED_FILES_MAP);
+
+            FileProducer creator = map.get(identifier);
+            
+            if (creator == null)
+            {
+                synchronized(this)
+                {
+                    creator = map.get(identifier);
+                    
+                    if (creator == null)
+                    {
+                        creator = new FileProducer();
+                        map.put(identifier, creator);
+                    }
+                }
+            }
+            
+            if (!creator.isCreated())
+            {
+                creator.createFile(facesContext, resourceMeta, file, this);
+            }
+        }
+        return file;
+    }    
+    
+    private File getCompressedFile(ResourceMeta resourceMeta)
+    {
+        return new File(_tempDir, COMPRESSION_BASE_DIR + resourceMeta.toString() + COMPRESSED_FILE_SUFFIX);
+    }
+
+    /**
+     * Uses GZIPOutputStream to compress this resource.
+     * It will be stored where getCompressedFile() points to.
+     *
+     * Note that the resource really must be compressable (isCompressable() must return true).
+     *
+     * @return
+     */
+    protected void createCompressedFileVersion(FacesContext facesContext, ResourceMeta resourceMeta,
File target)
+    {
+        //File target = getCompressedFile(resourceMeta);
+        target.mkdirs();  // ensure necessary directories exist
+        target.delete();  // remove any existing file
+
+        InputStream inputStream = null;
+        FileOutputStream fileOutputStream;
+        GZIPOutputStream gzipOutputStream = null;
+        try
+        {
+            inputStream = getWrapped().getResourceInputStream(resourceMeta);
+            fileOutputStream = new FileOutputStream(target);
+            gzipOutputStream = new GZIPOutputStream(fileOutputStream);
+            byte[] buffer = new byte[BUFFER_SIZE];
+
+            pipeBytes(inputStream, gzipOutputStream, buffer);
+        }
+        catch (FileNotFoundException e)
+        {
+            throw new FacesException("Unexpected exception while create file:", e);
+        }
+        catch (IOException e)
+        {
+            throw new FacesException("Unexpected exception while create file:", e);
+        }
+        finally
+        {
+            if (inputStream != null)
+            {
+                try
+                {
+                    inputStream.close();
+                }
+                catch (IOException e)
+                {
+                    // Ignore
+                }
+            }
+            if (gzipOutputStream != null)
+            {
+                // also closes fileOutputStream   
+                try
+                {
+                    gzipOutputStream.close();
+                }
+                catch (IOException e)
+                {
+                    // Ignore
+                }
+            }
+        }
+    }
+    
+    /**
+     * Reads the specified input stream into the provided byte array storage and
+     * writes it to the output stream.
+     */
+    private static void pipeBytes(InputStream in, OutputStream out, byte[] buffer) throws
IOException
+    {
+        int length;
+
+        while ((length = (in.read(buffer))) >= 0)
+        {
+            out.write(buffer, 0, length);
+        }
+    }
+    
+    public static class FileProducer {
+        
+        public volatile boolean created = false;
+        
+        public FileProducer()
+        {
+            super();
+        }
+
+        public boolean isCreated()
+        {
+            return created;
+        }
+
+        public synchronized void createFile(FacesContext facesContext, ResourceMeta resourceMeta,
File file, GZIPResourceLoader loader)
+        {
+            if (!created)
+            {
+                loader.createCompressedFileVersion(facesContext, resourceMeta, file);
+                created = true;
+            }
+        }
+    }
+    
+    public ResourceLoader getWrapped()
+    {
+        return delegate;
+    }
+}

Modified: myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/config/AdvancedResourceHandlerConfig.java
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/config/AdvancedResourceHandlerConfig.java?rev=1138272&r1=1138271&r2=1138272&view=diff
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/config/AdvancedResourceHandlerConfig.java
(original)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/config/AdvancedResourceHandlerConfig.java
Wed Jun 22 01:26:26 2011
@@ -18,8 +18,6 @@
  */
 package org.apache.myfaces.commons.resourcehandler.config;
 
-import org.apache.myfaces.commons.resourcehandler.ResourceUtils;
-
 import java.util.Collection;
 import java.util.HashSet;
 
@@ -59,7 +57,44 @@ public class AdvancedResourceHandlerConf
      */
     public boolean isAdvancedLibrary(String library)
     {
-        return libraries.contains(ResourceUtils.trimSlashes(library));
+        return libraries.contains(trimSlashes(library));
     }
 
+    /**
+     * Removes leading and trailing slashes (= '/') from the given String.
+     *
+     * @param s
+     * @return
+     */
+    private static String trimSlashes(String s)
+    {
+        if (s != null)
+        {
+            // remove at begin
+            int index = 0;
+            int startIndex = index;
+            while (s.charAt(index) == '/')
+            {
+                index++;
+            }
+            if (index != startIndex)
+            {
+                s = s.substring(index);
+            }
+
+            // remove at end
+            index = s.length() - 1;
+            startIndex = index;
+            while (s.charAt(index) == '/')
+            {
+                index--;
+            }
+            if (index != startIndex)
+            {
+                s = s.substring(0, index + 1);
+            }
+        }
+
+        return s;
+    }
 }

Modified: myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/config/AdvancedResourceHandlerConfigParser.java
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/config/AdvancedResourceHandlerConfigParser.java?rev=1138272&r1=1138271&r2=1138272&view=diff
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/config/AdvancedResourceHandlerConfigParser.java
(original)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/config/AdvancedResourceHandlerConfigParser.java
Wed Jun 22 01:26:26 2011
@@ -32,7 +32,7 @@ import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
 import org.apache.myfaces.commons.resourcehandler.AdvancedResourceHandler;
-import org.apache.myfaces.commons.resourcehandler.ResourceUtils;
+import org.apache.myfaces.commons.util.ClassUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
 import org.xml.sax.Locator;
@@ -51,7 +51,7 @@ public class AdvancedResourceHandlerConf
 
     public void parse(AdvancedResourceHandlerConfig config)
     {
-        ClassLoader classLoader = ResourceUtils.getContextClassLoader();
+        ClassLoader classLoader = ClassUtils.getContextClassLoader();
         Enumeration<URL> configUrls = null;
 
         try

Modified: myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/resource/ResourceLoader.java
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/resource/ResourceLoader.java?rev=1138272&r1=1138271&r2=1138272&view=diff
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/resource/ResourceLoader.java
(original)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/resource/ResourceLoader.java
Wed Jun 22 01:26:26 2011
@@ -62,6 +62,11 @@ public abstract class ResourceLoader
     
     public abstract boolean libraryExists(String libraryName);
     
+    public boolean resourceExists(ResourceMeta resourceMeta)
+    {
+        return (getResourceURL(resourceMeta) != null);
+    }
+    
     private Comparator<String> _versionComparator = null;
 
     protected Comparator<String> getVersionComparator()

Added: myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/resource/ResourceLoaderWrapper.java
URL: http://svn.apache.org/viewvc/myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/resource/ResourceLoaderWrapper.java?rev=1138272&view=auto
==============================================================================
--- myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/resource/ResourceLoaderWrapper.java
(added)
+++ myfaces/commons/branches/jsf_20/myfaces-commons-resourcehandler/src/main/java/org/apache/myfaces/commons/resourcehandler/resource/ResourceLoaderWrapper.java
Wed Jun 22 01:26:26 2011
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.commons.resourcehandler.resource;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Comparator;
+
+import javax.faces.FacesWrapper;
+
+/**
+ * 
+ * @author Leonardo Uribe
+ *
+ */
+public abstract class ResourceLoaderWrapper extends ResourceLoader implements FacesWrapper<ResourceLoader>
+{
+    
+    public ResourceLoaderWrapper()
+    {
+        super(null);
+    }
+
+    public String getResourceVersion(String path)
+    {
+        return getWrapped().getResourceVersion(path);
+    }
+
+    public String getLibraryVersion(String path)
+    {
+        return getWrapped().getLibraryVersion(path);
+    }
+
+    public URL getResourceURL(ResourceMeta resourceMeta)
+    {
+        return getWrapped().getResourceURL(resourceMeta);
+    }
+
+    public InputStream getResourceInputStream(ResourceMeta resourceMeta)
+    {
+        return getWrapped().getResourceInputStream(resourceMeta);
+    }
+
+    public ResourceMeta createResourceMeta(String prefix, String libraryName,
+            String libraryVersion, String resourceName, String resourceVersion)
+    {
+        return getWrapped().createResourceMeta(prefix, libraryName, libraryVersion,
+                resourceName, resourceVersion);
+    }
+
+    public boolean libraryExists(String libraryName)
+    {
+        return getWrapped().libraryExists(libraryName);
+    }
+
+    public String getPrefix()
+    {
+        return getWrapped().getPrefix();
+    }
+
+    public void setPrefix(String prefix)
+    {
+        getWrapped().setPrefix(prefix);
+    }
+
+    @Override
+    public boolean resourceExists(ResourceMeta resourceMeta)
+    {
+        return getWrapped().resourceExists(resourceMeta);
+    }
+
+    @Override
+    protected Comparator<String> getVersionComparator()
+    {
+        return getWrapped().getVersionComparator();
+    }
+
+    @Override
+    protected void setVersionComparator(Comparator<String> versionComparator)
+    {
+        getWrapped().setVersionComparator(versionComparator);
+    }
+    
+}



Mime
View raw message