Java tutorial
/******************************************************************************* * Copyright (c) 2011 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is 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: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.maven.jsf.configurators; import static org.jboss.tools.maven.jsf.configurators.JSFUtils.JSF_VERSION_1_1; import static org.jboss.tools.maven.jsf.configurators.JSFUtils.JSF_VERSION_1_2; import static org.jboss.tools.maven.jsf.configurators.JSFUtils.JSF_VERSION_2_0; import static org.jboss.tools.maven.jsf.configurators.JSFUtils.JSF_VERSION_2_1; import java.util.List; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.model.Plugin; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jst.j2ee.project.facet.IJ2EEFacetConstants; import org.eclipse.jst.jsf.core.internal.project.facet.IJSFFacetInstallDataModelProperties; import org.eclipse.m2e.core.project.IMavenProjectFacade; import org.eclipse.m2e.core.project.MavenProjectChangedEvent; import org.eclipse.m2e.core.project.configurator.AbstractProjectConfigurator; import org.eclipse.m2e.core.project.configurator.ProjectConfigurationRequest; import org.eclipse.wst.common.componentcore.ModuleCoreNature; import org.eclipse.wst.common.frameworks.datamodel.IDataModel; import org.eclipse.wst.common.project.facet.core.IFacetedProject; import org.eclipse.wst.common.project.facet.core.IProjectFacet; import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager; import org.jboss.tools.maven.core.IJBossMavenConstants; import org.jboss.tools.maven.core.MavenUtil; import org.jboss.tools.maven.core.ProjectUtil; import org.jboss.tools.maven.core.internal.project.facet.MavenFacetInstallDataModelProvider; import org.jboss.tools.maven.jsf.MavenJSFActivator; import org.jboss.tools.maven.jsf.MavenJSFConstants; import org.jboss.tools.maven.jsf.Messages; import org.jboss.tools.maven.ui.Activator; /** * * @author snjeza * */ public class JSFProjectConfigurator extends AbstractProjectConfigurator { private static final String JSF_API_GROUP_ID = "javax.faces"; //$NON-NLS-1$ private static final String JSF_API2_GROUP_ID = "com.sun.faces"; //$NON-NLS-1$ private static final String JSF_API_ARTIFACT_ID = "jsf-api"; //$NON-NLS-1$ private static final String WAR_SOURCE_FOLDER = "/src/main/webapp"; public static final IProjectFacet JSF_FACET; public static final IProjectFacetVersion JSF_FACET_VERSION_2_1; public static final IProjectFacetVersion JSF_FACET_VERSION_2_0; public static final IProjectFacetVersion JSF_FACET_VERSION_1_2; public static final IProjectFacetVersion JSF_FACET_VERSION_1_1; protected static final IProjectFacet m2Facet; protected static final IProjectFacetVersion m2Version; static { JSF_FACET = ProjectFacetsManager.getProjectFacet("jst.jsf"); //$NON-NLS-1$ JSF_FACET_VERSION_2_0 = JSF_FACET.getVersion(JSF_VERSION_2_0); JSF_FACET_VERSION_1_2 = JSF_FACET.getVersion(JSF_VERSION_1_2); //$NON-NLS-1$ JSF_FACET_VERSION_1_1 = JSF_FACET.getVersion(JSF_VERSION_1_1); //$NON-NLS-1$ IProjectFacetVersion jsf21Version = null; try { jsf21Version = JSF_FACET.getVersion(JSF_VERSION_2_1); } catch (Exception e) { MavenJSFActivator.warn("JSF 2.1 Facet is unavailable, fall back to 2.0"); jsf21Version = JSF_FACET_VERSION_2_0; } JSF_FACET_VERSION_2_1 = jsf21Version; m2Facet = ProjectFacetsManager.getProjectFacet("jboss.m2"); //$NON-NLS-1$ m2Version = m2Facet.getVersion("1.0"); //$NON-NLS-1$ } @Override public void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException { MavenProject mavenProject = request.getMavenProject(); IProject project = request.getProject(); configureInternal(mavenProject, project, monitor); } private void configureInternal(MavenProject mavenProject, IProject project, IProgressMonitor monitor) throws CoreException { if (!"war".equals(mavenProject.getPackaging())) {//$NON-NLS-1$ return; } IPreferenceStore store = Activator.getDefault().getPreferenceStore(); boolean configureJSF = store.getBoolean(Activator.CONFIGURE_JSF); if (!configureJSF) { return; } final IFacetedProject fproj = ProjectFacetsManager.create(project); if (fproj != null && fproj.hasProjectFacet(JSF_FACET) && fproj.hasProjectFacet(m2Facet)) { //everything already installed. Since there's no support for version update -yet- we bail return; } String jsfVersion = getJSFVersion(mavenProject, fproj); if (fproj != null && jsfVersion != null) { installWarFacets(fproj, jsfVersion, mavenProject, monitor); } } @Override public void mavenProjectChanged(MavenProjectChangedEvent event, IProgressMonitor monitor) throws CoreException { IMavenProjectFacade facade = event.getMavenProject(); if (facade != null) { IProject project = facade.getProject(); if (isWTPProject(project)) { MavenProject mavenProject = facade.getMavenProject(monitor); IMavenProjectFacade oldFacade = event.getOldMavenProject(); if (oldFacade != null) { MavenProject oldProject = oldFacade.getMavenProject(monitor); if (oldProject != null && oldProject.getArtifacts().equals(mavenProject.getArtifacts())) { //Nothing changed since last build, no need to lookup for new JSF facets return; } } configureInternal(mavenProject, project, monitor); } } super.mavenProjectChanged(event, monitor); } private boolean isWTPProject(IProject project) { return ModuleCoreNature.getModuleCoreNature(project) != null; } private void installM2Facet(IFacetedProject fproj, IProgressMonitor monitor) throws CoreException { if (!fproj.hasProjectFacet(m2Facet)) { IDataModel config = (IDataModel) new MavenFacetInstallDataModelProvider().create(); config.setBooleanProperty(IJBossMavenConstants.MAVEN_PROJECT_EXISTS, true); fproj.installProjectFacet(m2Version, config, monitor); } } private void installWarFacets(IFacetedProject fproj, String jsfVersion, MavenProject mavenProject, IProgressMonitor monitor) throws CoreException { if (!fproj.hasProjectFacet(IJ2EEFacetConstants.DYNAMIC_WEB_FACET)) { Activator.log(Messages.JSFProjectConfigurator_The_project_does_not_contain_the_Web_Module_facet); } else { installJSFFacet(fproj, jsfVersion, mavenProject, monitor); } installM2Facet(fproj, monitor); } private void installJSFFacet(IFacetedProject fproj, String jsfVersionString, MavenProject mavenProject, IProgressMonitor monitor) throws CoreException { markerManager.deleteMarkers(fproj.getProject(), MavenJSFConstants.JSF_CONFIGURATION_ERROR_MARKER_ID); if (!fproj.hasProjectFacet(JSF_FACET)) { IProject project = fproj.getProject(); //JBIDE-10785 : refresh parent to prevent // org.osgi.service.prefs.BackingStoreException: Resource '/parent/web/.settings' does not exist. MavenUtil.refreshParent(mavenProject); String warSourceDir = getWarSourceDirectory(mavenProject, project); String facesConfigPath = "WEB-INF/faces-config.xml"; IFile defaultFacesConfig = project.getFolder(warSourceDir).getFile(facesConfigPath); IFile generatedFacesConfig = ProjectUtil.getGeneratedWebResourceFile(project, facesConfigPath); IFile actualFacesConfig = JSFUtils.getFacesconfig(project); IFolder libFolder = project.getFolder(warSourceDir).getFolder("WEB-INF/lib"); //faces-config.xml will not be created in the source folder and it doesn't exist yet // => We'll have to fix it after setting the JSF facet boolean shouldFixFacesConfig = generatedFacesConfig != null && !generatedFacesConfig.getLocation().equals(defaultFacesConfig.getLocation()) && !generatedFacesConfig.exists(); boolean defaultFacesConfigAlreadyExists = defaultFacesConfig.exists(); boolean libFolderAlreadyExists = libFolder.exists(); IProjectFacetVersion facetVersion = null; boolean configureServlet = false;//Fix for JBIDE-9454, where existing web.xml is completely overwritten. if (jsfVersionString.startsWith(JSF_VERSION_1_1)) { facetVersion = JSF_FACET_VERSION_1_1; } else if (jsfVersionString.startsWith(JSF_VERSION_1_2)) { facetVersion = JSF_FACET_VERSION_1_2; } else if (jsfVersionString.startsWith(JSF_VERSION_2_0)) { facetVersion = JSF_FACET_VERSION_2_0; } else if (jsfVersionString.startsWith(JSF_VERSION_2_1)) { facetVersion = JSF_FACET_VERSION_2_1; } if (facetVersion != null) { IStatus status = facetVersion.getConstraint().check(fproj.getProjectFacets()); if (status.isOK()) { IDataModel model = MavenJSFActivator.getDefault().createJSFDataModel(fproj, facetVersion); model.setBooleanProperty(IJSFFacetInstallDataModelProperties.CONFIGURE_SERVLET, configureServlet); fproj.installProjectFacet(facetVersion, model, monitor); } else { addErrorMarker(fproj.getProject(), facetVersion + " can not be installed : " + status.getMessage()); for (IStatus st : status.getChildren()) { addErrorMarker(fproj.getProject(), st.getMessage()); } } } if (shouldFixFacesConfig && generatedFacesConfig.exists()) { if (defaultFacesConfig.exists()) { //We have 2 config files. Delete the gen'd one generatedFacesConfig.delete(true, monitor); } else { //move the gen'd config file to the appropriate source folder IContainer destination = defaultFacesConfig.getParent(); if (destination != null && !destination.exists()) { destination.getLocation().toFile().mkdirs(); } generatedFacesConfig.move(defaultFacesConfig.getFullPath(), true, monitor); } } if (actualFacesConfig != null && !defaultFacesConfigAlreadyExists && !defaultFacesConfig.getLocation().equals(actualFacesConfig.getLocation()) && defaultFacesConfig.exists()/*file has just been created*/) { defaultFacesConfig.delete(true, monitor); } //JBIDE-11413 : don't create an unnecessary lib folder libFolder.refreshLocal(IResource.DEPTH_ZERO, monitor); if (!libFolderAlreadyExists && libFolder.exists() && libFolder.members().length == 0) { libFolder.delete(true, monitor); } } } private void addErrorMarker(IProject project, String message) { markerManager.addMarker(project, MavenJSFConstants.JSF_CONFIGURATION_ERROR_MARKER_ID, message, -1, IMarker.SEVERITY_ERROR); } private String getWarSourceDirectory(MavenProject mavenProject, IProject project) { Plugin plugin = mavenProject.getPlugin("org.apache.maven.plugins:maven-war-plugin"); if (plugin == null) { return null; } Xpp3Dom config = (Xpp3Dom) plugin.getConfiguration(); if (config == null) { return WAR_SOURCE_FOLDER; } Xpp3Dom[] warSourceDirectory = config.getChildren("warSourceDirectory"); if (warSourceDirectory != null && warSourceDirectory.length > 0) { String dir = warSourceDirectory[0].getValue(); if (project != null) { return tryProjectRelativePath(project, dir).toOSString(); } return dir; } return WAR_SOURCE_FOLDER; } private IPath tryProjectRelativePath(IProject project, String resourceLocation) { if (resourceLocation == null) { return null; } IPath projectLocation = project.getLocation(); IPath directory = Path.fromOSString(resourceLocation); if (projectLocation == null || !projectLocation.isPrefixOf(directory)) { return directory; } return directory.removeFirstSegments(projectLocation.segmentCount()).makeRelative().setDevice(null); } /* private boolean configureWebxml() { IPreferenceStore store = Activator.getDefault().getPreferenceStore(); return store.getBoolean(Activator.CONFIGURE_WEBXML_JSF20); } */ private String getJSFVersion(MavenProject mavenProject, IFacetedProject fproj) { String version = null; IProject project = fproj.getProject(); version = JSFUtils.getVersionFromFacesconfig(project); if (version == null) { version = Activator.getDefault().getDependencyVersion(mavenProject, JSF_API_GROUP_ID, JSF_API_ARTIFACT_ID); } if (version == null) { //Check if there's a JSF 2.x dependency version = Activator.getDefault().getDependencyVersion(mavenProject, JSF_API2_GROUP_ID, JSF_API_ARTIFACT_ID); } if (version == null) { //JBIDE-9242 determine JSF version from classpath version = JSFUtils.getJSFVersionFromClasspath(project); } if (version == null) { version = inferJsfVersionFromDependencies(mavenProject, JSF_API2_GROUP_ID, JSF_API_ARTIFACT_ID, JSF_VERSION_2_0); } if (version == null && hasFacesServletInWebXml(mavenProject, project)) { //No dependency on JSF, no faces-config, but uses faces-servlet //so we try to best guess the version depending on the installed web facet IProjectFacetVersion webVersion = fproj.getInstalledVersion(IJ2EEFacetConstants.DYNAMIC_WEB_FACET); if (webVersion.compareTo(IJ2EEFacetConstants.DYNAMIC_WEB_30) < 0) { version = JSF_VERSION_1_2; } else { version = JSF_VERSION_2_0; } } return version; } private boolean hasFacesServletInWebXml(MavenProject mavenProject, IProject project) { //We look for javax.faces.webapp.FacesServlet in web.xml //We should look for a custom web.xml at this point, but WTP would then crash on the JSF Facet installation //if it's not in a standard location, so we stick with the regular file. IFile webXml = getWebXml(project); return webXml != null && webXml.exists() && JSFUtils.hasFacesServlet(webXml); } private IFile getWebXml(IProject project) { return ProjectUtil.getWebResourceFile(project, "WEB-INF/web.xml"); } private String inferJsfVersionFromDependencies(MavenProject mavenProject, String groupId, String artifactId, String defaultVersion) { boolean hasCandidates = false; String jsfVersion = null; List<ArtifactRepository> repos = mavenProject.getRemoteArtifactRepositories(); for (Artifact artifact : mavenProject.getArtifacts()) { if (isKnownJsfBasedArtifact(artifact)) { hasCandidates = true; jsfVersion = Activator.getDefault().getDependencyVersion(artifact, repos, groupId, artifactId); if (jsfVersion != null) { //TODO should probably not break and take the highest version returned from all dependencies break; } } } //Fallback to default JSF version if (hasCandidates && jsfVersion == null) { return defaultVersion; } return jsfVersion; } private boolean isKnownJsfBasedArtifact(Artifact artifact) { return artifact.getGroupId().startsWith("org.jboss.seam.") //$NON-NLS-1$ && artifact.getArtifactId().equals("seam-faces") //$NON-NLS-1$ && artifact.getVersion().startsWith("3."); //$NON-NLS-1$ } }