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