You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by we...@apache.org on 2012/03/09 10:06:05 UTC

svn commit: r1298758 [1/2] - /myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/

Author: werpu
Date: Fri Mar  9 09:06:05 2012
New Revision: 1298758

URL: http://svn.apache.org/viewvc?rev=1298758&view=rev
Log:
EXTSCRIPT-154: Code Rewrite/Refactoring, adding the resource handlers, we don´t do anything with those in this rewrite, maybe in the next one we will patch facelets in the impl directly to handle that.

Added:
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/AliasResourceMetaImpl.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/BaseResourceHandlerSupport.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ClassLoaderResourceLoader.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ExternalContextResourceLoader.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/FacesServletMapping.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerCache.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerImpl.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerSupport.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceImpl.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceLoader.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceLoaderUtils.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceMeta.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceMetaImpl.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/SourceResourceHandler.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/SourceResourceHandlerSupport.java
    myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/SourceResourceLoader.java

Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/AliasResourceMetaImpl.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/AliasResourceMetaImpl.java?rev=1298758&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/AliasResourceMetaImpl.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/AliasResourceMetaImpl.java Fri Mar  9 09:06:05 2012
@@ -0,0 +1,96 @@
+/*
+ * 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 rewrite.org.apache.myfaces.extensions.scripting.jsf.resources;
+
+/**
+ * Contains the metadata information to reference a resource 
+ * 
+ * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
+ * @version $Revision: 700544 $ $Date: 2008-09-30 13:44:02 -0500 (Mar, 30 Sep 2008) $
+ */
+public class AliasResourceMetaImpl extends ResourceMetaImpl
+{
+    private String _realResourceName;
+    
+    private boolean _couldContainValueExpressions;
+
+    public AliasResourceMetaImpl(String prefix, String libraryName, String libraryVersion,
+            String resourceName, String resourceVersion, String realResourceName, boolean couldContainValueExpressions)
+    {
+        super(prefix, libraryName, libraryVersion,
+            resourceName, resourceVersion);
+        _realResourceName = realResourceName;
+        _couldContainValueExpressions = couldContainValueExpressions;
+    }
+    
+    public String getRealResourceName()
+    {
+        return _realResourceName;
+    }
+
+    public void setRealResourceName(String realResourceName)
+    {
+        _realResourceName = realResourceName;
+    }
+    
+    @Override
+    public String getResourceIdentifier()
+    {
+        StringBuilder builder = new StringBuilder();
+        boolean firstSlashAdded = false;
+        if (getLocalePrefix() != null && getLocalePrefix().length() > 0)
+        {
+            builder.append(getLocalePrefix());
+            firstSlashAdded = true;
+        }
+        if (getLibraryName() != null)
+        {
+            if (firstSlashAdded) builder.append('/');
+            builder.append(getLibraryName());
+            firstSlashAdded = true;
+        }
+        if (getLibraryVersion() != null)
+        {
+            if (firstSlashAdded) builder.append('/');
+            builder.append(getLibraryVersion());
+            firstSlashAdded = true;
+        }
+        if (getRealResourceName() != null)
+        {
+            if (firstSlashAdded) builder.append('/');
+            builder.append(getRealResourceName());
+            firstSlashAdded = true;
+        }
+        if (getResourceVersion() != null)
+        {
+            if (firstSlashAdded) builder.append('/');
+            builder.append(getResourceVersion());
+            builder.append(
+                    getRealResourceName().substring(getRealResourceName().lastIndexOf('.')));
+            firstSlashAdded = true;
+        }
+        return builder.toString();
+    }
+
+    @Override
+    public boolean couldResourceContainValueExpressions()
+    {
+        return _couldContainValueExpressions;
+    }
+}

Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/BaseResourceHandlerSupport.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/BaseResourceHandlerSupport.java?rev=1298758&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/BaseResourceHandlerSupport.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/BaseResourceHandlerSupport.java Fri Mar  9 09:06:05 2012
@@ -0,0 +1,236 @@
+/*
+ * 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 rewrite.org.apache.myfaces.extensions.scripting.jsf.resources;
+
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import java.util.Map;
+
+/**
+ * A ResourceHandlerSupport implementation for use with standard Java Servlet engines,
+ * ie an engine that supports javax.servlet, and uses a standard web.xml file.
+ * 
+ * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
+ * @version $Revision: 946779 $ $Date: 2010-05-20 15:31:42 -0500 (Jue, 20 May 2010) $
+ */
+public class BaseResourceHandlerSupport extends ResourceHandlerSupport
+{
+
+    /**
+     * Set the max time in miliseconds set on the "Expires" header for a resource.
+     * (default to one week in miliseconds or 604800000) 
+     */
+    public static final String RESOURCE_MAX_TIME_EXPIRES = "org.apache.myfaces.RESOURCE_MAX_TIME_EXPIRES";
+
+    /**
+     * Identifies the FacesServlet mapping in the current request map.
+     */
+    private static final String CACHED_SERVLET_MAPPING =
+        BaseResourceHandlerSupport.class.getName() + ".CACHED_SERVLET_MAPPING";
+    
+    private Long _startupTime;
+    
+    private Long _maxTimeExpires;
+        
+    public BaseResourceHandlerSupport()
+    {
+        _startupTime = System.currentTimeMillis();
+    }
+    
+    public ResourceLoader[] getResourceLoaders()
+    {
+        return null;
+    }
+
+    public String calculateResourceBasePath(FacesContext facesContext)
+    {        
+        FacesServletMapping mapping = getFacesServletMapping(facesContext);
+        ExternalContext externalContext = facesContext.getExternalContext();      
+        
+        if (mapping != null)
+        {
+            String resourceBasePath = null;
+            if (mapping.isExtensionMapping())
+            {
+                // Mapping using a suffix. In this case we have to strip 
+                // the suffix. If we have a url like:
+                // http://localhost:8080/testjsf20/javax.faces.resource/imagen.jpg.jsf?ln=dojo
+                // 
+                // The servlet path is /javax.faces.resource/imagen.jpg.jsf
+                //
+                // For obtain the resource name we have to remove the .jsf suffix and 
+                // the prefix ResourceHandler.RESOURCE_IDENTIFIER
+                resourceBasePath = externalContext.getRequestServletPath();
+                int stripPoint = resourceBasePath.lastIndexOf('.');
+                if (stripPoint > 0)
+                {
+                    resourceBasePath = resourceBasePath.substring(0, stripPoint);
+                }
+            }
+            else
+            {
+                // Mapping using prefix. In this case we have to strip 
+                // the prefix used for mapping. If we have a url like:
+                // http://localhost:8080/testjsf20/faces/javax.faces.resource/imagen.jpg?ln=dojo
+                //
+                // The servlet path is /faces
+                // and the path info is /javax.faces.resource/imagen.jpg
+                //
+                // For obtain the resource name we have to remove the /faces prefix and 
+                // then the prefix ResourceHandler.RESOURCE_IDENTIFIER
+                resourceBasePath = externalContext.getRequestPathInfo();
+            }
+            return resourceBasePath;            
+        }
+        else
+        {
+            //If no mapping is detected, just return the
+            //information follows the servlet path but before
+            //the query string
+            return externalContext.getRequestPathInfo();
+        }
+    }
+
+    public boolean isExtensionMapping()
+    {
+        FacesServletMapping mapping = getFacesServletMapping(
+                FacesContext.getCurrentInstance());
+        if (mapping != null)
+        {
+            if (mapping.isExtensionMapping())
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    public String getMapping()
+    {
+        FacesServletMapping mapping = getFacesServletMapping(
+                FacesContext.getCurrentInstance());
+        if (mapping != null)
+        {
+            if (mapping.isExtensionMapping())
+            {
+                return mapping.getExtension();
+            }
+            else
+            {
+                return mapping.getPrefix();
+            }
+        }
+        return "";
+    }
+
+    /**
+     * Read the web.xml file that is in the classpath and parse its internals to
+     * figure out how the FacesServlet is mapped for the current webapp.
+     */
+    protected FacesServletMapping getFacesServletMapping(FacesContext context)
+    {
+        Map<Object, Object> attributes = context.getAttributes();
+
+        // Has the mapping already been determined during this request?
+        FacesServletMapping mapping = (FacesServletMapping) attributes.get(CACHED_SERVLET_MAPPING);
+        if (mapping == null)
+        {
+            ExternalContext externalContext = context.getExternalContext();
+            mapping = calculateFacesServletMapping(externalContext.getRequestServletPath(),
+                    externalContext.getRequestPathInfo());
+
+            attributes.put(CACHED_SERVLET_MAPPING, mapping);
+        }
+        return mapping;
+    }
+
+    /**
+     * Determines the mapping of the FacesServlet in the web.xml configuration
+     * file. However, there is no need to actually parse this configuration file
+     * as runtime information is sufficient.
+     *
+     * @param servletPath The servletPath of the current request
+     * @param pathInfo    The pathInfo of the current request
+     * @return the mapping of the FacesServlet in the web.xml configuration file
+     */
+    protected static FacesServletMapping calculateFacesServletMapping(
+        String servletPath, String pathInfo)
+    {
+        if (pathInfo != null)
+        {
+            // If there is a "extra path", it's definitely no extension mapping.
+            // Now we just have to determine the path which has been specified
+            // in the url-pattern, but that's easy as it's the same as the
+            // current servletPath. It doesn't even matter if "/*" has been used
+            // as in this case the servletPath is just an empty string according
+            // to the Servlet Specification (SRV 4.4).
+            return FacesServletMapping.createPrefixMapping(servletPath);
+        }
+        else
+        {
+            // In the case of extension mapping, no "extra path" is available.
+            // Still it's possible that prefix-based mapping has been used.
+            // Actually, if there was an exact match no "extra path"
+            // is available (e.g. if the url-pattern is "/faces/*"
+            // and the request-uri is "/context/faces").
+            int slashPos = servletPath.lastIndexOf('/');
+            int extensionPos = servletPath.lastIndexOf('.');
+            if (extensionPos > -1 && extensionPos > slashPos)
+            {
+                String extension = servletPath.substring(extensionPos);
+                return FacesServletMapping.createExtensionMapping(extension);
+            }
+            else
+            {
+                // There is no extension in the given servletPath and therefore
+                // we assume that it's an exact match using prefix-based mapping.
+                return FacesServletMapping.createPrefixMapping(servletPath);
+            }
+        }
+    }
+
+    public long getStartupTime()
+    {
+        return _startupTime;
+    }
+    
+    public long getMaxTimeExpires()
+    {
+        if (_maxTimeExpires == null)
+        {
+            String time = FacesContext.getCurrentInstance().getExternalContext().getInitParameter(RESOURCE_MAX_TIME_EXPIRES);
+            if (time != null && time.length() > 0)
+            {
+                try
+                {
+                    _maxTimeExpires = Long.parseLong(time);
+                }
+                catch (NumberFormatException e)
+                {
+                    _maxTimeExpires = 604800000L;
+                }
+            }
+            else
+            {
+                _maxTimeExpires = 604800000L;
+            }
+        }
+        return _maxTimeExpires;
+    }
+}

Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ClassLoaderResourceLoader.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ClassLoaderResourceLoader.java?rev=1298758&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ClassLoaderResourceLoader.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ClassLoaderResourceLoader.java Fri Mar  9 09:06:05 2012
@@ -0,0 +1,479 @@
+/*
+ * 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 rewrite.org.apache.myfaces.extensions.scripting.jsf.resources;
+
+import org.apache.myfaces.extensions.scripting.core.util.ClassLoaderUtils;
+
+import javax.faces.application.ProjectStage;
+import javax.faces.context.FacesContext;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * A resource loader implementation which loads resources from the thread ClassLoader.
+ * 
+ */
+public class ClassLoaderResourceLoader extends ResourceLoader
+{
+    /**
+     * It checks version like this: 1, 1_0, 1_0_0, 100_100
+     * 
+     * Used on getLibraryVersion to filter resource directories
+     **/
+    //protected static Pattern VERSION_CHECKER = Pattern.compile("\\p{Digit}+(_\\p{Digit}*)*");
+
+    /**
+     * It checks version like this: /1.js, /1_0.js, /1_0_0.js, /100_100.js
+     * 
+     * Used on getResourceVersion to filter resources
+     **/
+    //protected static Pattern RESOURCE_VERSION_CHECKER = Pattern.compile("/\\p{Digit}+(_\\p{Digit}*)*\\..*");
+
+    /*
+    private FileFilter _libraryFileFilter = new FileFilter()
+    {
+        public boolean accept(File pathname)
+        {
+            if (pathname.isDirectory() && VERSION_CHECKER.matcher(pathname.getName()).matches())
+            {
+                return true;
+            }
+            return false;
+        }
+    };*/
+
+    /*
+    private FileFilter _resourceFileFilter = new FileFilter()
+    {
+        public boolean accept(File pathname)
+        {
+            if (pathname.isDirectory() && RESOURCE_VERSION_CHECKER.matcher(pathname.getName()).matches())
+            {
+                return true;
+            }
+            return false;
+        }
+    };*/
+    
+    private final boolean _developmentStage;
+
+    public ClassLoaderResourceLoader(String prefix)
+    {
+        super(prefix);
+        _developmentStage = FacesContext.getCurrentInstance().isProjectStage(ProjectStage.Development);
+    }
+
+    @Override
+    public String getLibraryVersion(String path)
+    {
+        return null;
+        /*
+        String libraryVersion = null;
+        if (getPrefix() != null)
+            path = getPrefix() + '/' + path;
+
+        URL url = getClassLoader().getResource(path);
+
+        if (url == null)
+        {
+            // This library does not exists for this
+            // ResourceLoader
+            return null;
+        }
+
+        // The problem here is how to scan the directory. When a ClassLoader
+        // is used two cases could occur
+        // 1. The files are unpacked so we can use Url.toURI and crawl
+        // the directory using the api for files.
+        // 2. The files are packed in a jar. This case is more tricky,
+        // because we only have a URL. Checking the jar api we can use
+        // JarURLConnection (Sounds strange, but the api of
+        // URL.openConnection says that for a jar connection a
+        // JarURLConnection is returned). From this point we can access
+        // to the jar api and solve the algoritm.
+        if (url.getProtocol().equals("file"))
+        {
+            try
+            {
+                File directory = new File(url.toURI());
+                if (directory.isDirectory())
+                {
+                    File[] versions = directory.listFiles(_libraryFileFilter);
+                    for (int i = 0; i < versions.length; i++)
+                    {
+                        String version = versions[i].getName();
+                        if (VERSION_CHECKER.matcher(version).matches())
+                        {
+                            if (libraryVersion == null)
+                            {
+                                libraryVersion = version;
+                            }
+                            else if (getVersionComparator().compare(libraryVersion, version) < 0)
+                            {
+                                libraryVersion = version;
+                            }
+                        }
+                    }
+                }
+            }
+            catch (URISyntaxException e)
+            {
+                // Just return null, because library version cannot be
+                // resolved.
+                Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName()); 
+                if (log.isLoggable(Level.WARNING))
+                {
+                    log.log(Level.WARNING, "url "+url.toString()+" cannot be translated to uri: "+e.getMessage(), e);
+                }
+            }
+        }
+        else if (isJarResourceProtocol(url.getProtocol()))
+        {
+            try
+            {
+                url = getClassLoader().getResource(path + '/');
+
+                if (url != null)
+                {
+                    JarURLConnection conn = (JarURLConnection)url.openConnection();
+                    // See DIGESTER-29 for related problem
+                    conn.setUseCaches(false);
+
+                    try
+                    {
+                        if (conn.getJarEntry().isDirectory())
+                        {
+                            // Unfortunately, we have to scan all entry files
+                            // because there is no proper api to scan it as a
+                            // directory tree.
+                            JarFile file = conn.getJarFile();
+                            for (Enumeration<JarEntry> en = file.entries(); en.hasMoreElements();)
+                            {
+                                JarEntry entry = en.nextElement();
+                                String entryName = entry.getName();
+    
+                                if (entryName.startsWith(path + '/'))
+                                {
+                                    if (entryName.length() == path.length() + 1)
+                                    {
+                                        // the same string, just skip it
+                                        continue;
+                                    }
+    
+                                    if (entryName.charAt(entryName.length() - 1) != '/')
+                                    {
+                                        // Skip files
+                                        continue;
+                                    }
+    
+                                    entryName = entryName.substring(path.length() + 1, entryName.length() - 1);
+    
+                                    if (entryName.indexOf('/') >= 0)
+                                    {
+                                        // Inner Directory
+                                        continue;
+                                    }
+    
+                                    String version = entryName;
+                                    if (VERSION_CHECKER.matcher(version).matches())
+                                    {
+                                        if (libraryVersion == null)
+                                        {
+                                            libraryVersion = version;
+                                        }
+                                        else if (getVersionComparator().compare(libraryVersion, version) < 0)
+                                        {
+                                            libraryVersion = version;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        //See TRINIDAD-73
+                        //just close the input stream again if
+                        //by inspecting the entries the stream
+                        //was let open.
+                        try
+                        {
+                            conn.getInputStream().close();
+                        }
+                        catch (Exception exception)
+                        {
+                            // Ignored
+                        }
+                    }
+                }
+            }
+            catch (IOException e)
+            {
+                // Just return null, because library version cannot be
+                // resolved.
+                Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName()); 
+                if (log.isLoggable(Level.WARNING))
+                {
+                    log.log(Level.WARNING, "IOException when scanning for resource in jar file:", e);
+                }
+            }
+        }
+        return libraryVersion;
+        */
+    }
+
+    @Override
+    public InputStream getResourceInputStream(ResourceMeta resourceMeta)
+    {
+        if (getPrefix() != null && !"".equals(getPrefix()))
+        {
+            return getClassLoader().getResourceAsStream(getPrefix() + '/' + resourceMeta.getResourceIdentifier());
+        }
+        else
+        {
+            return getClassLoader().getResourceAsStream(resourceMeta.getResourceIdentifier());
+        }
+    }
+
+    @Override
+    public URL getResourceURL(ResourceMeta resourceMeta)
+    {
+        if (getPrefix() != null && !"".equals(getPrefix()))
+        {
+            return getClassLoader().getResource(getPrefix() + '/' + resourceMeta.getResourceIdentifier());
+        }
+        else
+        {
+            return getClassLoader().getResource(resourceMeta.getResourceIdentifier());
+        }
+    }
+
+    @Override
+    public String getResourceVersion(String path)
+    {
+        return null;
+        /*
+        String resourceVersion = null;
+
+        if (getPrefix() != null)
+            path = getPrefix() + '/' + path;
+
+        URL url = getClassLoader().getResource(path);
+
+        if (url == null)
+        {
+            // This library does not exists for this
+            // ResourceLoader
+            return null;
+        }
+
+        if (url.getProtocol().equals("file"))
+        {
+            try
+            {
+                File directory = new File(url.toURI());
+                if (directory.isDirectory())
+                {
+                    File[] versions = directory.listFiles(_resourceFileFilter);
+                    for (int i = 0; i < versions.length; i++)
+                    {
+                        String version = versions[i].getName();
+                        if (resourceVersion == null)
+                        {
+                            resourceVersion = version;
+                        }
+                        else if (getVersionComparator().compare(resourceVersion, version) < 0)
+                        {
+                            resourceVersion = version;
+                        }
+                    }
+                    //Since it is a directory and no version found set resourceVersion as invalid
+                    if (resourceVersion == null)
+                    {
+                        resourceVersion = VERSION_INVALID;
+                    }
+                }
+            }
+            catch (URISyntaxException e)
+            {
+                Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName()); 
+                if (log.isLoggable(Level.WARNING))
+                {
+                    log.log(Level.WARNING, "url "+url.toString()+" cannot be translated to uri: "+e.getMessage(), e);
+                }
+            }
+        }
+        else if (isJarResourceProtocol(url.getProtocol()))
+        {
+            try
+            {
+                url = getClassLoader().getResource(path + '/');
+
+                if (url != null)
+                {
+                    JarURLConnection conn = (JarURLConnection)url.openConnection();
+                    // See DIGESTER-29 for related problem
+                    conn.setUseCaches(false);
+
+                    try
+                    {
+                        if (conn.getJarEntry().isDirectory())
+                        {
+                            // Unfortunately, we have to scan all entry files
+                            JarFile file = conn.getJarFile();
+                            for (Enumeration<JarEntry> en = file.entries(); en.hasMoreElements();)
+                            {
+                                JarEntry entry = en.nextElement();
+                                String entryName = entry.getName();
+    
+                                if (entryName.startsWith(path + '/'))
+                                {
+                                    if (entryName.length() == path.length() + 1)
+                                    {
+                                        // the same string, just skip it
+                                        continue;
+                                    }
+        
+                                    entryName = entryName.substring(path.length());
+                                    if (RESOURCE_VERSION_CHECKER.matcher(entryName).matches())
+                                    {
+                                        String version = entryName.substring(1, entryName.lastIndexOf('.'));
+                                        if (resourceVersion == null)
+                                        {
+                                            resourceVersion = version;
+                                        }
+                                        else if (getVersionComparator().compare(resourceVersion, version) < 0)
+                                        {
+                                            resourceVersion = version;
+                                        }
+                                    }
+                                }
+                            }
+                            if (resourceVersion == null)
+                            {
+                                resourceVersion = VERSION_INVALID;
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        //See TRINIDAD-73
+                        //just close the input stream again if
+                        //by inspecting the entries the stream
+                        //was let open.
+                        try
+                        {
+                            conn.getInputStream().close();
+                        }
+                        catch (Exception exception)
+                        {
+                            // Ignored
+                        }
+                    }
+
+                }
+            }
+            catch (IOException e)
+            {
+                // Just return null, because library version cannot be
+                // resolved.
+                Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName()); 
+                if (log.isLoggable(Level.WARNING))
+                {
+                    log.log(Level.WARNING, "IOException when scanning for resource in jar file:", e);
+                }
+            }
+        }
+        return resourceVersion;
+        */
+    }
+
+    @Override
+    public ResourceMeta createResourceMeta(String prefix, String libraryName, String libraryVersion,
+                                           String resourceName, String resourceVersion)
+    {
+        if (_developmentStage && libraryName != null && 
+                ResourceLoaderUtils.JAVAX_FACES_LIBRARY_NAME.equals(libraryName) &&
+                ResourceLoaderUtils.JSF_JS_RESOURCE_NAME.equals(resourceName))
+        {
+            // InternalClassLoaderResourceLoader will serve it, so return null in this case.
+            return null;
+        } else if (_developmentStage && libraryName != null &&
+                ResourceLoaderUtils.MYFACES_LIBRARY_NAME.equals(libraryName) &&
+                ResourceLoaderUtils.MYFACES_JS_RESOURCE_NAME.equals(resourceName)) {
+            // InternalClassLoaderResourceLoader will serve it, so return null in this case.
+             return null;
+        } else
+        {
+            return new ResourceMetaImpl(prefix, libraryName, libraryVersion, resourceName, resourceVersion);
+        }
+    }
+
+    /**
+     * Returns the ClassLoader to use when looking up resources under the top level package. By default, this is the
+     * context class loader.
+     * 
+     * @return the ClassLoader used to lookup resources
+     */
+    protected ClassLoader getClassLoader()
+    {
+        return ClassLoaderUtils.getDefaultClassLoader();
+    }
+
+    @Override
+    public boolean libraryExists(String libraryName)
+    {
+        if (getPrefix() != null && !"".equals(getPrefix()))
+        {
+            URL url = getClassLoader().getResource(getPrefix() + '/' + libraryName);
+            if (url != null)
+            {
+                return true;
+            }
+        }
+        else
+        {
+            URL url = getClassLoader().getResource(libraryName);
+            if (url != null)
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * <p>Determines whether the given URL resource protocol refers to a JAR file. Note that
+     * BEA WebLogic and IBM WebSphere don't use the "jar://" protocol for some reason even
+     * though you can treat these resources just like normal JAR files, i.e. you can ignore
+     * the difference between these protocols after this method has returned.</p>
+     *
+     * @param protocol the URL resource protocol you want to check
+     *
+     * @return <code>true</code> if the given URL resource protocol refers to a JAR file,
+     *          <code>false</code> otherwise
+     */
+    /*
+    private static boolean isJarResourceProtocol(String protocol)
+    {
+        // Websphere uses the protocol "wsjar://" and Weblogic uses the protocol "zip://".
+        return "jar".equals(protocol) || "wsjar".equals(protocol) || "zip".equals(protocol); 
+    }*/
+
+}

Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ExternalContextResourceLoader.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ExternalContextResourceLoader.java?rev=1298758&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ExternalContextResourceLoader.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ExternalContextResourceLoader.java Fri Mar  9 09:06:05 2012
@@ -0,0 +1,205 @@
+/*
+ * 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 rewrite.org.apache.myfaces.extensions.scripting.jsf.resources;
+
+import javax.faces.context.FacesContext;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * A resource loader implementation which loads resources from the webapp root. It uses the methods on ExternalContext
+ * for handle resources.
+ * 
+ */
+public class ExternalContextResourceLoader extends ResourceLoader
+{
+    /**
+     * It checks version like this: /1/, /1_0/, /1_0_0/, /100_100/
+     * 
+     * Used on getLibraryVersion to filter resource directories
+     **/
+    protected static Pattern VERSION_CHECKER = Pattern.compile("/\\p{Digit}+(_\\p{Digit}*)*/");
+
+    /**
+     * It checks version like this: /1.js, /1_0.js, /1_0_0.js, /100_100.js
+     * 
+     * Used on getResourceVersion to filter resources
+     **/
+    protected static Pattern RESOURCE_VERSION_CHECKER = Pattern.compile("/\\p{Digit}+(_\\p{Digit}*)*\\..*");
+
+    public ExternalContextResourceLoader(String prefix)
+    {
+        super(prefix);
+    }
+
+    protected Set<String> getResourcePaths(String path)
+    {
+        return FacesContext.getCurrentInstance().getExternalContext().getResourcePaths(getPrefix() + '/' + path);
+    }
+
+    @Override
+    public String getResourceVersion(String path)
+    {
+        String resourceVersion = null;
+        Set<String> resourcePaths = this.getResourcePaths(path);
+        if (getPrefix() != null)
+            path = getPrefix() + '/' + path;
+
+        if (null != resourcePaths && !resourcePaths.isEmpty())
+        {
+            // resourceVersion = // execute the comment
+            // Look in the resourcePaths for versioned resources.
+            // If one or more versioned resources are found, take
+            // the one with the "highest" version number as the value
+            // of resourceVersion. If no versioned libraries
+            // are found, let resourceVersion remain null.
+            for (String resourcePath : resourcePaths)
+            {
+                String version = resourcePath.substring(path.length());
+
+                if (RESOURCE_VERSION_CHECKER.matcher(version).matches())
+                {
+                    version = version.substring(1, version.lastIndexOf('.'));
+                    if (resourceVersion == null)
+                    {
+                        resourceVersion = version;
+                    }
+                    else if (getVersionComparator().compare(resourceVersion, version) < 0)
+                    {
+                        resourceVersion = version;
+                    }
+                }
+            }
+            //Since it is a directory and no version was found, set as invalid
+            if (resourceVersion == null)
+            {
+                resourceVersion = VERSION_INVALID;
+            }
+        }
+        return resourceVersion;
+    }
+
+    @Override
+    public String getLibraryVersion(String path)
+    {
+        String libraryVersion = null;
+        Set<String> libraryPaths = this.getResourcePaths(path);
+        path = getPrefix() + '/' + path;
+        if (null != libraryPaths && !libraryPaths.isEmpty())
+        {
+            // Look in the libraryPaths for versioned libraries.
+            // If one or more versioned libraries are found, take
+            // the one with the "highest" version number as the value
+            // of libraryVersion. If no versioned libraries
+            // are found, let libraryVersion remain null.
+
+            for (Iterator<String> it = libraryPaths.iterator(); it.hasNext();)
+            {
+                String libraryPath = it.next();
+                String version = libraryPath.substring(path.length());
+
+                if (VERSION_CHECKER.matcher(version).matches())
+                {
+                    version = version.substring(1, version.length() - 1);
+                    if (libraryVersion == null)
+                    {
+                        libraryVersion = version;
+                    }
+                    else if (getVersionComparator().compare(libraryVersion, version) < 0)
+                    {
+                        libraryVersion = version;
+                    }
+                }
+            }
+        }
+        return libraryVersion;
+    }
+
+    @Override
+    public URL getResourceURL(ResourceMeta resourceMeta)
+    {
+        try
+        {
+            return FacesContext.getCurrentInstance().getExternalContext().getResource(
+                getPrefix() + '/' + resourceMeta.getResourceIdentifier());
+        }
+        catch (MalformedURLException e)
+        {
+            return null;
+        }
+    }
+
+    @Override
+    public InputStream getResourceInputStream(ResourceMeta resourceMeta)
+    {
+        return FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream(
+            getPrefix() + '/' + resourceMeta.getResourceIdentifier());
+    }
+
+    @Override
+    public ResourceMeta createResourceMeta(String prefix, String libraryName, String libraryVersion,
+                                           String resourceName, String resourceVersion)
+    {
+        return new ResourceMetaImpl(prefix, libraryName, libraryVersion, resourceName, resourceVersion);
+    }
+
+    @Override
+    public boolean libraryExists(String libraryName)
+    {
+        if (getPrefix() != null && !"".equals(getPrefix()))
+        {
+            try
+            {
+                URL url =
+                    FacesContext.getCurrentInstance().getExternalContext().getResource(
+                        getPrefix() + '/' + libraryName);
+                if (url != null)
+                {
+                    return true;
+                }
+            }
+            catch (MalformedURLException e)
+            {
+                return false;
+            }
+        }
+        else
+        {
+            try
+            {
+
+                URL url = FacesContext.getCurrentInstance().getExternalContext().getResource(libraryName);
+
+                if (url != null)
+                {
+                    return true;
+                }
+            }
+            catch (MalformedURLException e)
+            {
+                return false;
+            }
+        }
+        return false;
+    }
+}

Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/FacesServletMapping.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/FacesServletMapping.java?rev=1298758&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/FacesServletMapping.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/FacesServletMapping.java Fri Mar  9 09:06:05 2012
@@ -0,0 +1,159 @@
+/*
+ * 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 rewrite.org.apache.myfaces.extensions.scripting.jsf.resources;
+
+/**
+ * Represents a mapping entry of the FacesServlet in the web.xml
+ * configuration file.
+ */
+public class FacesServletMapping
+{
+
+    /**
+     * The path ("/faces", for example) which has been specified in the
+     * url-pattern of the FacesServlet mapping.
+     */
+    private String prefix;
+
+    /**
+     * The extension (".jsf", for example) which has been specified in the
+     * url-pattern of the FacesServlet mapping.
+     */
+    private String extension;
+
+    /**
+     * Creates a new FacesServletMapping object using prefix mapping.
+     *
+     * @param path The path ("/faces", for example) which has been specified
+     *             in the url-pattern of the FacesServlet mapping.
+     * @return a newly created FacesServletMapping
+     */
+    public static FacesServletMapping createPrefixMapping(String path)
+    {
+        FacesServletMapping mapping = new FacesServletMapping();
+        mapping.setPrefix(path);
+        return mapping;
+    }
+
+    /**
+     * Creates a new FacesServletMapping object using extension mapping.
+     *
+     * @param path The extension (".jsf", for example) which has been
+     *             specified in the url-pattern of the FacesServlet mapping.
+     * @return a newly created FacesServletMapping
+     */
+    public static FacesServletMapping createExtensionMapping(
+        String extension)
+    {
+        FacesServletMapping mapping = new FacesServletMapping();
+        mapping.setExtension(extension);
+        return mapping;
+    }
+
+    /**
+     * Returns the path ("/faces", for example) which has been specified in
+     * the url-pattern of the FacesServlet mapping. If this mapping is based
+     * on an extension, <code>null</code> will be returned. Note that this
+     * path is not the same as the specified url-pattern as the trailing
+     * "/*" is omitted.
+     *
+     * @return the path which has been specified in the url-pattern
+     */
+    public String getPrefix()
+    {
+        return prefix;
+    }
+
+    /**
+     * Sets the path ("/faces/", for example) which has been specified in
+     * the url-pattern.
+     *
+     * @param path The path which has been specified in the url-pattern
+     */
+    public void setPrefix(String path)
+    {
+        this.prefix = path;
+    }
+
+    /**
+     * Returns the extension (".jsf", for example) which has been specified
+     * in the url-pattern of the FacesServlet mapping. If this mapping is
+     * not based on an extension, <code>null</code> will be returned.
+     *
+     * @return the extension which has been specified in the url-pattern
+     */
+    public String getExtension()
+    {
+        return extension;
+    }
+
+    /**
+     * Sets the extension (".jsf", for example) which has been specified in
+     * the url-pattern of the FacesServlet mapping.
+     *
+     * @param extension The extension which has been specified in the url-pattern
+     */
+    public void setExtension(String extension)
+    {
+        this.extension = extension;
+    }
+
+    /**
+     * Indicates whether this mapping is based on an extension (e.g.
+     * ".jsp").
+     *
+     * @return <code>true</code>, if this mapping is based is on an
+     *         extension, <code>false</code> otherwise
+     */
+    public boolean isExtensionMapping()
+    {
+        return extension != null;
+    }
+
+    /**
+     * Indicates whether this mapping is based on a prefix (e.g.
+     * /faces/*").
+     *
+     * @return <code>true</code>, if this mapping is based is on a
+     *         prefix, <code>false</code> otherwise
+     */
+    public boolean isPrefixMapping()
+    {
+        return prefix != null;
+    }
+
+    /**
+     * Returns the url-pattern entry for this servlet mapping.
+     *
+     * @return the url-pattern entry for this servlet mapping
+     */
+    public String getUrlPattern()
+    {
+        if (isExtensionMapping())
+        {
+            return "*" + extension;
+        }
+        else
+        {
+            return prefix + "/*";
+        }
+    }
+
+}
\ No newline at end of file

Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerCache.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerCache.java?rev=1298758&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerCache.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerCache.java Fri Mar  9 09:06:05 2012
@@ -0,0 +1,241 @@
+/*
+ * 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 rewrite.org.apache.myfaces.extensions.scripting.jsf.resources;
+
+import javax.faces.application.ProjectStage;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class ResourceHandlerCache
+{
+    private static final Logger log = Logger
+            .getLogger(ResourceHandlerCache.class.getName());
+
+    private Boolean _resourceCacheEnabled = null;
+    private Map<ResourceKey, ResourceValue> _resourceCacheMap = null;
+
+    private static final String RESOURCE_HANDLER_CACHE_SIZE_ATTRIBUTE = "org.apache.myfaces.RESOURCE_HANDLER_CACHE_SIZE";
+    private static final int RESOURCE_HANDLER_CACHE_DEFAULT_SIZE = 500;
+
+    private static final String RESOURCE_HANDLER_CACHE_ENABLED_ATTRIBUTE = "org.apache.myfaces.RESOURCE_HANDLER_CACHE_ENABLED";
+    private static final boolean RESOURCE_HANDLER_CACHE_ENABLED_DEFAULT = true;
+
+    public ResourceValue getResource(String resourceName, String libraryName,
+            String contentType)
+    {
+        if (!isResourceCachingEnabled() || _resourceCacheMap == null)
+            return null;
+
+        if (log.isLoggable(Level.FINE))
+            log.log(Level.FINE, "Attemping to get resource from cache for "
+                    + resourceName);
+
+        ResourceKey key = new ResourceKey(resourceName, libraryName,
+                contentType);
+
+        return _resourceCacheMap.get(key);
+    }
+    
+    public boolean containsResource(String resourceName, String libraryName,
+            String contentType)
+    {
+        if (!isResourceCachingEnabled() || _resourceCacheMap == null)
+            return false;
+        ResourceKey key = new ResourceKey(resourceName, libraryName,
+                contentType);
+        return _resourceCacheMap.containsKey(key);
+    }
+
+    public void putResource(String resourceName, String libraryName,
+            String contentType, ResourceMeta resource, ResourceLoader loader)
+    {
+        if (!isResourceCachingEnabled())
+            return;
+
+        if (log.isLoggable(Level.FINE))
+            log.log(Level.FINE, "Attemping to put resource to cache for "
+                    + resourceName);
+
+        if (_resourceCacheMap == null)
+        {
+            if (log.isLoggable(Level.FINE))
+                log.log(Level.FINE, "Initializing resource cache map");
+            _resourceCacheMap = Collections
+                    .synchronizedMap(new _ResourceMap<ResourceKey, ResourceValue>(
+                            getMaxSize()));
+        }
+
+        _resourceCacheMap.put(new ResourceKey(resourceName, libraryName,
+                contentType), new ResourceValue(resource, loader));
+    }
+
+    private boolean isResourceCachingEnabled()
+    {
+        if (_resourceCacheEnabled == null)
+        {
+            FacesContext facesContext = FacesContext.getCurrentInstance();
+
+            //first, check to make sure that ProjectStage is production, if not, skip caching
+            if (!facesContext.isProjectStage(ProjectStage.Production))
+            {
+                return _resourceCacheEnabled = Boolean.FALSE;
+            }
+
+            ExternalContext externalContext = facesContext.getExternalContext();
+            if (externalContext == null)
+                return false; //don't cache right now, but don't disable it yet either
+
+            //if in production, make sure that the cache is not explicitly disabled via context param
+            String configParam = externalContext
+                    .getInitParameter(ResourceHandlerCache.RESOURCE_HANDLER_CACHE_ENABLED_ATTRIBUTE);
+            _resourceCacheEnabled = configParam == null ? ResourceHandlerCache.RESOURCE_HANDLER_CACHE_ENABLED_DEFAULT
+                    : Boolean.parseBoolean(configParam);
+
+            if (log.isLoggable(Level.FINE))
+            {
+                log.log(Level.FINE, "MyFaces Resource Caching Enabled="
+                        + _resourceCacheEnabled);
+            }
+        }
+        return _resourceCacheEnabled;
+    }
+
+    private int getMaxSize()
+    {
+        ExternalContext externalContext = FacesContext.getCurrentInstance()
+                .getExternalContext();
+
+        String configParam = externalContext == null ? null : externalContext
+                .getInitParameter(RESOURCE_HANDLER_CACHE_SIZE_ATTRIBUTE);
+        return configParam == null ? RESOURCE_HANDLER_CACHE_DEFAULT_SIZE
+                : Integer.parseInt(configParam);
+    }
+
+    public static class ResourceKey
+    {
+        private String resourceName;
+        private String libraryName;
+        private String contentType;
+
+        public ResourceKey(String resourceName, String libraryName,
+                String contentType)
+        {
+            this.resourceName = resourceName;
+            this.libraryName = libraryName;
+            this.contentType = contentType;
+        }
+
+        @Override
+        public int hashCode()
+        {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result
+                    + ((contentType == null) ? 0 : contentType.hashCode());
+            result = prime * result
+                    + ((libraryName == null) ? 0 : libraryName.hashCode());
+            result = prime * result
+                    + ((resourceName == null) ? 0 : resourceName.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj)
+        {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            ResourceKey other = (ResourceKey) obj;
+            if (contentType == null)
+            {
+                if (other.contentType != null)
+                    return false;
+            }
+            else if (!contentType.equals(other.contentType))
+                return false;
+            if (libraryName == null)
+            {
+                if (other.libraryName != null)
+                    return false;
+            }
+            else if (!libraryName.equals(other.libraryName))
+                return false;
+            if (resourceName == null)
+            {
+                if (other.resourceName != null)
+                    return false;
+            }
+            else if (!resourceName.equals(other.resourceName))
+                return false;
+            return true;
+        }
+    }
+    
+    public static class ResourceValue
+    {
+        private ResourceMeta resourceMeta;
+        
+        private ResourceLoader resourceLoader;
+
+        public ResourceValue(ResourceMeta resourceMeta,
+                ResourceLoader resourceLoader)
+        {
+            super();
+            this.resourceMeta = resourceMeta;
+            this.resourceLoader = resourceLoader;
+        }
+
+        public ResourceMeta getResourceMeta()
+        {
+            return resourceMeta;
+        }
+
+        public ResourceLoader getResourceLoader()
+        {
+            return resourceLoader;
+        }
+    }
+
+    private static class _ResourceMap<K, V> extends LinkedHashMap<K, V>
+    {
+        private static final long serialVersionUID = 1L;
+        private int maxCapacity;
+
+        public _ResourceMap(int cacheSize)
+        {
+            // create map at max capacity and 1.1 load factor to avoid rehashing
+            super(cacheSize + 1, 1.1f, true);
+            maxCapacity = cacheSize;
+        }
+
+        @Override
+        protected boolean removeEldestEntry(Map.Entry<K, V> eldest)
+        {
+            return size() > maxCapacity;
+        }
+    }
+}
\ No newline at end of file

Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerImpl.java?rev=1298758&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerImpl.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerImpl.java Fri Mar  9 09:06:05 2012
@@ -0,0 +1,567 @@
+/*
+ * 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 rewrite.org.apache.myfaces.extensions.scripting.jsf.resources;
+
+import org.apache.myfaces.extensions.scripting.core.util.ClassLoaderUtils;
+import org.apache.myfaces.renderkit.ErrorPageWriter;
+
+import javax.faces.application.Resource;
+import javax.faces.application.ResourceHandler;
+import javax.faces.context.FacesContext;
+import javax.servlet.http.HttpServletResponse;
+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;
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author Simon Lessard (latest modification by $Author: slessard $)
+ *
+ * @version $Revision: 696515 $ $Date: 2008-09-17 19:37:53 -0500 (mer., 17 sept. 2008) $
+ */
+public abstract class ResourceHandlerImpl extends ResourceHandler
+{
+
+    private static final String IS_RESOURCE_REQUEST = "org.apache.myfaces.IS_RESOURCE_REQUEST";
+
+    private ResourceHandlerSupport _resourceHandlerSupport;
+
+    private ResourceHandlerCache _resourceHandlerCache;
+
+    //private static final Log log = LogFactory.getLog(ResourceHandlerImpl.class);
+    private static final Logger log = Logger.getLogger(ResourceHandlerImpl.class.getName());
+
+    private static final int _BUFFER_SIZE = 2048;
+
+    @Override
+    public Resource createResource(String resourceName)
+    {
+        return createResource(resourceName, null);
+    }
+
+    @Override
+    public Resource createResource(String resourceName, String libraryName)
+    {
+        return createResource(resourceName, libraryName, null);
+    }
+
+    @Override
+    public Resource createResource(String resourceName, String libraryName,
+            String contentType)
+    {
+        Resource resource = null;
+
+        if (contentType == null)
+        {
+            //Resolve contentType using ExternalContext.getMimeType
+            contentType = FacesContext.getCurrentInstance().getExternalContext().getMimeType(resourceName);
+        }
+
+        if(getResourceLoaderCache().containsResource(resourceName, libraryName, contentType))
+        {
+            ResourceHandlerCache.ResourceValue resourceValue = getResourceLoaderCache().getResource(resourceName, libraryName, contentType);
+            resource = new ResourceImpl(resourceValue.getResourceMeta(), resourceValue.getResourceLoader(),
+                    getResourceHandlerSupport(), contentType);
+        }
+        else
+        {
+            for (ResourceLoader loader : getResourceHandlerSupport()
+                    .getResourceLoaders())
+            {
+                ResourceMeta resourceMeta = deriveResourceMeta(loader,
+                        resourceName, libraryName);
+
+                if (resourceMeta != null)
+                {
+                    resource = new ResourceImpl(resourceMeta, loader,
+                            getResourceHandlerSupport(), contentType);
+
+                    getResourceLoaderCache().putResource(resourceName, libraryName, contentType, resourceMeta, loader);
+                    break;
+                }
+            }
+        }
+
+        return resource;
+    }
+
+    /**
+     * This method try to create a ResourceMeta for a specific resource
+     * loader. If no library, or resource is found, just return null,
+     * so the algorithm in createResource can continue checking with the
+     * next registered ResourceLoader.
+     */
+    protected ResourceMeta deriveResourceMeta(ResourceLoader resourceLoader,
+            String resourceName, String libraryName)
+    {
+        String localePrefix = getLocalePrefixForLocateResource();
+        String resourceVersion = null;
+        String libraryVersion = null;
+        ResourceMeta resourceId = null;
+
+        //1. Try to locate resource in a localized path
+        if (localePrefix != null)
+        {
+            if (null != libraryName)
+            {
+                String pathToLib = localePrefix + '/' + libraryName;
+                libraryVersion = resourceLoader.getLibraryVersion(pathToLib);
+
+                if (null != libraryVersion)
+                {
+                    String pathToResource = localePrefix + '/'
+                            + libraryName + '/' + libraryVersion + '/'
+                            + resourceName;
+                    resourceVersion = resourceLoader
+                            .getResourceVersion(pathToResource);
+                }
+                else
+                {
+                    String pathToResource = localePrefix + '/'
+                            + libraryName + '/' + resourceName;
+                    resourceVersion = resourceLoader
+                            .getResourceVersion(pathToResource);
+                }
+
+                if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+                {
+                    resourceId = resourceLoader.createResourceMeta(localePrefix, libraryName,
+                            libraryVersion, resourceName, resourceVersion);
+                }
+            }
+            else
+            {
+                resourceVersion = resourceLoader
+                        .getResourceVersion(localePrefix + '/'+ resourceName);
+                if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+                {
+                    resourceId = resourceLoader.createResourceMeta(localePrefix, null, null,
+                            resourceName, resourceVersion);
+                }
+            }
+
+            if (resourceId != null)
+            {
+                URL url = resourceLoader.getResourceURL(resourceId);
+                if (url == null)
+                {
+                    resourceId = null;
+                }
+            }
+        }
+
+        //2. Try to localize resource in a non localized path
+        if (resourceId == null)
+        {
+            if (null != libraryName)
+            {
+                libraryVersion = resourceLoader.getLibraryVersion(libraryName);
+
+                if (null != libraryVersion)
+                {
+                    String pathToResource = (libraryName + '/' + libraryVersion
+                            + '/' + resourceName);
+                    resourceVersion = resourceLoader
+                            .getResourceVersion(pathToResource);
+                }
+                else
+                {
+                    String pathToResource = (libraryName + '/'
+                            + resourceName);
+                    resourceVersion = resourceLoader
+                            .getResourceVersion(pathToResource);
+                }
+
+                if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+                {
+                    resourceId = resourceLoader.createResourceMeta(null, libraryName,
+                            libraryVersion, resourceName, resourceVersion);
+                }
+            }
+            else
+            {
+                resourceVersion = resourceLoader
+                        .getResourceVersion(resourceName);
+
+                if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+                {
+                    resourceId = resourceLoader.createResourceMeta(null, null, null,
+                            resourceName, resourceVersion);
+                }
+            }
+
+            if (resourceId != null)
+            {
+                URL url = resourceLoader.getResourceURL(resourceId);
+                if (url == null)
+                {
+                    resourceId = null;
+                }
+            }
+        }
+
+        return resourceId;
+    }
+
+    @Override
+    public String getRendererTypeForResourceName(String resourceName)
+    {
+        if (resourceName.endsWith(".js"))
+            return "javax.faces.resource.Script";
+        else if (resourceName.endsWith(".css"))
+            return "javax.faces.resource.Stylesheet";
+        return null;
+    }
+
+    /**
+     *  Handle the resource request, writing in the output.
+     *
+     *  This method implements an algorithm semantically identical to
+     *  the one described on the javadoc of ResourceHandler.handleResourceRequest
+     */
+    @Override
+    public void handleResourceRequest(FacesContext facesContext) throws IOException
+    {
+        try
+        {
+            String resourceBasePath = getResourceHandlerSupport()
+                    .calculateResourceBasePath(facesContext);
+
+            if (resourceBasePath == null)
+            {
+                // No base name could be calculated, so no further
+                //advance could be done here. HttpServletResponse.SC_NOT_FOUND
+                //cannot be returned since we cannot extract the
+                //resource base name
+                return;
+            }
+
+            // We neet to get an instance of HttpServletResponse, but sometimes
+            // the response object is wrapped by several instances of
+            // ServletResponseWrapper (like ResponseSwitch).
+            // Since we are handling a resource, we can expect to get an
+            // HttpServletResponse.
+            Object response = facesContext.getExternalContext().getResponse();
+
+            //TODO merge the servlet response determination in
+            HttpServletResponse httpServletResponse = (HttpServletResponse) response;
+            if (httpServletResponse == null)
+            {
+                throw new IllegalStateException("Could not obtain an instance of HttpServletResponse.");
+            }
+
+            if (isResourceIdentifierExcluded(facesContext, resourceBasePath))
+            {
+                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                return;
+            }
+
+            String resourceName = null;
+            if (resourceBasePath.startsWith(ResourceHandler.RESOURCE_IDENTIFIER))
+            {
+                resourceName = resourceBasePath
+                        .substring(ResourceHandler.RESOURCE_IDENTIFIER.length() + 1);
+            }
+            else
+            {
+                //Does not have the conditions for be a resource call
+                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                return;
+            }
+
+            String libraryName = facesContext.getExternalContext()
+                    .getRequestParameterMap().get("ln");
+
+            Resource resource = null;
+            if (libraryName != null)
+            {
+                //log.info("libraryName=" + libraryName);
+                resource = facesContext.getApplication().getResourceHandler().createResource(resourceName, libraryName);
+            }
+            else
+            {
+                resource = facesContext.getApplication().getResourceHandler().createResource(resourceName);
+            }
+
+            if (resource == null)
+            {
+                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                return;
+            }
+
+            if (!resource.userAgentNeedsUpdate(facesContext))
+            {
+                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+                return;
+            }
+
+            httpServletResponse.setContentType(resource.getContentType());
+
+            Map<String, String> headers = resource.getResponseHeaders();
+
+            for (Map.Entry<String, String> entry : headers.entrySet())
+            {
+                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);
+                }
+                finally
+                {
+                    try
+                    {
+                        in.close();
+                    }
+                    finally
+                    {
+                        out.close();
+                    }
+                }
+            }
+            catch (IOException e)
+            {
+                //TODO: Log using a localized message (which one?)
+                if (log.isLoggable(Level.SEVERE))
+                    log.severe("Error trying to load resource " + resourceName
+                            + " with library " + libraryName + " :"
+                            + e.getMessage());
+                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
+            }
+        }
+        catch (Throwable ex)
+        {
+            // handle the Throwable accordingly. Maybe generate an error page.
+            // FIXME we are creating a html error page for a non html request here
+            // shouln't we do something better? -=Jakob Korherr=-
+            ErrorPageWriter.handleThrowable(facesContext, ex);
+        }
+    }
+
+    /**
+     * Reads the specified input stream into the provided byte array storage and
+     * writes it to the output stream.
+     */
+    private static int pipeBytes(InputStream in, OutputStream out, byte[] buffer)
+            throws IOException
+    {
+        int count = 0;
+        int length;
+
+        while ((length = (in.read(buffer))) >= 0)
+        {
+            out.write(buffer, 0, length);
+            count += length;
+        }
+        return count;
+    }
+
+    @Override
+    public boolean isResourceRequest(FacesContext facesContext)
+    {
+        // Since this method could be called many times we save it
+        //on request map so the first time is calculated it remains
+        //alive until the end of the request
+        Boolean value = (Boolean) facesContext.getAttributes().get(IS_RESOURCE_REQUEST);
+
+        if (value != null && value)
+        {
+            //return the saved value
+            return value;
+        }
+        else
+        {
+            String resourceBasePath = getResourceHandlerSupport()
+                    .calculateResourceBasePath(facesContext);
+
+            if (resourceBasePath != null
+                    && resourceBasePath.startsWith(ResourceHandler.RESOURCE_IDENTIFIER))
+            {
+                facesContext.getAttributes().put(IS_RESOURCE_REQUEST, Boolean.TRUE);
+                return true;
+            }
+            else
+            {
+                facesContext.getAttributes().put(IS_RESOURCE_REQUEST, Boolean.FALSE);
+                return false;
+            }
+        }
+    }
+
+    protected String getLocalePrefixForLocateResource()
+    {
+        String localePrefix = null;
+        FacesContext context = FacesContext.getCurrentInstance();
+
+        String bundleName = context.getApplication().getMessageBundle();
+
+        if (null != bundleName)
+        {
+            Locale locale = context.getApplication().getViewHandler()
+                    .calculateLocale(context);
+
+            ResourceBundle bundle = ResourceBundle
+                    .getBundle(bundleName, locale, ClassLoaderUtils.getDefaultClassLoader());
+
+            if (bundle != null)
+            {
+                try
+                {
+                    localePrefix = bundle.getString(ResourceHandler.LOCALE_PREFIX);
+                }
+                catch (MissingResourceException e)
+                {
+                    // Ignore it and return null
+                }
+            }
+        }
+        return localePrefix;
+    }
+
+    private static ResourceBundle getBundle(FacesContext facesContext, Locale locale, String bundleName)
+    {
+        try
+        {
+            // First we try the JSF implementation class loader
+            return ResourceBundle.getBundle(bundleName, locale, facesContext.getClass().getClassLoader());
+        }
+        catch (MissingResourceException ignore1)
+        {
+            try
+            {
+                // Next we try the JSF API class loader
+                return ResourceBundle.getBundle(bundleName, locale, ResourceHandlerImpl.class.getClassLoader());
+            }
+            catch (MissingResourceException ignore2)
+            {
+                try
+                {
+                    // Last resort is the context class loader
+                    return ResourceBundle.getBundle(bundleName, locale, ClassLoaderUtils.getDefaultClassLoader());
+                }
+                catch (MissingResourceException damned)
+                {
+                    return null;
+                }
+            }
+        }
+    }
+
+    protected boolean isResourceIdentifierExcluded(FacesContext context,
+            String resourceIdentifier)
+    {
+        String value = context.getExternalContext().getInitParameter(
+                RESOURCE_EXCLUDES_PARAM_NAME);
+        if (value == null)
+        {
+            value = RESOURCE_EXCLUDES_DEFAULT_VALUE;
+        }
+        //TODO: optimize this code
+        String[] extensions = value.split("\\s+");
+        for (int i = 0; i < extensions.length; i++)
+        {
+            if (resourceIdentifier.endsWith(extensions[i]))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check if a library exists or not. This is done delegating
+     * to each ResourceLoader used, because each one has a different
+     * prefix and way to load resources.
+     *
+     */
+    @Override
+    public boolean libraryExists(String libraryName)
+    {
+        String localePrefix = getLocalePrefixForLocateResource();
+
+        String pathToLib = null;
+
+        if (localePrefix != null)
+        {
+            //Check with locale
+            pathToLib = localePrefix + '/' + libraryName;
+
+            for (ResourceLoader loader : getResourceHandlerSupport()
+                    .getResourceLoaders())
+            {
+                if (loader.libraryExists(pathToLib))
+                {
+                    return true;
+                }
+            }
+        }
+
+        //Check without locale
+        for (ResourceLoader loader : getResourceHandlerSupport()
+                .getResourceLoaders())
+        {
+            if (loader.libraryExists(libraryName))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @param resourceHandlerSupport
+     *            the resourceHandlerSupport to set
+     */
+    public void setResourceHandlerSupport(
+            ResourceHandlerSupport resourceHandlerSupport)
+    {
+        _resourceHandlerSupport = resourceHandlerSupport;
+    }
+
+    /**
+     * @return the resourceHandlerSupport
+     */
+    protected abstract ResourceHandlerSupport getResourceHandlerSupport();
+
+    private ResourceHandlerCache getResourceLoaderCache()
+    {
+        if (_resourceHandlerCache == null)
+            _resourceHandlerCache = new ResourceHandlerCache();
+        return _resourceHandlerCache;
+    }
+}

Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerSupport.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerSupport.java?rev=1298758&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerSupport.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/resources/ResourceHandlerSupport.java Fri Mar  9 09:06:05 2012
@@ -0,0 +1,86 @@
+/*
+ * 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 rewrite.org.apache.myfaces.extensions.scripting.jsf.resources;
+
+import javax.faces.context.FacesContext;
+
+/**
+ * A utility class to isolate a ResourceHandler implementation from its
+ * underlying implementation
+ * 
+ * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
+ * @version $Revision: 891494 $ $Date: 2009-12-16 19:42:18 -0500 (Mié, 16 Dic 2009) $
+ */
+public abstract class ResourceHandlerSupport
+{
+
+    /**
+     * Calculate the resource base path.
+     * 
+     * It should extract a string like:
+     * 
+     * ResourceHandler.RESOURCE_IDENTIFIER + '/' + getResourceName()
+     * 
+     * For example:
+     * 
+     * /javax.faces.resource/image.jpg
+     * 
+     * This is used on ResourceHandler.handleResourceRequest()
+     * 
+     */
+    public abstract String calculateResourceBasePath(FacesContext facesContext);
+
+    /**
+     * Return an array of resource loaders used to find resources
+     * using the standard. The order of ResourceLoaders define
+     * its precedence. 
+     * 
+     * @return
+     */
+    public abstract ResourceLoader[] getResourceLoaders();
+    
+    /**
+     * Check if the mapping used is done using extensions (.xhtml, .jsf)
+     * or if it is not (/faces/*)
+     * @return
+     */
+    public abstract boolean isExtensionMapping();
+    
+    /**
+     * Get the mapping used as prefix(/faces) or sufix(.jsf)
+     * 
+     * @return
+     */
+    public abstract String getMapping();
+    
+    /**
+     * Return the time when the app started. This is useful to set the
+     * "Last-Modified" header in some specific cases.
+     * 
+     * @return
+     */
+    public abstract long getStartupTime();
+    
+    /**
+     * Return the time that should be set on "Expires" header in a resource.
+     * 
+     * @return
+     */
+    public abstract long getMaxTimeExpires();
+}