blob: 43b0455266bde2e82be5cb65c85798dab9d63647 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 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:
* Ian Trimble - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.jsf.core.jsfappconfig;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.resources.IResourceProxyVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.content.IContentTypeManager;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jst.j2ee.common.ParamValue;
import org.eclipse.jst.j2ee.internal.J2EEVersionConstants;
import org.eclipse.jst.j2ee.model.IModelProvider;
import org.eclipse.jst.j2ee.model.ModelProviderManager;
import org.eclipse.jst.j2ee.web.componentcore.util.WebArtifactEdit;
import org.eclipse.jst.j2ee.webapplication.ContextParam;
import org.eclipse.jst.j2ee.webapplication.WebApp;
import org.eclipse.jst.jsf.common.internal.componentcore.AbstractVirtualComponentQuery.DefaultVirtualComponentQuery;
import org.eclipse.jst.jsf.core.IJSFCoreConstants;
import org.eclipse.jst.jsf.core.internal.JSFCorePlugin;
import org.eclipse.jst.jsf.core.internal.Messages;
import org.eclipse.jst.jsf.facesconfig.emf.FacesConfigFactory;
import org.eclipse.jst.jsf.facesconfig.emf.ManagedBeanExtensionType;
import org.eclipse.jst.jsf.facesconfig.emf.ManagedBeanType;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.common.componentcore.resources.IVirtualFolder;
import org.eclipse.wst.common.project.facet.core.IFacetedProject;
import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager;
/**
* JSFAppConfigUtils provides utility methods useful in processing of a JSF
* application configuration.
*
* <p><b>Provisional API - subject to change</b></p>
*
* @author Ian Trimble - Oracle
*/
public class JSFAppConfigUtils {
/**
* Name of JSF CONFIG_FILES context parameter ("javax.faces.CONFIG_FILES").
*/
public static final String CONFIG_FILES_CONTEXT_PARAM_NAME = "javax.faces.CONFIG_FILES"; //$NON-NLS-1$
/**
* Location in JAR file of application configuration resource file
* ("META-INF/faces-config.xml").
*/
public static final String FACES_CONFIG_IN_JAR_PATH = "META-INF/faces-config.xml"; //$NON-NLS-1$
/** ID of managed bean's description instance to indicate content identifies bean's "source" **/
public static final String MANAGEDBEAN_SOURCE_ID = "MANAGEDBEAN_SOURCE_ID"; //$NON-NLS-1$
/** Indicates that a managed bean was defined in a faces-config file **/
public static final String MANAGEDBEAN_SOURCE_FACES_CONFIG_FILE = "FACES_CONFIG_FILE"; //$NON-NLS-1$
/** Indicates that a managed bean was defined by a JSF annotation **/
public static final String MANAGEDBEAN_SOURCE_JSF_ANNOTATION = "JSF_ANNOTATION"; //$NON-NLS-1$
/** Indicates that a managed bean was defined by a CDI annotation **/
public static final String MANAGEDBEAN_SOURCE_CDI_ANNOTATION = "CDI_ANNOTATION"; //$NON-NLS-1$
/**
* @param project
* @param minVersion
* @return true if project is a JSF facet project and the version of the project
* is at least minVersion.
*/
public static boolean isValidJSFProject(IProject project, String minVersion)
{
boolean isValid = false;
final IProjectFacetVersion projectFacetVersion = getProjectFacet(project);
if (projectFacetVersion != null)
{
try
{
final String versionString =
projectFacetVersion.getVersionString();
final Comparator comparator =
projectFacetVersion.getProjectFacet().getVersionComparator();
final int compareToMin =
comparator.compare(versionString, minVersion);
if (compareToMin >=0)
{
return true;
}
}
catch (CoreException ce)
{
JSFCorePlugin.log(ce, "Error checking facet version"); //$NON-NLS-1$
}
}
return isValid;
}
/**
* Tests if the passed IProject instance is a valid JSF project in the
* following ways:
* <ul>
* <li>project is not null and is accessible, </li>
* <li>project has the JSF facet set on it.</li>
* </ul>
*
* @param project IProject instance to be tested.
* @return true if the IProject instance is a valid JSF project, else
* false.
*/
public static boolean isValidJSFProject(IProject project) {
boolean isValid = false;
IProjectFacetVersion projectFacet = getProjectFacet(project);
if (projectFacet != null)
{
isValid = true;
}
return isValid;
}
/**
* Get the facet version for the project
* @param project
* @return the project facet version or null if could not be found or if
* project is not accessible
*/
public static IProjectFacetVersion getProjectFacet(IProject project)
{
//check for null or inaccessible project
if (project != null && project.isAccessible()) {
//check for JSF facet on project
try {
IFacetedProject facetedProject = ProjectFacetsManager.create(project);
if (facetedProject != null) {
Set projectFacets = facetedProject.getProjectFacets();
Iterator itProjectFacets = projectFacets.iterator();
while (itProjectFacets.hasNext()) {
IProjectFacetVersion projectFacetVersion = (IProjectFacetVersion)itProjectFacets.next();
if (IJSFCoreConstants.JSF_CORE_FACET_ID.equals(projectFacetVersion.getProjectFacet().getId()))
{
return projectFacetVersion;
}
}
}
} catch(CoreException ce) {
//log error
JSFCorePlugin.log(IStatus.ERROR, ce.getLocalizedMessage(), ce);
}
}
return null;
}
/**
* Gets an IVirtualFolder instance which represents the root context's
* web content folder.
*
* @param project IProject instance for which to get the folder.
* @return IVirtualFolder instance which represents the root context's
* web content folder.
* @deprecated Call DefaultVirtualComponentQuery.getWebContentFolder instead
*/
public static IVirtualFolder getWebContentFolder(IProject project) {
return new DefaultVirtualComponentQuery().getWebContentFolder(project);
}
/**
* Gets an IPath instance representing the path of the passed IFile
* instance relative to the web content folder.
*
* @param file IFile instance for which a path is required.
* @return IPath instance representing the path relative to the web content
* folder.
*/
public static IPath getWebContentFolderRelativePath(IFile file) {
IPath path = null;
if (file != null) {
IVirtualFolder webContentFolder = getWebContentFolder(file.getProject());
if (webContentFolder != null) {
IPath webContentPath = webContentFolder.getProjectRelativePath();
IPath filePath = file.getProjectRelativePath();
int matchingFirstSegments = webContentPath.matchingFirstSegments(filePath);
path = filePath.removeFirstSegments(matchingFirstSegments);
}
}
return path;
}
/**
* Gets list of application configuration file names as listed in the JSF
* CONFIG_FILES context parameter ("javax.faces.CONFIG_FILES"). Will return
* an empty list if WebArtifactEdit is null, if WebApp is null, if context
* parameter does not exist, or if trimmed context parameter's value is
* an empty String.
*
* @param project IProject instance for which to get the context
* parameter's value.
* @return List of application configuration file names as listed in the
* JSF CONFIG_FILES context parameter ("javax.faces.CONFIG_FILES"); list
* may be empty.
*/
public static List getConfigFilesFromContextParam(IProject project) {
List filesList = Collections.EMPTY_LIST;
if (isValidJSFProject(project)) {
IModelProvider provider = ModelProviderManager.getModelProvider(project);
Object webAppObj = provider.getModelObject();
if (webAppObj != null){
if (webAppObj instanceof WebApp)
filesList = getConfigFilesForJ2EEApp(project);
else if (webAppObj instanceof org.eclipse.jst.javaee.web.WebApp)
filesList = getConfigFilesForJEEApp((org.eclipse.jst.javaee.web.WebApp)webAppObj);
}
}
return filesList;
}
private static List getConfigFilesForJEEApp(org.eclipse.jst.javaee.web.WebApp webApp) {
String filesString = null;
List contextParams = webApp.getContextParams();
Iterator itContextParams = contextParams.iterator();
while (itContextParams.hasNext()) {
org.eclipse.jst.javaee.core.ParamValue paramValue = (org.eclipse.jst.javaee.core.ParamValue)itContextParams.next();
if (paramValue.getParamName().equals(CONFIG_FILES_CONTEXT_PARAM_NAME)) {
filesString = paramValue.getParamValue();
break;
}
}
return parseFilesString(filesString);
}
private static List getConfigFilesForJ2EEApp(IProject project){
List filesList = new ArrayList();
WebArtifactEdit webArtifactEdit = WebArtifactEdit.getWebArtifactEditForRead(project);
if (webArtifactEdit != null) {
try {
WebApp webApp = null;
try {
webApp = webArtifactEdit.getWebApp();
} catch(ClassCastException cce) {
//occasionally thrown from WTP code in RC3 and possibly later
JSFCorePlugin.log(IStatus.ERROR, cce.getLocalizedMessage(), cce);
return filesList;
}
if (webApp != null) {
String filesString = null;
//need to branch here due to model version differences (BugZilla #119442)
if (webApp.getVersionID() == J2EEVersionConstants.WEB_2_3_ID) {
EList contexts = webApp.getContexts();
Iterator itContexts = contexts.iterator();
while (itContexts.hasNext()) {
ContextParam contextParam = (ContextParam)itContexts.next();
if (contextParam.getParamName().equals(CONFIG_FILES_CONTEXT_PARAM_NAME)) {
filesString = contextParam.getParamValue();
break;
}
}
} else {
EList contextParams = webApp.getContextParams();
Iterator itContextParams = contextParams.iterator();
while (itContextParams.hasNext()) {
ParamValue paramValue = (ParamValue)itContextParams.next();
if (paramValue.getName().equals(CONFIG_FILES_CONTEXT_PARAM_NAME)) {
filesString = paramValue.getValue();
break;
}
}
}
filesList = parseFilesString(filesString);
}
} finally {
webArtifactEdit.dispose();
}
}
return filesList;
}
private static List parseFilesString(String filesString) {
List filesList = new ArrayList();
if (filesString != null && filesString.trim().length() > 0) {
StringTokenizer stFilesString = new StringTokenizer(filesString, ","); //$NON-NLS-1$
while (stFilesString.hasMoreTokens()) {
String configFile = stFilesString.nextToken().trim();
filesList.add(configFile);
}
}
return filesList;
}
/**
* Gets list of JAR file names, where each file name represents a JAR on
* the classpath that contains a /META-INF/faces-config.xml entry. Will
* return an empty list if no such JAR files are located.
*
* @param project IProject instance for which to scan the classpath.
* @return List of JAR file names, where each file name represents a JAR
* on the classpath that contains a ...META-INF/faces-config.xml entry;
* list may be empty.
* @throws CoreException Thrown when underlying calls into JavaCore fail.
* @throws IOException Thrown when attempt to open JAR to determine if it
* contains a /META-INF/faces-config.xml entry fails.
*/
public static List getConfigFileJARsFromClasspath(IProject project) throws CoreException, IOException {
ArrayList JARsList = new ArrayList();
if (project.isAccessible()
&& project.hasNature(JavaCore.NATURE_ID)) {
IJavaProject javaProject = JavaCore.create(project);
if (javaProject != null) {
IClasspathEntry[] classpathEntries = javaProject.getResolvedClasspath(true);
if (classpathEntries != null && classpathEntries.length > 0) {
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
for (int i = 0; i < classpathEntries.length; i++) {
IClasspathEntry classpathEntry = classpathEntries[i];
if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
IPath libraryPath = classpathEntry.getPath();
if (libraryPath.getFileExtension() != null && libraryPath.getFileExtension().length() > 0) {
if (libraryPath.getDevice() == null && workspaceRoot.getProject(libraryPath.segment(0)).exists()) {
libraryPath = workspaceRoot.getFile(libraryPath).getLocation();
}
String libraryPathString = libraryPath.toString();
JarFile jarFile = null;
try {
//check existence first [222249]
File file = new File(libraryPathString);
if (file.exists()) {
jarFile = new JarFile(file, false);
if (jarFile != null) {
JarEntry jarEntry = jarFile.getJarEntry(FACES_CONFIG_IN_JAR_PATH);
if (jarEntry != null) {
JARsList.add(libraryPathString);
}
}
}
} catch (FileNotFoundException fnfex) {
//should not get here, but eat error since this could only occur in under strange circumstances [222249]
} catch(IOException ioe) {
JSFCorePlugin.log(
IStatus.ERROR,
NLS.bind(Messages.JSFAppConfigUtils_ErrorOpeningJarFile, libraryPathString),
ioe);
} finally {
if (jarFile != null) {
jarFile.close();
}
}
}
}
}
}
}
}
return JARsList;
}
//Bug 306451 - [JSF2.0] Support for Implicit navigation
/**
* Get all files that are possible destinations for implicit navigation (JSF 2.x or greater).
*
* @param fromFile IFile instance that navigation is from.
* @return List of IFile instances that are possible destinations.
*/
public static List<IFile> getImplicitNavigationFiles(final IFile fromFile) {
List<IFile> files = new ArrayList<IFile>();
if (fromFile != null) {
final IProject project = fromFile.getProject();
if (isValidJSFProject(project, IJSFCoreConstants.JSF_VERSION_2_0)) {
final IVirtualFolder webContentFolder = new DefaultVirtualComponentQuery().getWebContentFolder(project);
if (webContentFolder != null) {
final IContainer[] rootContainers = webContentFolder.getUnderlyingFolders();
if (rootContainers != null && rootContainers.length > 0) {
for (int i = 0; i < rootContainers.length; i++) {
try {
rootContainers[i].accept(new JSFAppConfigUtils().new ImplicitNavigationResourceProxyVisitor(files), IResource.NONE);
} catch(CoreException cEx) {
JSFCorePlugin.log(IStatus.ERROR, cEx.getLocalizedMessage(), cEx);
}
}
files.remove(fromFile);
}
}
}
}
return files;
}
/**
* Sets the "source" (one of the MANAGEDBEAN_SOURCE_* constants) of the managed bean.
* @param managedBean Managed bean instance.
* @param source "Source" of the managed bean.
*/
public static void setManagedBeanSource(final ManagedBeanType managedBean, final String source) {
if (managedBean != null) {
ManagedBeanExtensionType extension = getManagedBeanSourceExtension(managedBean);
if (extension == null) {
extension = FacesConfigFactory.eINSTANCE.createManagedBeanExtensionType();
extension.setId(MANAGEDBEAN_SOURCE_ID);
managedBean.getManagedBeanExtension().add(extension);
}
final String content = extension.getTextContent();
if (content != null) {
if (!content.trim().equals(source)) {
extension.setTextContent(source);
}
} else {
extension.setTextContent(source);
}
}
}
/**
* Gets the "source" (one of the MANAGEDBEAN_SOURCE_* constants) of the managed bean.
* @param managedBean Managed bean instance.
* @return "Source" of the managed bean (assumes MANAGEDBEAN_SOURCE_FACES_CONFIG_FILE if not
* set on the managed bean).
*/
public static String getManagedBeanSource(final ManagedBeanType managedBean) {
String source = MANAGEDBEAN_SOURCE_FACES_CONFIG_FILE;
final ManagedBeanExtensionType extension = getManagedBeanSourceExtension(managedBean);
if (extension != null) {
source = extension.getTextContent().trim();
}
return source;
}
/**
* Gets the managed bean instance's extension object that has ID of MANAGEDBEAN_SOURCE_ID.
* @param managedBean Managed bean instance.
* @return The managed bean's extension object that has ID of MANAGEDBEAN_SOURCE_ID.
*/
public static ManagedBeanExtensionType getManagedBeanSourceExtension(final ManagedBeanType managedBean) {
ManagedBeanExtensionType extension = null;
if (managedBean != null) {
final EList extensions = managedBean.getManagedBeanExtension();
for (final Object curExtObj: extensions) {
if (curExtObj instanceof ManagedBeanExtensionType) {
final ManagedBeanExtensionType curExt = (ManagedBeanExtensionType) curExtObj;
final String id = curExt.getId();
if (id != null && id.equals(MANAGEDBEAN_SOURCE_ID)) {
extension = curExt;
break;
}
}
}
}
return extension;
}
/**
* Returns <code>true</code> if the managed bean is defined in a faces-config file.
* @param managedBean Managed bean instance to test.
* @return <code>true</code> if the managed bean is defined in a faces-config file, else
* <code>false</code>.
*/
public static boolean isDefinedInFacesConfigFile(final ManagedBeanType managedBean) {
boolean ret = false;
if (managedBean != null) {
ret = !isDefinedByJSFAnnotation(managedBean) && !isDefinedByCDIAnnotation(managedBean);
}
return ret;
}
/**
* Returns <code>true</code> if the managed bean is defined by a JSF annotation.
* @param managedBean Managed bean instance to test.
* @return <code>true</code> if the managed bean is defined by a JSF annotation, else
* <code>false</code>.
*/
public static boolean isDefinedByJSFAnnotation(final ManagedBeanType managedBean) {
boolean ret = false;
if (managedBean != null) {
final String source = getManagedBeanSource(managedBean);
if (source != null && source.equals(MANAGEDBEAN_SOURCE_JSF_ANNOTATION)) {
ret = true;
}
}
return ret;
}
/**
* Returns <code>true</code> if the managed bean is defined by a CDI annotation.
* @param managedBean Managed bean instance to test.
* @return <code>true</code> if the managed bean is defined by a CDI annotation, else
* <code>false</code>.
*/
public static boolean isDefinedByCDIAnnotation(final ManagedBeanType managedBean) {
boolean ret = false;
if (managedBean != null) {
final String source = getManagedBeanSource(managedBean);
if (source != null && source.equals(MANAGEDBEAN_SOURCE_CDI_ANNOTATION)) {
ret = true;
}
}
return ret;
}
class ImplicitNavigationResourceProxyVisitor implements IResourceProxyVisitor {
private List<IFile> files;
private IContentTypeManager contentTypeMgr;
private IContentType jspSourceType;
private IContentType htmlSourceType;
public ImplicitNavigationResourceProxyVisitor(List<IFile> files) {
this.files = files;
this.contentTypeMgr = Platform.getContentTypeManager();
this.jspSourceType = contentTypeMgr.getContentType("org.eclipse.jst.jsp.core.jspsource"); //$NON-NLS-1$
this.htmlSourceType = contentTypeMgr.getContentType("org.eclipse.wst.html.core.htmlsource"); //$NON-NLS-1$
}
public boolean visit(IResourceProxy proxy) throws CoreException {
switch (proxy.getType()) {
case IResource.FOLDER:
return true;
case IResource.FILE:
IContentType contentType = contentTypeMgr.findContentTypeFor(proxy.getName());
if (contentType != null) {
if (contentType.isKindOf(jspSourceType) || contentType.isKindOf(htmlSourceType)) {
files.add((IFile)proxy.requestResource());
}
}
break;
}
return false;
}
}
}