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 2010/08/20 23:50:47 UTC

svn commit: r987645 [2/3] - in /myfaces/core/trunk/impl/src/main/java/org/apache/myfaces: config/ config/annotation/ spi/ spi/impl/ view/facelets/compiler/

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/annotation/DefaultAnnotationProvider.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/annotation/DefaultAnnotationProvider.java?rev=987645&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/annotation/DefaultAnnotationProvider.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/annotation/DefaultAnnotationProvider.java Fri Aug 20 21:50:46 2010
@@ -0,0 +1,659 @@
+/*
+ * 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.config.annotation;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.faces.FacesException;
+import javax.faces.bean.ManagedBean;
+import javax.faces.component.FacesComponent;
+import javax.faces.component.behavior.FacesBehavior;
+import javax.faces.context.ExternalContext;
+import javax.faces.convert.FacesConverter;
+import javax.faces.event.NamedEvent;
+import javax.faces.render.FacesBehaviorRenderer;
+import javax.faces.render.FacesRenderer;
+import javax.faces.validator.FacesValidator;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
+import org.apache.myfaces.shared_impl.util.ClassUtils;
+import org.apache.myfaces.spi.AnnotationProvider;
+import org.apache.myfaces.view.facelets.util.Classpath;
+
+/**
+ * 
+ * @since 2.0.2
+ * @author Leonardo Uribe
+ */
+public class DefaultAnnotationProvider extends AnnotationProvider
+{
+    private static final Logger log = Logger.getLogger(DefaultAnnotationProvider.class.getName());
+    
+    /**
+     * <p> Servlet context init parameter which defines which packages to scan
+     * for beans, separated by commas.</p>
+     */
+    @JSFWebConfigParam(since="2.0")
+    public static final String SCAN_PACKAGES = "org.apache.myfaces.annotation.SCAN_PACKAGES";
+
+    /**
+     * <p>Prefix path used to locate web application classes for this
+     * web application.</p>
+     */
+    private static final String WEB_CLASSES_PREFIX = "/WEB-INF/classes/";
+    
+    /**
+     * <p>Prefix path used to locate web application libraries for this
+     * web application.</p>
+     */
+    private static final String WEB_LIB_PREFIX = "/WEB-INF/lib/";
+    
+    private static final String META_INF_PREFIX = "META-INF/";
+
+    private static final String FACES_CONFIG_SUFFIX = ".faces-config.xml";
+    
+    private static final String STANDARD_FACES_CONFIG_RESOURCE = "META-INF/standard-faces-config.xml";
+
+    /**
+     * <p>Resource path used to acquire implicit resources buried
+     * inside application JARs.</p>
+     */
+    private static final String FACES_CONFIG_IMPLICIT = "META-INF/faces-config.xml";
+    
+    private final _ClassByteCodeAnnotationFilter _filter;
+
+    /**
+     * This set contains the annotation names that this AnnotationConfigurator is able to scan
+     * in the format that is read from .class file.
+     */
+    private static Set<String> byteCodeAnnotationsNames;
+
+    static
+    {
+        Set<String> bcan = new HashSet<String>(10, 1f);
+        bcan.add("Ljavax/faces/component/FacesComponent;");
+        bcan.add("Ljavax/faces/component/behavior/FacesBehavior;");
+        bcan.add("Ljavax/faces/convert/FacesConverter;");
+        bcan.add("Ljavax/faces/validator/FacesValidator;");
+        bcan.add("Ljavax/faces/render/FacesRenderer;");
+        bcan.add("Ljavax/faces/bean/ManagedBean;");
+        bcan.add("Ljavax/faces/event/NamedEvent;");
+        //bcan.add("Ljavax/faces/event/ListenerFor;");
+        //bcan.add("Ljavax/faces/event/ListenersFor;");
+        bcan.add("Ljavax/faces/render/FacesBehaviorRenderer;");
+
+        byteCodeAnnotationsNames = Collections.unmodifiableSet(bcan);
+    }
+    
+    private static Set<Class<? extends Annotation>> JSF_ANNOTATION_CLASSES;
+    
+    static
+    {
+        Set<Class<? extends Annotation>> bcan = new HashSet<Class<? extends Annotation>>(10, 1f);
+        bcan.add(FacesComponent.class);
+        bcan.add(FacesBehavior.class);
+        bcan.add(FacesConverter.class);
+        bcan.add(FacesValidator.class);
+        bcan.add(FacesRenderer.class);
+        bcan.add(ManagedBean.class);
+        bcan.add(NamedEvent.class);
+        bcan.add(FacesBehaviorRenderer.class);
+        JSF_ANNOTATION_CLASSES = Collections.unmodifiableSet(bcan);
+    }
+    
+    public DefaultAnnotationProvider()
+    {
+        super();
+        _filter = new _ClassByteCodeAnnotationFilter();
+    }
+    
+    @Override
+    public Map<Class<? extends Annotation>, Set<Class<?>>> getAnnotatedClasses(ExternalContext ctx)
+    {
+        Map<Class<? extends Annotation>,Set<Class<?>>> map = new HashMap<Class<? extends Annotation>, Set<Class<?>>>();
+        Collection<Class<?>> classes = null;
+
+        //1. Scan for annotations on /WEB-INF/classes
+        try
+        {
+            classes = getAnnotatedWebInfClasses(ctx);
+        }
+        catch (IOException e)
+        {
+            throw new FacesException(e);
+        }
+
+        for (Class<?> clazz : classes)
+        {
+            processClass(map, clazz);
+        }
+        
+        //2. Scan for annotations on classpath
+        try
+        {
+            classes = getAnnotatedMetaInfClasses(ctx, getBaseUrls());
+        }
+        catch (IOException e)
+        {
+            throw new FacesException(e);
+        }
+        
+        for (Class<?> clazz : classes)
+        {
+            processClass(map, clazz);
+        }
+        
+        //3. Scan on myfaces-impl for annotations available on myfaces-impl.
+        //Also scan jar including META-INF/standard-faces-config.xml
+        //(myfaces-impl jar file)
+        URL url = getClassLoader().getResource(STANDARD_FACES_CONFIG_RESOURCE);
+        if (url == null)
+        {
+            url = getClass().getClassLoader().getResource(STANDARD_FACES_CONFIG_RESOURCE);
+        }
+        classes = getAnnotatedMyfacesImplClasses(ctx, url);
+        for (Class<?> clazz : classes)
+        {
+            processClass(map, clazz);
+        }
+        
+        return map;
+    }
+    
+    @Override
+    public Set<URL> getBaseUrls() throws IOException
+    {
+        Set<URL> urlSet = new HashSet<URL>();
+        
+        //This usually happens when maven-jetty-plugin is used
+        //Scan jars looking for paths including META-INF/faces-config.xml
+        Enumeration<URL> resources = getClassLoader().getResources(FACES_CONFIG_IMPLICIT);
+        while (resources.hasMoreElements())
+        {
+            urlSet.add(resources.nextElement());
+        }
+
+        //Scan files inside META-INF ending with .faces-config.xml
+        URL[] urls = Classpath.search(getClassLoader(), META_INF_PREFIX, FACES_CONFIG_SUFFIX);
+        for (int i = 0; i < urls.length; i++)
+        {
+            urlSet.add(urls[i]);
+        }
+        
+        return urlSet;
+    }
+
+    protected Collection<Class<?>> getAnnotatedMetaInfClasses(ExternalContext ctx, Set<URL> urls)
+    {
+        if (urls != null && !urls.isEmpty())
+        {
+            List<Class<?>> list = new ArrayList<Class<?>>();
+            for (URL url : urls)
+            {
+                try
+                {
+                    JarFile jarFile = getJarFile(url);
+                    if (jarFile != null)
+                    {
+                        archiveClasses(ctx, jarFile, list);
+                    }
+                }
+                catch(IOException e)
+                {
+                    log.log(Level.SEVERE, "cannot scan jar file for annotations:"+url, e);
+                }
+            }
+            return list;
+        }
+        return Collections.emptyList();
+    }
+
+    protected Collection<Class<?>> getAnnotatedMyfacesImplClasses(ExternalContext ctx, URL url)
+    {
+        return Collections.emptyList();
+        /*
+        try
+        {
+            List<Class<?>> list = new ArrayList<Class<?>>();
+            JarFile jarFile = getJarFile(url);
+            if (jarFile == null)
+            {
+                return list;
+            }
+            else
+            {
+                return archiveClasses(ctx, jarFile, list);
+            }
+        }
+        catch(IOException e)
+        {
+            throw new FacesException("cannot scan jar file for annotations:"+url, e);
+        }*/
+    }
+
+    protected Collection<Class<?>> getAnnotatedWebInfClasses(ExternalContext ctx) throws IOException
+    {
+        String scanPackages = ctx.getInitParameter(SCAN_PACKAGES);
+        if (scanPackages != null)
+        {
+            try
+            {
+                return packageClasses(ctx, scanPackages);
+            }
+            catch (ClassNotFoundException e)
+            {
+                throw new FacesException(e);
+            }
+            catch (IOException e)
+            {
+                throw new FacesException(e);
+            }
+        }
+        else
+        {
+            return webClasses(ctx);
+        }
+    }
+    
+    /**
+     * <p>Return a list of the classes defined within the given packages
+     * If there are no such classes, a zero-length list will be returned.</p>
+     *
+     * @param scanPackages the package configuration
+     *
+     * @exception ClassNotFoundException if a located class cannot be loaded
+     * @exception IOException if an input/output error occurs
+     */
+    private List<Class<?>> packageClasses(final ExternalContext externalContext,
+            final String scanPackages) throws ClassNotFoundException, IOException
+    {
+
+        List<Class<?>> list = new ArrayList<Class<?>>();
+
+        String[] scanPackageTokens = scanPackages.split(",");
+        for (String scanPackageToken : scanPackageTokens)
+        {
+            if (scanPackageToken.toLowerCase().endsWith(".jar"))
+            {
+                URL jarResource = externalContext.getResource(WEB_LIB_PREFIX
+                        + scanPackageToken);
+                String jarURLString = "jar:" + jarResource.toString() + "!/";
+                URL url = new URL(jarURLString);
+                JarFile jarFile = ((JarURLConnection) url.openConnection())
+                        .getJarFile();
+
+                archiveClasses(externalContext, jarFile, list);
+            }
+            else
+            {
+                List<Class> list2 = new ArrayList<Class>();
+                _PackageInfo.getInstance().getClasses(list2, scanPackageToken);
+                for (Class c : list2)
+                {
+                    list.add(c);                    
+                }
+            }
+        }
+        return list;
+    }    
+    
+    /**
+     * <p>Return a list of classes to examine from the specified JAR archive.
+     * If this archive has no classes in it, a zero-length list is returned.</p>
+     *
+     * @param context <code>ExternalContext</code> instance for
+     *  this application
+     * @param jar <code>JarFile</code> for the archive to be scanned
+     *
+     * @exception ClassNotFoundException if a located class cannot be loaded
+     */
+    private List<Class<?>> archiveClasses(ExternalContext context, JarFile jar, List<Class<?>> list)
+    {
+
+        // Accumulate and return a list of classes in this JAR file
+        ClassLoader loader = ClassUtils.getContextClassLoader();
+        if (loader == null)
+        {
+            loader = this.getClass().getClassLoader();
+        }
+        Enumeration<JarEntry> entries = jar.entries();
+        while (entries.hasMoreElements())
+        {
+            JarEntry entry = entries.nextElement();
+            if (entry.isDirectory())
+            {
+                continue; // This is a directory
+            }
+            String name = entry.getName();
+            if (name.startsWith("META-INF/"))
+            {
+                continue; // Attribute files
+            }
+            if (!name.endsWith(".class"))
+            {
+                continue; // This is not a class
+            }
+
+            DataInputStream in = null;
+            boolean couldContainAnnotation = false;
+            try
+            {
+                in = new DataInputStream(jar.getInputStream(entry));
+                couldContainAnnotation = _filter
+                        .couldContainAnnotationsOnClassDef(in,
+                                byteCodeAnnotationsNames);
+            }
+            catch (IOException e)
+            {
+                // Include this class - we can't scan this class using
+                // the filter, but it could be valid, so we need to
+                // load it using the classLoader. Anyway, log a debug
+                // message.
+                couldContainAnnotation = true;
+                if (log.isLoggable(Level.FINE))
+                {
+                    log.fine("IOException when filtering class " + name
+                            + " for annotations");
+                }
+            }
+            finally
+            {
+                if (in != null)
+                    try
+                    {
+                        in.close();
+                    }
+                    catch (IOException e)
+                    {
+                        // No Op
+                    }
+            }
+
+            if (couldContainAnnotation)
+            {
+                name = name.substring(0, name.length() - 6); // Trim ".class"
+                Class<?> clazz = null;
+                try
+                {
+                    clazz = loader.loadClass(name.replace('/', '.'));
+                }
+                catch (NoClassDefFoundError e)
+                {
+                    ; // Skip this class - we cannot analyze classes we cannot load
+                }
+                catch (Exception e)
+                {
+                    ; // Skip this class - we cannot analyze classes we cannot load
+                }
+                if (clazz != null)
+                {
+                    list.add(clazz);
+                }
+            }
+        }
+        return list;
+
+    }
+    
+    /**
+     * <p>Return a list of the classes defined under the
+     * <code>/WEB-INF/classes</code> directory of this web
+     * application.  If there are no such classes, a zero-length list
+     * will be returned.</p>
+     *
+     * @param externalContext <code>ExternalContext</code> instance for
+     *  this application
+     *
+     * @exception ClassNotFoundException if a located class cannot be loaded
+     */
+    private List<Class<?>> webClasses(ExternalContext externalContext)
+    {
+        List<Class<?>> list = new ArrayList<Class<?>>();
+        webClasses(externalContext, WEB_CLASSES_PREFIX, list);
+        return list;
+    }
+
+    /**
+     * <p>Add classes found in the specified directory to the specified
+     * list, recursively calling this method when a directory is encountered.</p>
+     *
+     * @param externalContext <code>ExternalContext</code> instance for
+     *  this application
+     * @param prefix Prefix specifying the "directory path" to be searched
+     * @param list List to be appended to
+     *
+     * @exception ClassNotFoundException if a located class cannot be loaded
+     */
+    private void webClasses(ExternalContext externalContext, String prefix,
+            List<Class<?>> list)
+    {
+
+        ClassLoader loader = getClassLoader();
+
+        Set<String> paths = externalContext.getResourcePaths(prefix);
+        if(paths == null)
+        {
+            return; //need this in case there is no WEB-INF/classes directory
+        }
+        if (log.isLoggable(Level.FINEST))
+        {
+            log.finest("webClasses(" + prefix + ") - Received " + paths.size()
+                    + " paths to check");
+        }
+
+        String path = null;
+
+        if (paths.isEmpty())
+        {
+            if (log.isLoggable(Level.WARNING))
+            {
+                log
+                        .warning("AnnotationConfigurator does not found classes "
+                                + "for annotations in "
+                                + prefix
+                                + " ."
+                                + " This could happen because maven jetty plugin is used"
+                                + " (goal jetty:run). Try configure "
+                                + SCAN_PACKAGES + " init parameter "
+                                + "or use jetty:run-exploded instead.");
+            }
+        }
+        else
+        {
+            for (Object pathObject : paths)
+            {
+                path = (String) pathObject;
+                if (path.endsWith("/"))
+                {
+                    webClasses(externalContext, path, list);
+                }
+                else if (path.endsWith(".class"))
+                {
+                    DataInputStream in = null;
+                    boolean couldContainAnnotation = false;
+                    try
+                    {
+                        in = new DataInputStream(externalContext
+                                .getResourceAsStream(path));
+                        couldContainAnnotation = _filter
+                                .couldContainAnnotationsOnClassDef(in,
+                                        byteCodeAnnotationsNames);
+                    }
+                    catch (IOException e)
+                    {
+                        // Include this class - we can't scan this class using
+                        // the filter, but it could be valid, so we need to
+                        // load it using the classLoader. Anyway, log a debug
+                        // message.
+                        couldContainAnnotation = true;
+                        if (log.isLoggable(Level.FINE))
+                        {
+                            log.fine("IOException when filtering class " + path
+                                    + " for annotations");
+                        }
+                    }
+                    finally
+                    {
+                        if (in != null)
+                            try
+                            {
+                                in.close();
+                            }
+                            catch (IOException e)
+                            {
+                                // No Op
+                            }
+                    }
+
+                    if (couldContainAnnotation)
+                    {
+                        //Load it and add it to list for later processing
+                        path = path.substring(WEB_CLASSES_PREFIX.length()); // Strip prefix
+                        path = path.substring(0, path.length() - 6); // Strip suffix
+                        path = path.replace('/', '.'); // Convert to FQCN
+
+                        Class<?> clazz = null;
+                        try
+                        {
+                            clazz = loader.loadClass(path);
+                        }
+                        catch (NoClassDefFoundError e)
+                        {
+                            ; // Skip this class - we cannot analyze classes we cannot load
+                        }
+                        catch (Exception e)
+                        {
+                            ; // Skip this class - we cannot analyze classes we cannot load
+                        }
+                        if (clazz != null)
+                        {
+                            list.add(clazz);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    private JarFile getJarFile(URL url) throws IOException
+    {
+        URLConnection conn = url.openConnection();
+        conn.setUseCaches(false);
+        conn.setDefaultUseCaches(false);
+
+        JarFile jarFile;
+        if (conn instanceof JarURLConnection)
+        {
+            jarFile = ((JarURLConnection) conn).getJarFile();
+        }
+        else
+        {
+            jarFile = _getAlternativeJarFile(url);
+        }
+        return jarFile;
+    }
+    
+
+    /**
+     * taken from org.apache.myfaces.view.facelets.util.Classpath
+     * 
+     * For URLs to JARs that do not use JarURLConnection - allowed by the servlet spec - attempt to produce a JarFile
+     * object all the same. Known servlet engines that function like this include Weblogic and OC4J. This is not a full
+     * solution, since an unpacked WAR or EAR will not have JAR "files" as such.
+     */
+    private static JarFile _getAlternativeJarFile(URL url) throws IOException
+    {
+        String urlFile = url.getFile();
+
+        // Trim off any suffix - which is prefixed by "!/" on Weblogic
+        int separatorIndex = urlFile.indexOf("!/");
+
+        // OK, didn't find that. Try the less safe "!", used on OC4J
+        if (separatorIndex == -1)
+        {
+            separatorIndex = urlFile.indexOf('!');
+        }
+
+        if (separatorIndex != -1)
+        {
+            String jarFileUrl = urlFile.substring(0, separatorIndex);
+            // And trim off any "file:" prefix.
+            if (jarFileUrl.startsWith("file:"))
+            {
+                jarFileUrl = jarFileUrl.substring("file:".length());
+            }
+
+            return new JarFile(jarFileUrl);
+        }
+
+        return null;
+    }
+        
+    private ClassLoader getClassLoader()
+    {
+        ClassLoader loader = ClassUtils.getContextClassLoader();
+        if (loader == null)
+        {
+            loader = this.getClass().getClassLoader();
+        }
+        return loader;
+    }
+    
+    private void processClass(Map<Class<? extends Annotation>,Set<Class<?>>> map, Class<?> clazz)
+    {
+        Annotation[] annotations = clazz.getAnnotations();
+        for (Annotation anno : annotations)
+        {
+            Class<? extends Annotation> annotationClass = anno.annotationType();
+            if (JSF_ANNOTATION_CLASSES.contains(annotationClass))
+            {
+                Set<Class<?>> set = map.get(annotationClass);
+                if (set == null)
+                {
+                    set = new HashSet<Class<?>>();
+                    set.add(clazz);
+                    map.put(annotationClass, set);
+                }
+                else
+                {
+                    set.add(clazz);
+                }
+
+            }
+        }
+    }
+}

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/AnnotationProvider.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/AnnotationProvider.java?rev=987645&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/AnnotationProvider.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/AnnotationProvider.java Fri Aug 20 21:50:46 2010
@@ -0,0 +1,104 @@
+/*
+ * 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.spi;
+
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.net.URL;
+import java.util.Map;
+import java.util.Set;
+
+import javax.faces.FacesWrapper;
+import javax.faces.context.ExternalContext;
+
+/**
+ * This interface provide a way to override myfaces annotation scanning algorithm that
+ * needs to be found at startup: 
+ * 
+ * <ul>
+ * <li>{@link javax.faces.bean.ManagedBean}</li>
+ * <li>{@link javax.faces.component.FacesComponent}</li>
+ * <li>{@link javax.faces.component.behavior.FacesBehavior}</li>
+ * <li>{@link javax.faces.convert.FacesConverter}</li>
+ * <li>{@link javax.faces.event.NamedEvent}</li>
+ * <li>{@link javax.faces.render.FacesRenderer}</li>
+ * <li>{@link javax.faces.render.FacesBehaviorRenderer}</li>
+ * <li>{@link javax.faces.validator.FacesValidator}</li>
+ * </ul>
+ * 
+ * <p>This is provided to allow application containers solve the following points</p>
+ * <ul>
+ * <li>It is common application containers to have its own protocols to handle files. It is
+ * not the same to scan annotation inside a jar than look on a directory.</li>
+ * <li>If the application container has some optimization related to annotation scanning or
+ * it already did that task, it is better to reuse that information instead do the same
+ * thing twice.</li>
+ * </ul>
+ * 
+ * <p>To override this class, create a file on a jar file with the following entry name:
+ * /META-INF/services/org.apache.myfaces.spi.AnnotationProvider and put the desired class name of
+ * the class that will override or extend the default AnnotationProvider.
+ * </p>
+ * 
+ * <p>To wrap the default AnnotationProvider, use a constructor like 
+ * CustomAnnotationProvider(AnnotationProvider ap)</p>
+ * 
+ * @since 2.0.2
+ * @author Leonardo Uribe 
+ */
+public abstract class AnnotationProvider implements FacesWrapper<AnnotationProvider>
+{
+
+    /**
+     * Retrieve a map containing the classes that contains annotations used by jsf implementation at
+     * startup.
+     * <p>The default implementation must comply with JSF 2.0 spec section 11.5.1 Requirements for scanning of 
+     * classes for annotations. 
+     * </p>
+     * <p>This method could call getBaseUrls() to obtain a list of URL that could be used to indicate jar files of
+     * annotations in the classpath.
+     * </p>
+     * <p>If the <faces-config> element in the WEB-INF/faces-config.xml file contains metadata-complete attribute 
+     * whose value is "true", this method should not be called.
+     * </p>
+     * 
+     * @param ctx The current ExternalContext
+     * @param urls A set of URL pointing to faces-config.xml files that could be used to retrieve annotations from
+     * the classpath.
+     * @return A map with all classes that could contain annotations.
+     */
+    public abstract Map<Class<? extends Annotation>,Set<Class<?>>> getAnnotatedClasses(ExternalContext ctx);
+
+    /**
+     * <p>The returned Set&lt;URL&gt; urls are calculated in this way ( see JSF 2.0 spec section 11.4.2 for definitions )    
+     * </p>
+     * <ol>
+     * <li>All resources that match either "META-INF/faces-config.xml" or end with ".facesconfig.xml" directly in 
+     * the "META-INF" directory (considered <code>applicationConfigurationResources)<code></li>
+     * </ol>
+     * 
+     * @return
+     */
+    public abstract Set<URL> getBaseUrls() throws IOException;
+    
+    public AnnotationProvider getWrapped()
+    {
+        return null;
+    }    
+}

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/AnnotationProviderFactory.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/AnnotationProviderFactory.java?rev=987645&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/AnnotationProviderFactory.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/AnnotationProviderFactory.java Fri Aug 20 21:50:46 2010
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.spi;
+
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+
+import org.apache.commons.discovery.tools.DiscoverSingleton;
+import org.apache.myfaces.spi.impl.DefaultAnnotationProviderFactory;
+
+/**
+ * 
+ * @since 2.0.2
+ * @author Leonardo Uribe
+ */
+public abstract class AnnotationProviderFactory
+{
+    protected static final String FACTORY_DEFAULT = DefaultAnnotationProviderFactory.class.getName();
+
+    //private static final String FACTORY_KEY = AnnotationProviderFactory.class.getName();
+
+    public static AnnotationProviderFactory getAnnotationProviderFactory(ExternalContext ctx)
+    {
+        //AnnotationProviderFactory instance = (AnnotationProviderFactory) ctx.getApplicationMap().get(FACTORY_KEY);
+        //if (instance != null)
+        //{
+        //    return instance;
+        //}
+        AnnotationProviderFactory lpf = null;
+        try
+        {
+
+            if (System.getSecurityManager() != null)
+            {
+                lpf = (AnnotationProviderFactory) AccessController.doPrivileged(new java.security.PrivilegedExceptionAction<Object>()
+                        {
+                            public Object run() throws PrivilegedActionException
+                            {
+                                return DiscoverSingleton.find(
+                                        AnnotationProviderFactory.class,
+                                        FACTORY_DEFAULT);
+                            }
+                        });
+            }
+            else
+            {
+                lpf = (AnnotationProviderFactory) DiscoverSingleton.find(AnnotationProviderFactory.class, FACTORY_DEFAULT);
+            }
+        }
+        catch (PrivilegedActionException pae)
+        {
+            throw new FacesException(pae);
+        }
+        //if (lpf != null)
+        //{
+        //    setAnnotationProviderFactory(ctx, lpf);
+        //}
+        return lpf;
+    }
+
+    //public static void setAnnotationProviderFactory(ExternalContext ctx, AnnotationProviderFactory instance)
+    //{
+    //    ctx.getApplicationMap().put(FACTORY_KEY, instance);
+    //}
+
+    public abstract AnnotationProvider createAnnotationProvider(ExternalContext externalContext);
+}

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FaceletConfigResourceProvider.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FaceletConfigResourceProvider.java?rev=987645&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FaceletConfigResourceProvider.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FaceletConfigResourceProvider.java Fri Aug 20 21:50:46 2010
@@ -0,0 +1,41 @@
+/*
+ * 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.spi;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collection;
+
+import javax.faces.context.ExternalContext;
+
+/**
+ * 
+ * @since 2.0.2
+ * @author Leonardo Uribe 
+ */
+public abstract class FaceletConfigResourceProvider
+{
+    
+    /**
+     * 
+     * @param context
+     * @return
+     */
+    public abstract Collection<URL> getFaceletTagLibConfigurationResources(ExternalContext context) throws IOException;
+}
\ No newline at end of file

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FaceletConfigResourceProviderFactory.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FaceletConfigResourceProviderFactory.java?rev=987645&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FaceletConfigResourceProviderFactory.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FaceletConfigResourceProviderFactory.java Fri Aug 20 21:50:46 2010
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.spi;
+
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+
+import org.apache.commons.discovery.tools.DiscoverSingleton;
+import org.apache.myfaces.spi.impl.DefaultFaceletConfigResourceProviderFactory;
+
+/**
+ * 
+ * @since 2.0.2
+ * @author Leonardo Uribe
+ */
+public abstract class FaceletConfigResourceProviderFactory
+{
+    protected static final String FACTORY_DEFAULT = DefaultFaceletConfigResourceProviderFactory.class.getName();
+
+    //private static final String FACTORY_KEY = FaceletConfigResourceProviderFactory.class.getName();
+
+    public static FaceletConfigResourceProviderFactory getFacesConfigResourceProviderFactory(ExternalContext ctx)
+    {
+        //FaceletConfigResourceProviderFactory instance = (FaceletConfigResourceProviderFactory) ctx.getApplicationMap().get(FACTORY_KEY);
+        //if (instance != null)
+        //{
+        //    return instance;
+        //}
+        FaceletConfigResourceProviderFactory lpf = null;
+        try
+        {
+
+            if (System.getSecurityManager() != null)
+            {
+                lpf = (FaceletConfigResourceProviderFactory) AccessController.doPrivileged(new java.security.PrivilegedExceptionAction<Object>()
+                        {
+                            public Object run() throws PrivilegedActionException
+                            {
+                                return DiscoverSingleton.find(
+                                        FaceletConfigResourceProviderFactory.class,
+                                        FACTORY_DEFAULT);
+                            }
+                        });
+            }
+            else
+            {
+                lpf = (FaceletConfigResourceProviderFactory) DiscoverSingleton.find(FaceletConfigResourceProviderFactory.class, FACTORY_DEFAULT);
+            }
+        }
+        catch (PrivilegedActionException pae)
+        {
+            throw new FacesException(pae);
+        }
+        //if (lpf != null)
+        //{
+        //    setFaceletConfigResourceProviderFactory(ctx, lpf);
+        //}
+        return lpf;
+    }
+
+    //public static void setFaceletConfigResourceProviderFactory(ExternalContext ctx, FaceletConfigResourceProviderFactory instance)
+    //{
+    //    ctx.getApplicationMap().put(FACTORY_KEY, instance);
+    //}
+
+    public abstract FaceletConfigResourceProvider createFaceletConfigResourceProvider(ExternalContext externalContext);
+}

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FacesConfigResourceProvider.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FacesConfigResourceProvider.java?rev=987645&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FacesConfigResourceProvider.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FacesConfigResourceProvider.java Fri Aug 20 21:50:46 2010
@@ -0,0 +1,41 @@
+/*
+ * 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.spi;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collection;
+
+import javax.faces.context.ExternalContext;
+
+/**
+ * 
+ * @since 2.0.2
+ * @author Leonardo Uribe 
+ */
+public abstract class FacesConfigResourceProvider
+{
+    
+    /**
+     * 
+     * @param context
+     * @return
+     */
+    public abstract Collection<URL> getMetaInfConfigurationResources(ExternalContext context) throws IOException;
+}
\ No newline at end of file

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FacesConfigResourceProviderFactory.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FacesConfigResourceProviderFactory.java?rev=987645&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FacesConfigResourceProviderFactory.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/FacesConfigResourceProviderFactory.java Fri Aug 20 21:50:46 2010
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.spi;
+
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+
+import org.apache.commons.discovery.tools.DiscoverSingleton;
+import org.apache.myfaces.spi.impl.DefaultFacesConfigResourceProviderFactory;
+
+/**
+ * 
+ * @since 2.0.2
+ * @author Leonardo Uribe
+ */
+public abstract class FacesConfigResourceProviderFactory
+{
+    protected static final String FACTORY_DEFAULT = DefaultFacesConfigResourceProviderFactory.class.getName();
+
+    //private static final String FACTORY_KEY = FacesConfigResourceProviderFactory.class.getName();
+
+    public static FacesConfigResourceProviderFactory getFacesConfigResourceProviderFactory(ExternalContext ctx)
+    {
+        //FacesConfigResourceProviderFactory instance = (FacesConfigResourceProviderFactory) ctx.getApplicationMap().get(FACTORY_KEY);
+        //if (instance != null)
+        //{
+        //    return instance;
+        //}
+        FacesConfigResourceProviderFactory lpf = null;
+        try
+        {
+
+            if (System.getSecurityManager() != null)
+            {
+                lpf = (FacesConfigResourceProviderFactory) AccessController.doPrivileged(new java.security.PrivilegedExceptionAction<Object>()
+                        {
+                            public Object run() throws PrivilegedActionException
+                            {
+                                return DiscoverSingleton.find(
+                                        FacesConfigResourceProviderFactory.class,
+                                        FACTORY_DEFAULT);
+                            }
+                        });
+            }
+            else
+            {
+                lpf = (FacesConfigResourceProviderFactory) DiscoverSingleton.find(FacesConfigResourceProviderFactory.class, FACTORY_DEFAULT);
+            }
+        }
+        catch (PrivilegedActionException pae)
+        {
+            throw new FacesException(pae);
+        }
+        //if (lpf != null)
+        //{
+        //    setFacesConfigResourceProviderFactory(ctx, lpf);
+        //}
+        return lpf;
+    }
+
+    //public static void setFacesConfigResourceProviderFactory(ExternalContext ctx, FacesConfigResourceProviderFactory instance)
+    //{
+    //    ctx.getApplicationMap().put(FACTORY_KEY, instance);
+    //}
+
+    public abstract FacesConfigResourceProvider createFacesConfigResourceProvider(ExternalContext externalContext);
+}

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultAnnotationProviderFactory.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultAnnotationProviderFactory.java?rev=987645&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultAnnotationProviderFactory.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultAnnotationProviderFactory.java Fri Aug 20 21:50:46 2010
@@ -0,0 +1,266 @@
+/*
+ * 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.spi.impl;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+
+import org.apache.commons.discovery.ResourceNameIterator;
+import org.apache.commons.discovery.resource.ClassLoaders;
+import org.apache.commons.discovery.resource.names.DiscoverServiceNames;
+import org.apache.myfaces.config.annotation.DefaultAnnotationProvider;
+import org.apache.myfaces.shared_impl.util.ClassUtils;
+import org.apache.myfaces.spi.AnnotationProvider;
+import org.apache.myfaces.spi.AnnotationProviderFactory;
+
+/**
+ * 
+ * @since 2.0.2
+ * @author Leonardo Uribe
+ */
+public class DefaultAnnotationProviderFactory extends AnnotationProviderFactory
+{
+    private static Logger log = Logger.getLogger(DefaultAnnotationProviderFactory.class.getName());
+
+    public static final String ANNOTATION_PROVIDER = AnnotationProvider.class.getName();
+    
+    @Override
+    public AnnotationProvider createAnnotationProvider(
+            ExternalContext externalContext)
+    {
+        AnnotationProvider returnValue = null;
+        final ExternalContext extContext = externalContext;
+        try
+        {
+            if (System.getSecurityManager() != null)
+            {
+                returnValue = AccessController.doPrivileged(new java.security.PrivilegedExceptionAction<AnnotationProvider>()
+                        {
+                            public AnnotationProvider run() throws ClassNotFoundException,
+                                    NoClassDefFoundError,
+                                    InstantiationException,
+                                    IllegalAccessException,
+                                    InvocationTargetException,
+                                    PrivilegedActionException
+                            {
+                                return resolveAnnotationProviderFromService(extContext);
+                            }
+                        });
+            }
+            else
+            {
+                returnValue = resolveAnnotationProviderFromService(extContext);
+            }
+        }
+        catch (ClassNotFoundException e)
+        {
+            // ignore
+        }
+        catch (NoClassDefFoundError e)
+        {
+            // ignore
+        }
+        catch (InstantiationException e)
+        {
+            log.log(Level.SEVERE, "", e);
+        }
+        catch (IllegalAccessException e)
+        {
+            log.log(Level.SEVERE, "", e);
+        }
+        catch (InvocationTargetException e)
+        {
+            log.log(Level.SEVERE, "", e);
+        }
+        catch (PrivilegedActionException e)
+        {
+            throw new FacesException(e);
+        }
+        return returnValue;
+    }
+    
+    private AnnotationProvider resolveAnnotationProviderFromService(
+            ExternalContext externalContext) throws ClassNotFoundException,
+            NoClassDefFoundError,
+            InstantiationException,
+            IllegalAccessException,
+            InvocationTargetException,
+            PrivilegedActionException
+    {
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+        if (classLoader == null)
+        {
+            classLoader = this.getClass().getClassLoader();
+        }
+        ClassLoaders loaders = new ClassLoaders();
+        loaders.put(classLoader);
+        DiscoverServiceNames dsn = new DiscoverServiceNames(loaders);
+        ResourceNameIterator iter = dsn.findResourceNames(ANNOTATION_PROVIDER);
+        return getApplicationObject(AnnotationProvider.class, iter, new DefaultAnnotationProvider());
+    }
+
+    private <T> T getApplicationObject(Class<T> interfaceClass, ResourceNameIterator classNamesIterator, T defaultObject)
+    {
+        return getApplicationObject(interfaceClass, null, null, classNamesIterator, defaultObject);
+    }
+
+    /**
+     * Creates ApplicationObjects like NavigationHandler or StateManager and creates 
+     * the right wrapping chain of the ApplicationObjects known as the decorator pattern. 
+     * @param <T>
+     * @param interfaceClass The class from which the implementation has to inherit from.
+     * @param extendedInterfaceClass A subclass of interfaceClass which specifies a more
+     *                               detailed implementation.
+     * @param extendedInterfaceWrapperClass A wrapper class for the case that you have an ApplicationObject
+     *                                      which only implements the interfaceClass but not the 
+     *                                      extendedInterfaceClass.
+     * @param classNamesIterator All the class names of the actual ApplicationObject implementations
+     *                           from the faces-config.xml.
+     * @param defaultObject The default implementation for the given ApplicationObject.
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    private <T> T getApplicationObject(Class<T> interfaceClass, Class<? extends T> extendedInterfaceClass,
+            Class<? extends T> extendedInterfaceWrapperClass,
+            ResourceNameIterator classNamesIterator, T defaultObject)
+    {
+        T current = defaultObject;
+
+        while (classNamesIterator.hasNext())
+        {
+            String implClassName = classNamesIterator.nextResourceName();
+            Class<? extends T> implClass = ClassUtils.simpleClassForName(implClassName);
+
+            // check, if class is of expected interface type
+            if (!interfaceClass.isAssignableFrom(implClass))
+            {
+                throw new IllegalArgumentException("Class " + implClassName + " is no " + interfaceClass.getName());
+            }
+
+            if (current == null)
+            {
+                // nothing to decorate
+                current = (T) ClassUtils.newInstance(implClass);
+            }
+            else
+            {
+                // let's check if class supports the decorator pattern
+                T newCurrent = null;
+                try
+                {
+                    Constructor<? extends T> delegationConstructor = null;
+                    
+                    // first, if there is a extendedInterfaceClass,
+                    // try to find a constructor that uses that
+                    if (extendedInterfaceClass != null 
+                            && extendedInterfaceClass.isAssignableFrom(current.getClass()))
+                    {
+                        try
+                        {
+                            delegationConstructor = 
+                                    implClass.getConstructor(new Class[] {extendedInterfaceClass});
+                        }
+                        catch (NoSuchMethodException mnfe)
+                        {
+                            // just eat it
+                        }
+                    }
+                    if (delegationConstructor == null)
+                    {
+                        // try to find the constructor with the "normal" interfaceClass
+                        delegationConstructor = 
+                                implClass.getConstructor(new Class[] {interfaceClass});
+                    }
+                    // impl class supports decorator pattern at this point
+                    try
+                    {
+                        // create new decorator wrapping current
+                        newCurrent = delegationConstructor.newInstance(new Object[] { current });
+                    }
+                    catch (InstantiationException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (IllegalAccessException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (InvocationTargetException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                }
+                catch (NoSuchMethodException e)
+                {
+                    // no decorator pattern support
+                    newCurrent = (T) ClassUtils.newInstance(implClass);
+                }
+                
+                // now we have a new current object (newCurrent)
+                // --> find out if it is assignable from extendedInterfaceClass
+                // and if not, wrap it in a backwards compatible wrapper (if available)
+                if (extendedInterfaceWrapperClass != null
+                        && !extendedInterfaceClass.isAssignableFrom(newCurrent.getClass()))
+                {
+                    try
+                    {
+                        Constructor<? extends T> wrapperConstructor
+                                = extendedInterfaceWrapperClass.getConstructor(
+                                        new Class[] {interfaceClass, extendedInterfaceClass});
+                        newCurrent = wrapperConstructor.newInstance(new Object[] {newCurrent, current});
+                    }
+                    catch (NoSuchMethodException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (InstantiationException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (IllegalAccessException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (InvocationTargetException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                }
+                
+                current = newCurrent;
+            }
+        }
+
+        return current;
+    }    
+}

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultFaceletConfigResourceProviderFactory.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultFaceletConfigResourceProviderFactory.java?rev=987645&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultFaceletConfigResourceProviderFactory.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultFaceletConfigResourceProviderFactory.java Fri Aug 20 21:50:46 2010
@@ -0,0 +1,266 @@
+/*
+ * 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.spi.impl;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+
+import org.apache.commons.discovery.ResourceNameIterator;
+import org.apache.commons.discovery.resource.ClassLoaders;
+import org.apache.commons.discovery.resource.names.DiscoverServiceNames;
+import org.apache.myfaces.shared_impl.util.ClassUtils;
+import org.apache.myfaces.spi.FaceletConfigResourceProvider;
+import org.apache.myfaces.spi.FaceletConfigResourceProviderFactory;
+import org.apache.myfaces.view.facelets.compiler.DefaultFaceletConfigResourceProvider;
+
+/**
+ * 
+ * @since 2.0.2
+ * @author Leonardo Uribe
+ */
+public class DefaultFaceletConfigResourceProviderFactory extends FaceletConfigResourceProviderFactory
+{
+    private static Logger log = Logger.getLogger(DefaultFaceletConfigResourceProviderFactory.class.getName());
+
+    public static final String ANNOTATION_PROVIDER = FaceletConfigResourceProvider.class.getName();
+    
+    @Override
+    public FaceletConfigResourceProvider createFaceletConfigResourceProvider(
+            ExternalContext externalContext)
+    {
+        FaceletConfigResourceProvider returnValue = null;
+        final ExternalContext extContext = externalContext;
+        try
+        {
+            if (System.getSecurityManager() != null)
+            {
+                returnValue = AccessController.doPrivileged(new java.security.PrivilegedExceptionAction<FaceletConfigResourceProvider>()
+                        {
+                            public FaceletConfigResourceProvider run() throws ClassNotFoundException,
+                                    NoClassDefFoundError,
+                                    InstantiationException,
+                                    IllegalAccessException,
+                                    InvocationTargetException,
+                                    PrivilegedActionException
+                            {
+                                return resolveFaceletConfigResourceProviderFromService(extContext);
+                            }
+                        });
+            }
+            else
+            {
+                returnValue = resolveFaceletConfigResourceProviderFromService(extContext);
+            }
+        }
+        catch (ClassNotFoundException e)
+        {
+            // ignore
+        }
+        catch (NoClassDefFoundError e)
+        {
+            // ignore
+        }
+        catch (InstantiationException e)
+        {
+            log.log(Level.SEVERE, "", e);
+        }
+        catch (IllegalAccessException e)
+        {
+            log.log(Level.SEVERE, "", e);
+        }
+        catch (InvocationTargetException e)
+        {
+            log.log(Level.SEVERE, "", e);
+        }
+        catch (PrivilegedActionException e)
+        {
+            throw new FacesException(e);
+        }
+        return returnValue;
+    }
+    
+    private FaceletConfigResourceProvider resolveFaceletConfigResourceProviderFromService(
+            ExternalContext externalContext) throws ClassNotFoundException,
+            NoClassDefFoundError,
+            InstantiationException,
+            IllegalAccessException,
+            InvocationTargetException,
+            PrivilegedActionException
+    {
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+        if (classLoader == null)
+        {
+            classLoader = this.getClass().getClassLoader();
+        }
+        ClassLoaders loaders = new ClassLoaders();
+        loaders.put(classLoader);
+        DiscoverServiceNames dsn = new DiscoverServiceNames(loaders);
+        ResourceNameIterator iter = dsn.findResourceNames(ANNOTATION_PROVIDER);
+        return getApplicationObject(FaceletConfigResourceProvider.class, iter, new DefaultFaceletConfigResourceProvider());
+    }
+
+    private <T> T getApplicationObject(Class<T> interfaceClass, ResourceNameIterator classNamesIterator, T defaultObject)
+    {
+        return getApplicationObject(interfaceClass, null, null, classNamesIterator, defaultObject);
+    }
+
+    /**
+     * Creates ApplicationObjects like NavigationHandler or StateManager and creates 
+     * the right wrapping chain of the ApplicationObjects known as the decorator pattern. 
+     * @param <T>
+     * @param interfaceClass The class from which the implementation has to inherit from.
+     * @param extendedInterfaceClass A subclass of interfaceClass which specifies a more
+     *                               detailed implementation.
+     * @param extendedInterfaceWrapperClass A wrapper class for the case that you have an ApplicationObject
+     *                                      which only implements the interfaceClass but not the 
+     *                                      extendedInterfaceClass.
+     * @param classNamesIterator All the class names of the actual ApplicationObject implementations
+     *                           from the faces-config.xml.
+     * @param defaultObject The default implementation for the given ApplicationObject.
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    private <T> T getApplicationObject(Class<T> interfaceClass, Class<? extends T> extendedInterfaceClass,
+            Class<? extends T> extendedInterfaceWrapperClass,
+            ResourceNameIterator classNamesIterator, T defaultObject)
+    {
+        T current = defaultObject;
+
+        while (classNamesIterator.hasNext())
+        {
+            String implClassName = classNamesIterator.nextResourceName();
+            Class<? extends T> implClass = ClassUtils.simpleClassForName(implClassName);
+
+            // check, if class is of expected interface type
+            if (!interfaceClass.isAssignableFrom(implClass))
+            {
+                throw new IllegalArgumentException("Class " + implClassName + " is no " + interfaceClass.getName());
+            }
+
+            if (current == null)
+            {
+                // nothing to decorate
+                current = (T) ClassUtils.newInstance(implClass);
+            }
+            else
+            {
+                // let's check if class supports the decorator pattern
+                T newCurrent = null;
+                try
+                {
+                    Constructor<? extends T> delegationConstructor = null;
+                    
+                    // first, if there is a extendedInterfaceClass,
+                    // try to find a constructor that uses that
+                    if (extendedInterfaceClass != null 
+                            && extendedInterfaceClass.isAssignableFrom(current.getClass()))
+                    {
+                        try
+                        {
+                            delegationConstructor = 
+                                    implClass.getConstructor(new Class[] {extendedInterfaceClass});
+                        }
+                        catch (NoSuchMethodException mnfe)
+                        {
+                            // just eat it
+                        }
+                    }
+                    if (delegationConstructor == null)
+                    {
+                        // try to find the constructor with the "normal" interfaceClass
+                        delegationConstructor = 
+                                implClass.getConstructor(new Class[] {interfaceClass});
+                    }
+                    // impl class supports decorator pattern at this point
+                    try
+                    {
+                        // create new decorator wrapping current
+                        newCurrent = delegationConstructor.newInstance(new Object[] { current });
+                    }
+                    catch (InstantiationException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (IllegalAccessException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (InvocationTargetException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                }
+                catch (NoSuchMethodException e)
+                {
+                    // no decorator pattern support
+                    newCurrent = (T) ClassUtils.newInstance(implClass);
+                }
+                
+                // now we have a new current object (newCurrent)
+                // --> find out if it is assignable from extendedInterfaceClass
+                // and if not, wrap it in a backwards compatible wrapper (if available)
+                if (extendedInterfaceWrapperClass != null
+                        && !extendedInterfaceClass.isAssignableFrom(newCurrent.getClass()))
+                {
+                    try
+                    {
+                        Constructor<? extends T> wrapperConstructor
+                                = extendedInterfaceWrapperClass.getConstructor(
+                                        new Class[] {interfaceClass, extendedInterfaceClass});
+                        newCurrent = wrapperConstructor.newInstance(new Object[] {newCurrent, current});
+                    }
+                    catch (NoSuchMethodException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (InstantiationException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (IllegalAccessException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (InvocationTargetException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                }
+                
+                current = newCurrent;
+            }
+        }
+
+        return current;
+    }    
+}

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultFacesConfigResourceProviderFactory.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultFacesConfigResourceProviderFactory.java?rev=987645&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultFacesConfigResourceProviderFactory.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultFacesConfigResourceProviderFactory.java Fri Aug 20 21:50:46 2010
@@ -0,0 +1,266 @@
+/*
+ * 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.spi.impl;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+
+import org.apache.commons.discovery.ResourceNameIterator;
+import org.apache.commons.discovery.resource.ClassLoaders;
+import org.apache.commons.discovery.resource.names.DiscoverServiceNames;
+import org.apache.myfaces.config.DefaultFacesConfigResourceProvider;
+import org.apache.myfaces.shared_impl.util.ClassUtils;
+import org.apache.myfaces.spi.FacesConfigResourceProvider;
+import org.apache.myfaces.spi.FacesConfigResourceProviderFactory;
+
+/**
+ * 
+ * @since 2.0.2
+ * @author Leonardo Uribe
+ */
+public class DefaultFacesConfigResourceProviderFactory extends FacesConfigResourceProviderFactory
+{
+    private static Logger log = Logger.getLogger(DefaultFacesConfigResourceProviderFactory.class.getName());
+
+    public static final String ANNOTATION_PROVIDER = FacesConfigResourceProvider.class.getName();
+    
+    @Override
+    public FacesConfigResourceProvider createFacesConfigResourceProvider(
+            ExternalContext externalContext)
+    {
+        FacesConfigResourceProvider returnValue = null;
+        final ExternalContext extContext = externalContext;
+        try
+        {
+            if (System.getSecurityManager() != null)
+            {
+                returnValue = AccessController.doPrivileged(new java.security.PrivilegedExceptionAction<FacesConfigResourceProvider>()
+                        {
+                            public FacesConfigResourceProvider run() throws ClassNotFoundException,
+                                    NoClassDefFoundError,
+                                    InstantiationException,
+                                    IllegalAccessException,
+                                    InvocationTargetException,
+                                    PrivilegedActionException
+                            {
+                                return resolveFacesConfigResourceProviderFromService(extContext);
+                            }
+                        });
+            }
+            else
+            {
+                returnValue = resolveFacesConfigResourceProviderFromService(extContext);
+            }
+        }
+        catch (ClassNotFoundException e)
+        {
+            // ignore
+        }
+        catch (NoClassDefFoundError e)
+        {
+            // ignore
+        }
+        catch (InstantiationException e)
+        {
+            log.log(Level.SEVERE, "", e);
+        }
+        catch (IllegalAccessException e)
+        {
+            log.log(Level.SEVERE, "", e);
+        }
+        catch (InvocationTargetException e)
+        {
+            log.log(Level.SEVERE, "", e);
+        }
+        catch (PrivilegedActionException e)
+        {
+            throw new FacesException(e);
+        }
+        return returnValue;
+    }
+    
+    private FacesConfigResourceProvider resolveFacesConfigResourceProviderFromService(
+            ExternalContext externalContext) throws ClassNotFoundException,
+            NoClassDefFoundError,
+            InstantiationException,
+            IllegalAccessException,
+            InvocationTargetException,
+            PrivilegedActionException
+    {
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+        if (classLoader == null)
+        {
+            classLoader = this.getClass().getClassLoader();
+        }
+        ClassLoaders loaders = new ClassLoaders();
+        loaders.put(classLoader);
+        DiscoverServiceNames dsn = new DiscoverServiceNames(loaders);
+        ResourceNameIterator iter = dsn.findResourceNames(ANNOTATION_PROVIDER);
+        return getApplicationObject(FacesConfigResourceProvider.class, iter, new DefaultFacesConfigResourceProvider());
+    }
+
+    private <T> T getApplicationObject(Class<T> interfaceClass, ResourceNameIterator classNamesIterator, T defaultObject)
+    {
+        return getApplicationObject(interfaceClass, null, null, classNamesIterator, defaultObject);
+    }
+
+    /**
+     * Creates ApplicationObjects like NavigationHandler or StateManager and creates 
+     * the right wrapping chain of the ApplicationObjects known as the decorator pattern. 
+     * @param <T>
+     * @param interfaceClass The class from which the implementation has to inherit from.
+     * @param extendedInterfaceClass A subclass of interfaceClass which specifies a more
+     *                               detailed implementation.
+     * @param extendedInterfaceWrapperClass A wrapper class for the case that you have an ApplicationObject
+     *                                      which only implements the interfaceClass but not the 
+     *                                      extendedInterfaceClass.
+     * @param classNamesIterator All the class names of the actual ApplicationObject implementations
+     *                           from the faces-config.xml.
+     * @param defaultObject The default implementation for the given ApplicationObject.
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    private <T> T getApplicationObject(Class<T> interfaceClass, Class<? extends T> extendedInterfaceClass,
+            Class<? extends T> extendedInterfaceWrapperClass,
+            ResourceNameIterator classNamesIterator, T defaultObject)
+    {
+        T current = defaultObject;
+
+        while (classNamesIterator.hasNext())
+        {
+            String implClassName = classNamesIterator.nextResourceName();
+            Class<? extends T> implClass = ClassUtils.simpleClassForName(implClassName);
+
+            // check, if class is of expected interface type
+            if (!interfaceClass.isAssignableFrom(implClass))
+            {
+                throw new IllegalArgumentException("Class " + implClassName + " is no " + interfaceClass.getName());
+            }
+
+            if (current == null)
+            {
+                // nothing to decorate
+                current = (T) ClassUtils.newInstance(implClass);
+            }
+            else
+            {
+                // let's check if class supports the decorator pattern
+                T newCurrent = null;
+                try
+                {
+                    Constructor<? extends T> delegationConstructor = null;
+                    
+                    // first, if there is a extendedInterfaceClass,
+                    // try to find a constructor that uses that
+                    if (extendedInterfaceClass != null 
+                            && extendedInterfaceClass.isAssignableFrom(current.getClass()))
+                    {
+                        try
+                        {
+                            delegationConstructor = 
+                                    implClass.getConstructor(new Class[] {extendedInterfaceClass});
+                        }
+                        catch (NoSuchMethodException mnfe)
+                        {
+                            // just eat it
+                        }
+                    }
+                    if (delegationConstructor == null)
+                    {
+                        // try to find the constructor with the "normal" interfaceClass
+                        delegationConstructor = 
+                                implClass.getConstructor(new Class[] {interfaceClass});
+                    }
+                    // impl class supports decorator pattern at this point
+                    try
+                    {
+                        // create new decorator wrapping current
+                        newCurrent = delegationConstructor.newInstance(new Object[] { current });
+                    }
+                    catch (InstantiationException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (IllegalAccessException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (InvocationTargetException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                }
+                catch (NoSuchMethodException e)
+                {
+                    // no decorator pattern support
+                    newCurrent = (T) ClassUtils.newInstance(implClass);
+                }
+                
+                // now we have a new current object (newCurrent)
+                // --> find out if it is assignable from extendedInterfaceClass
+                // and if not, wrap it in a backwards compatible wrapper (if available)
+                if (extendedInterfaceWrapperClass != null
+                        && !extendedInterfaceClass.isAssignableFrom(newCurrent.getClass()))
+                {
+                    try
+                    {
+                        Constructor<? extends T> wrapperConstructor
+                                = extendedInterfaceWrapperClass.getConstructor(
+                                        new Class[] {interfaceClass, extendedInterfaceClass});
+                        newCurrent = wrapperConstructor.newInstance(new Object[] {newCurrent, current});
+                    }
+                    catch (NoSuchMethodException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (InstantiationException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (IllegalAccessException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (InvocationTargetException e)
+                    {
+                        log.log(Level.SEVERE, e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                }
+                
+                current = newCurrent;
+            }
+        }
+
+        return current;
+    }    
+}

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/DefaultFaceletConfigResourceProvider.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/DefaultFaceletConfigResourceProvider.java?rev=987645&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/DefaultFaceletConfigResourceProvider.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/DefaultFaceletConfigResourceProvider.java Fri Aug 20 21:50:46 2010
@@ -0,0 +1,74 @@
+/*
+ * 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.view.facelets.compiler;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.faces.context.ExternalContext;
+
+import org.apache.myfaces.shared_impl.util.ClassUtils;
+import org.apache.myfaces.spi.FaceletConfigResourceProvider;
+import org.apache.myfaces.view.facelets.util.Classpath;
+
+/**
+ * 
+ * @since 2.0.2
+ * @author Leonardo Uribe
+ */
+public class DefaultFaceletConfigResourceProvider extends FaceletConfigResourceProvider
+{
+    private static final String META_INF_PREFIX = "META-INF/";
+
+    private static final String FACELET_TAGLIB_SUFFIX = ".taglib.xml";
+
+    public DefaultFaceletConfigResourceProvider()
+    {
+        super();
+    }
+
+    @Override
+    public Collection<URL> getFaceletTagLibConfigurationResources(
+            ExternalContext context) throws IOException
+    {
+        List<URL> urlSet = new ArrayList<URL>();
+        
+        //Scan files inside META-INF ending with .faces-config.xml
+        URL[] urls = Classpath.search(getClassLoader(), META_INF_PREFIX, FACELET_TAGLIB_SUFFIX);
+        for (int i = 0; i < urls.length; i++)
+        {
+            urlSet.add(urls[i]);
+        }
+        
+        return urlSet;
+    }
+
+    private ClassLoader getClassLoader()
+    {
+        ClassLoader loader = ClassUtils.getContextClassLoader();
+        if (loader == null)
+        {
+            loader = this.getClass().getClassLoader();
+        }
+        return loader;
+    }
+}