You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2011/06/22 03:26:26 UTC
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...
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);
+ }
+
+}