You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2013/05/24 03:27:33 UTC

svn commit: r1485917 [1/4] - in /myfaces/core/trunk: api/src/main/java/javax/faces/application/ api/src/main/java/javax/faces/context/ api/src/main/java/javax/faces/view/ impl/src/main/java/org/apache/myfaces/application/ impl/src/main/java/org/apache/...

Author: lu4242
Date: Fri May 24 01:27:31 2013
New Revision: 1485917

URL: http://svn.apache.org/r1485917
Log:
MYFACES-3729 Implement resource library contracts specification 

Added:
    myfaces/core/trunk/api/src/main/java/javax/faces/application/ViewResource.java   (with props)
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/_LocaleUtils.java
      - copied, changed from r1470662, myfaces/core/trunk/api/src/main/java/javax/faces/component/_LocaleUtils.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/resource/ClassLoaderContractResourceLoader.java   (with props)
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/resource/DefaultResourceLibraryContractsProvider.java   (with props)
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/resource/ExternalContextContractResourceLoader.java   (with props)
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/resource/FacesFlowClassLoaderResourceLoader.java   (with props)
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/resource/RootExternalContextResourceLoader.java
      - copied, changed from r1470662, myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/ExternalContextResourceLoader.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/ResourceLibraryContractsProvider.java
      - copied, changed from r1470662, myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FaceletConfigResourceProvider.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/ResourceLibraryContractsProviderFactory.java
      - copied, changed from r1470662, myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FaceletConfigResourceProviderFactory.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultResourceLibraryContractsProviderFactory.java
      - copied, changed from r1470662, myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultFaceletConfigResourceProviderFactory.java
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/ResourceHandlerImplContractTest.java   (with props)
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/contracts/
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/contracts/ContractsCreateResourceMyFacesRequestTestCase.java
      - copied, changed from r1470662, myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/AcidMyFacesRequestTestCase.java
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/contracts/DefaultContractsConfigMyFacesRequestTestCase.java
      - copied, changed from r1470662, myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/AcidMyFacesRequestTestCase.java
    myfaces/core/trunk/impl/src/test/resources/META-INF/contracts/
    myfaces/core/trunk/impl/src/test/resources/META-INF/contracts/blue/
    myfaces/core/trunk/impl/src/test/resources/META-INF/contracts/blue/javax.faces.contract.xml   (with props)
    myfaces/core/trunk/impl/src/test/resources/META-INF/contracts/blue/mylib/   (with props)
    myfaces/core/trunk/impl/src/test/resources/META-INF/contracts/blue/mylib/myjs.js   (with props)
    myfaces/core/trunk/impl/src/test/resources/META-INF/contracts/blue/panel.xhtml
      - copied, changed from r1470662, myfaces/current22/client-window-example/src/main/webapp/flashKeep1.xhtml
    myfaces/core/trunk/impl/src/test/resources/META-INF/contracts/yellow/   (with props)
    myfaces/core/trunk/impl/src/test/resources/META-INF/contracts/yellow/javax.faces.contract.xml   (with props)
    myfaces/core/trunk/impl/src/test/resources/META-INF/contracts/yellow/mylib/   (with props)
    myfaces/core/trunk/impl/src/test/resources/META-INF/contracts/yellow/mylib/myjs.js   (with props)
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/contracts/
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/contracts/blue-faces-config.xml
      - copied, changed from r1470662, myfaces/current22/client-window-example/src/main/webapp/WEB-INF/faces-config.xml
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/contracts/contracts/   (with props)
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/contracts/contracts/red/   (with props)
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/contracts/contracts/red/mylib/   (with props)
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/contracts/contracts/red/mylib/myjs.js   (with props)
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/contracts/index.xhtml
      - copied, changed from r1470662, myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/index.xhtml
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/ContractResource.java   (with props)
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/ContractResourceLoader.java   (with props)
Modified:
    myfaces/core/trunk/api/src/main/java/javax/faces/application/Resource.java
    myfaces/core/trunk/api/src/main/java/javax/faces/application/ResourceHandler.java
    myfaces/core/trunk/api/src/main/java/javax/faces/application/ResourceHandlerWrapper.java
    myfaces/core/trunk/api/src/main/java/javax/faces/context/FacesContext.java
    myfaces/core/trunk/api/src/main/java/javax/faces/view/ViewDeclarationLanguage.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/DefaultResourceHandlerSupport.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ResourceHandlerImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/RuntimeConfig.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/context/servlet/FacesContextImplBase.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/resource/InternalClassLoaderResourceLoader.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletFactory.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultResourceResolver.java
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/ApplicationImplJsfTest.java
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/ResourceHandlerImplTest.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/AliasResourceMetaImpl.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/BaseResourceHandlerSupport.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/ClassLoaderResourceLoader.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/ExternalContextResourceLoader.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/ResourceHandlerCache.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/ResourceHandlerSupport.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/ResourceImpl.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/ResourceLoader.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/ResourceLoaderWrapper.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/ResourceMeta.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/ResourceMetaImpl.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/resource/ResourceValidationUtils.java

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/application/Resource.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/application/Resource.java?rev=1485917&r1=1485916&r2=1485917&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/application/Resource.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/application/Resource.java Fri May 24 01:27:31 2013
@@ -31,7 +31,7 @@ import javax.faces.context.FacesContext;
  * 
  * @since 2.0
  */
-public abstract class Resource
+public abstract class Resource extends ViewResource
 {
     /**
      * This constant is used as the key in the component attribute map of a composite component to 

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/application/ResourceHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/application/ResourceHandler.java?rev=1485917&r1=1485916&r2=1485917&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/application/ResourceHandler.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/application/ResourceHandler.java Fri May 24 01:27:31 2013
@@ -42,6 +42,21 @@ public abstract class ResourceHandler
     public static final String RESOURCE_EXCLUDES_PARAM_NAME = "javax.faces.RESOURCE_EXCLUDES";
     public static final String RESOURCE_IDENTIFIER = "/javax.faces.resource";
     
+    /**
+     * @since 2.2
+     */
+    public static final String RESOURCE_CONTRACT_XML = "javax.faces.contract.xml";
+    
+    /**
+     * @since 2.2
+     */
+    public static final String WEBAPP_CONTRACTS_DIRECTORY_PARAM_NAME = "javax.faces.WEBAPP_CONTRACTS_DIRECTORY";
+
+    /**
+     * @since 2.2
+     */
+    public static final String WEBAPP_RESOURCES_DIRECTORY_PARAM_NAME = "javax.faces.WEBAPP_RESOURCES_DIRECTORY";
+     
     public abstract Resource createResource(String resourceName);
     
     public abstract Resource createResource(String resourceName, String libraryName);
@@ -55,4 +70,27 @@ public abstract class ResourceHandler
     public abstract boolean isResourceRequest(FacesContext context);
     
     public abstract  boolean libraryExists(String libraryName);
+    
+    /**
+     * @since 2.2
+     * @param resourceId
+     * @return 
+     */
+    public Resource createResourceFromId(String resourceId)
+    {
+        return null;
+    }
+    
+    /**
+     * 
+     * @since 2.2
+     * @param context
+     * @param resourceName
+     * @return 
+     */
+    public Resource createViewResource(FacesContext context,
+                                       String resourceName)
+    {
+        return context.getApplication().getResourceHandler().createResource(resourceName);
+    }
 }

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/application/ResourceHandlerWrapper.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/application/ResourceHandlerWrapper.java?rev=1485917&r1=1485916&r2=1485917&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/application/ResourceHandlerWrapper.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/application/ResourceHandlerWrapper.java Fri May 24 01:27:31 2013
@@ -73,6 +73,18 @@ public abstract class ResourceHandlerWra
     {
         return getWrapped().libraryExists(libraryName);
     }
+
+    @Override
+    public Resource createResourceFromId(String resourceId)
+    {
+        return getWrapped().createResourceFromId(resourceId);
+    }
+
+    @Override
+    public Resource createViewResource(FacesContext context, String resourceName)
+    {
+        return getWrapped().createViewResource(context, resourceName);
+    }
     
     public abstract ResourceHandler getWrapped();
 }

Added: myfaces/core/trunk/api/src/main/java/javax/faces/application/ViewResource.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/application/ViewResource.java?rev=1485917&view=auto
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/application/ViewResource.java (added)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/application/ViewResource.java Fri May 24 01:27:31 2013
@@ -0,0 +1,34 @@
+/*
+ * 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 javax.faces.application;
+
+import java.net.URL;
+
+/**
+ *
+ * @since 2.2
+ */
+public abstract class ViewResource
+{
+    public ViewResource()
+    {
+    }
+    
+    public abstract URL getURL();
+}

Propchange: myfaces/core/trunk/api/src/main/java/javax/faces/application/ViewResource.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/context/FacesContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/context/FacesContext.java?rev=1485917&r1=1485916&r2=1485917&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/context/FacesContext.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/context/FacesContext.java Fri May 24 01:27:31 2013
@@ -18,6 +18,7 @@
  */
 package javax.faces.context;
 
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -431,4 +432,35 @@ public abstract class FacesContext
 
         return ctx.isReleased();
     }
+    
+    /**
+     * @since 2.2
+     * @return 
+     */
+    public List<String> getResourceLibraryContracts()
+    {
+        FacesContext ctx = firstInstance.get();
+        
+        if (ctx == null)
+        {
+            return Collections.emptyList();
+        }        
+        
+        return ctx.getResourceLibraryContracts();
+    }
+    
+    /**
+     * @since 2.2
+     * @param contracts 
+     */
+    public void setResourceLibraryContracts(List<String> contracts)
+    {
+        FacesContext ctx = firstInstance.get();
+        
+        if (ctx == null)
+        {
+            return;
+        }
+        ctx.setResourceLibraryContracts(contracts);
+    }
 }

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/view/ViewDeclarationLanguage.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/view/ViewDeclarationLanguage.java?rev=1485917&r1=1485916&r2=1485917&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/view/ViewDeclarationLanguage.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/view/ViewDeclarationLanguage.java Fri May 24 01:27:31 2013
@@ -22,6 +22,7 @@ import java.beans.BeanInfo;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.util.List;
+import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -108,4 +109,32 @@ public abstract class ViewDeclarationLan
         }
         return false;
     }
+    
+    /**
+     * @since 2.2
+     * @param context
+     * @param taglibURI
+     * @param tagName
+     * @param attributes
+     * @return 
+     */
+    public UIComponent createComponent(FacesContext context,
+                                   String taglibURI,
+                                   String tagName,
+                                   Map<String,Object> attributes)
+    {
+        return null;
+    }
+    
+    /**
+     * @since 2.2
+     * @param context
+     * @param viewId
+     * @return 
+     */
+    public List<String> calculateResourceLibraryContracts(FacesContext context,
+                                                      String viewId)
+    {
+        return null;
+    }
 }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/DefaultResourceHandlerSupport.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/DefaultResourceHandlerSupport.java?rev=1485917&r1=1485916&r2=1485917&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/DefaultResourceHandlerSupport.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/DefaultResourceHandlerSupport.java Fri May 24 01:27:31 2013
@@ -19,13 +19,19 @@
 package org.apache.myfaces.application;
 
 import javax.faces.application.ProjectStage;
+import javax.faces.application.ResourceHandler;
 import javax.faces.context.FacesContext;
+import org.apache.myfaces.resource.ClassLoaderContractResourceLoader;
+import org.apache.myfaces.resource.ExternalContextContractResourceLoader;
+import org.apache.myfaces.resource.FacesFlowClassLoaderResourceLoader;
 
 import org.apache.myfaces.resource.InternalClassLoaderResourceLoader;
+import org.apache.myfaces.resource.RootExternalContextResourceLoader;
 import org.apache.myfaces.resource.TempDirFileCacheResourceLoader;
 import org.apache.myfaces.shared.renderkit.html.util.ResourceUtils;
 import org.apache.myfaces.shared.resource.BaseResourceHandlerSupport;
 import org.apache.myfaces.shared.resource.ClassLoaderResourceLoader;
+import org.apache.myfaces.shared.resource.ContractResourceLoader;
 import org.apache.myfaces.shared.resource.ExternalContextResourceLoader;
 import org.apache.myfaces.shared.resource.ResourceLoader;
 import org.apache.myfaces.shared.util.WebConfigParamUtils;
@@ -41,11 +47,17 @@ public class DefaultResourceHandlerSuppo
 {
 
     private static final String META_INF_RESOURCES = "META-INF/resources";
-    private static final String RESOURCES = "/resources";
+    private static final String RESOURCES = "resources";
     private static final String META_INF_INTERNAL_RESOURCES = "META-INF/internal-resources";
+    private static final String META_INF_CONTRACTS = "META-INF/contracts";
+    private static final String CONTRACTS = "contracts";
 
     private ResourceLoader[] _resourceLoaders;
     
+    private ContractResourceLoader[] _contractResourceLoaders;
+    
+    private ResourceLoader[] _viewResourceLoaders;
+    
     public DefaultResourceHandlerSupport()
     {
         super();
@@ -57,6 +69,9 @@ public class DefaultResourceHandlerSuppo
         {
             FacesContext facesContext = FacesContext.getCurrentInstance(); 
             
+            String directory = WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(), 
+                ResourceHandler.WEBAPP_RESOURCES_DIRECTORY_PARAM_NAME, RESOURCES);
+            
             if (TempDirFileCacheResourceLoader.isValidCreateTemporalFiles(facesContext))
             {
                 //The ExternalContextResourceLoader has precedence over
@@ -69,7 +84,8 @@ public class DefaultResourceHandlerSuppo
                      !renderedJSFJS.equals(ResourceUtils.JSF_MYFACES_JSFJS_NORMAL))
                 {
                     _resourceLoaders = new ResourceLoader[] {
-                            new TempDirFileCacheResourceLoader(new ExternalContextResourceLoader(RESOURCES)),
+                            new TempDirFileCacheResourceLoader(new ExternalContextResourceLoader("/"+directory)),
+                            new TempDirFileCacheResourceLoader(new FacesFlowClassLoaderResourceLoader()),
                             new TempDirFileCacheResourceLoader(
                                              new InternalClassLoaderResourceLoader(META_INF_INTERNAL_RESOURCES)),
                             new TempDirFileCacheResourceLoader(new ClassLoaderResourceLoader(META_INF_RESOURCES))
@@ -78,7 +94,8 @@ public class DefaultResourceHandlerSuppo
                 else
                 {
                     _resourceLoaders = new ResourceLoader[] {
-                            new TempDirFileCacheResourceLoader(new ExternalContextResourceLoader(RESOURCES)),
+                            new TempDirFileCacheResourceLoader(new ExternalContextResourceLoader("/"+directory)),
+                            new TempDirFileCacheResourceLoader(new FacesFlowClassLoaderResourceLoader()),
                             new TempDirFileCacheResourceLoader(new ClassLoaderResourceLoader(META_INF_RESOURCES))
                     };
                 }
@@ -95,7 +112,8 @@ public class DefaultResourceHandlerSuppo
                      !renderedJSFJS.equals(ResourceUtils.JSF_MYFACES_JSFJS_NORMAL))
                 {
                     _resourceLoaders = new ResourceLoader[] {
-                            new ExternalContextResourceLoader(RESOURCES),
+                            new ExternalContextResourceLoader("/"+directory),
+                            new FacesFlowClassLoaderResourceLoader(),
                             new InternalClassLoaderResourceLoader(META_INF_INTERNAL_RESOURCES),
                             new ClassLoaderResourceLoader(META_INF_RESOURCES)
                     };
@@ -103,7 +121,8 @@ public class DefaultResourceHandlerSuppo
                 else
                 {
                     _resourceLoaders = new ResourceLoader[] {
-                            new ExternalContextResourceLoader(RESOURCES),
+                            new ExternalContextResourceLoader("/"+directory),
+                            new FacesFlowClassLoaderResourceLoader(),
                             new ClassLoaderResourceLoader(META_INF_RESOURCES)
                     };
                 }
@@ -111,4 +130,66 @@ public class DefaultResourceHandlerSuppo
         }
         return _resourceLoaders;
     }
+    
+    @Override
+    public ContractResourceLoader[] getContractResourceLoaders()
+    {
+        if (_contractResourceLoaders == null)
+        {
+            FacesContext facesContext = FacesContext.getCurrentInstance(); 
+            
+            String directory = WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(), 
+                ResourceHandler.WEBAPP_CONTRACTS_DIRECTORY_PARAM_NAME, CONTRACTS);
+
+            if (directory.startsWith("/"))
+            {
+                throw new IllegalStateException("javax.faces.WEBAPP_CONTRACTS_DIRECTORY cannot start with '/");
+            }
+            
+            /* TODO: Implement me!
+            FacesContext facesContext = FacesContext.getCurrentInstance(); 
+
+            if (TempDirFileCacheResourceLoader.isValidCreateTemporalFiles(facesContext))
+            {
+                _contractResourceLoaders= new ContractResourceLoader[] { 
+                    new ExternalContextContractResourceLoader(CONTRACTS),
+                    new ClassLoaderContractResourceLoader(META_INF_CONTRACTS)
+                };
+            }
+            else
+            {*/
+            
+                _contractResourceLoaders= new ContractResourceLoader[] { 
+                    new ExternalContextContractResourceLoader("/"+directory),
+                    new ClassLoaderContractResourceLoader(META_INF_CONTRACTS)
+                };
+            //}
+        }
+        return _contractResourceLoaders;
+    }
+    
+    @Override
+    public ResourceLoader[] getViewResourceLoaders()
+    {
+        if (_viewResourceLoaders == null)
+        {
+            FacesContext facesContext = FacesContext.getCurrentInstance(); 
+            if (TempDirFileCacheResourceLoader.isValidCreateTemporalFiles(facesContext))
+            {
+                _viewResourceLoaders = new ResourceLoader[] {
+                        new RootExternalContextResourceLoader(),
+                        new TempDirFileCacheResourceLoader(new FacesFlowClassLoaderResourceLoader())
+                };
+            }
+            else
+            {
+                _viewResourceLoaders = new ResourceLoader[] {
+                        new RootExternalContextResourceLoader(),
+                        new FacesFlowClassLoaderResourceLoader()
+                };
+            }
+        }
+        return _viewResourceLoaders;
+    }
+
 }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ResourceHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ResourceHandlerImpl.java?rev=1485917&r1=1485916&r2=1485917&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ResourceHandlerImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ResourceHandlerImpl.java Fri May 24 01:27:31 2013
@@ -40,13 +40,16 @@ import javax.servlet.http.HttpServletRes
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.net.URL;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.MissingResourceException;
 import java.util.ResourceBundle;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import java.util.regex.Pattern;
+import org.apache.myfaces.shared.resource.ContractResource;
+import org.apache.myfaces.shared.resource.ContractResourceLoader;
 
 /**
  * DOCUMENT ME!
@@ -85,6 +88,9 @@ public class ResourceHandlerImpl extends
     public static final String INIT_PARAM_RESOURCE_BUFFER_SIZE = "org.apache.myfaces.RESOURCE_BUFFER_SIZE";
     public static final int INIT_PARAM_RESOURCE_BUFFER_SIZE_DEFAULT = 2048;
     
+    public static final Pattern LIBRARY_VERSION_CHECKER = Pattern.compile("\\p{Digit}+(_\\p{Digit}*)*");
+    public static final Pattern RESOURCE_VERSION_CHECKER = Pattern.compile("\\p{Digit}+(_\\p{Digit}*)*\\..*");    
+    
     private Boolean _allowSlashLibraryName;
     private int _resourceBufferSize = -1;
     
@@ -108,6 +114,13 @@ public class ResourceHandlerImpl extends
     {
         Resource resource = null;
         
+        if (resourceName.charAt(0) == '/')
+        {
+            // If resourceName starts with '/', remove that character because it
+            // does not have any meaning (with and without should point to the 
+            // same resource).
+            resourceName = resourceName.substring(1);
+        }        
         if (!ResourceValidationUtils.isValidResourceName(resourceName))
         {
             return null;
@@ -117,45 +130,248 @@ public class ResourceHandlerImpl extends
         {
             return null;
         }
-        
+        FacesContext facesContext = FacesContext.getCurrentInstance();
         if (contentType == null)
         {
             //Resolve contentType using ExternalContext.getMimeType
-            contentType = FacesContext.getCurrentInstance().getExternalContext().getMimeType(resourceName);
+            contentType = facesContext.getExternalContext().getMimeType(resourceName);
         }
 
-        final String localePrefix = getLocalePrefixForLocateResource();
-
-        // check cache
-        if(getResourceLoaderCache().containsResource(resourceName, libraryName, contentType, localePrefix))
+        final String localePrefix = getLocalePrefixForLocateResource(facesContext);
+        final List<String> contracts = facesContext.getResourceLibraryContracts(); 
+        boolean found = false;
+        String contractSelected = null;
+        String contractPreferred = getContractNameForLocateResource(facesContext);
+        
+        // Check cache:
+        //
+        // Contracts are on top of everything, because it is a concept that defines
+        // resources in a application scope concept. It means all resources in
+        // /resources or /META-INF/resources can be overriden using a contract. Note
+        // it also means resources under /META-INF/flows can also be overriden using
+        // a contract.
+        
+        // Check first the preferred contract if any. If not found, try the remaining
+        // contracts and finally if not found try to found a resource without a 
+        // contract name.
+        if (contractPreferred != null)
+        {
+            if (getResourceLoaderCache().containsResource(
+                    resourceName, libraryName, contentType, localePrefix, contractPreferred))
+            {
+                contractSelected = contractPreferred;
+                found = true;
+            }
+        }
+        if (!found && !contracts.isEmpty())
+        {
+            // Try to get resource but try with a contract name
+            for (String contract : contracts)
+            {
+                if (getResourceLoaderCache().containsResource(
+                    resourceName, libraryName, contentType, localePrefix, contract))
+                {
+                    contractSelected = contract;
+                    found = true;
+                    break;
+                }
+            }
+        }
+        // Only if no contract preferred try without it.
+        if (!found)
+        {
+            // Try to get resource without contract name
+            found = getResourceLoaderCache().containsResource(resourceName, libraryName, contentType, localePrefix);
+        }
+        
+        if(found)
         {
             ResourceValue resourceValue = getResourceLoaderCache().getResource(
-                    resourceName, libraryName, contentType, localePrefix);
+                    resourceName, libraryName, contentType, localePrefix, contractSelected);
             
             resource = new ResourceImpl(resourceValue.getResourceMeta(), resourceValue.getResourceLoader(),
                     getResourceHandlerSupport(), contentType);
         }
         else
         {
-            for (ResourceLoader loader : getResourceHandlerSupport().getResourceLoaders())
+            boolean resolved = false;
+            // Try preferred contract first
+            if (contractPreferred != null)
             {
-                ResourceMeta resourceMeta = deriveResourceMeta(loader, resourceName, libraryName, localePrefix);
-    
-                if (resourceMeta != null)
+                for (ContractResourceLoader loader : getResourceHandlerSupport().getContractResourceLoaders())
                 {
-                    resource = new ResourceImpl(resourceMeta, loader, getResourceHandlerSupport(), contentType);
+                    ResourceMeta resourceMeta = deriveResourceMeta(loader, resourceName, libraryName, 
+                        localePrefix, contractPreferred);
+                    if (resourceMeta != null)
+                    {
+                        resource = new ResourceImpl(resourceMeta, loader, 
+                            getResourceHandlerSupport(), contentType);
 
-                    // cache it
-                    getResourceLoaderCache().putResource(resourceName, libraryName, contentType,
-                            localePrefix, resourceMeta, loader);
-                    break;
+                        // cache it
+                        getResourceLoaderCache().putResource(resourceName, libraryName, contentType,
+                                localePrefix, contractPreferred, resourceMeta, loader);
+                        resolved = true;
+                        break;
+                    }
+                }
+            }
+            if (!resolved && !contracts.isEmpty())
+            {
+                for (ContractResourceLoader loader : 
+                    getResourceHandlerSupport().getContractResourceLoaders())
+                {
+                    for (String contract : contracts)
+                    {
+                        ResourceMeta resourceMeta = deriveResourceMeta(
+                            loader, resourceName, libraryName, 
+                            localePrefix, contract);
+                        if (resourceMeta != null)
+                        {
+                            resource = new ResourceImpl(resourceMeta, loader, 
+                                getResourceHandlerSupport(), contentType);
+
+                            // cache it
+                            getResourceLoaderCache().putResource(
+                                    resourceName, libraryName, contentType,
+                                    localePrefix, contract, resourceMeta, loader);
+                            resolved = true;
+                            break;
+                        }
+                    }
+                }
+            }
+            if (!resolved)
+            {
+                for (ResourceLoader loader : getResourceHandlerSupport().getResourceLoaders())
+                {
+                    ResourceMeta resourceMeta = deriveResourceMeta(
+                        loader, resourceName, libraryName, localePrefix);
+
+                    if (resourceMeta != null)
+                    {
+                        resource = new ResourceImpl(
+                            resourceMeta, loader, getResourceHandlerSupport(), contentType);
+
+                        // cache it
+                        getResourceLoaderCache().putResource(resourceName, libraryName, contentType,
+                                localePrefix, resourceMeta, loader);
+                        break;
+                    }
                 }
             }
         }
-        
         return resource;
     }
 
+    protected ResourceMeta deriveResourceMeta(ContractResourceLoader resourceLoader,
+            String resourceName, String libraryName, String localePrefix, String contractName)
+    {
+        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, contractName);
+
+                if (null != libraryVersion)
+                {
+                    String pathToResource = localePrefix + '/'
+                            + libraryName + '/' + libraryVersion + '/'
+                            + resourceName;
+                    resourceVersion = resourceLoader
+                            .getResourceVersion(pathToResource, contractName);
+                }
+                else
+                {
+                    String pathToResource = localePrefix + '/'
+                            + libraryName + '/' + resourceName;
+                    resourceVersion = resourceLoader
+                            .getResourceVersion(pathToResource, contractName);
+                }
+
+                if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+                {
+                    resourceId = resourceLoader.createResourceMeta(localePrefix, libraryName,
+                            libraryVersion, resourceName, resourceVersion, contractName);
+                }
+            }
+            else
+            {
+                resourceVersion = resourceLoader
+                        .getResourceVersion(localePrefix + '/'+ resourceName, contractName);
+                if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+                {               
+                    resourceId = resourceLoader.createResourceMeta(localePrefix, null, null,
+                            resourceName, resourceVersion, contractName);
+                }
+            }
+
+            if (resourceId != null)
+            {
+                if (!resourceLoader.resourceExists(resourceId))
+                {
+                    resourceId = null;
+                }
+            }            
+        }
+        
+        //2. Try to localize resource in a non localized path
+        if (resourceId == null)
+        {
+            if (null != libraryName)
+            {
+                libraryVersion = resourceLoader.getLibraryVersion(libraryName, contractName);
+
+                if (null != libraryVersion)
+                {
+                    String pathToResource = (libraryName + '/' + libraryVersion
+                            + '/' + resourceName);
+                    resourceVersion = resourceLoader
+                            .getResourceVersion(pathToResource, contractName);
+                }
+                else
+                {
+                    String pathToResource = (libraryName + '/'
+                            + resourceName);
+                    resourceVersion = resourceLoader
+                            .getResourceVersion(pathToResource, contractName);
+                }
+
+                if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+                {               
+                    resourceId = resourceLoader.createResourceMeta(null, libraryName,
+                            libraryVersion, resourceName, resourceVersion, contractName);
+                }
+            }
+            else
+            {
+                resourceVersion = resourceLoader
+                        .getResourceVersion(resourceName, contractName);
+                
+                if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+                {               
+                    resourceId = resourceLoader.createResourceMeta(null, null, null,
+                            resourceName, resourceVersion, contractName);
+                }
+            }
+
+            if (resourceId != null)
+            {
+                if (!resourceLoader.resourceExists(resourceId))
+                {
+                    resourceId = null;
+                }
+            }            
+        }
+        
+        return resourceId;
+    }
+    
     /**
      * This method try to create a ResourceMeta for a specific resource
      * loader. If no library, or resource is found, just return null,
@@ -212,8 +428,7 @@ public class ResourceHandlerImpl extends
 
             if (resourceId != null)
             {
-                URL url = resourceLoader.getResourceURL(resourceId);
-                if (url == null)
+                if (!resourceLoader.resourceExists(resourceId))
                 {
                     resourceId = null;
                 }
@@ -262,8 +477,7 @@ public class ResourceHandlerImpl extends
 
             if (resourceId != null)
             {
-                URL url = resourceLoader.getResourceURL(resourceId);
-                if (url == null)
+                if (!resourceLoader.resourceExists(resourceId))
                 {
                     resourceId = null;
                 }
@@ -495,8 +709,12 @@ public class ResourceHandlerImpl extends
 
     protected String getLocalePrefixForLocateResource()
     {
+        return getLocalePrefixForLocateResource(FacesContext.getCurrentInstance());
+    }
+
+    protected String getLocalePrefixForLocateResource(FacesContext context)
+    {
         String localePrefix = null;
-        FacesContext context = FacesContext.getCurrentInstance();
         boolean isResourceRequest = context.getApplication().getResourceHandler().isResourceRequest(context);
 
         if (isResourceRequest)
@@ -546,6 +764,31 @@ public class ResourceHandlerImpl extends
         }
         return localePrefix;
     }
+    
+    protected String getContractNameForLocateResource(FacesContext context)
+    {
+        String contractName = null;
+        boolean isResourceRequest = context.getApplication().getResourceHandler().isResourceRequest(context);
+
+        if (isResourceRequest)
+        {
+            contractName = context.getExternalContext().getRequestParameterMap().get("con");
+        }
+        
+        // Check if the contract has been injected.
+        if (contractName == null)
+        {
+            contractName = (String) context.getAttributes().get(ContractResource.CONTRACT_SELECTED);
+        }
+        
+        //Validate
+        if (contractName != null &&
+            !ResourceValidationUtils.isValidContractName(contractName))
+        {
+            return null;
+        }
+        return contractName;
+    }
 
     protected boolean isResourceIdentifierExcluded(FacesContext context, String resourceIdentifier)
     {
@@ -577,7 +820,9 @@ public class ResourceHandlerImpl extends
     @Override
     public boolean libraryExists(String libraryName)
     {
-        String localePrefix = getLocalePrefixForLocateResource();
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        String localePrefix = getLocalePrefixForLocateResource(facesContext);
+        final List<String> contracts = facesContext.getResourceLibraryContracts(); 
 
         String pathToLib = null;
         
@@ -592,6 +837,21 @@ public class ResourceHandlerImpl extends
             //Check with locale
             pathToLib = localePrefix + '/' + libraryName;
             
+            if (!contracts.isEmpty())
+            {
+                for (String contract : contracts)
+                {
+                    for (ContractResourceLoader loader : getResourceHandlerSupport()
+                            .getContractResourceLoaders())
+                    {
+                        if (loader.libraryExists(pathToLib, contract))
+                        {
+                            return true;
+                        }
+                    }
+                }
+            }
+            
             for (ResourceLoader loader : getResourceHandlerSupport()
                     .getResourceLoaders())
             {
@@ -603,6 +863,21 @@ public class ResourceHandlerImpl extends
         }
 
         //Check without locale
+        if (!contracts.isEmpty())
+        {
+            for (String contract : contracts)
+            {
+                for (ContractResourceLoader loader : getResourceHandlerSupport()
+                        .getContractResourceLoaders())
+                {
+                    if (loader.libraryExists(contract, libraryName))
+                    {
+                        return true;
+                    }
+                }
+            }
+        }
+
         for (ResourceLoader loader : getResourceHandlerSupport()
                 .getResourceLoaders())
         {
@@ -711,4 +986,777 @@ public class ResourceHandlerImpl extends
         return _resourceBufferSize;
     }
 
+    @Override
+    public Resource createResourceFromId(String resourceId)
+    {
+        Resource resource = null;
+
+        if (resourceId == null)
+        {
+            throw new NullPointerException();
+        }
+        
+        // Later in deriveResourceMeta the resourceId is decomposed and
+        // its elements validated properly.
+        if (!ResourceValidationUtils.isValidResourceId(resourceId))
+        {
+            return null;
+        }
+        
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        final List<String> contracts = facesContext.getResourceLibraryContracts(); 
+        boolean found = false;
+        String contractSelected = null;
+        String contractPreferred = getContractNameForLocateResource(facesContext);
+        
+        // Check cache:
+        //
+        // Contracts are on top of everything, because it is a concept that defines
+        // resources in a application scope concept. It means all resources in
+        // /resources or /META-INF/resources can be overriden using a contract. Note
+        // it also means resources under /META-INF/flows can also be overriden using
+        // a contract.
+        if (contractPreferred != null)
+        {
+            if (getResourceLoaderCache().containsResource(
+                    resourceId, contractPreferred))
+            {
+                contractSelected = contractPreferred;
+                found = true;
+            }
+        }
+        if (!found && !contracts.isEmpty())
+        {
+            // Try to get resource but try with a contract name
+            for (String contract : contracts)
+            {
+                if (getResourceLoaderCache().containsResource(resourceId, contract))
+                {
+                    contractSelected = contract;
+                    found = true;
+                    break;
+                }
+            }
+        }
+        if (!found)
+        {
+            // Try to get resource without contract name
+            found = getResourceLoaderCache().containsResource(resourceId);
+        }
+        
+        if(found)
+        {        
+            ResourceValue resourceValue = contractSelected != null ?
+                getResourceLoaderCache().getResource(resourceId, contractSelected) :
+                getResourceLoaderCache().getResource(resourceId);
+            
+            //Resolve contentType using ExternalContext.getMimeType
+            String contentType = facesContext.getExternalContext().getMimeType(
+                resourceValue.getResourceMeta().getResourceName());
+
+            resource = new ResourceImpl(resourceValue.getResourceMeta(), resourceValue.getResourceLoader(),
+                    getResourceHandlerSupport(), contentType);
+        }
+        else 
+        {
+            boolean resolved = false;
+            if (contractPreferred != null)
+            {
+                for (ContractResourceLoader loader : getResourceHandlerSupport().getContractResourceLoaders())
+                {
+                    ResourceMeta resourceMeta = deriveResourceMeta(
+                        facesContext, loader, resourceId, contractPreferred);
+                    if (resourceMeta != null)
+                    {
+                        String contentType = facesContext.getExternalContext().getMimeType(
+                            resourceMeta.getResourceName());
+                        
+                        resource = new ResourceImpl(resourceMeta, loader, 
+                            getResourceHandlerSupport(), contentType);
+
+                        // cache it
+                        getResourceLoaderCache().putResource(resourceId, resourceMeta, loader);
+                        
+                        resolved = true;
+                        break;
+                    }
+                }
+            }
+            if (!resolved && !contracts.isEmpty())
+            {
+                for (ContractResourceLoader loader : 
+                        getResourceHandlerSupport().getContractResourceLoaders())
+                {
+                    for (String contract : contracts)
+                    {
+                        ResourceMeta resourceMeta = deriveResourceMeta(
+                            facesContext, loader, resourceId, contract);
+                        if (resourceMeta != null)
+                        {
+                            String contentType = facesContext.getExternalContext().getMimeType(
+                                resourceMeta.getResourceName());
+
+                            resource = new ResourceImpl(resourceMeta, loader, 
+                                getResourceHandlerSupport(), contentType);
+
+                            // cache it
+                            getResourceLoaderCache().putResource(resourceId, resourceMeta, loader);
+
+                            resolved = true;
+                            break;
+                        }
+                    }
+                }
+            }
+            if (!resolved)
+            {
+                for (ResourceLoader loader : getResourceHandlerSupport().getResourceLoaders())
+                {
+                    ResourceMeta resourceMeta = deriveResourceMeta(facesContext, loader, resourceId);
+
+                    if (resourceMeta != null)
+                    {
+                        String contentType = facesContext.getExternalContext().getMimeType(
+                            resourceMeta.getResourceName());
+
+                        resource = new ResourceImpl(resourceMeta, loader, getResourceHandlerSupport(), contentType);
+
+                        // cache it
+                        getResourceLoaderCache().putResource(resourceId, resourceMeta, loader);
+                        break;
+                    }
+                }
+            }
+        }
+        return resource;
+    }
+
+    protected ResourceMeta deriveResourceMeta(FacesContext context, ResourceLoader resourceLoader,
+            String resourceId)
+    {
+        ResourceMeta resourceMeta = null;
+        String token = null;
+        String localePrefix = null;
+        String libraryName = null;
+        String libraryVersion = null;
+        String resourceName = null;
+        String resourceVersion = null;
+        
+        // Check if resource exists. It avoids additional 
+        // checks and it can be done very quickly because the 
+        // loader always uses the resourceId structure to
+        // organize resources. But decompose the resourceId is
+        // even faster.
+        //if (resourceLoader.resourceIdExists(resourceId))
+        //{
+        int lastSlash = resourceId.lastIndexOf('/');
+        if (lastSlash < 0)
+        {
+            //no slashes, so it is just a plain resource.
+            resourceName = resourceId;
+        }
+        else
+        {
+            token = resourceId.substring(lastSlash+1);
+            if (RESOURCE_VERSION_CHECKER.matcher(token).matches())
+            {
+                int secondLastSlash = resourceId.lastIndexOf('/', lastSlash-1);
+                if (secondLastSlash < 0)
+                {
+                    secondLastSlash = 0;
+                }
+
+                String rnToken = resourceId.substring(secondLastSlash+1, lastSlash);
+                int lastPoint = rnToken.lastIndexOf('.');
+                if (lastPoint < 0)
+                {
+                    //does not match, the token is not a resource version
+                }
+                else
+                {
+                    String ext = rnToken.substring(lastPoint);
+                    if (token.endsWith(ext))
+                    {
+                        //It match a versioned resource
+                        resourceVersion = token.substring(0,token.length()-ext.length());
+                    }
+                }
+            }
+
+            // 1. Extract the library path and locale prefix if necessary
+            int start = 0;
+            int firstSlash = resourceId.indexOf('/');
+
+            // At least one slash, check if the start is locale prefix.
+            String bundleName = context.getApplication().getMessageBundle();
+            //If no bundle set, it can't be localePrefix
+            if (null != bundleName)
+            {
+                token = resourceId.substring(start, firstSlash);
+                //Try to derive a locale object
+                Locale locale = _LocaleUtils.deriveLocale(token);
+
+                // If the locale was derived and it is available, 
+                // assume that portion of the resourceId it as a locale prefix.
+                if (locale != null && _LocaleUtils.isAvailableLocale(locale))
+                {
+                    localePrefix = token;
+                    start = firstSlash+1;
+                }
+            }
+
+            //Check slash again from start
+            firstSlash = resourceId.indexOf('/', start);
+            if (firstSlash < 0)
+            {
+                //no slashes.
+                resourceName = resourceId.substring(start);
+            }
+            else
+            {
+                //check libraryName
+                token = resourceId.substring(start, firstSlash);
+                int minResourceNameSlash = (resourceVersion != null) ?
+                    resourceId.lastIndexOf('/', lastSlash-1) : lastSlash;
+                //if (resourceLoader.libraryExists(token))
+                if (start < minResourceNameSlash)
+                {
+                    libraryName = token;
+                    start = firstSlash+1;
+
+                    //Now that libraryName exists, check libraryVersion
+                    firstSlash = resourceId.indexOf('/', start);
+                    if (firstSlash >= 0)
+                    {
+                        token = resourceId.substring(start, firstSlash);
+                        if (LIBRARY_VERSION_CHECKER.matcher(token).matches())
+                        {
+                            libraryVersion = token;
+                            start = firstSlash+1;
+                        }
+                    }
+                }
+
+                firstSlash = resourceId.indexOf('/', start);
+                if (firstSlash < 0)
+                {
+                    //no slashes.
+                    resourceName = resourceId.substring(start);
+                }
+                else
+                {
+                    // Check resource version. 
+                    if (resourceVersion != null)
+                    {
+                        resourceName = resourceId.substring(start,lastSlash);
+                    }
+                    else
+                    {
+                        //no resource version, assume the remaining to be resource name
+                        resourceName = resourceId.substring(start);
+                    }
+                }
+            }
+        }
+
+        //Check libraryName and resourceName
+        if (resourceName == null)
+        {
+            return null;
+        }
+        if (!ResourceValidationUtils.isValidResourceName(resourceName))
+        {
+            return null;
+        }
+
+        if (libraryName != null && !ResourceValidationUtils.isValidLibraryName(
+                libraryName, isAllowSlashesLibraryName()))
+        {
+            return null;
+        }
+
+        // If some variable is "" set it as null.
+        if (localePrefix != null && localePrefix.length() == 0)
+        {
+            localePrefix = null;
+        }
+        if (libraryName != null && libraryName.length() == 0)
+        {
+            libraryName = null;
+        }
+        if (libraryVersion != null && libraryVersion.length() == 0)
+        {
+            libraryVersion = null;
+        }
+        if (resourceName != null && resourceName.length() == 0)
+        {
+            resourceName = null;
+        }
+        if (resourceVersion != null && resourceVersion.length() == 0)
+        {
+            resourceVersion = null;
+        }
+
+        resourceMeta = resourceLoader.createResourceMeta(
+            localePrefix, libraryName, libraryVersion, resourceName, resourceVersion);
+
+        if (resourceMeta != null &&
+            !resourceLoader.resourceExists(resourceMeta))
+        {
+            resourceMeta = null;
+        }
+        //}
+        return resourceMeta;
+    }
+    
+    protected ResourceMeta deriveResourceMeta(FacesContext context, ContractResourceLoader resourceLoader,
+            String resourceId, String contractName)
+    {
+        ResourceMeta resourceMeta = null;
+        String token = null;
+        String localePrefix = null;
+        String libraryName = null;
+        String libraryVersion = null;
+        String resourceName = null;
+        String resourceVersion = null;
+        
+        // Check if resource exists. It avoids additional 
+        // checks and it can be done very quickly because the 
+        // loader always uses the resourceId structure to
+        // organize resources. But decompose the resourceId is
+        // even faster.
+        //if (resourceLoader.resourceIdExists(resourceId))
+        //{
+        int lastSlash = resourceId.lastIndexOf('/');
+        if (lastSlash < 0)
+        {
+            //no slashes, so it is just a plain resource.
+            resourceName = resourceId;
+        }
+        else
+        {
+            token = resourceId.substring(lastSlash+1);
+            if (RESOURCE_VERSION_CHECKER.matcher(token).matches())
+            {
+                int secondLastSlash = resourceId.lastIndexOf('/', lastSlash-1);
+                if (secondLastSlash < 0)
+                {
+                    secondLastSlash = 0;
+                }
+
+                String rnToken = resourceId.substring(secondLastSlash+1, lastSlash);
+                int lastPoint = rnToken.lastIndexOf('.');
+                if (lastPoint < 0)
+                {
+                    //does not match, the token is not a resource version
+                }
+                else
+                {
+                    String ext = rnToken.substring(lastPoint);
+                    if (token.endsWith(ext))
+                    {
+                        //It match a versioned resource
+                        resourceVersion = token.substring(0,token.length()-ext.length());
+                    }
+                }
+            }
+
+            // 1. Extract the library path and locale prefix if necessary
+            int start = 0;
+            int firstSlash = resourceId.indexOf('/');
+
+            // At least one slash, check if the start is locale prefix.
+            String bundleName = context.getApplication().getMessageBundle();
+            //If no bundle set, it can't be localePrefix
+            if (null != bundleName)
+            {
+                token = resourceId.substring(start, firstSlash);
+                //Try to derive a locale object
+                Locale locale = _LocaleUtils.deriveLocale(token);
+
+                // If the locale was derived and it is available, 
+                // assume that portion of the resourceId it as a locale prefix.
+                if (locale != null && _LocaleUtils.isAvailableLocale(locale))
+                {
+                    localePrefix = token;
+                    start = firstSlash+1;
+                }
+            }
+
+            //Check slash again from start
+            firstSlash = resourceId.indexOf('/', start);
+            if (firstSlash < 0)
+            {
+                //no slashes.
+                resourceName = resourceId.substring(start);
+            }
+            else
+            {
+                //check libraryName
+                token = resourceId.substring(start, firstSlash);
+                int minResourceNameSlash = (resourceVersion != null) ?
+                    resourceId.lastIndexOf('/', lastSlash-1) : lastSlash;
+                //if (resourceLoader.libraryExists(token))
+                if (start < minResourceNameSlash)
+                {
+                    libraryName = token;
+                    start = firstSlash+1;
+
+                    //Now that libraryName exists, check libraryVersion
+                    firstSlash = resourceId.indexOf('/', start);
+                    if (firstSlash >= 0)
+                    {
+                        token = resourceId.substring(start, firstSlash);
+                        if (LIBRARY_VERSION_CHECKER.matcher(token).matches())
+                        {
+                            libraryVersion = token;
+                            start = firstSlash+1;
+                        }
+                    }
+                }
+
+                firstSlash = resourceId.indexOf('/', start);
+                if (firstSlash < 0)
+                {
+                    //no slashes.
+                    resourceName = resourceId.substring(start);
+                }
+                else
+                {
+                    // Check resource version. 
+                    if (resourceVersion != null)
+                    {
+                        resourceName = resourceId.substring(start,lastSlash);
+                    }
+                    else
+                    {
+                        //no resource version, assume the remaining to be resource name
+                        resourceName = resourceId.substring(start);
+                    }
+                }
+            }
+        }
+
+        //Check libraryName and resourceName
+        if (resourceName == null)
+        {
+            return null;
+        }
+        if (!ResourceValidationUtils.isValidResourceName(resourceName))
+        {
+            return null;
+        }
+
+        if (libraryName != null && !ResourceValidationUtils.isValidLibraryName(
+                libraryName, isAllowSlashesLibraryName()))
+        {
+            return null;
+        }
+
+        // If some variable is "" set it as null.
+        if (localePrefix != null && localePrefix.length() == 0)
+        {
+            localePrefix = null;
+        }
+        if (libraryName != null && libraryName.length() == 0)
+        {
+            libraryName = null;
+        }
+        if (libraryVersion != null && libraryVersion.length() == 0)
+        {
+            libraryVersion = null;
+        }
+        if (resourceName != null && resourceName.length() == 0)
+        {
+            resourceName = null;
+        }
+        if (resourceVersion != null && resourceVersion.length() == 0)
+        {
+            resourceVersion = null;
+        }
+
+        resourceMeta = resourceLoader.createResourceMeta(
+            localePrefix, libraryName, libraryVersion, resourceName, resourceVersion, contractName);
+
+        if (resourceMeta != null &&
+            !resourceLoader.resourceExists(resourceMeta))
+        {
+            resourceMeta = null;
+        }
+        //}
+        return resourceMeta;
+    }
+    
+    protected ResourceMeta deriveViewResourceMeta(FacesContext context, ResourceLoader resourceLoader,
+            String resourceName, String localePrefix)
+    {
+        ResourceMeta resourceMeta = null;
+        String resourceVersion = null;
+
+        //1. Try to locate resource in a localized path
+        if (localePrefix != null)
+        {
+            resourceVersion = resourceLoader
+                    .getResourceVersion(localePrefix + '/'+ resourceName);
+            if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+            {
+                resourceMeta = resourceLoader.createResourceMeta(localePrefix, null, null,
+                         resourceName, resourceVersion);
+            }
+
+            if (resourceMeta != null)
+            {
+                if (!resourceLoader.resourceExists(resourceMeta))
+                {
+                    resourceMeta = null;
+                }
+            }            
+        }
+        
+        //2. Try to localize resource in a non localized path
+        if (resourceMeta == null)
+        {
+            resourceVersion = resourceLoader
+                    .getResourceVersion(resourceName);
+            if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+            {
+                resourceMeta = resourceLoader.createResourceMeta(null, null, null,
+                         resourceName, resourceVersion);
+            }
+
+            if (resourceMeta != null)
+            {
+                if (!resourceLoader.resourceExists(resourceMeta))
+                {
+                    resourceMeta = null;
+                }
+            }            
+        }
+
+        return resourceMeta;        
+    }
+    
+    protected ResourceMeta deriveViewResourceMeta(FacesContext context, ContractResourceLoader resourceLoader,
+            String resourceName, String localePrefix, String contractName)
+    {
+        ResourceMeta resourceMeta = null;
+        String resourceVersion = null;
+
+        //1. Try to locate resource in a localized path
+        if (localePrefix != null)
+        {
+            resourceVersion = resourceLoader
+                    .getResourceVersion(localePrefix + '/'+ resourceName, contractName);
+            if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+            {
+                resourceMeta = resourceLoader.createResourceMeta(localePrefix, null, null,
+                     resourceName, resourceVersion, contractName);
+            }
+
+            if (resourceMeta != null)
+            {
+                if (!resourceLoader.resourceExists(resourceMeta))
+                {
+                    resourceMeta = null;
+                }
+            }            
+        }
+        
+        //2. Try to localize resource in a non localized path
+        if (resourceMeta == null)
+        {
+            resourceVersion = resourceLoader
+                    .getResourceVersion(resourceName, contractName);
+            if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
+            {
+                resourceMeta = resourceLoader.createResourceMeta(null, null, null,
+                         resourceName, resourceVersion, contractName);
+            }
+
+            if (resourceMeta != null)
+            {
+                if (!resourceLoader.resourceExists(resourceMeta))
+                {
+                    resourceMeta = null;
+                }
+            }            
+        }
+
+        return resourceMeta;
+    }
+
+    @Override
+    public Resource createViewResource(FacesContext context, String resourceName)
+    {
+        // There are some special points to remember for a view resource in comparison
+        // with a normal resource:
+        //
+        // - A view resource never has an associated library name 
+        //   (this was done to keep simplicity).
+        // - A view resource can be inside a resource library contract.
+        // - A view resource could be internationalized in the same way a normal resource.
+        // - A view resource can be created from the webapp root folder, 
+        //   a normal resource cannot.
+        // - A view resource cannot be created from /resources or META-INF/resources.
+        // 
+        // For example, a valid resourceId for a view resource is like this:
+        //
+        // [localePrefix/]resourceName[/resourceVersion]
+        //
+        // but the resource loader can ignore localePrefix or resourceVersion, like
+        // for example the webapp root folder.
+        // 
+        // When createViewResource() is called, the view must be used to derive
+        // the localePrefix and facesContext must be used to get the available contracts.
+        
+        Resource resource = null;
+
+        if (resourceName == null)
+        {
+            throw new NullPointerException();
+        }
+        if (resourceName.charAt(0) == '/')
+        {
+            // If resourceName starts with '/', remove that character because it
+            // does not have any meaning (with and without should point to the 
+            // same resource).
+            resourceName = resourceName.substring(1);
+        }
+        
+        // Later in deriveResourceMeta the resourceId is decomposed and
+        // its elements validated properly.
+        if (!ResourceValidationUtils.isValidViewResource(resourceName))
+        {
+            return null;
+        }
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        final String localePrefix = getLocalePrefixForLocateResource(facesContext);
+        String contentType = facesContext.getExternalContext().getMimeType(resourceName);
+        final List<String> contracts = facesContext.getResourceLibraryContracts(); 
+        boolean found = false;
+        String contractSelected = null;
+        String contractPreferred = getContractNameForLocateResource(facesContext);
+        
+        // Check cache:
+        //
+        // Contracts are on top of everything, because it is a concept that defines
+        // resources in a application scope concept. It means all resources in
+        // /resources or /META-INF/resources can be overriden using a contract. Note
+        // it also means resources under /META-INF/flows can also be overriden using
+        // a contract.
+        if (contractPreferred != null)
+        {
+            if (getResourceLoaderCache().containsViewResource(
+                    resourceName, contentType, localePrefix, contractPreferred))
+            {
+                contractSelected = contractPreferred;
+                found = true;
+            }
+        }
+        if (!found && !contracts.isEmpty())
+        {
+            // Try to get resource but try with a contract name
+            for (String contract : contracts)
+            {
+                if (getResourceLoaderCache().containsViewResource(
+                    resourceName, contentType, localePrefix, contract))
+                {
+                    contractSelected = contract;
+                    found = true;
+                    break;
+                }
+            }
+        }
+        if (!found)
+        {
+            // Try to get resource without contract name
+            found = getResourceLoaderCache().containsViewResource(
+                resourceName, contentType, localePrefix);
+        }
+                
+        
+        if(found)
+        {        
+            ResourceValue resourceValue = contractSelected != null ?
+                getResourceLoaderCache().getViewResource(resourceName, 
+                    contentType, localePrefix, contractSelected) :
+                getResourceLoaderCache().getViewResource(resourceName,
+                    contentType, localePrefix);
+            
+            resource = new ResourceImpl(resourceValue.getResourceMeta(), resourceValue.getResourceLoader(),
+                    getResourceHandlerSupport(), contentType);
+        }
+        else 
+        {
+            boolean resolved = false;
+            if (contractPreferred != null)
+            {
+                for (ContractResourceLoader loader : getResourceHandlerSupport().getContractResourceLoaders())
+                {
+                    ResourceMeta resourceMeta = deriveViewResourceMeta(
+                        facesContext, loader, resourceName, localePrefix, contractPreferred);
+                    if (resourceMeta != null)
+                    {
+                        resource = new ResourceImpl(resourceMeta, loader, 
+                            getResourceHandlerSupport(), contentType);
+
+                        // cache it
+                        getResourceLoaderCache().putViewResource(
+                            resourceName, contentType, localePrefix, contractPreferred, resourceMeta, loader);
+                        
+                        resolved = true;
+                        break;
+                    }
+                }
+            }
+            if (!resolved && !contracts.isEmpty())
+            {
+                for (ContractResourceLoader loader : 
+                        getResourceHandlerSupport().getContractResourceLoaders())
+                {
+                    for (String contract : contracts)
+                    {
+                        ResourceMeta resourceMeta = deriveViewResourceMeta(
+                            facesContext, loader, resourceName, localePrefix, contract);
+                        if (resourceMeta != null)
+                        {
+                            resource = new ResourceImpl(resourceMeta, loader, 
+                                getResourceHandlerSupport(), contentType);
+
+                            // cache it
+                            getResourceLoaderCache().putViewResource(
+                                resourceName, contentType, localePrefix, contract, resourceMeta, loader);
+
+                            resolved = true;
+                            break;
+                        }
+                    }
+                }
+            }
+            if (!resolved)
+            {
+                // "... Considering the web app root ..."
+                
+                // "... Considering faces flows (at the locations specified in the spec prose document section 
+                // Faces Flows in the Using JSF in Web Applications chapter) ..."
+                for (ResourceLoader loader : getResourceHandlerSupport().getViewResourceLoaders())
+                {
+                    ResourceMeta resourceMeta = deriveViewResourceMeta(
+                        facesContext, loader, resourceName, localePrefix);
+
+                    if (resourceMeta != null)
+                    {
+                        resource = new ResourceImpl(resourceMeta, loader, getResourceHandlerSupport(), contentType);
+
+                        // cache it
+                        getResourceLoaderCache().putViewResource(
+                            resourceName, contentType, localePrefix, resourceMeta, loader);
+                        break;
+                    }
+                }
+            }
+        }
+        return resource;
+    }
+
 }

Copied: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/_LocaleUtils.java (from r1470662, myfaces/core/trunk/api/src/main/java/javax/faces/component/_LocaleUtils.java)
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/_LocaleUtils.java?p2=myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/_LocaleUtils.java&p1=myfaces/core/trunk/api/src/main/java/javax/faces/component/_LocaleUtils.java&r1=1470662&r2=1485917&rev=1485917&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/component/_LocaleUtils.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/_LocaleUtils.java Fri May 24 01:27:31 2013
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package javax.faces.component;
+package org.apache.myfaces.application;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -143,6 +143,64 @@ class _LocaleUtils
             }
         }
     }
+    
+    /**
+     * Same as toLocale(), but return null when it cannot derive a valid Locale object.
+     * 
+     * @param str
+     * @return 
+     */
+    public static Locale deriveLocale(String str)
+    {
+        if (str == null)
+        {
+            return null;
+        }
+        int len = str.length();
+        if (len != 2 && len != 5 && len < 7)
+        {
+            return null;
+        }
+        char ch0 = str.charAt(0);
+        char ch1 = str.charAt(1);
+        if (ch0 < 'a' || ch0 > 'z' || ch1 < 'a' || ch1 > 'z')
+        {
+            return null;
+        }
+        if (len == 2)
+        {
+            return new Locale(str, "");
+        }
+        else
+        {
+            if (str.charAt(2) != '_')
+            {
+                return null;
+            }
+            char ch3 = str.charAt(3);
+            if (ch3 == '_')
+            {
+                return new Locale(str.substring(0, 2), "", str.substring(4));
+            }
+            char ch4 = str.charAt(4);
+            if (ch3 < 'A' || ch3 > 'Z' || ch4 < 'A' || ch4 > 'Z')
+            {
+                return null;
+            }
+            if (len == 5)
+            {
+                return new Locale(str.substring(0, 2), str.substring(3, 5));
+            }
+            else
+            {
+                if (str.charAt(5) != '_')
+                {
+                    return null;
+                }
+                return new Locale(str.substring(0, 2), str.substring(3, 5), str.substring(6));
+            }
+        }
+    }
 
     //-----------------------------------------------------------------------
 

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java?rev=1485917&r1=1485916&r2=1485917&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java Fri May 24 01:27:31 2013
@@ -75,6 +75,7 @@ import org.apache.myfaces.config.annotat
 import org.apache.myfaces.config.annotation.LifecycleProviderFactory;
 import org.apache.myfaces.config.element.Behavior;
 import org.apache.myfaces.config.element.ClientBehaviorRenderer;
+import org.apache.myfaces.config.element.ContractMapping;
 import org.apache.myfaces.config.element.FaceletsProcessing;
 import org.apache.myfaces.config.element.FacesConfig;
 import org.apache.myfaces.config.element.FacesConfigData;
@@ -102,10 +103,13 @@ import org.apache.myfaces.shared.config.
 import org.apache.myfaces.shared.util.ClassUtils;
 import org.apache.myfaces.shared.util.LocaleUtils;
 import org.apache.myfaces.shared.util.StateUtils;
+import org.apache.myfaces.shared.util.StringUtils;
 import org.apache.myfaces.shared_impl.util.serial.DefaultSerialFactory;
 import org.apache.myfaces.shared_impl.util.serial.SerialFactory;
 import org.apache.myfaces.spi.FacesConfigurationMerger;
 import org.apache.myfaces.spi.FacesConfigurationMergerFactory;
+import org.apache.myfaces.spi.ResourceLibraryContractsProvider;
+import org.apache.myfaces.spi.ResourceLibraryContractsProviderFactory;
 import org.apache.myfaces.util.ContainerUtils;
 import org.apache.myfaces.util.ExternalSpecifications;
 import org.apache.myfaces.view.ViewDeclarationLanguageFactoryImpl;
@@ -697,6 +701,13 @@ public class FacesConfigurator
                     dispenser.getVariableResolverIterator(),
                     new VariableResolverImpl()));
         }
+        
+        for (ContractMapping mapping : dispenser.getResourceLibraryContractMappings())
+        {
+            String urlPattern = mapping.getUrlPattern();
+            String[] contracts = StringUtils.trim(StringUtils.splitShortString(mapping.getContracts(), ' '));
+            runtimeConfig.addContractMapping(urlPattern, contracts);
+        }
     }
 
     /**
@@ -861,6 +872,57 @@ public class FacesConfigurator
         {
             runtimeConfig.addFaceletProcessingConfiguration(faceletsProcessing.getFileExtension(), faceletsProcessing);
         }
+        
+        ResourceLibraryContractsProvider rlcp = ResourceLibraryContractsProviderFactory.
+            getFacesConfigResourceProviderFactory(_externalContext).
+            createResourceLibraryContractsProvider(_externalContext);
+        
+        try
+        {
+            // JSF 2.2 section 11.4.2.1 scan for available resource library contracts
+            // and store the result in a internal data structure, so it can be used 
+            // later in ViewDeclarationLanguage.calculateResourceLibraryContracts(
+            //   FacesContext context, String viewId)
+            runtimeConfig.setExternalContextResourceLibraryContracts(
+                rlcp.getExternalContextResourceLibraryContracts(_externalContext));
+            runtimeConfig.setClassLoaderResourceLibraryContracts(
+                rlcp.getClassloaderResourceLibraryContracts(_externalContext));
+        }
+        catch(Exception e)
+        {
+            if (log.isLoggable(Level.SEVERE))
+            {
+                log.log(Level.SEVERE, 
+                    "An error was found when scanning for resource library contracts", e);
+            }
+        }
+        
+        
+        // JSF 2.2 section 11.4.2.1 check all contracts are loaded
+        if (log.isLoggable(Level.INFO))
+        {
+            for (List<String> list : runtimeConfig.getContractMappings().values())
+            {
+                for (String contract : list)
+                {
+                    if (!runtimeConfig.getResourceLibraryContracts().contains(contract))
+                    {
+                        log.log(Level.INFO, 
+                            "Resource Library Contract "+ contract + " was not found while scanning for "
+                            + "available contracts.");
+                    }
+                }
+            }
+        }
+        
+        // JSF 2.2 section 11.4.2.1 if no contractMappings set, all available contracts applies
+        // to all views.
+        if (runtimeConfig.getContractMappings().isEmpty())
+        {
+            String[] contracts = runtimeConfig.getResourceLibraryContracts().toArray(
+                new String[runtimeConfig.getResourceLibraryContracts().size()]);
+            runtimeConfig.addContractMapping("*", contracts);
+        }
     }
 
     private void removePurgedBeansFromSessionAndApplication(RuntimeConfig runtimeConfig)

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/RuntimeConfig.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/RuntimeConfig.java?rev=1485917&r1=1485916&r2=1485917&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/RuntimeConfig.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/RuntimeConfig.java Fri May 24 01:27:31 2013
@@ -23,8 +23,10 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -88,6 +90,20 @@ public class RuntimeConfig
     
     private final Map<String, FaceletsProcessing> _faceletsProcessingByFileExtension =
         new HashMap<String, FaceletsProcessing>();
+    
+    /**
+     * JSF 2.2 section 11.4.2.1. 
+     * 
+     * Scanning for all available contracts is necessary because the spec says 
+     * "... if the information from the application configuration resources refers 
+     * to a contract that is not available to the application, an informative error 
+     * message must be logged. ..."
+     */
+    private Set<String> _externalContextResourceLibraryContracts = new HashSet<String>();
+    private Set<String> _classLoaderResourceLibraryContracts = new HashSet<String>();
+    private Set<String> _resourceLibraryContracts = new HashSet<String>();
+    
+    private Map<String, List<String>> _contractMappings = new HashMap<String, List<String>>();
 
     public static RuntimeConfig getCurrentInstance(ExternalContext externalContext)
     {
@@ -109,6 +125,9 @@ public class RuntimeConfig
         _managedBeans.clear();
         _navigationRulesChanged = false;
         _converterClassNameToConfigurationMap.clear();
+        _externalContextResourceLibraryContracts.clear();
+        _classLoaderResourceLibraryContracts.clear();
+        _resourceLibraryContracts.clear();
     }
 
     /**
@@ -378,4 +397,84 @@ public class RuntimeConfig
     {
         return _faceletsProcessingByFileExtension.values();
     }
+
+    /**
+     * @return the _externalContextResourceLibraryContracts
+     */
+    public Set<String> getExternalContextResourceLibraryContracts()
+    {
+        return _externalContextResourceLibraryContracts;
+    }
+
+    /**
+     * @param externalContextResourceLibraryContracts the _externalContextResourceLibraryContracts to set
+     */
+    public void setExternalContextResourceLibraryContracts(Set<String> externalContextResourceLibraryContracts)
+    {
+        this._externalContextResourceLibraryContracts = externalContextResourceLibraryContracts;
+        this._resourceLibraryContracts.clear();
+        this._resourceLibraryContracts.addAll(this._externalContextResourceLibraryContracts);
+        this._resourceLibraryContracts.addAll(this._classLoaderResourceLibraryContracts);
+    }
+
+    /**
+     * @return the _classLoaderResourceLibraryContracts
+     */
+    public Set<String> getClassLoaderResourceLibraryContracts()
+    {
+        return _classLoaderResourceLibraryContracts;
+    }
+
+    /**
+     * @param classLoaderResourceLibraryContracts the _classLoaderResourceLibraryContracts to set
+     */
+    public void setClassLoaderResourceLibraryContracts(Set<String> classLoaderResourceLibraryContracts)
+    {
+        this._classLoaderResourceLibraryContracts = classLoaderResourceLibraryContracts;
+        this._resourceLibraryContracts.clear();
+        this._resourceLibraryContracts.addAll(this._externalContextResourceLibraryContracts);
+        this._resourceLibraryContracts.addAll(this._classLoaderResourceLibraryContracts);
+    }
+
+    /**
+     * @return the _resourceLibraryContracts
+     */
+    public Set<String> getResourceLibraryContracts()
+    {
+        return _resourceLibraryContracts;
+    }
+
+    /**
+     * @return the _contractMappings
+     */
+    public Map<String, List<String>> getContractMappings()
+    {
+        return _contractMappings;
+    }
+
+    public void addContractMapping(String urlPattern, String[] contracts)
+    {
+        List<String> contractsList = _contractMappings.get(urlPattern);
+        if (contractsList == null)
+        {
+            contractsList = new ArrayList<String>();
+            _contractMappings.put(urlPattern, contractsList);
+        }
+        for (String contract : contracts)
+        {
+            contractsList.add(contract);
+        }
+    }
+    
+    public void addContractMapping(String urlPattern, String contract)
+    {
+        List<String> contractsList = _contractMappings.get(urlPattern);
+        if (contractsList == null)
+        {
+            contractsList = new ArrayList<String>();
+            _contractMappings.put(urlPattern, contractsList);
+        }
+        contractsList.add(contract);
+    }    
+
 }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/context/servlet/FacesContextImplBase.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/context/servlet/FacesContextImplBase.java?rev=1485917&r1=1485916&r2=1485917&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/context/servlet/FacesContextImplBase.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/context/servlet/FacesContextImplBase.java Fri May 24 01:27:31 2013
@@ -18,7 +18,10 @@
  */
 package org.apache.myfaces.context.servlet;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import javax.el.ELContext;
@@ -64,6 +67,8 @@ public abstract class FacesContextImplBa
     protected boolean _released = false;
     
     private ApplicationFactory _applicationFactory = null;
+    
+    private List<String> _resourceLibraryContracts;
 
     /**
      * Base constructor.
@@ -308,6 +313,40 @@ public abstract class FacesContextImplBa
         
         return _cachedRenderKit;
     }
+
+    @Override
+    public List<String> getResourceLibraryContracts()
+    {
+        assertNotReleased();
+        
+        if (_resourceLibraryContracts == null)
+        {
+            return Collections.emptyList();
+        }
+        else
+        {
+            return _resourceLibraryContracts;
+        }
+    }
+    
+    @Override
+    public void setResourceLibraryContracts(List<String> contracts)
+    {
+        assertNotReleased();
+     
+        if (contracts == null)
+        {
+            _resourceLibraryContracts = null;
+        }
+        else if (contracts.isEmpty())
+        {
+            _resourceLibraryContracts = null;
+        }
+        else
+        {
+            _resourceLibraryContracts = new ArrayList<String>(contracts);
+        }
+    }
     
     /**
      * has to be thrown in many of the methods if the method is called after the instance has been released!