MYFACESTEST-13 MockResource must implement all its methods
diff --git a/test20/src/main/java/org/apache/myfaces/test/mock/MockApplication20.java b/test20/src/main/java/org/apache/myfaces/test/mock/MockApplication20.java
index 72dce99..242d475 100644
--- a/test20/src/main/java/org/apache/myfaces/test/mock/MockApplication20.java
+++ b/test20/src/main/java/org/apache/myfaces/test/mock/MockApplication20.java
@@ -19,6 +19,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.myfaces.test.mock.resource.MockResourceHandler;
 
 import javax.faces.FacesException;
 import javax.faces.application.ProjectStage;
@@ -50,6 +51,7 @@
         
         // install the 2.0-ViewHandler-Mock
         this.setViewHandler(new MockViewHandler20());
+        this.setResourceHandler(new MockResourceHandler());
     }
 
     private static class SystemListenerEntry
diff --git a/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockClassLoaderResourceLoader.java b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockClassLoaderResourceLoader.java
new file mode 100644
index 0000000..5064789
--- /dev/null
+++ b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockClassLoaderResourceLoader.java
@@ -0,0 +1,122 @@
+/*

+ * 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.test.mock.resource;

+

+import java.io.InputStream;

+import java.net.URL;

+

+/**

+ * A resource loader implementation which loads resources from the thread ClassLoader.

+ * 

+ * @author Leonardo Uribe (latest modification by $Author: lu4242 $)

+ * @version $Revision: 882702 $ $Date: 2009-11-20 15:16:07 -0500 (Vie, 20 Nov 2009) $

+ */

+public class MockClassLoaderResourceLoader extends MockResourceLoader

+{

+    private ClassLoader _classLoader;

+    

+    public MockClassLoaderResourceLoader(ClassLoader loader, String prefix)

+    {

+        super(prefix);

+        _classLoader = loader;

+    }

+

+    @Override

+    public String getLibraryVersion(String path)

+    {

+        return null;

+    }

+

+    @Override

+    public InputStream getResourceInputStream(MockResourceMeta resourceMeta)

+    {

+        if (getPrefix() != null && !"".equals(getPrefix()))

+        {

+            return getClassLoader().getResourceAsStream(getPrefix() + '/' + resourceMeta.getResourceIdentifier());

+        }

+        else

+        {

+            return getClassLoader().getResourceAsStream(resourceMeta.getResourceIdentifier());

+        }

+    }

+

+    @Override

+    public URL getResourceURL(MockResourceMeta 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;

+    }

+

+    @Override

+    public MockResourceMeta createResourceMeta(String prefix, String libraryName, String libraryVersion,

+                                           String resourceName, String resourceVersion)

+    {

+        return new MockResourceMeta(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

+     */

+    public ClassLoader getClassLoader()

+    {

+        return _classLoader;

+    }

+    

+    public void setClassLoader(ClassLoader loader)

+    {

+        _classLoader = loader;

+    }

+

+    @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;

+    }

+}

diff --git a/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockExternalContextResourceLoader.java b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockExternalContextResourceLoader.java
new file mode 100644
index 0000000..f32372e
--- /dev/null
+++ b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockExternalContextResourceLoader.java
@@ -0,0 +1,208 @@
+/*

+ * 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.test.mock.resource;

+

+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;

+

+import javax.faces.context.FacesContext;

+

+/**

+ * A resource loader implementation which loads resources from the webapp root. 

+ * It uses the methods on ExternalContext for handle resources.

+ * 

+ * @author Leonardo Uribe (latest modification by $Author: lu4242 $)

+ * @version $Revision: 882702 $ $Date: 2009-11-20 15:16:07 -0500 (Vie, 20 Nov 2009) $

+ */

+public class MockExternalContextResourceLoader extends MockResourceLoader

+{

+    /**

+     * 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 MockExternalContextResourceLoader(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(MockResourceMeta resourceMeta)

+    {

+        try

+        {

+            return FacesContext.getCurrentInstance().getExternalContext().getResource(

+                getPrefix() + '/' + resourceMeta.getResourceIdentifier());

+        }

+        catch (MalformedURLException e)

+        {

+            return null;

+        }

+    }

+

+    @Override

+    public InputStream getResourceInputStream(MockResourceMeta resourceMeta)

+    {

+        return FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream(

+            getPrefix() + '/' + resourceMeta.getResourceIdentifier());

+    }

+

+    @Override

+    public MockResourceMeta createResourceMeta(String prefix, String libraryName, String libraryVersion,

+                                           String resourceName, String resourceVersion)

+    {

+        return new MockResourceMeta(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;

+    }

+}

diff --git a/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResource.java b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResource.java
index f1d02b7..9c1fc94 100644
--- a/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResource.java
+++ b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResource.java
@@ -17,115 +17,79 @@
 
 package org.apache.myfaces.test.mock.resource;
 
-import org.apache.myfaces.test.mock.MockServletContext;
-
-import javax.faces.application.Resource;
-import javax.faces.context.FacesContext;
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.Collections;
 import java.util.Map;
 
+import javax.faces.application.Resource;
+import javax.faces.application.ResourceHandler;
+import javax.faces.context.FacesContext;
+
 /**
  * <p>Mock implementation of <code>Resource</code>.</p>
  * <p/>
- * $Id$
- *
- * @since 2.0
+ * @author Leonardo Uribe (latest modification by $Author$)
+ * @version $Revision$ $Date$
  */
 public class MockResource extends Resource
 {
-
-    private String _prefix;
-    private String _libraryName;
-    private String _libraryVersion;
-    private String _resourceName;
-    private String _resourceVersion;
-    private File _documentRoot;
-
-    /**
-     * Creates new resource object
-     *
-     * @param prefix          locale prefix if any
-     * @param libraryName     resource library name
-     * @param libraryVersion  resource library version if any
-     * @param resourceName    resource file name
-     * @param resourceVersion resource version if any
-     * @param documentRoot    parent folder of resource directories. Must not be <code>null</code>
-     */
-    public MockResource(String prefix, String libraryName, String libraryVersion, String resourceName, String resourceVersion, File documentRoot)
+    private MockResourceMeta _resourceMeta;
+    private MockResourceLoader _resourceLoader;
+    private MockResourceHandlerSupport _resourceHandlerSupport;
+    
+    public MockResource(MockResourceMeta resourceMeta, 
+            MockResourceLoader resourceLoader, MockResourceHandlerSupport support, String contentType)
     {
-        _prefix = prefix;
-        _libraryName = libraryName;
-        _libraryVersion = libraryVersion;
-        _resourceName = resourceName;
-        _resourceVersion = resourceVersion;
-        _documentRoot = documentRoot;
-
-        if (_documentRoot == null) {
-            throw new IllegalArgumentException("documentRoot must not be null");
-        }
-    }
-
-    @Override
-    public String getResourceName()
-    {
-        return _resourceName;
-    }
-
-    @Override
-    public void setResourceName(String resourceName)
-    {
-        _resourceName = resourceName;
-    }
-
-    @Override
-    public String getLibraryName()
-    {
-        return _libraryName;
+        _resourceMeta = resourceMeta;
+        _resourceLoader = resourceLoader;
+        _resourceHandlerSupport = support;
+        setLibraryName(resourceMeta.getLibraryName());
+        setResourceName(resourceMeta.getResourceName());
+        setContentType(contentType);
     }
     
-    @Override
-    public void setLibraryName(String libraryName)
+    public MockResourceLoader getResourceLoader()
     {
-        _libraryName = libraryName;
-    }
-
+        return _resourceLoader;
+    }    
+    
     @Override
     public InputStream getInputStream() throws IOException
     {
-        MockServletContext servletContext = (MockServletContext)
-            FacesContext.getCurrentInstance().getExternalContext().getContext();
-        servletContext.setDocumentRoot(_documentRoot);
-        return servletContext.getResourceAsStream(buildResourcePath());
+        return getResourceLoader().getResourceInputStream(_resourceMeta);            
     }
 
     @Override
     public String getRequestPath()
     {
-        throw new UnsupportedOperationException();
+        String path;
+        if (_resourceHandlerSupport.isExtensionMapping())
+        {
+            path = ResourceHandler.RESOURCE_IDENTIFIER + '/' + 
+                getResourceName() + _resourceHandlerSupport.getMapping();
+        }
+        else
+        {
+            String mapping = _resourceHandlerSupport.getMapping(); 
+            path = ResourceHandler.RESOURCE_IDENTIFIER + '/' + getResourceName();
+            path = (mapping == null) ? path : mapping + path;
+        }
+        
+        return path;
     }
 
     @Override
     public Map<String, String> getResponseHeaders()
     {
-        throw new UnsupportedOperationException();
+        return Collections.emptyMap();
     }
 
     @Override
     public URL getURL()
     {
-        MockServletContext servletContext = (MockServletContext)
-            FacesContext.getCurrentInstance().getExternalContext().getContext();
-        servletContext.setDocumentRoot(_documentRoot);
-
-        try {
-            return servletContext.getResource(buildResourcePath());
-        } catch (MalformedURLException e) {
-            return null;
-        }
+        return getResourceLoader().getResourceURL(_resourceMeta);
     }
 
     @Override
@@ -133,47 +97,4 @@
     {
         return true;
     }
-
-    private String buildResourcePath()
-    {
-        StringBuilder builder = new StringBuilder();
-        builder.append('/');
-        boolean firstSlashAdded = false;
-        if (_prefix != null && _prefix.length() > 0) {
-            builder.append(_prefix);
-            firstSlashAdded = true;
-        }
-        if (_libraryName != null) {
-            if (firstSlashAdded) {
-                builder.append('/');
-            }
-            builder.append(_libraryName);
-            firstSlashAdded = true;
-        }
-        if (_libraryVersion != null) {
-            if (firstSlashAdded) {
-                builder.append('/');
-            }
-            builder.append(_libraryVersion);
-            firstSlashAdded = true;
-        }
-        if (_resourceName != null) {
-            if (firstSlashAdded) {
-                builder.append('/');
-            }
-            builder.append(_resourceName);
-            firstSlashAdded = true;
-        }
-        if (_resourceVersion != null) {
-            if (firstSlashAdded) {
-                builder.append('/');
-            }
-            builder.append(_resourceVersion);
-            builder.append(
-                _resourceName.substring(_resourceName.lastIndexOf('.')));
-        }
-
-        return builder.toString();
-    }
-
-}
+}
\ No newline at end of file
diff --git a/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResourceHandler.java b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResourceHandler.java
index 75addb5..e3d6243 100644
--- a/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResourceHandler.java
+++ b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResourceHandler.java
@@ -17,64 +17,64 @@
 
 package org.apache.myfaces.test.mock.resource;
 
-import org.apache.myfaces.test.mock.MockServletContext;
-
-import javax.faces.FacesException;
-import javax.faces.application.Resource;
-import javax.faces.application.ResourceHandler;
-import javax.faces.context.ExternalContext;
-import javax.faces.context.FacesContext;
-import java.io.File;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
-import java.util.*;
-import java.util.regex.Pattern;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import javax.faces.FacesException;
+import javax.faces.application.Resource;
+import javax.faces.application.ResourceHandler;
+import javax.faces.context.FacesContext;
 
 /**
  * <p>Mock implementation of <code>ResourceHandler</code>.</p>
- * <p/>
- * $Id$
+ * <p>This ResourceHandler implementation try to follow the default algorithm
+ * defined by the spec, so it try to load resources using the current 
+ * ExternalContext and the specified ClassLoader, in the same locations
+ * it is expected ("resources" and "META-INF/resources").</p>
  * 
- * @since 2.0
+ * @author Leonardo Uribe (latest modification by $Author$)
+ * @version $Revision$ $Date$
  */
 public class MockResourceHandler extends ResourceHandler
 {
 
-    private static final String IS_RESOURCE_REQUEST = "org.apache.myfaces.IS_RESOURCE_REQUEST";
+    private boolean _resourceRequest;
 
-    /**
-     * It checks version like this: /1/, /1_0/, /1_0_0/, /100_100/
-     * <p/>
-     * Used on getLibraryVersion to filter resource directories
-     */
-    protected static Pattern VERSION_CHECKER = Pattern.compile("/\\p{Digit}+(_\\p{Digit}*)*/");
+    private MockResourceHandlerSupport resourceHandlerSupport;
+    
+    private ClassLoader _classLoader;
 
-    /**
-     * It checks version like this: /1.js, /1_0.js, /1_0_0.js, /100_100.js
-     * <p/>
-     * Used on getResourceVersion to filter resources
-     */
-    protected static Pattern RESOURCE_VERSION_CHECKER = Pattern.compile("/\\p{Digit}+(_\\p{Digit}*)*\\..*");
-
-    private File _documentRoot;
-
-    /**
-     * @param documentRoot parent folder of resource directories. Must not be <code>null</code>
-     */
-    public MockResourceHandler(File documentRoot)
+    public MockResourceHandler()
     {
-        if (documentRoot == null) {
-            throw new NullPointerException("documentRoot must not be null");
-        }
-
-        _documentRoot = documentRoot;
-
-        ((MockServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext())
-            .setDocumentRoot(_documentRoot);
+        _classLoader = getContextClassLoader();
+        resourceHandlerSupport = new MockResourceHandlerSupport(true, ".jsf",_classLoader);
+    }
+    
+    public MockResourceHandler(ClassLoader classLoader)
+    {
+        if (classLoader == null)
+            _classLoader = getContextClassLoader();
+        else
+            _classLoader = classLoader;
+        
+        resourceHandlerSupport = new MockResourceHandlerSupport(true, ".jsf",_classLoader);
+    }
+    
+    public MockResourceHandler(boolean extensionMapping, String mapping, ClassLoader classLoader)
+    {
+        if (classLoader == null)
+            _classLoader = getContextClassLoader();
+        else
+            _classLoader = classLoader;
+        
+        resourceHandlerSupport = new MockResourceHandlerSupport(extensionMapping, mapping,_classLoader);
     }
 
     @Override
@@ -92,22 +92,147 @@
     @Override
     public Resource createResource(String resourceName, String libraryName, String contentType)
     {
-        String prefix = getLocalePrefixForLocateResource();
-        String libraryVersion = getLibraryVersion(prefix + "/" + libraryName);
-
-        String pathToResource;
-        if (null != libraryVersion) {
-            pathToResource = prefix + '/'
-                + libraryName + '/' + libraryVersion + '/'
-                + resourceName;
-        }
-        else {
-            pathToResource = prefix + '/'
-                + libraryName + '/' + resourceName;
+        Resource resource = null;
+        
+        if (contentType == null)
+        {
+            //Resolve contentType using ExternalContext.getMimeType
+            contentType = FacesContext.getCurrentInstance().getExternalContext().getMimeType(resourceName);
         }
 
-        return new MockResource(prefix, libraryName, libraryVersion, resourceName, getResourceVersion(pathToResource), _documentRoot);
+        for (MockResourceLoader loader : getResourceHandlerSupport()
+                .getResourceLoaders())
+        {
+            MockResourceMeta resourceMeta = deriveResourceMeta(loader,
+                    resourceName, libraryName);
+
+            if (resourceMeta != null)
+            {
+                resource = new MockResource(resourceMeta, loader,
+                        getResourceHandlerSupport(), contentType);
+                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 MockResourceMeta deriveResourceMeta(MockResourceLoader resourceLoader,
+            String resourceName, String libraryName)
+    {
+        String localePrefix = getLocalePrefixForLocateResource();
+        String resourceVersion = null;
+        String libraryVersion = null;
+        MockResourceMeta 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 && MockResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+                {
+                    resourceId = resourceLoader.createResourceMeta(localePrefix, libraryName,
+                            libraryVersion, resourceName, resourceVersion);
+                }
+            }
+            else
+            {
+                resourceVersion = resourceLoader
+                        .getResourceVersion(localePrefix + '/'+ resourceName);
+                if (!(resourceVersion != null && MockResourceLoader.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 && MockResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+                {               
+                    resourceId = resourceLoader.createResourceMeta(null, libraryName,
+                            libraryVersion, resourceName, resourceVersion);
+                }
+            }
+            else
+            {
+                resourceVersion = resourceLoader
+                        .getResourceVersion(resourceName);
+                
+                if (!(resourceVersion != null && MockResourceLoader.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)
@@ -130,33 +255,7 @@
     @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.getExternalContext()
-            .getRequestMap().get(IS_RESOURCE_REQUEST);
-
-        if (value != null && value.booleanValue()) {
-            //return the saved value
-            return value.booleanValue();
-        }
-        else {
-            // assuming that we don't have servlet mapping
-            String resourceBasePath = facesContext.getExternalContext().getRequestPathInfo();
-
-            if (resourceBasePath != null
-                && resourceBasePath
-                .startsWith(ResourceHandler.RESOURCE_IDENTIFIER)) {
-                facesContext.getExternalContext().getRequestMap().put(
-                    IS_RESOURCE_REQUEST, Boolean.TRUE);
-                return true;
-            }
-            else {
-                facesContext.getExternalContext().getRequestMap().put(
-                    IS_RESOURCE_REQUEST, Boolean.FALSE);
-                return false;
-            }
-        }
+        return _resourceRequest;
     }
 
     @Override
@@ -214,9 +313,8 @@
      * against java2 security to ensure no security related exceptions are encountered.
      *
      * @return ClassLoader
-     * @since 3.0.6
      */
-    private static ClassLoader getContextClassLoader()
+    static ClassLoader getContextClassLoader()
     {
         if (System.getSecurityManager() != null) {
             try {
@@ -238,114 +336,24 @@
         }
     }
 
-    private String getLibraryVersion(String path)
+    public MockResourceHandlerSupport getResourceHandlerSupport()
     {
-        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
-
-        String libraryVersion = null;
-        Set<String> libraryPaths = context.getResourcePaths("/" + 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 (String libraryPath : libraryPaths) {
-                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 (compareVersion(libraryVersion, version) < 0) {
-                        libraryVersion = version;
-                    }
-                }
-            }
-        }
-        return libraryVersion;
+        return resourceHandlerSupport;
     }
 
-    private int compareVersion(String s1, String s2)
+    public void setResourceHandlerSupport(
+            MockResourceHandlerSupport resourceHandlerSupport)
     {
-        int n1 = 0;
-        int n2 = 0;
-        String o1 = s1;
-        String o2 = s2;
-
-        boolean p1 = true;
-        boolean p2 = true;
-
-        while (n1 == n2 && (p1 || p2)) {
-            int i1 = o1.indexOf('_');
-            int i2 = o2.indexOf('_');
-            if (i1 < 0) {
-                if (o1.length() > 0) {
-                    p1 = false;
-                    n1 = Integer.valueOf(o1);
-                    o1 = "";
-                }
-                else {
-                    p1 = false;
-                    n1 = 0;
-                }
-            }
-            else {
-                n1 = Integer.valueOf(o1.substring(0, i1));
-                o1 = o1.substring(i1 + 1);
-            }
-            if (i2 < 0) {
-                if (o2.length() > 0) {
-                    p2 = false;
-                    n2 = Integer.valueOf(o2);
-                    o2 = "";
-                }
-                else {
-                    p2 = false;
-                    n2 = 0;
-                }
-            }
-            else {
-                n2 = Integer.valueOf(o2.substring(0, i2));
-                o2 = o2.substring(i2 + 1);
-            }
-        }
-
-        if (n1 == n2) {
-            return s1.length() - s2.length();
-        }
-        return n1 - n2;
+        this.resourceHandlerSupport = resourceHandlerSupport;
     }
 
-    private String getResourceVersion(String path)
+    public void setResourceRequest(boolean resourceRequest)
     {
-        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
-        String resourceVersion = null;
-        Set<String> resourcePaths = context.getResourcePaths("/" + 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 (compareVersion(resourceVersion, version) < 0) {
-                        resourceVersion = version;
-                    }
-                }
-            }
-        }
-        return resourceVersion;
+        this._resourceRequest = resourceRequest;
     }
-}
+
+    public boolean isResourceRequest()
+    {
+        return _resourceRequest;
+    }
+}
\ No newline at end of file
diff --git a/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResourceHandlerSupport.java b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResourceHandlerSupport.java
new file mode 100644
index 0000000..fb90f43
--- /dev/null
+++ b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResourceHandlerSupport.java
@@ -0,0 +1,115 @@
+/*

+ * 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.test.mock.resource;

+

+

+/**

+ * Store additional info used by MockResource and MockResourceHandler

+ * 

+ * @author Leonardo Uribe (latest modification by $Author: jakobk $)

+ * @version $Revision: 960906 $ $Date: 2010-07-06 09:45:40 -0500 (Mar, 06 Jul 2010) $

+ */

+public class MockResourceHandlerSupport

+{

+

+    private boolean _extensionMapping;

+

+    private String _mapping;

+

+    private MockResourceLoader[] _resourceLoaders;

+

+    public MockResourceHandlerSupport()

+    {

+        _extensionMapping = true;

+        _mapping = ".jsf";

+        _resourceLoaders = new MockResourceLoader[]{ new MockExternalContextResourceLoader("/resources"),

+                new MockClassLoaderResourceLoader(MockResourceHandler.getContextClassLoader(), "META-INF/resources")};

+    }

+    

+    public MockResourceHandlerSupport(boolean extensionMapping, String mapping)

+    {

+        super();

+        _extensionMapping = extensionMapping;

+        _mapping = mapping;

+        _resourceLoaders = new MockResourceLoader[]{ new MockExternalContextResourceLoader("/resources"),

+                new MockClassLoaderResourceLoader(MockResourceHandler.getContextClassLoader(), "META-INF/resources")};

+    }

+

+    public MockResourceHandlerSupport(boolean extensionMapping, String mapping, ClassLoader classLoader)

+    {

+        _extensionMapping = extensionMapping;

+        _mapping = mapping;

+        _resourceLoaders = new MockResourceLoader[]{ new MockExternalContextResourceLoader("/resources"),

+                new MockClassLoaderResourceLoader(classLoader, "META-INF/resources")};

+    }

+

+    public MockResourceHandlerSupport(boolean extensionMapping, String mapping,

+            MockResourceLoader[] resourceLoaders)

+    {

+        super();

+        _extensionMapping = extensionMapping;

+        _mapping = mapping;

+        _resourceLoaders = resourceLoaders;

+    }

+

+    /**

+     * Check if the mapping used is done using extensions (.xhtml, .jsf)

+     * or if it is not (/faces/*)

+     * @return

+     */

+    public boolean isExtensionMapping()

+    {

+        return _extensionMapping;

+    }

+    

+    public void setExtensionMapping(boolean extensionMapping)

+    {

+        _extensionMapping = extensionMapping;

+    }

+

+    /**

+     * Get the mapping used as prefix(/faces) or sufix(.jsf)

+     * 

+     * @return

+     */

+    public String getMapping()

+    {

+        return _mapping;

+    }

+    

+    public void setMapping(String prefix)

+    {

+        _mapping = prefix;

+    }

+    

+    /**

+     * Return an array of resource loaders used to find resources

+     * using the standard. The order of ResourceLoaders define

+     * its precedence. 

+     * 

+     * @return

+     */

+    public MockResourceLoader[] getResourceLoaders()

+    {

+        return _resourceLoaders; 

+    }

+

+    public void setResourceLoaders(MockResourceLoader[] resourceLoaders)

+    {

+        _resourceLoaders = resourceLoaders;

+    }

+}

diff --git a/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResourceLoader.java b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResourceLoader.java
new file mode 100644
index 0000000..81bf0e2
--- /dev/null
+++ b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResourceLoader.java
@@ -0,0 +1,155 @@
+/*

+ * 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.test.mock.resource;

+

+import java.io.InputStream;

+import java.net.URL;

+import java.util.Comparator;

+

+/**

+ * Base class for resource loaders.  Resource loaders can lookup resources 

+ * as URLs from arbitrary locations, including JAR files.

+ * 

+ * @author Leonardo Uribe (latest modification by $Author: lu4242 $)

+ * @version $Revision: 882702 $ $Date: 2009-11-20 15:16:07 -0500 (Vie, 20 Nov 2009) $

+ */

+public abstract class MockResourceLoader

+{

+    

+    public static final String VERSION_INVALID = "INVALID";

+    

+    private String _prefix;

+    

+    public MockResourceLoader(String prefix)

+    {

+        _prefix = prefix;

+    }

+

+    public abstract String getResourceVersion(String path);

+

+    /**

+     * Return the max available version found (if exists) or

+     * return null if no version available. 

+     */

+    public abstract String getLibraryVersion(String path);

+

+    /**

+     * Return the max available version found (if exists) or

+     * return null if no version available. 

+     */

+    public abstract URL getResourceURL(MockResourceMeta resourceMeta);

+

+    public abstract InputStream getResourceInputStream(MockResourceMeta resourceMeta);

+    

+    public abstract MockResourceMeta createResourceMeta(String prefix, String libraryName, String libraryVersion,

+            String resourceName, String resourceVersion);

+    

+    public abstract boolean libraryExists(String libraryName);

+    

+    private Comparator<String> _versionComparator = null;

+

+    protected Comparator<String> getVersionComparator()

+    {

+        if (_versionComparator == null)

+        {

+            _versionComparator = new VersionComparator();

+        }

+        return _versionComparator;

+    }

+

+    protected void setVersionComparator(Comparator<String> versionComparator)

+    {

+        _versionComparator = versionComparator;

+    }

+

+    public class VersionComparator implements Comparator<String>

+    {

+

+        public int compare(String s1, String s2)

+        {

+            int n1 = 0;

+            int n2 = 0;

+            String o1 = s1;

+            String o2 = s2;

+

+            boolean p1 = true;

+            boolean p2 = true;

+

+            while (n1 == n2 && (p1 || p2))

+            {

+                int i1 = o1.indexOf('_');

+                int i2 = o2.indexOf('_');

+                if (i1 < 0)

+                {

+                    if (o1.length() > 0)

+                    {

+                        p1 = false;

+                        n1 = Integer.valueOf(o1);

+                        o1 = "";

+                    }

+                    else

+                    {

+                        p1 = false;

+                        n1 = 0;

+                    }

+                }

+                else

+                {

+                    n1 = Integer.valueOf(o1.substring(0, i1));

+                    o1 = o1.substring(i1 + 1);

+                }

+                if (i2 < 0)

+                {

+                    if (o2.length() > 0)

+                    {

+                        p2 = false;

+                        n2 = Integer.valueOf(o2);

+                        o2 = "";

+                    }

+                    else

+                    {

+                        p2 = false;

+                        n2 = 0;

+                    }

+                }

+                else

+                {

+                    n2 = Integer.valueOf(o2.substring(0, i2));

+                    o2 = o2.substring(i2 + 1);

+                }

+            }

+

+            if (n1 == n2)

+            {

+                return s1.length() - s2.length();

+            }

+            return n1 - n2;

+        }

+    }

+    

+    public String getPrefix()

+    {

+        return _prefix;

+    }

+

+    public void setPrefix(String prefix)

+    {

+        _prefix = prefix;

+    }

+}

diff --git a/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResourceMeta.java b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResourceMeta.java
new file mode 100644
index 0000000..9fee22e
--- /dev/null
+++ b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockResourceMeta.java
@@ -0,0 +1,110 @@
+/*

+ * 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.test.mock.resource;

+

+/**

+ * Contains the metadata information to reference a resource 

+ * 

+ * @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 MockResourceMeta

+{

+    

+    private final String _prefix;

+    private final String _libraryName;

+    private final String _libraryVersion;

+    private final String _resourceName;

+    private final String _resourceVersion;

+    

+    public MockResourceMeta(String prefix, String libraryName, String libraryVersion,

+            String resourceName, String resourceVersion)

+    {

+        _prefix = prefix;

+        _libraryName = libraryName;

+        _libraryVersion = libraryVersion;

+        _resourceName = resourceName;

+        _resourceVersion = resourceVersion;

+    }

+

+    public String getLibraryName()

+    {

+        return _libraryName;

+    }    

+    

+    public String getResourceName()

+    {

+        return _resourceName;

+    }    

+

+    public String getLocalePrefix()

+    {

+        return _prefix;

+    }

+

+    public String getLibraryVersion()

+    {

+        return _libraryVersion;

+    }

+

+    public String getResourceVersion()

+    {

+        return _resourceVersion;

+    }

+    

+    public String getResourceIdentifier()

+    {

+        StringBuilder builder = new StringBuilder();

+        boolean firstSlashAdded = false;

+        if (_prefix != null && _prefix.length() > 0)

+        {

+            builder.append(_prefix);

+            firstSlashAdded = true;

+        }

+        if (_libraryName != null)

+        {

+            if (firstSlashAdded) builder.append('/');

+            builder.append(_libraryName);

+            firstSlashAdded = true;

+        }

+        if (_libraryVersion != null)

+        {

+            if (firstSlashAdded) builder.append('/');

+            builder.append(_libraryVersion);

+            firstSlashAdded = true;

+        }

+        if (_resourceName != null)

+        {

+            if (firstSlashAdded) builder.append('/');

+            builder.append(_resourceName);

+            firstSlashAdded = true;

+        }

+        if (_resourceVersion != null)

+        {

+            if (firstSlashAdded) builder.append('/');

+            builder.append(_resourceVersion);

+            builder.append(

+                    _resourceName.substring(_resourceName.lastIndexOf('.')));

+            firstSlashAdded = true;

+        }

+

+        return builder.toString();

+    }

+

+}

diff --git a/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockSimpleResource.java b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockSimpleResource.java
new file mode 100644
index 0000000..56dbcc9
--- /dev/null
+++ b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockSimpleResource.java
@@ -0,0 +1,182 @@
+/*

+ * 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.test.mock.resource;

+

+import org.apache.myfaces.test.mock.MockServletContext;

+

+import javax.faces.application.Resource;

+import javax.faces.context.FacesContext;

+import java.io.File;

+import java.io.IOException;

+import java.io.InputStream;

+import java.net.MalformedURLException;

+import java.net.URL;

+import java.util.Map;

+

+/**

+ * <p>Mock simple implementation of <code>Resource</code>.</p>

+ * 

+ * <p>

+ * It is used by MockSimpleResourceHandler to wrap resource instances.

+ * </p>

+ * 

+ * @author Jakob Korherr (latest modification by $Author: lu4242 $)

+ * @version $Revision: 882702 $ $Date: 2009-11-20 15:16:07 -0500 (Vie, 20 Nov 2009) $

+ */

+public class MockSimpleResource extends Resource

+{

+

+    private String _prefix;

+    private String _libraryName;

+    private String _libraryVersion;

+    private String _resourceName;

+    private String _resourceVersion;

+    private File _documentRoot;

+

+    /**

+     * Creates new resource object

+     *

+     * @param prefix          locale prefix if any

+     * @param libraryName     resource library name

+     * @param libraryVersion  resource library version if any

+     * @param resourceName    resource file name

+     * @param resourceVersion resource version if any

+     * @param documentRoot    parent folder of resource directories. Must not be <code>null</code>

+     */

+    public MockSimpleResource(String prefix, String libraryName, String libraryVersion, String resourceName, String resourceVersion, File documentRoot)

+    {

+        _prefix = prefix;

+        _libraryName = libraryName;

+        _libraryVersion = libraryVersion;

+        _resourceName = resourceName;

+        _resourceVersion = resourceVersion;

+        _documentRoot = documentRoot;

+

+        if (_documentRoot == null) {

+            throw new IllegalArgumentException("documentRoot must not be null");

+        }

+    }

+

+    @Override

+    public String getResourceName()

+    {

+        return _resourceName;

+    }

+

+    @Override

+    public void setResourceName(String resourceName)

+    {

+        _resourceName = resourceName;

+    }

+

+    @Override

+    public String getLibraryName()

+    {

+        return _libraryName;

+    }

+    

+    @Override

+    public void setLibraryName(String libraryName)

+    {

+        _libraryName = libraryName;

+    }

+

+    @Override

+    public InputStream getInputStream() throws IOException

+    {

+        MockServletContext servletContext = (MockServletContext)

+            FacesContext.getCurrentInstance().getExternalContext().getContext();

+        servletContext.setDocumentRoot(_documentRoot);

+        return servletContext.getResourceAsStream(buildResourcePath());

+    }

+

+    @Override

+    public String getRequestPath()

+    {

+        throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public Map<String, String> getResponseHeaders()

+    {

+        throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public URL getURL()

+    {

+        MockServletContext servletContext = (MockServletContext)

+            FacesContext.getCurrentInstance().getExternalContext().getContext();

+        servletContext.setDocumentRoot(_documentRoot);

+

+        try {

+            return servletContext.getResource(buildResourcePath());

+        } catch (MalformedURLException e) {

+            return null;

+        }

+    }

+

+    @Override

+    public boolean userAgentNeedsUpdate(FacesContext context)

+    {

+        return true;

+    }

+

+    private String buildResourcePath()

+    {

+        StringBuilder builder = new StringBuilder();

+        builder.append('/');

+        boolean firstSlashAdded = false;

+        if (_prefix != null && _prefix.length() > 0) {

+            builder.append(_prefix);

+            firstSlashAdded = true;

+        }

+        if (_libraryName != null) {

+            if (firstSlashAdded) {

+                builder.append('/');

+            }

+            builder.append(_libraryName);

+            firstSlashAdded = true;

+        }

+        if (_libraryVersion != null) {

+            if (firstSlashAdded) {

+                builder.append('/');

+            }

+            builder.append(_libraryVersion);

+            firstSlashAdded = true;

+        }

+        if (_resourceName != null) {

+            if (firstSlashAdded) {

+                builder.append('/');

+            }

+            builder.append(_resourceName);

+            firstSlashAdded = true;

+        }

+        if (_resourceVersion != null) {

+            if (firstSlashAdded) {

+                builder.append('/');

+            }

+            builder.append(_resourceVersion);

+            builder.append(

+                _resourceName.substring(_resourceName.lastIndexOf('.')));

+        }

+

+        return builder.toString();

+    }

+

+}

diff --git a/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockSimpleResourceHandler.java b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockSimpleResourceHandler.java
new file mode 100644
index 0000000..eebf58f
--- /dev/null
+++ b/test20/src/main/java/org/apache/myfaces/test/mock/resource/MockSimpleResourceHandler.java
@@ -0,0 +1,352 @@
+/*

+ * 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.test.mock.resource;

+

+import org.apache.myfaces.test.mock.MockServletContext;

+

+import javax.faces.FacesException;

+import javax.faces.application.Resource;

+import javax.faces.application.ResourceHandler;

+import javax.faces.context.ExternalContext;

+import javax.faces.context.FacesContext;

+import java.io.File;

+import java.io.IOException;

+import java.net.MalformedURLException;

+import java.net.URL;

+import java.security.AccessController;

+import java.security.PrivilegedActionException;

+import java.security.PrivilegedExceptionAction;

+import java.util.*;

+import java.util.regex.Pattern;

+

+/**

+ * <p>Mock implementation of <code>ResourceHandler</code>.</p>

+ * <p>This Mock could be used on situations where all resources

+ * are on a specific path.</p>

+ * 

+ * @author Jakob Korherr (latest modification by $Author: lu4242 $)

+ * @version $Revision: 882702 $ $Date: 2009-11-20 15:16:07 -0500 (Vie, 20 Nov 2009) $

+ */

+public class MockSimpleResourceHandler extends ResourceHandler

+{

+

+    private static final String IS_RESOURCE_REQUEST = "org.apache.myfaces.IS_RESOURCE_REQUEST";

+

+    /**

+     * It checks version like this: /1/, /1_0/, /1_0_0/, /100_100/

+     * <p/>

+     * 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

+     * <p/>

+     * Used on getResourceVersion to filter resources

+     */

+    protected static Pattern RESOURCE_VERSION_CHECKER = Pattern.compile("/\\p{Digit}+(_\\p{Digit}*)*\\..*");

+

+    private File _documentRoot;

+

+    /**

+     * @param documentRoot parent folder of resource directories. Must not be <code>null</code>

+     */

+    public MockSimpleResourceHandler(File documentRoot)

+    {

+        if (documentRoot == null) {

+            throw new NullPointerException("documentRoot must not be null");

+        }

+

+        _documentRoot = documentRoot;

+

+        ((MockServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext())

+            .setDocumentRoot(_documentRoot);

+    }

+

+    @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)

+    {

+        String prefix = getLocalePrefixForLocateResource();

+        String libraryVersion = getLibraryVersion(prefix + "/" + libraryName);

+

+        String pathToResource;

+        if (null != libraryVersion) {

+            pathToResource = prefix + '/'

+                + libraryName + '/' + libraryVersion + '/'

+                + resourceName;

+        }

+        else {

+            pathToResource = prefix + '/'

+                + libraryName + '/' + resourceName;

+        }

+

+        return new MockSimpleResource(prefix, libraryName, libraryVersion, resourceName, getResourceVersion(pathToResource), _documentRoot);

+    }

+

+    @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;

+    }

+

+    @Override

+    public void handleResourceRequest(FacesContext context) throws IOException

+    {

+        throw new UnsupportedOperationException();

+    }

+

+    @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.getExternalContext()

+            .getRequestMap().get(IS_RESOURCE_REQUEST);

+

+        if (value != null && value.booleanValue()) {

+            //return the saved value

+            return value.booleanValue();

+        }

+        else {

+            // assuming that we don't have servlet mapping

+            String resourceBasePath = facesContext.getExternalContext().getRequestPathInfo();

+

+            if (resourceBasePath != null

+                && resourceBasePath

+                .startsWith(ResourceHandler.RESOURCE_IDENTIFIER)) {

+                facesContext.getExternalContext().getRequestMap().put(

+                    IS_RESOURCE_REQUEST, Boolean.TRUE);

+                return true;

+            }

+            else {

+                facesContext.getExternalContext().getRequestMap().put(

+                    IS_RESOURCE_REQUEST, Boolean.FALSE);

+                return false;

+            }

+        }

+    }

+

+    @Override

+    public boolean libraryExists(String libraryName)

+    {

+        String localePrefix = getLocalePrefixForLocateResource();

+

+        String pathToLib;

+

+        if (localePrefix != null) {

+            //Check with locale

+            pathToLib = localePrefix + '/' + libraryName;

+        }

+        else {

+            pathToLib = libraryName;

+        }

+

+        try {

+            URL url = FacesContext.getCurrentInstance().getExternalContext().getResource("/" + pathToLib);

+            return (url != null);

+        }

+        catch (MalformedURLException e) {

+            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, getContextClassLoader());

+

+            if (bundle != null) {

+                try {

+                    localePrefix = bundle.getString(ResourceHandler.LOCALE_PREFIX);

+                }

+                catch (MissingResourceException e) {

+                    // Ignore it and return null

+                }

+            }

+        }

+        return localePrefix;

+    }

+

+    /**

+     * Gets the ClassLoader associated with the current thread.  Includes a check for priviledges

+     * against java2 security to ensure no security related exceptions are encountered.

+     *

+     * @return ClassLoader

+     * @since 3.0.6

+     */

+    private static ClassLoader getContextClassLoader()

+    {

+        if (System.getSecurityManager() != null) {

+            try {

+                ClassLoader cl = AccessController.doPrivileged(new PrivilegedExceptionAction<ClassLoader>()

+                {

+                    public ClassLoader run() throws PrivilegedActionException

+                    {

+                        return Thread.currentThread().getContextClassLoader();

+                    }

+                });

+                return cl;

+            }

+            catch (PrivilegedActionException pae) {

+                throw new FacesException(pae);

+            }

+        }

+        else {

+            return Thread.currentThread().getContextClassLoader();

+        }

+    }

+

+    private String getLibraryVersion(String path)

+    {

+        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();

+

+        String libraryVersion = null;

+        Set<String> libraryPaths = context.getResourcePaths("/" + 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 (String libraryPath : libraryPaths) {

+                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 (compareVersion(libraryVersion, version) < 0) {

+                        libraryVersion = version;

+                    }

+                }

+            }

+        }

+        return libraryVersion;

+    }

+

+    private int compareVersion(String s1, String s2)

+    {

+        int n1 = 0;

+        int n2 = 0;

+        String o1 = s1;

+        String o2 = s2;

+

+        boolean p1 = true;

+        boolean p2 = true;

+

+        while (n1 == n2 && (p1 || p2)) {

+            int i1 = o1.indexOf('_');

+            int i2 = o2.indexOf('_');

+            if (i1 < 0) {

+                if (o1.length() > 0) {

+                    p1 = false;

+                    n1 = Integer.valueOf(o1);

+                    o1 = "";

+                }

+                else {

+                    p1 = false;

+                    n1 = 0;

+                }

+            }

+            else {

+                n1 = Integer.valueOf(o1.substring(0, i1));

+                o1 = o1.substring(i1 + 1);

+            }

+            if (i2 < 0) {

+                if (o2.length() > 0) {

+                    p2 = false;

+                    n2 = Integer.valueOf(o2);

+                    o2 = "";

+                }

+                else {

+                    p2 = false;

+                    n2 = 0;

+                }

+            }

+            else {

+                n2 = Integer.valueOf(o2.substring(0, i2));

+                o2 = o2.substring(i2 + 1);

+            }

+        }

+

+        if (n1 == n2) {

+            return s1.length() - s2.length();

+        }

+        return n1 - n2;

+    }

+

+    private String getResourceVersion(String path)

+    {

+        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();

+        String resourceVersion = null;

+        Set<String> resourcePaths = context.getResourcePaths("/" + 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 (compareVersion(resourceVersion, version) < 0) {

+                        resourceVersion = version;

+                    }

+                }

+            }

+        }

+        return resourceVersion;

+    }

+}

diff --git a/test20/src/test/java/org/apache/myfaces/test/mock/MockResourceTestCase.java b/test20/src/test/java/org/apache/myfaces/test/mock/MockResourceTestCase.java
index e5d9fe1..bf74832 100644
--- a/test20/src/test/java/org/apache/myfaces/test/mock/MockResourceTestCase.java
+++ b/test20/src/test/java/org/apache/myfaces/test/mock/MockResourceTestCase.java
@@ -17,18 +17,20 @@
 
 package org.apache.myfaces.test.mock;
 
-import junit.framework.Test;
-import junit.framework.TestSuite;
-import org.apache.myfaces.test.base.AbstractJsfTestCase;
-import org.apache.myfaces.test.mock.resource.MockResource;
-import org.apache.myfaces.test.mock.resource.MockResourceHandler;
-
-import javax.faces.application.Resource;
-import javax.faces.application.ResourceHandler;
 import java.io.File;
 import java.io.InputStream;
 import java.net.URL;
 
+import javax.faces.application.Resource;
+import javax.faces.application.ResourceHandler;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.myfaces.test.base.AbstractJsfTestCase;
+import org.apache.myfaces.test.mock.resource.MockSimpleResource;
+import org.apache.myfaces.test.mock.resource.MockSimpleResourceHandler;
+
 /**
  * Test case for resource handling
  */
@@ -58,7 +60,7 @@
 
     public void testGetResource() throws Exception {
 
-        Resource resource = new MockResource(null, "testlib", null, "testfile.js", null, _documentRoot);
+        Resource resource = new MockSimpleResource(null, "testlib", null, "testfile.js", null, _documentRoot);
 
         URL resourceUrl = resource.getURL();
         assertNotNull("Could not find resource", resourceUrl);
@@ -67,27 +69,27 @@
 
     public void testGetNotExistingResource() throws Exception {
 
-        Resource resource = new MockResource(null, "testlib", null, "notexisting.js", null, _documentRoot);
+        Resource resource = new MockSimpleResource(null, "testlib", null, "notexisting.js", null, _documentRoot);
 
         assertNull(resource.getURL());
     }
 
     public void testGetAsStream() throws Exception {
-        Resource resource = new MockResource(null, "testlib", null, "testfile.js", null, _documentRoot);
+        Resource resource = new MockSimpleResource(null, "testlib", null, "testfile.js", null, _documentRoot);
         InputStream stream = resource.getInputStream();
         assertNotNull(stream);
         assertTrue(stream.read() != -1);
     }
 
     public void testCreateResource() throws Exception {
-        ResourceHandler handler = new MockResourceHandler(_documentRoot);
+        ResourceHandler handler = new MockSimpleResourceHandler(_documentRoot);
         Resource resource = handler.createResource("testfile.js", "testlib");
         assertNotNull("resource could not be created", resource);
         assertTrue(resource.getURL().toString().endsWith("org/apache/myfaces/test/mock/resources/testlib/testfile.js"));
     }
 
     public void testResourceHandler() throws Exception {
-       ResourceHandler handler = new MockResourceHandler(_documentRoot);
+       ResourceHandler handler = new MockSimpleResourceHandler(_documentRoot);
 
         assertTrue(handler.libraryExists("testlib"));
         assertFalse(handler.libraryExists("notexistinglib"));