blob: 71fa94b7ecf160bb5eb0f1346bb24a51df725246 [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:
* Gerry Kessler - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.jsf.core.internal.project.facet;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jst.j2ee.model.IModelProvider;
import org.eclipse.jst.j2ee.webapplication.WebapplicationFactory;
import org.eclipse.jst.javaee.core.JavaeeFactory;
import org.eclipse.jst.javaee.web.WebAppVersionType;
import org.eclipse.jst.javaee.web.WebFactory;
import org.eclipse.jst.jsf.core.JSFVersion;
import org.eclipse.jst.jsf.core.internal.JSFCorePlugin;
import org.eclipse.jst.jsf.core.internal.Messages;
import org.eclipse.jst.jsf.core.internal.jsflibraryregistry.ArchiveFile;
import org.eclipse.jst.jsf.core.internal.jsflibraryregistry.JSFLibrary;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.common.frameworks.datamodel.IDataModel;
/**
*
*/
@SuppressWarnings("deprecation")
public abstract class JSFUtils {
/**
* The default name for the Faces servlet
*/
public static final String JSF_DEFAULT_SERVLET_NAME = "Faces Servlet"; //$NON-NLS-1$
/**
* The default name of the Faces servlet class
*/
public static final String JSF_SERVLET_CLASS = "javax.faces.webapp.FacesServlet"; //$NON-NLS-1$
/**
* The name of the context parameter used for JSF configuration files
*/
public static final String JSF_CONFIG_CONTEXT_PARAM = "javax.faces.CONFIG_FILES"; //$NON-NLS-1$
/**
* The name of the context parameter used for defining the default JSP file extension
*/
public static final String JSF_DEFAULT_SUFFIX_CONTEXT_PARAM = "javax.faces.DEFAULT_SUFFIX"; //$NON-NLS-1$
/**
* The path to the default application configuration file
*/
public static final String JSF_DEFAULT_CONFIG_PATH = "/WEB-INF/faces-config.xml"; //$NON-NLS-1$
/**
* Default URL mapping to faces servlet
*/
public static final String JSF_DEFAULT_URL_MAPPING = "/faces/*"; //$NON-NLS-1$
/**
* the key for implementation libraries in persistent properties
*/
public static final String PP_JSF_IMPLEMENTATION_LIBRARIES = "jsf.implementation.libraries"; //$NON-NLS-1$
/**
* the key for component libraries in persistent properties
*/
public static final String PP_JSF_COMPONENT_LIBRARIES = "jsf.component.libraries"; //$NON-NLS-1$
/**
* the key for implementation type in persistent properties
*/
public static final String PP_JSF_IMPLEMENTATION_TYPE = "jsf.implementation.type"; //$NON-NLS-1$
private static final String DEFAULT_DEFAULT_MAPPING_SUFFIX = "jsp"; //$NON-NLS-1$
/**
* In cases where there is no servlet mapping defined (where it can be implicit and provided
* by the container), this system property can be used to provide the "implicit" servlet
* mapping.
*/
private static final String SYS_PROP_SERVLET_MAPPING = "org.eclipse.jst.jsf.servletMapping"; //$NON-NLS-1$
private final JSFVersion _version;
private final IModelProvider _modelProvider;
/**
* @param version
* @param modelProvider
*/
protected JSFUtils(final JSFVersion version, final IModelProvider modelProvider)
{
_version = version;
_modelProvider = modelProvider;
}
/**
* @return the jsf version that this instance is for.
*/
public final JSFVersion getVersion()
{
return _version;
}
/**
* @param config
* @return servlet display name to use from wizard data model
*/
protected final String getDisplayName(IDataModel config) {
String displayName = config.getStringProperty(IJSFFacetInstallDataModelProperties.SERVLET_NAME);
if (displayName == null || displayName.trim().length() == 0)
displayName = JSF_DEFAULT_SERVLET_NAME;
return displayName.trim();
}
/**
* @param config
* @return servlet display name to use from wizard data model
*/
protected final String getServletClassname(IDataModel config) {
String className = config.getStringProperty(IJSFFacetInstallDataModelProperties.SERVLET_CLASSNAME);
if (className == null || className.trim().equals("")) //$NON-NLS-1$
className = JSF_SERVLET_CLASS;
return className.trim();
}
/**
* @return IModelProvider
*/
public final IModelProvider getModelProvider() {
Object webAppObj = _modelProvider.getModelObject();
if (webAppObj == null)
{
return null;
}
return _modelProvider;
}
/**
* @param configPath
*/
public final void createConfigFile(IPath configPath)
{
FileOutputStream os = null;
// final String QUOTE = new String(new char[] { '"' });
try {
IPath dirPath = configPath.removeLastSegments(1);
dirPath.toFile().mkdirs();
File file = configPath.toFile();
file.createNewFile();
os = new FileOutputStream(file);
printConfigFile(os);
} catch (FileNotFoundException e) {
JSFCorePlugin.log(IStatus.ERROR, Messages.JSFUtils_ErrorCreatingConfigFile, e);
} catch (IOException e) {
JSFCorePlugin.log(IStatus.ERROR, Messages.JSFUtils_ErrorCreatingConfigFile, e);
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
JSFCorePlugin.log(IStatus.ERROR, Messages.JSFUtils_ErrorClosingConfigFile, e);
}
}
}
}
/**
* @param out
*/
protected final void printConfigFile(final OutputStream out)
{
PrintWriter pw = null;
try
{
pw = new PrintWriter(out);
doVersionSpecificConfigFile(pw);
}
finally
{
if (pw != null)
{
pw.close();
}
}
}
/**
* @param pw
*/
public abstract void doVersionSpecificConfigFile(final PrintWriter pw);
/**
* @param webAppObj
* @return true if this going into a JavaEE (1.5 and later) or a J2EE (1.4 and earlier)
* configured application.
*/
public boolean isJavaEE(final Object webAppObj)
{
if (webAppObj instanceof org.eclipse.jst.javaee.web.WebApp)
{
org.eclipse.jst.javaee.web.WebApp webApp = (org.eclipse.jst.javaee.web.WebApp)webAppObj;
return WebAppVersionType.VALUES.contains(webApp.getVersion());
}
return false;
}
/**
* @param config
* @return list of URL patterns from the datamodel
*/
protected final List<String> getServletMappings(final IDataModel config) {
final List<String> mappings = new ArrayList<String>();
final String[] patterns = (String[])config.getProperty(IJSFFacetInstallDataModelProperties.SERVLET_URL_PATTERNS);
if (patterns != null)
{
for (final String pattern : patterns)
{
mappings.add(pattern);
}
}
return mappings;
}
/**
* Does an update of the web application's config file.
*
* @param webApp must be WebApp of the appropriate type.
* @param config
* @throws ClassCastException if webApp is not the appropriate type.
*/
public abstract void updateWebApp(Object webApp, IDataModel config);
/**
* Called on a facet uninstall to remove JSF related changes.
* @param webApp
*/
public abstract void rollbackWebApp(Object webApp);
/**
* @param fileExtension
* @return true if the file extension is deemed to be for a JSF.
*/
protected boolean isValidKnownExtension(String fileExtension) {
//Bug 313830 - JSFUtils should use content type instead file extension in isValidKnownExtension.
List<String> validKnownExtensions = new ArrayList<String>();
for (String contentTypeId: new String[]{
"org.eclipse.jst.jsp.core.jspsource", //$NON-NLS-1$
"org.eclipse.jst.jsp.core.jspfragmentsource", //$NON-NLS-1$
"jsf.facelet"}) { //$NON-NLS-1$
IContentType contentType = Platform.getContentTypeManager().getContentType(contentTypeId);
if (contentType != null) {
String[] contentTypeExts = contentType.getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
if (contentTypeExts != null) {
validKnownExtensions.addAll(Arrays.asList(contentTypeExts));
}
}
}
if (fileExtension != null) {
return validKnownExtensions.contains(fileExtension);
}
return false;
}
/**
* @param resource
* @return true if the resource is deemed to be a JSF page.
*/
protected boolean isJSFPage(IResource resource) {
// currently always return true if resource != null.
// need to find quick way of determining whether this is a JSF JSP Page
boolean isJSFPage = true;
if (resource == null) {
isJSFPage = false;
}
return isJSFPage;
}
/**
* @param webApp
* @return the default file extension from the context param. Default is
* "jsp" if no context param.
*/
protected String getDefaultSuffix(Object webApp) {
String contextParam = null;
if (webApp != null) {
if(isJavaEE(webApp)) {
contextParam = JEEUtils.getContextParam((org.eclipse.jst.javaee.web.WebApp) webApp, JSF_DEFAULT_SUFFIX_CONTEXT_PARAM);
}
else {
contextParam = J2EEUtils.getContextParam((org.eclipse.jst.j2ee.webapplication.WebApp) webApp, JSF_DEFAULT_SUFFIX_CONTEXT_PARAM);
}
}
if (contextParam == null) {
return getDefaultDefaultSuffix();
}
return normalizeSuffix(contextParam);
}
/**
* @return the default value for the default mapping suffix
*/
protected String getDefaultDefaultSuffix()
{
return DEFAULT_DEFAULT_MAPPING_SUFFIX;
}
/**
* @param name
* @param value
* @return the
*/
protected final String calculateSuffix(final String name, final String value)
{
if (name != null
&& JSF_DEFAULT_SUFFIX_CONTEXT_PARAM.equals(name
.trim()))
{
return normalizeSuffix(value != null ? value.trim() : null);
}
return null;
}
/**
* @param defSuffix
* @return the suffix value with any leading dot removed
*/
protected final String normalizeSuffix(String defSuffix)
{
if (defSuffix != null && defSuffix.startsWith(".")) //$NON-NLS-1$
{
defSuffix = defSuffix.substring(1);
}
return defSuffix;
}
/**
* Holds all the obsolete JSF Library stuff. This will go away post-Helios.
* @author cbateman
*
*/
public static class JSFLibraryHandler
{
/**
* Construct an array that hold paths for all JARs in a JSF library.
*
* @param jsfLib
* @param logMissingJar true to log an error for each invalid JAR.
* @return elements
*/
public final IPath[] getJARPathforJSFLib(JSFLibrary jsfLib, boolean logMissingJar) {
EList archiveFiles = jsfLib.getArchiveFiles();
int numJars = archiveFiles.size();
IPath[] elements = new IPath[numJars];
ArchiveFile ar = null;
for (int i= 0; i < numJars; i++) {
ar = (ArchiveFile)archiveFiles.get(i);
if ( !ar.exists() && logMissingJar ) {
logErroronMissingJAR(jsfLib, ar);
}
elements[i] = new Path(((ArchiveFile)archiveFiles.get(i)).getResolvedSourceLocation()).makeAbsolute();
}
return elements;
}
private int numberofValidJar(EList archiveFiles) {
int total = 0;
final Iterator it = archiveFiles.iterator();
ArchiveFile ar = null;
while(it.hasNext()) {
ar = (ArchiveFile) it.next();
if (ar.exists()) {
total++;
}
}
return total;
}
private void logErroronMissingJAR(JSFLibrary jsfLib, ArchiveFile ar) {
String msg = NLS.bind(Messages.JSFUtils_MissingJAR,
ar.getName(),
jsfLib.getLabel());
JSFCorePlugin.log(IStatus.ERROR, msg);
}
/**
* Construct an array that hold paths for all JARs in a JSF library.
* However, archive files that no longer exist are filtered out.
*
* @param jsfLib
* @param logMissingJar true to log an error for each invalid JAR.
* @return elements
*/
public final IPath[] getJARPathforJSFLibwFilterMissingJars(JSFLibrary jsfLib, boolean logMissingJar) {
EList archiveFiles = jsfLib.getArchiveFiles();
int numJars = numberofValidJar(archiveFiles);
IPath[] elements = new IPath[numJars];
ArchiveFile ar = null;
int idxValidJar = 0;
for (int i= 0; i < archiveFiles.size(); i++) {
ar = (ArchiveFile)archiveFiles.get(i);
if ( !ar.exists() ) {
if (logMissingJar) {
logErroronMissingJAR(jsfLib, ar);
}
} else {
elements[idxValidJar] = new Path(((ArchiveFile)archiveFiles.get(i)).getResolvedSourceLocation()).makeAbsolute();
idxValidJar++;
}
}
return elements;
}
}
/**
* Finds and returns a JSF Servlet definition, or null if servlet is not defined.
*
* @param webApp
* @return Servlet or null
*/
protected Object findJSFServlet(Object webApp) {
if(isJavaEE(webApp)) {
return JEEUtils.findServlet((org.eclipse.jst.javaee.web.WebApp) webApp, JSF_SERVLET_CLASS);
}
return J2EEUtils.findServlet((org.eclipse.jst.j2ee.webapplication.WebApp) webApp, JSF_SERVLET_CLASS);
}
/**
* Creates servlet reference in WebApp if not present or updates servlet
* name if found using the passed configuration.
*
* @param webApp
* @param config
* @param servlet
* @return Servlet servlet - if passed servlet was null, will return created
* servlet
*/
protected Object createOrUpdateServletRef(final Object webApp,
final IDataModel config, Object servlet)
{
String displayName = getDisplayName(config);
String className = getServletClassname(config);
if(isJavaEE(webApp)) {
return JEEUtils.createOrUpdateServletRef((org.eclipse.jst.javaee.web.WebApp) webApp, displayName, className, (org.eclipse.jst.javaee.web.Servlet) servlet);
}
return J2EEUtils.createOrUpdateServletRef((org.eclipse.jst.j2ee.webapplication.WebApp) webApp, displayName, className, (org.eclipse.jst.j2ee.webapplication.Servlet) servlet);
}
/**
* Creates servlet-mappings for the servlet for 2.5 WebModules or greated
*
* @param webApp
* @param urlMappingList
* - list of string values to be used in url-pattern for
* servlet-mapping
* @param servlet
*/
protected void setUpURLMappings(final Object webApp,
final List<String> urlMappingList, final Object servlet)
{
if(isJavaEE(webApp)) {
JEEUtils.setUpURLMappings((org.eclipse.jst.javaee.web.WebApp) webApp, urlMappingList, (org.eclipse.jst.javaee.web.Servlet) servlet);
}
else {
J2EEUtils.setUpURLMappings((org.eclipse.jst.j2ee.webapplication.WebApp) webApp, urlMappingList, (org.eclipse.jst.j2ee.webapplication.Servlet) servlet);
}
}
/**
* Removes servlet-mappings for servlet using servlet-name for >= 2.5 WebModules.
* @param webApp
* @param servlet
*/
protected void removeURLMappings(final Object webApp, final Object servlet) {
if(isJavaEE(webApp)) {
JEEUtils.removeURLMappings((org.eclipse.jst.javaee.web.WebApp) webApp, (org.eclipse.jst.javaee.web.Servlet) servlet);
}
else {
J2EEUtils.removeURLMappings((org.eclipse.jst.j2ee.webapplication.WebApp) webApp, (org.eclipse.jst.j2ee.webapplication.Servlet) servlet);
}
}
/**
* Removes servlet definition
* @param webApp
* @param servlet
*/
protected void removeJSFServlet(final Object webApp, final Object servlet) {
if(isJavaEE(webApp)) {
JEEUtils.removeServlet((org.eclipse.jst.javaee.web.WebApp) webApp, (org.eclipse.jst.javaee.web.Servlet) servlet);
}
else {
J2EEUtils.removeServlet((org.eclipse.jst.j2ee.webapplication.WebApp) webApp, (org.eclipse.jst.j2ee.webapplication.Servlet) servlet);
}
}
/**
* Removes context-param
* @param webApp
*/
protected void removeJSFContextParams(final Object webApp) {
if(isJavaEE(webApp)) {
JEEUtils.removeContextParam((org.eclipse.jst.javaee.web.WebApp) webApp, JSF_CONFIG_CONTEXT_PARAM);
}
else {
J2EEUtils.removeContextParam((org.eclipse.jst.j2ee.webapplication.WebApp) webApp, JSF_CONFIG_CONTEXT_PARAM);
}
}
/**
* Creates or updates context-params
* @param webApp
* @param config
*/
protected void setupContextParams(final Object webApp, final IDataModel config) {
final String paramValue = config.getStringProperty(IJSFFacetInstallDataModelProperties.CONFIG_PATH);
if (paramValue != null && !paramValue.equals(JSF_DEFAULT_CONFIG_PATH)) {
if(isJavaEE(webApp)) {
JEEUtils.setupContextParam((org.eclipse.jst.javaee.web.WebApp) webApp, JSF_CONFIG_CONTEXT_PARAM, paramValue);
}
else {
J2EEUtils.setupContextParam((org.eclipse.jst.j2ee.webapplication.WebApp) webApp, JSF_CONFIG_CONTEXT_PARAM, paramValue);
}
}
}
/**
* @param map
* @param webApp
* @return extension from map. Will return null if file extension not found
* in url patterns.
*/
protected String getFileExtensionFromMap(final Object webApp, final Object map) {
if(isJavaEE(webApp)) {
return JEEUtils.getFileExtensionFromMap((org.eclipse.jst.javaee.web.ServletMapping) map);
}
return J2EEUtils.getFileExtensionFromMap((org.eclipse.jst.j2ee.webapplication.ServletMapping) map);
}
/**
* @param webApp
* @param map
* @return prefix mapping. may return null.
*/
protected String getPrefixMapping(final Object webApp, final Object map) {
if(isJavaEE(webApp)) {
return JEEUtils.getPrefixMapping((org.eclipse.jst.javaee.web.ServletMapping) map);
}
return J2EEUtils.getPrefixMapping((org.eclipse.jst.j2ee.webapplication.ServletMapping) map);
}
/**
* @param webAppObj
* @param resource
* @param existingURL
* @return the modified url path for the (possibly) jsf resource.
*/
public IPath getFileUrlPath(Object webAppObj, IResource resource,
IPath existingURL) {
// if not a JSF page, do nothing
if (!isJSFPage(resource))
{
return null;
}
Object servlet = findJSFServlet(webAppObj);
List implicitServletMappings = new ArrayList();
if (servlet == null)
{
servlet = createImplicitServletAndMapping(webAppObj, implicitServletMappings);
}
String defaultSuffix = getDefaultSuffix(webAppObj);
// is the resource using default_suffix
String fileExtension = resource.getFileExtension();
boolean canUseExtensionMapping = fileExtension != null && fileExtension.equalsIgnoreCase(defaultSuffix);
// if not using default extension and is not a known file extension,
// then we will abort
if (!canUseExtensionMapping
&& !isValidKnownExtension(resource.getFileExtension()))
return null;
if(isJavaEE(webAppObj)) {
org.eclipse.jst.javaee.web.WebApp webApp = (org.eclipse.jst.javaee.web.WebApp) webAppObj;
final String servletName = ((org.eclipse.jst.javaee.web.Servlet) servlet).getServletName();
String foundFileExtension = null;
List mappings;
if (webApp.getServletMappings().size() > 0) {
mappings = webApp.getServletMappings();
} else {
mappings = implicitServletMappings;
}
for (final org.eclipse.jst.javaee.web.ServletMapping map : (List<org.eclipse.jst.javaee.web.ServletMapping>) mappings)
{
if (map != null &&
map.getServletName() != null &&
map.getServletName().trim().equals(servletName.trim()))
{
foundFileExtension = getFileExtensionFromMap(webAppObj, map);
if (foundFileExtension != null && canUseExtensionMapping)
{
return existingURL.removeFileExtension()
.addFileExtension(foundFileExtension);
}
String foundPrefixMapping = getPrefixMapping(webAppObj, map);
if (foundPrefixMapping != null)
{
return new Path(foundPrefixMapping).append(existingURL);
}
}
}
if (!canUseExtensionMapping && foundFileExtension != null)
{
// we could prompt user that this may not work...
// for now we will return the extension mapping
return existingURL.removeFileExtension().addFileExtension(
foundFileExtension);
}
// we could, at this point, add a url mapping to the faces servlet,
// or prompt user that it may be a good idea to add one...
}
else {
List mappings;
if (((org.eclipse.jst.j2ee.webapplication.Servlet)servlet).getMappings().size() > 0) {
mappings = ((org.eclipse.jst.j2ee.webapplication.Servlet)servlet).getMappings();
} else {
mappings = implicitServletMappings;
}
Iterator itMappings = mappings.iterator();
org.eclipse.jst.j2ee.webapplication.ServletMapping map = null;
String foundFileExtension = null;
String foundPrefixMapping = null;
while (itMappings.hasNext())
{
map = (org.eclipse.jst.j2ee.webapplication.ServletMapping)itMappings.next();
foundFileExtension = getFileExtensionFromMap(webAppObj, map);
if (foundFileExtension != null && canUseExtensionMapping)
{
return existingURL.removeFileExtension().addFileExtension(foundFileExtension);
}
if (foundPrefixMapping == null)
{
foundPrefixMapping = getPrefixMapping(webAppObj, map);
}
}
if (foundPrefixMapping != null)
{
return new Path(foundPrefixMapping).append(existingURL);
}
if (! canUseExtensionMapping && foundFileExtension != null){
//we could prompt user that this may not work...
//for now we will return the extension mapping
return existingURL.removeFileExtension().addFileExtension(foundFileExtension);
}
// we could, at this point, add a url mapping to the faces servlet,
// or prompt user that it may be a good idea to add one...
}
return null;
}
/**
* This creates a servlet and servlet mapping suitable for
* {@link #getFileUrlPath(Object, IResource, IPath)} to be able to proceed, but the returned
* objects are not fully-initialized for any and all purposes. USE WITH CAUTION.
*
* @param webApp Web App object.
* @param mappings List to which the that the created servlet mapping will be added.
* @return Servlet instance (and a servlet mapping added to mappings).
*/
private Object createImplicitServletAndMapping(Object webApp, List mappings) {
Object servlet;
String sysPropServletMapping = System.getProperty(SYS_PROP_SERVLET_MAPPING);
if (sysPropServletMapping == null) {
sysPropServletMapping = JSF_DEFAULT_URL_MAPPING;
}
if (isJavaEE(webApp)) {
servlet = WebFactory.eINSTANCE.createServlet();
((org.eclipse.jst.javaee.web.Servlet)servlet).setServletName(JSF_DEFAULT_SERVLET_NAME);
org.eclipse.jst.javaee.web.ServletMapping mapping = WebFactory.eINSTANCE.createServletMapping();
mapping.setServletName(JSF_DEFAULT_SERVLET_NAME);
org.eclipse.jst.javaee.core.UrlPatternType pattern = JavaeeFactory.eINSTANCE.createUrlPatternType();
pattern.setValue(sysPropServletMapping);
mapping.getUrlPatterns().add(pattern);
mappings.add(mapping);
} else {
servlet = WebapplicationFactory.eINSTANCE.createServlet();
((org.eclipse.jst.j2ee.webapplication.Servlet)servlet).setServletName(JSF_DEFAULT_SERVLET_NAME);
org.eclipse.jst.j2ee.webapplication.ServletMapping mapping = WebapplicationFactory.eINSTANCE.createServletMapping();
mapping.setUrlPattern(sysPropServletMapping);
mappings.add(mapping);
}
return servlet;
}
}