Add JSF 2.x annotations support
Bug 306428 - [JSF2.0] Support for Annotation-based artifact declaration
Bug 336053 - [JSF2.0] Autocomplete Annotated Managed Beans
Bug 357885 - [JSF2.0] Support @FacesConverter for converter id validation
diff --git a/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/AnnotationJSFAppConfigLocator.java b/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/AnnotationJSFAppConfigLocator.java
new file mode 100644
index 0000000..929d784
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/AnnotationJSFAppConfigLocator.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Oracle Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Andrew McCulloch - initial API and implementation
+ *******************************************************************************/ 
+package org.eclipse.jst.jsf.core.jsfappconfig;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.ElementChangedEvent;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IElementChangedListener;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaElementDelta;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jst.jsf.common.internal.componentcore.AbstractVirtualComponentQuery.DefaultVirtualComponentQuery;
+import org.eclipse.jst.jsf.core.jsfappconfig.AbstractJSFAppConfigLocater;
+import org.eclipse.jst.jsf.core.jsfappconfig.JSFAppConfigUtils;
+import org.eclipse.wst.common.componentcore.resources.IVirtualFolder;
+
+/**
+ * AnnotationJSFAppConfigLocator locates JSF configuration specified as JSF 2.x annotations.
+ * 
+ * <p><b>Provisional API - subject to change</b></p>
+ * 
+ * @author Andrew McCulloch - Oracle
+ */
+public class AnnotationJSFAppConfigLocator extends AbstractJSFAppConfigLocater {
+
+    private final IElementChangedListener listener = new ElementChangeListener();
+    
+    private IPath webInfLibPath = null;
+    private IPath webInfClassesPath = null;
+
+    public void startLocating() {
+        IProject project = getJSFAppConfigManager().getProject();
+        if (JSFAppConfigUtils.isValidJSFProject(project, "2.0")) { //$NON-NLS-1$
+            IVirtualFolder webContent = new DefaultVirtualComponentQuery().getWebContentFolder(project);
+            if (webContent != null) {
+                IContainer webContentFolder = webContent.getUnderlyingFolder();
+                if (webContentFolder != null && webContentFolder.exists()) {
+                    IPath webContentPath = webContentFolder.getProjectRelativePath();
+                    if (webContentPath != null) {
+                        webInfLibPath = webContentPath.append("WEB-INF/lib"); //$NON-NLS-1$
+                        webInfClassesPath = webContentPath.append("WEB-INF/classes"); //$NON-NLS-1$
+                        
+                        addProvider();
+                        JavaCore.addElementChangedListener(listener);
+                    }
+                }
+            }
+        }
+    }
+
+    private void addProvider() {
+        Set newConfigProviders = new LinkedHashSet();
+        newConfigProviders.add(new AnnotationJSFAppConfigProvider());
+        updateConfigProviders(newConfigProviders);
+    }
+
+    @Override
+    public void stopLocating() {
+        JavaCore.removeElementChangedListener(listener);
+    }
+
+    private class ElementChangeListener implements IElementChangedListener {
+
+        public void elementChanged(ElementChangedEvent event) {
+            if (isRelevantChange(event.getDelta(), getJSFAppConfigManager().getProject())) {
+                addProvider();
+            }
+        }
+
+        /*
+         * 11.5.1 Requirements for scanning of classes for annotations =
+         * [P1_start-annotation-discovery]If the <faces-config> element in the
+         * WEB-INF/faces-config.xml file contains metadata-complete attribute
+         * whose value is "true", the implementation must not perform annotation
+         * scanning on any classes except for those classes provided by the
+         * implementation itself. Otherwise, continue as follows. = If the
+         * runtime discovers a conflict between an entry in the Application
+         * Configuration Resources and an annotation, the entry in the
+         * Application Configuration Resources takes precedence. = All classes
+         * in WEB-INF/classes must be scanned. = For every jar in the
+         * application's WEB-INF/lib directory, if the jar contains a
+         * "META-INF/faces-config.xml" file or a file that matches the regular
+         * expression ".*\.faces-config.xml" (even an empty one), all classes in
+         * that jar must be scanned.[P1_end-annotation-discovery]
+         */
+
+        private final boolean isRelevantChange(IJavaElementDelta delta, IProject project) {
+            int deltaFlags = delta.getFlags();
+            /*
+             * F_CONTENT means the content of an element changed.  If the element is a class in web-inf/classes this is relevant
+             * F_ADDED_TO_CLASSPATH, F_ARCHIVE_CONTENT_CHANGED, F_REMOVED_FROM_CLASSPATH all indicate archive changes which are relevant 
+             *    if the archive has the metadata and is in web-inf/lib.
+             * F_CLASSPATH_REORDER could indicate a class with a bean annotation has been discovered or hidden by classpath changes.
+             */
+            if ((deltaFlags & (IJavaElementDelta.F_CONTENT | IJavaElementDelta.F_ADDED_TO_CLASSPATH | IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED | 
+                                IJavaElementDelta.F_REMOVED_FROM_CLASSPATH | IJavaElementDelta.F_REORDER | IJavaElementDelta.F_PRIMARY_RESOURCE)) != 0) {
+                IJavaElement changedElement = delta.getElement();
+                switch (changedElement.getElementType()) {
+                    case IJavaElement.COMPILATION_UNIT:
+                        if (changedElement instanceof ICompilationUnit) {
+                            return true;
+                        }
+                        IType type = (IType)changedElement;
+                        IPath classFilePath = type.getPath();
+                        if (classFilePath != null) {
+                            if (project.getFullPath().append(webInfClassesPath).isPrefixOf(classFilePath)) {
+                                return true;
+                            }
+                        }
+                    case IJavaElement.PACKAGE_FRAGMENT_ROOT:
+                        IPackageFragmentRoot root = (IPackageFragmentRoot)changedElement;
+                        if (root.isArchive() && !root.isExternal()) {
+                            IPath archivePath = root.getPath();
+                            if (archivePath != null) {
+                                if (project.getFullPath().append(webInfLibPath).isPrefixOf(archivePath)) {
+                                    if ((deltaFlags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0) {
+                                        return true;
+                                    }
+                                    //don't bother processing this delta or children if the root is missing
+                                    AnnotationPackageFragmentRoot wrapper = new AnnotationPackageFragmentRoot(root);
+                                    return wrapper.canContainAnnotatedComponents();
+                                }
+                            }
+                        }
+                    default://do nothing
+                }
+            }
+            IJavaElementDelta[] childDeltas = delta.getAffectedChildren();
+            if (childDeltas != null) {
+                for (IJavaElementDelta childDelta : childDeltas) {
+                    if (isRelevantChange(childDelta, project)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+   }
+}
diff --git a/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/AnnotationJSFAppConfigProvider.java b/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/AnnotationJSFAppConfigProvider.java
new file mode 100644
index 0000000..99bb956
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/AnnotationJSFAppConfigProvider.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Oracle Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Andrew McCulloch - initial API and implementation
+ *    Ian Trimble/Oracle - maintenance
+ *******************************************************************************/ 
+package org.eclipse.jst.jsf.core.jsfappconfig;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.search.IJavaSearchConstants;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.core.search.SearchEngine;
+import org.eclipse.jdt.core.search.SearchParticipant;
+import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.core.search.SearchRequestor;
+import org.eclipse.jst.jsf.core.internal.JSFCorePlugin;
+import org.eclipse.jst.jsf.core.jsfappconfig.AbstractJSFAppConfigProvider;
+import org.eclipse.jst.jsf.facesconfig.emf.FacesConfigFactory;
+import org.eclipse.jst.jsf.facesconfig.emf.FacesConfigType;
+
+/**
+ * Provides a configuration model specified as JSF 2.x annotations.
+ * 
+ * <p><b>Provisional API - subject to change</b></p>
+ * 
+ * @author Andrew McCulloch - Oracle 
+ */
+public class AnnotationJSFAppConfigProvider extends AbstractJSFAppConfigProvider {
+
+    static final String MANAGED_BEAN_ANNOTATION_CLASS = "javax.faces.bean.ManagedBean"; //$NON-NLS-1$
+    static final String REFERENCED_BEAN_ANNOTATION_CLASS = "javax.faces.bean.ReferencedBean"; //$NON-NLS-1$
+    static final String FACES_COMPONENT_ANNOTATION_CLASS = "javax.faces.component.FacesComponent"; //$NON-NLS-1$
+    static final String FACES_CONVERTER_ANNOTATION_CLASS = "javax.faces.convert.FacesConverter"; //$NON-NLS-1$
+    static final String FACES_RENDERER_ANNOTATION_CLASS = "javax.faces.render.FacesRenderer"; //$NON-NLS-1$
+    static final String FACES_VALIDATOR_ANNOTATION_CLASS = "javax.faces.validator.FacesValidator"; //$NON-NLS-1$
+    
+    static final String VIEW_SCOPED_ANNOTATION_CLASS = "javax.faces.bean.ViewScoped"; //$NON-NLS-1$
+    static final String APPLICATION_SCOPED_ANNOTATION_CLASS = "javax.faces.bean.ApplicationScoped"; //$NON-NLS-1$
+    static final String NONE_SCOPED_ANNOTATION_CLASS = "javax.faces.bean.NoneScoped"; //$NON-NLS-1$
+    static final String SESSION_SCOPED_ANNOTATION_CLASS = "javax.faces.bean.SessionScoped"; //$NON-NLS-1$
+    static final String CUSTOM_SCOPED_ANNOTATION_CLASS = "javax.faces.bean.CustomScoped";  //$NON-NLS-1$
+
+    /**
+     * Cached {@link FacesConfigType} instance.
+     */
+    private FacesConfigType facesConfig = null;
+
+    @Override
+    public synchronized FacesConfigType getFacesConfigModel() {
+        if (facesConfig == null) {
+            try {
+                discoverFacesConfig();
+            } catch (CoreException ce) {
+                JSFCorePlugin.log(IStatus.ERROR, ce.getLocalizedMessage(), ce);
+                facesConfig = null;
+            }
+
+            if (facesConfig != null) {
+                jsfAppConfigLocater.getJSFAppConfigManager().addFacesConfigChangeAdapter(facesConfig);
+            }
+        }
+        return facesConfig;
+    }
+
+    @Override
+    public void releaseFacesConfigModel() {
+        jsfAppConfigLocater.getJSFAppConfigManager().removeFacesConfigChangeAdapter(facesConfig);
+        facesConfig = null;
+    }
+
+    private void discoverFacesConfig() throws CoreException {
+        facesConfig = FacesConfigFactory.eINSTANCE.createFacesConfigType();
+        IJavaProject jProject = JavaCore.create(this.jsfAppConfigLocater.getJSFAppConfigManager().getProject());
+        IPackageFragmentRoot[] roots = jProject.getAllPackageFragmentRoots();
+        List<IPackageFragmentRoot> scannableRoots = new ArrayList<IPackageFragmentRoot>();
+        if (roots != null) {
+            for (IPackageFragmentRoot root : roots) {
+                AnnotationPackageFragmentRoot facesRoot = new AnnotationPackageFragmentRoot(root);
+                if (facesRoot.canContainAnnotatedComponents()) {
+                    scannableRoots.add(root);
+                }
+            }
+        }
+
+        if (!scannableRoots.isEmpty()) {
+            findAnnotatedComponents(jProject, scannableRoots);
+        }
+    }
+
+    private final void findAnnotatedComponents(final IJavaProject jProject, final List<IPackageFragmentRoot> scannableRoots)
+            throws CoreException {
+        SearchPattern pattern = orPattern(null, jProject.findType(MANAGED_BEAN_ANNOTATION_CLASS));
+        pattern = orPattern(pattern, jProject.findType(REFERENCED_BEAN_ANNOTATION_CLASS));
+        pattern = orPattern(pattern, jProject.findType(FACES_COMPONENT_ANNOTATION_CLASS));
+        pattern = orPattern(pattern, jProject.findType(FACES_CONVERTER_ANNOTATION_CLASS));
+        pattern = orPattern(pattern, jProject.findType(FACES_RENDERER_ANNOTATION_CLASS));
+        pattern = orPattern(pattern, jProject.findType(FACES_VALIDATOR_ANNOTATION_CLASS));
+
+        if (pattern != null) {
+            SearchEngine engine = new SearchEngine();
+            SearchParticipant[] participants = new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() };
+            IJavaSearchScope scope = SearchEngine.createJavaSearchScope(scannableRoots.toArray(new IJavaElement[scannableRoots
+                    .size()]), IJavaSearchScope.SOURCES | IJavaSearchScope.APPLICATION_LIBRARIES);
+
+            SearchRequestor requestor = new AnnotationSearchRequestor(facesConfig);
+            engine.search(pattern, participants, scope, requestor, new NullProgressMonitor());
+        }
+    }
+
+    private SearchPattern orPattern(SearchPattern pattern, IJavaElement element) {
+        if (element == null) {
+            return pattern;
+        }
+        if (pattern == null) {
+            return SearchPattern.createPattern(element, IJavaSearchConstants.REFERENCES);
+        }
+        return SearchPattern.createOrPattern(pattern, SearchPattern.createPattern(element, IJavaSearchConstants.REFERENCES));
+    }
+}
\ No newline at end of file
diff --git a/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/AnnotationPackageFragmentRoot.java b/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/AnnotationPackageFragmentRoot.java
new file mode 100644
index 0000000..160c4d9
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/AnnotationPackageFragmentRoot.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Oracle Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Andrew McCulloch - initial API and implementation
+ *******************************************************************************/ 
+package org.eclipse.jst.jsf.core.jsfappconfig;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJarEntryResource;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jst.jsf.common.internal.componentcore.AbstractVirtualComponentQuery.DefaultVirtualComponentQuery;
+import org.eclipse.wst.common.componentcore.resources.IVirtualFolder;
+
+/**
+ * Wrapper around IPackageFragmentRoot that determines if the
+ * IPackageFragmentRoot meets the conditions to be searched for annotated Faces
+ * components.
+ * 
+ * This class does not check the faces version or metadata-complete flag.
+ * This instance is invalid if the project is renamed and must be recreated.
+ * 
+ * <p><b>Provisional API - subject to change</b></p>
+ * 
+ * @author Andrew McCulloch - Oracle
+ */
+public class AnnotationPackageFragmentRoot {
+
+    private final IPackageFragmentRoot root;
+    private final IJavaProject jProject;
+    private final IPath webInfLibPath;
+    private final IPath webInfClassesPath;
+
+    /**
+     * Construct the wrapper around a package fragment root.
+     * 
+     * @param root
+     */
+    public AnnotationPackageFragmentRoot(IPackageFragmentRoot root) {
+        if (root != null && root.exists() && !root.isExternal()) {
+            this.root = root;
+            IPath tempWebInfLibPath = null;
+            IPath tempWebInfClassesPath = null;
+            jProject = root.getJavaProject();
+            if (jProject != null) {
+                IProject project = jProject.getProject();
+                if (project != null) {
+                    IVirtualFolder webContent = new DefaultVirtualComponentQuery().getWebContentFolder(project);
+                    if (webContent != null) {
+                        IContainer webContentFolder = webContent.getUnderlyingFolder();
+                        if (webContentFolder != null && webContentFolder.exists()) {
+                            IPath webContentPath = webContentFolder.getFullPath();
+                            if (webContentPath != null) {
+                                tempWebInfLibPath = webContentPath.append("WEB-INF/lib"); //$NON-NLS-1$
+                                tempWebInfClassesPath = webContentPath.append("WEB-INF/classes"); //$NON-NLS-1$
+                            }
+                        }
+                    }
+                }
+            }
+            webInfClassesPath = tempWebInfClassesPath;
+            webInfLibPath = tempWebInfLibPath;
+        } else {
+            this.root = null;
+            this.webInfClassesPath = null;
+            this.webInfLibPath = null;
+            this.jProject = null;
+        }
+    }
+    
+    /**
+     * @return true if this package fragment root wrapper should be scanned for annotated faces components.
+     */
+    public final boolean canContainAnnotatedComponents() {
+        if (root == null || !root.exists() || webInfClassesPath == null || webInfLibPath == null) {
+            return false;
+        }
+        IPath rootPath = root.getPath();
+        if (rootPath != null) {
+            return isWebInfClasses(root) || isFacesArchive(rootPath);
+        }
+        return false;
+    }
+
+    private final boolean isWebInfClasses(IPackageFragmentRoot root_) {
+        IClasspathEntry cpe;
+        try {
+            cpe = root_.getResolvedClasspathEntry();
+//            IPath rootPath = cpe.getOutputLocation(); 
+            return cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE;
+//            if (rootPath == null) {
+//                rootPath = jProject.getOutputLocation();
+//            }
+//            return webInfClassesPath.equals(rootPath);
+        } catch (JavaModelException e) {
+            return false;
+        }
+    }
+
+    private final boolean isFacesArchive(IPath rootPath) {
+        if (webInfLibPath.isPrefixOf(rootPath)) {
+
+            Object[] nonJavaResources;
+            try {
+                nonJavaResources = root.getNonJavaResources();
+                if (nonJavaResources != null) {
+                    for (Object nonJavaResource : nonJavaResources) {
+                        if (nonJavaResource instanceof IJarEntryResource) {
+                            IJarEntryResource jarEntry = (IJarEntryResource) nonJavaResource;
+                            if (!jarEntry.isFile()) {
+                                String entryName = jarEntry.getName();
+                                if ("META-INF".equals(entryName)) { //$NON-NLS-1$
+                                    IJarEntryResource[] metaInfContents = jarEntry.getChildren();
+                                    for (IJarEntryResource resource : metaInfContents) {
+                                        if (resource.isFile() && "faces-config.xml".equals(resource.getName())) { //$NON-NLS-1$
+                                            return true;
+                                        }
+                                    }
+                                } else if (entryName != null && jarEntry.getName().charAt(0) == '.') {
+                                    return hasDotFacesConfigFile(jarEntry);
+                                }
+                            }
+                        }
+                    }
+                }
+            } catch (JavaModelException e) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    private final boolean hasDotFacesConfigFile(IJarEntryResource jarEntry) {
+        IJarEntryResource[] contents = jarEntry.getChildren();
+        for (IJarEntryResource resource : contents) {
+            if (resource.isFile()) {
+                if (".faces-config.xml".equals(resource.getName())) { //$NON-NLS-1$
+                    return true;
+                }
+            } else {
+                if (hasDotFacesConfigFile(resource)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/AnnotationSearchRequestor.java b/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/AnnotationSearchRequestor.java
new file mode 100644
index 0000000..f015b7f
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/AnnotationSearchRequestor.java
@@ -0,0 +1,360 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Oracle Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Andrew McCulloch - initial API and implementation
+ *    Ian Trimble - maintenance
+ *******************************************************************************/ 
+package org.eclipse.jst.jsf.core.jsfappconfig;
+
+import static org.eclipse.jst.jsf.core.jsfappconfig.AnnotationJSFAppConfigProvider.MANAGED_BEAN_ANNOTATION_CLASS;
+import static org.eclipse.jst.jsf.core.jsfappconfig.AnnotationJSFAppConfigProvider.REFERENCED_BEAN_ANNOTATION_CLASS;
+import static org.eclipse.jst.jsf.core.jsfappconfig.AnnotationJSFAppConfigProvider.FACES_COMPONENT_ANNOTATION_CLASS;
+import static org.eclipse.jst.jsf.core.jsfappconfig.AnnotationJSFAppConfigProvider.FACES_CONVERTER_ANNOTATION_CLASS;
+import static org.eclipse.jst.jsf.core.jsfappconfig.AnnotationJSFAppConfigProvider.FACES_RENDERER_ANNOTATION_CLASS;
+import static org.eclipse.jst.jsf.core.jsfappconfig.AnnotationJSFAppConfigProvider.FACES_VALIDATOR_ANNOTATION_CLASS;
+import static org.eclipse.jst.jsf.core.jsfappconfig.AnnotationJSFAppConfigProvider.VIEW_SCOPED_ANNOTATION_CLASS;
+import static org.eclipse.jst.jsf.core.jsfappconfig.AnnotationJSFAppConfigProvider.APPLICATION_SCOPED_ANNOTATION_CLASS;
+import static org.eclipse.jst.jsf.core.jsfappconfig.AnnotationJSFAppConfigProvider.NONE_SCOPED_ANNOTATION_CLASS;
+import static org.eclipse.jst.jsf.core.jsfappconfig.AnnotationJSFAppConfigProvider.SESSION_SCOPED_ANNOTATION_CLASS;
+import static org.eclipse.jst.jsf.core.jsfappconfig.AnnotationJSFAppConfigProvider.CUSTOM_SCOPED_ANNOTATION_CLASS;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.jdt.core.IAnnotation;
+import org.eclipse.jdt.core.IMemberValuePair;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.search.SearchMatch;
+import org.eclipse.jdt.core.search.SearchRequestor;
+import org.eclipse.jst.jsf.facesconfig.emf.ComponentClassType;
+import org.eclipse.jst.jsf.facesconfig.emf.ComponentFamilyType;
+import org.eclipse.jst.jsf.facesconfig.emf.ComponentType;
+import org.eclipse.jst.jsf.facesconfig.emf.ComponentTypeType;
+import org.eclipse.jst.jsf.facesconfig.emf.ConverterClassType;
+import org.eclipse.jst.jsf.facesconfig.emf.ConverterForClassType;
+import org.eclipse.jst.jsf.facesconfig.emf.ConverterIdType;
+import org.eclipse.jst.jsf.facesconfig.emf.ConverterType;
+import org.eclipse.jst.jsf.facesconfig.emf.FacesConfigFactory;
+import org.eclipse.jst.jsf.facesconfig.emf.FacesConfigType;
+import org.eclipse.jst.jsf.facesconfig.emf.ManagedBeanClassType;
+import org.eclipse.jst.jsf.facesconfig.emf.ManagedBeanNameType;
+import org.eclipse.jst.jsf.facesconfig.emf.ManagedBeanScopeType;
+import org.eclipse.jst.jsf.facesconfig.emf.ManagedBeanType;
+import org.eclipse.jst.jsf.facesconfig.emf.ReferencedBeanClassType;
+import org.eclipse.jst.jsf.facesconfig.emf.ReferencedBeanNameType;
+import org.eclipse.jst.jsf.facesconfig.emf.ReferencedBeanType;
+import org.eclipse.jst.jsf.facesconfig.emf.RenderKitIdType;
+import org.eclipse.jst.jsf.facesconfig.emf.RenderKitType;
+import org.eclipse.jst.jsf.facesconfig.emf.RendererClassType;
+import org.eclipse.jst.jsf.facesconfig.emf.RendererType;
+import org.eclipse.jst.jsf.facesconfig.emf.RendererTypeType;
+import org.eclipse.jst.jsf.facesconfig.emf.ValidatorClassType;
+import org.eclipse.jst.jsf.facesconfig.emf.ValidatorIdType;
+import org.eclipse.jst.jsf.facesconfig.emf.ValidatorType;
+
+/**
+ * SearchRequestor that looks at annotations for JSF configuration.
+ * 
+ * <p><b>Provisional API - subject to change</b></p>
+ * 
+ * @author Andrew McCulloch - Oracle
+ */
+public class AnnotationSearchRequestor extends SearchRequestor {
+    
+    private final FacesConfigType facesConfig;
+    
+    AnnotationSearchRequestor(final FacesConfigType facesConfig) {
+         this.facesConfig = facesConfig;
+    }
+    
+    public void acceptSearchMatch(SearchMatch match) throws CoreException {
+        if (match.getAccuracy() == SearchMatch.A_ACCURATE) {
+            Object element = match.getElement();
+            if (element instanceof IType) {
+                IType type = (IType) element;
+                IAnnotation[] annotations = type.getAnnotations();
+                if (annotations != null) {
+                    for (int i = 0, k = annotations.length; i < k; i++) {
+                        if (annotations[i].exists()) {
+                            String annotationType = annotations[i].getElementName();
+                            String[][] resolvedAnnotationTypes = type.resolveType(annotationType);
+                            if (resolvedAnnotationTypes != null) {
+                                String resolvedAnnotationClassName = new StringBuffer(resolvedAnnotationTypes[0][0]).append('.').append(resolvedAnnotationTypes[0][1]).toString();
+                                if (MANAGED_BEAN_ANNOTATION_CLASS.equals(resolvedAnnotationClassName)) {
+                                    addManagedBean(annotations[i], type);
+                                } else if (REFERENCED_BEAN_ANNOTATION_CLASS.equals(resolvedAnnotationClassName)) {
+                                    addReferencedBean(annotations[i], type);
+                                } else if (FACES_COMPONENT_ANNOTATION_CLASS.equals(resolvedAnnotationClassName)) {
+                                    addComponent(annotations[i], type);
+                                } else if (FACES_CONVERTER_ANNOTATION_CLASS.equals(resolvedAnnotationClassName)) {
+                                    addConverter(annotations[i], type);
+                                } else if (FACES_RENDERER_ANNOTATION_CLASS.equals(resolvedAnnotationClassName)) {
+                                    addRenderer(annotations[i], type);
+                                } else if (FACES_VALIDATOR_ANNOTATION_CLASS.equals(resolvedAnnotationClassName)) {
+                                    addValidator(annotations[i], type);
+                                }               
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private void addReferencedBean(IAnnotation referencedBeanAnnotation, IType beanType) throws JavaModelException {
+        IMemberValuePair[] pairs = referencedBeanAnnotation.getMemberValuePairs();
+        String beanNameString = null;
+        if (pairs != null) {
+            for (IMemberValuePair pair : pairs) {
+                if ("name".equals(pair.getMemberName()) && pair.getValueKind() == IMemberValuePair.K_STRING) { //$NON-NLS-1$
+                    beanNameString = (String)pair.getValue();
+                }
+            }
+        }
+        if (beanNameString == null) {
+            beanNameString = beanType.getElementName();
+            if (beanNameString != null && beanNameString.length() > 0) {
+                StringBuffer casedName = new StringBuffer(String.valueOf(beanNameString.charAt(0)).toUpperCase());
+                beanNameString = casedName.append(beanNameString.substring(1)).toString();
+            }
+        }
+        String beanClassName = beanType.getFullyQualifiedName();
+
+        if (beanNameString != null && beanClassName != null) {
+            ReferencedBeanType bean = FacesConfigFactory.eINSTANCE.createReferencedBeanType();
+            ReferencedBeanNameType beanName = FacesConfigFactory.eINSTANCE.createReferencedBeanNameType();
+            beanName.setTextContent(beanNameString);
+            bean.setReferencedBeanName(beanName);
+            ReferencedBeanClassType beanClass = FacesConfigFactory.eINSTANCE.createReferencedBeanClassType();
+            beanClass.setTextContent(beanClassName);
+            bean.setReferencedBeanClass(beanClass);
+            facesConfig.getReferencedBean().add(bean);
+        }
+    }
+
+    private void addManagedBean(IAnnotation beanAnnotation, IType beanType) throws JavaModelException {
+        IMemberValuePair[] pairs = beanAnnotation.getMemberValuePairs();
+        String beanNameString = null;
+        Boolean isBeanEager = Boolean.FALSE;
+        if (pairs != null) {
+            for (IMemberValuePair pair : pairs) {
+                if ("name".equals(pair.getMemberName()) && pair.getValueKind() == IMemberValuePair.K_STRING) { //$NON-NLS-1$
+                    beanNameString = (String)pair.getValue();
+                } else if ("eager".equals(pair.getMemberName()) && pair.getValueKind() == IMemberValuePair.K_BOOLEAN) { //$NON-NLS-1$
+                    isBeanEager = (Boolean)pair.getValue();
+                }
+            }
+        }
+        if (beanNameString == null || beanNameString.length() < 1) {
+            beanNameString = beanType.getElementName();
+            if (beanNameString != null && beanNameString.length() > 0) {
+                StringBuffer casedName = new StringBuffer(String.valueOf(beanNameString.charAt(0)).toLowerCase());
+                beanNameString = casedName.append(beanNameString.substring(1)).toString();
+            }
+        }
+        String beanClassName = beanType.getFullyQualifiedName();
+
+        String beanScopeString = "request"; //$NON-NLS-1$
+        IAnnotation[] annotations = beanType.getAnnotations();
+        if (annotations != null) {
+	        for (int i = 0, k = annotations.length; i < k; i++) {
+                if (annotations[i].exists()) {
+                    String annotationType = annotations[i].getElementName();
+                    String[][] resolvedAnnotationTypes = beanType.resolveType(annotationType);
+                    if (resolvedAnnotationTypes != null) {
+                        String resolvedAnnotationClassName = new StringBuffer(resolvedAnnotationTypes[0][0]).append('.').append(resolvedAnnotationTypes[0][1]).toString();
+                        if (APPLICATION_SCOPED_ANNOTATION_CLASS.equals(resolvedAnnotationClassName)) {
+                        	beanScopeString = "application"; //$NON-NLS-1$
+                        } else if (VIEW_SCOPED_ANNOTATION_CLASS.equals(resolvedAnnotationClassName)) {
+                        	beanScopeString = "view"; //$NON-NLS-1$
+                        } else if (NONE_SCOPED_ANNOTATION_CLASS.equals(resolvedAnnotationClassName)) {
+                        	beanScopeString = "none"; //$NON-NLS-1$
+                        } else if (SESSION_SCOPED_ANNOTATION_CLASS.equals(resolvedAnnotationClassName)) {
+                        	beanScopeString = "session"; //$NON-NLS-1$
+                        } else if (CUSTOM_SCOPED_ANNOTATION_CLASS.equals(resolvedAnnotationClassName)) {
+                            IMemberValuePair[] scopePairs = annotations[i].getMemberValuePairs();
+                            if (scopePairs != null && scopePairs.length == 1 && scopePairs[0].getValueKind() == IMemberValuePair.K_STRING) {
+                                beanScopeString = (String)scopePairs[0].getValue();
+                            }
+                        }
+                    }
+                }
+	        }
+        }
+
+        if (beanNameString != null && beanClassName != null) {
+            ManagedBeanType bean = FacesConfigFactory.eINSTANCE.createManagedBeanType();
+            ManagedBeanNameType beanName = FacesConfigFactory.eINSTANCE.createManagedBeanNameType();
+            beanName.setTextContent(beanNameString);
+            bean.setManagedBeanName(beanName);
+            ManagedBeanClassType beanClass = FacesConfigFactory.eINSTANCE.createManagedBeanClassType();
+            beanClass.setTextContent(beanClassName);
+            bean.setManagedBeanClass(beanClass);
+            ManagedBeanScopeType beanScope = FacesConfigFactory.eINSTANCE.createManagedBeanScopeType();
+            beanScope.setTextContent(beanScopeString);
+            bean.setManagedBeanScope(beanScope);
+            bean.setEager(isBeanEager.booleanValue());
+            facesConfig.getManagedBean().add(bean);
+        }
+    }
+
+    private void addValidator(IAnnotation validatorAnnotation, IType validatorType) throws JavaModelException {
+        String validatorClassName = validatorType.getFullyQualifiedName();
+        IMemberValuePair[] pairs = validatorAnnotation.getMemberValuePairs();
+        String validatorIDString = null;
+//        Boolean isDefaultBoolean = null;
+        if (pairs != null) {
+            for (IMemberValuePair pair : pairs) {
+                if ("value".equals(pair.getMemberName()) && pair.getValueKind() == IMemberValuePair.K_STRING) { //$NON-NLS-1$
+                    validatorIDString = (String)pair.getValue();
+                    //isDefault not used in emf model
+//                } else if ("isDefault".equals(pair.getMemberName()) && pair.getValueKind() == IMemberValuePair.K_BOOLEAN) {  //$NON-NLS-1$
+//                    isDefaultBoolean = (Boolean)pair.getValue();
+                }
+            }
+        }
+        
+        if (validatorClassName != null && validatorIDString != null) {
+            ValidatorType validator = FacesConfigFactory.eINSTANCE.createValidatorType();
+            ValidatorClassType validatorClass = FacesConfigFactory.eINSTANCE.createValidatorClassType();
+            validatorClass.setTextContent(validatorClassName);
+            validator.setValidatorClass(validatorClass);
+            
+            ValidatorIdType validatorID = FacesConfigFactory.eINSTANCE.createValidatorIdType();
+            validatorID.setTextContent(validatorIDString);
+            validator.setValidatorId(validatorID);
+            
+
+//          if (isDefaultBoolean == null) {
+//              isDefaultBoolean = Boolean.FALSE;
+//          }
+            
+            facesConfig.getValidator().add(validator);
+        }
+    }
+
+    private void addRenderer(IAnnotation rendererAnnotation, IType rendererType) throws JavaModelException {
+        String rendererClassName = rendererType.getFullyQualifiedName();
+        IMemberValuePair[] pairs = rendererAnnotation.getMemberValuePairs();
+        String rendererTypeString = null;
+        String componentFamilyString = null;
+        String renderKitIDString = null;
+        if (pairs != null) {
+            for (IMemberValuePair pair : pairs) {
+                if ("rendererType".equals(pair.getMemberName()) && pair.getValueKind() == IMemberValuePair.K_STRING) { //$NON-NLS-1$
+                    rendererTypeString = (String)pair.getValue();
+                } else if ("componentFamily".equals(pair.getMemberName()) && pair.getValueKind() == IMemberValuePair.K_STRING) {  //$NON-NLS-1$
+                    componentFamilyString = (String)pair.getValue();
+                } else if ("renderKitId".equals(pair.getMemberName()) && pair.getValueKind() == IMemberValuePair.K_STRING) {  //$NON-NLS-1$
+                    renderKitIDString = (String)pair.getValue();
+                }
+            }
+        }
+        
+        if (rendererClassName != null && rendererTypeString != null && componentFamilyString != null) {
+            RendererType renderer = FacesConfigFactory.eINSTANCE.createRendererType();
+            RendererClassType rendererClass = FacesConfigFactory.eINSTANCE.createRendererClassType();
+            rendererClass.setTextContent(rendererClassName);
+            renderer.setRendererClass(rendererClass);
+
+
+            RendererTypeType rendererTypeType = FacesConfigFactory.eINSTANCE.createRendererTypeType();
+            rendererTypeType.setTextContent(rendererTypeString);
+            renderer.setRendererType(rendererTypeType);
+            
+            ComponentFamilyType componentFamily = FacesConfigFactory.eINSTANCE.createComponentFamilyType();
+            componentFamily.setTextContent(componentFamilyString);
+            renderer.setComponentFamily(componentFamily);
+
+            
+            if (renderKitIDString == null) {
+                //use the default
+                renderKitIDString = "HTML_BASIC"; //$NON-NLS-1$
+            }
+            EList renderKits = facesConfig.getRenderKit();
+            if (renderKits != null) {
+                RenderKitType renderKit = null;
+                for (int i = 0, k = renderKits.size(); i < k; i++) {
+                    if (((RenderKitType)renderKits.get(i)).getRenderKitId() != null && renderKitIDString.equals(((RenderKitType)renderKits.get(i)).getRenderKitId().getTextContent())) {
+                        renderKit = (RenderKitType)(renderKits.get(i));
+                    }
+                }
+                if (renderKit == null) {
+                    renderKit = FacesConfigFactory.eINSTANCE.createRenderKitType();
+                    RenderKitIdType renderKitID = FacesConfigFactory.eINSTANCE.createRenderKitIdType();
+                    renderKitID.setTextContent(renderKitIDString);
+                    renderKit.setRenderKitId(renderKitID);
+                    renderKits.add(renderKit);
+                }
+                renderKit.getRenderer().add(renderer);
+            }
+        }
+    }
+
+    private void addConverter(IAnnotation converterAnnotation, IType converterType) throws JavaModelException {
+        String converterClassName = converterType.getFullyQualifiedName();
+        IMemberValuePair[] pairs = converterAnnotation.getMemberValuePairs();
+        String converterIDString = null;
+        String converterForClassString = null;
+        if (pairs != null) {
+            for (IMemberValuePair pair : pairs) {
+                if ("value".equals(pair.getMemberName()) && pair.getValueKind() == IMemberValuePair.K_STRING) { //$NON-NLS-1$
+                    converterIDString = (String)pair.getValue();
+                } else if ("forClass".equals(pair.getMemberName()) && pair.getValueKind() == IMemberValuePair.K_CLASS) {  //$NON-NLS-1$
+                    converterForClassString = (String)pair.getValue();
+                }
+            }
+        }
+        if (converterClassName != null) {
+            ConverterType converter = FacesConfigFactory.eINSTANCE.createConverterType();
+            ConverterClassType converterClass = FacesConfigFactory.eINSTANCE.createConverterClassType();
+            converterClass.setTextContent(converterClassName);
+            converter.setConverterClass(converterClass);
+
+            if (converterIDString != null) {
+                ConverterIdType converterID = FacesConfigFactory.eINSTANCE.createConverterIdType();
+                converterID.setTextContent(converterIDString);
+                converter.setConverterId(converterID);
+            }  
+            
+            if (converterForClassString == null) {
+                //use the default
+                converterForClassString = "java.lang.Object"; //$NON-NLS-1$
+            }
+            ConverterForClassType converterForClass = FacesConfigFactory.eINSTANCE.createConverterForClassType();
+            converterForClass.setTextContent(converterForClassString);
+            converter.setConverterForClass(converterForClass);
+            facesConfig.getConverter().add(converter);
+        }
+    }
+
+    private void addComponent(IAnnotation componentAnnotation, IType componentType) throws JavaModelException {
+        String componentClassName = componentType.getFullyQualifiedName();
+        IMemberValuePair[] pairs = componentAnnotation.getMemberValuePairs();
+        String componentTypeString = null;
+        if (pairs != null) {
+            for (IMemberValuePair pair : pairs) {
+                if ("value".equals(pair.getMemberName()) && pair.getValueKind() == IMemberValuePair.K_STRING) { //$NON-NLS-1$
+                    componentTypeString = (String)pair.getValue();
+                }
+            }
+        }
+        if (componentTypeString != null && componentClassName != null) {
+            ComponentType component =  FacesConfigFactory.eINSTANCE.createComponentType();
+            ComponentClassType componentClass = FacesConfigFactory.eINSTANCE.createComponentClassType();
+            componentClass.setTextContent(componentClassName);
+            component.setComponentClass(componentClass);
+            
+            ComponentTypeType componentTypeType = FacesConfigFactory.eINSTANCE.createComponentTypeType();
+            componentTypeType.setTextContent(componentTypeString);
+            component.setComponentType(componentTypeType);
+            
+            facesConfig.getComponent().add(component);
+        }
+    }
+}
\ No newline at end of file
diff --git a/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/internal/DefaultJSFAppConfigLocatorProviderStrategy.java b/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/internal/DefaultJSFAppConfigLocatorProviderStrategy.java
index b4a16dd..7c51187 100644
--- a/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/internal/DefaultJSFAppConfigLocatorProviderStrategy.java
+++ b/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/jsfappconfig/internal/DefaultJSFAppConfigLocatorProviderStrategy.java
@@ -5,6 +5,7 @@
 import java.util.List;
 
 import org.eclipse.core.resources.IProject;
+import org.eclipse.jst.jsf.core.jsfappconfig.AnnotationJSFAppConfigLocator;
 import org.eclipse.jst.jsf.core.jsfappconfig.ContextParamSpecifiedJSFAppConfigLocater;
 import org.eclipse.jst.jsf.core.jsfappconfig.DefaultJSFAppConfigLocater;
 import org.eclipse.jst.jsf.core.jsfappconfig.IJSFAppConfigLocater;
@@ -12,7 +13,7 @@
 import org.eclipse.jst.jsf.core.jsfappconfig.RuntimeClasspathJSFAppConfigLocater;
 
 /**
- * The platforms default LocatorProviderStrategy.
+ * The platform's default JSFAppConfigLocatorProviderStrategy.
  * <p>
  * Will return:
  * <ol>
@@ -20,6 +21,7 @@
  * <li>DefaultJSFAppConfigLocater</li>
  * <li>ContextParamSpecifiedJSFAppConfigLocater</li>
  * <li>RuntimeClasspathJSFAppConfigLocater</li>
+ * <li>AnnotationJSFAppConfigLocator</li>
  * <ol>
  *
  */
@@ -49,7 +51,11 @@
 		// runtime classpath locater
 		IJSFAppConfigLocater classpathConfigLocater = new RuntimeClasspathJSFAppConfigLocater();
 		ret.add(classpathConfigLocater);
-		
+
+		// annotation config locator
+		IJSFAppConfigLocater annotationConfigLocator = new AnnotationJSFAppConfigLocator();
+		ret.add(annotationConfigLocator);
+
 		return Collections.unmodifiableList(ret);
 	}
 
diff --git a/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/designtime/symbols/DefaultBeanSymbolSourceProvider.java b/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/designtime/symbols/DefaultBeanSymbolSourceProvider.java
index 5984adb..5464d49 100644
--- a/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/designtime/symbols/DefaultBeanSymbolSourceProvider.java
+++ b/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/designtime/symbols/DefaultBeanSymbolSourceProvider.java
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *    Cameron Bateman/Oracle - initial API and implementation
+ *    Ian Trimble/Oracle - maintenance (JSF 2.x custom scope)
  *    
  ********************************************************************************/
 
@@ -29,6 +30,8 @@
 import org.eclipse.jst.jsf.context.symbol.ISymbol;
 import org.eclipse.jst.jsf.context.symbol.SymbolFactory;
 import org.eclipse.jst.jsf.context.symbol.source.ISymbolConstants;
+import org.eclipse.jst.jsf.core.IJSFCoreConstants;
+import org.eclipse.jst.jsf.core.jsfappconfig.JSFAppConfigUtils;
 import org.eclipse.jst.jsf.core.jsfappconfig.internal.IJSFAppConfigManager;
 import org.eclipse.jst.jsf.core.jsfappconfig.internal.JSFAppConfigManagerFactory;
 import org.eclipse.jst.jsf.facesconfig.emf.DescriptionType;
@@ -126,9 +129,15 @@
             for (final Iterator aIt = configManager.getManagedBeans().iterator(); aIt.hasNext();)
             {
                 ManagedBeanType  bean = (ManagedBeanType) aIt.next();
-                
+
                 // only bother with all this if we care about the scope of this bean
-                if (isBeanScopeInMask(bean.getManagedBeanScope(), symbolScopeMask))
+                // allow for custom scopes (any value) in JSF 2.x if mask is "ISymbolConstants.SYMBOL_SCOPE_ALL"
+                final boolean beanIsInScope =
+                		isBeanScopeInMask(bean.getManagedBeanScope(), symbolScopeMask) ||
+            			(JSFAppConfigUtils.isValidJSFProject(iProject, IJSFCoreConstants.FACET_VERSION_2_0) &&
+            			(symbolScopeMask == ISymbolConstants.SYMBOL_SCOPE_ALL));
+
+                if (beanIsInScope)
                 {
                     final String name = bean.getManagedBeanName().getTextContent();
                     final String detailedDescription = createAdditionalProposalInfo(bean);