/*******************************************************************************
* Copyright 2011 Google Inc. All Rights Reserved.
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.google.gdt.eclipse.maven.configurators;
import com.google.gdt.eclipse.core.StringUtilities;
import com.google.gdt.eclipse.core.properties.WebAppProjectProperties;
import com.google.gdt.eclipse.maven.Activator;
import com.google.gdt.eclipse.maven.sdk.GWTMavenRuntime;
import com.google.gwt.eclipse.core.nature.GWTNature;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.m2e.core.lifecyclemapping.model.IPluginExecutionMetadata;
import org.eclipse.m2e.core.project.IMavenProjectFacade;
import org.eclipse.m2e.core.project.MavenProjectChangedEvent;
import org.eclipse.m2e.core.project.configurator.AbstractBuildParticipant;
import org.eclipse.m2e.core.project.configurator.MojoExecutionBuildParticipant;
import org.eclipse.m2e.core.project.configurator.ProjectConfigurationRequest;
import org.osgi.service.prefs.BackingStoreException;
import java.util.List;
/**
* M2Eclipse project configuration extension that configures a project to get the GWT project nature.
* <p>
* NOTE: Do not access this class from outside of the configurators package. All classes in the configurators package
* have dependencies on plugins that may or may not be present in the user's installation. As long as these classes are
* only invoked through m2Eclipe's extension points, other parts of this plug-in can be used without requiring the
* m2Eclipse dependencies.
*/
public class MavenProjectConfigurator extends AbstracMavenProjectConfigurator {
/**
* These properties may be pulled from the gwt-maven-plugin configuration of the pom to be used in configuring the GWT
* Web Application settings for the Eclipse project. If not present, defaults are used.
*/
private static final String ECLIPSE_LAUNCH_SRC_DIR_PROPERTY_KEY = "eclipseLaunchFromWarDir";
private static final boolean ECLIPSE_LAUNCH_SRC_DIR_DEFAULT = false;
private static final String WAR_SRC_DIR_PROPERTY_KEY = "warSourceDirectory";
private static final String WEB_APP_DIRECTORY = "webappDirectory";
private static final String HOSTED_WEB_APP_DIRECTORY = "hostedWebapp"; // GWT Maven Plugin 1 only
private static final String GWT_MAVEN_MODULENAME = "moduleName";
private static final String GWT_MAVEN_MODULESHORTNAME = "moduleShortName";
private static final String WAR_SRC_DIR_DEFAULT = "src/main/webapp";
@Override
protected void doConfigure(final MavenProject mavenProject, IProject project, ProjectConfigurationRequest unused,
final IProgressMonitor monitor) throws CoreException {
Activator.log("MavenProjectConfigurator.doConfigure() invoked");
// configure the GWT Nature
boolean hasGwtNature = configureNature(project, mavenProject, GWTNature.NATURE_ID, true, new NatureCallback() {
@Override
protected void beforeAddingNature() {
configureGwtProject(mavenProject, monitor);
}
}, monitor);
// retrieve gwt-maven-plugin configuration if it exists
Plugin gwtMavenPlugin = getGwtMavenPlugin(mavenProject);
Xpp3Dom mavenConfig = gwtMavenPlugin == null ? null : (Xpp3Dom) gwtMavenPlugin.getConfiguration();
// Persist GWT nature settings
if (!hasGwtNature) {
Activator.log("MavenProjectConfigurator: Skipping Maven configuration because GWT nature is false. hasGWTNature="
+ hasGwtNature);
// Exit no maven plugin found
return;
}
try {
persistGwtNatureSettings(project, mavenProject, mavenConfig);
} catch (BackingStoreException exception) {
Activator.logError("MavenProjectConfigurator: Problem configuring maven project.", exception);
}
}
@Override
public AbstractBuildParticipant getBuildParticipant(final IMavenProjectFacade projectFacade, MojoExecution execution,
final IPluginExecutionMetadata executionMetadata) {
Activator.log("MavenProjectConfigurator.getBuildParticipant for Maven invoked");
// Run the execution generate-module for maven2 plugin
// Don't run on war for gwt maven plugin1
MojoExecutionBuildParticipant build = null;
MavenProject mavenProject = projectFacade.getMavenProject();
if (mavenProject != null && isGwtMavenPlugin2(mavenProject)) {
Activator.log("MavenProjectConfigurator.getBuildParticipant adding build participant for generate-module.");
build = new MojoExecutionBuildParticipant(execution, true, true);
}
return build;
}
@Override
public void mavenProjectChanged(MavenProjectChangedEvent event, IProgressMonitor monitor) throws CoreException {
super.mavenProjectChanged(event, monitor);
}
@Override
public void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException {
Activator.log("MavenProjectConfigurator.configure invoked");
super.configure(request, monitor);
}
/**
* Save the settings for the GWT nature in the application GWT preferences.
*
* @param project
* @param mavenProject
* @param mavenConfig
* @throws BackingStoreException
*/
private void persistGwtNatureSettings(IProject project, MavenProject mavenProject, Xpp3Dom mavenConfig)
throws BackingStoreException {
IPath warOutDir = getWarOutDir(project, mavenProject);
WebAppProjectProperties.setWarSrcDir(project, getWarSrcDir(mavenProject, mavenConfig)); // src/main/webapp
WebAppProjectProperties.setWarSrcDirIsOutput(project, getLaunchFromHere(mavenConfig)); // false
// TODO the extension should be used, from WarArgProcessor
WebAppProjectProperties.setLastUsedWarOutLocation(project, warOutDir);
WebAppProjectProperties.setGwtMavenModuleName(project, getGwtModuleName(mavenProject));
WebAppProjectProperties.setGwtMavenModuleShortName(project, getGwtModuleShortName(mavenProject));
String message = "MavenProjectConfiguratior Maven: Success with setting up GWT Nature\n";
message += "\tartifactId=" + mavenProject.getArtifactId() + "\n";
message += "\tversion=" + mavenProject.getVersion() + "\n";
message += "\twarOutDir=" + warOutDir;
Activator.log(message);
}
/**
* Get the GWT Maven plugin 2 <moduleName/>.
*
* @param mavenProject
* @return the moduleName from configuration
*/
private String getGwtModuleName(MavenProject mavenProject) {
if (!isGwtMavenPlugin2(mavenProject)) {
return null;
}
Plugin gwtPlugin2 = getGwtMavenPlugin2(mavenProject);
if (gwtPlugin2 == null) {
return null;
}
Xpp3Dom gwtPluginConfig = (Xpp3Dom) gwtPlugin2.getConfiguration();
if (gwtPluginConfig == null) {
return null;
}
String moduleName = null;
for (Xpp3Dom child : gwtPluginConfig.getChildren()) {
if (child != null && GWT_MAVEN_MODULENAME.equals(child.getName())) {
moduleName = child.getValue().trim();
}
}
return moduleName;
}
/**
* Get the GWT Maven plugin 2 <moduleShort=Name/>.
*
* @param mavenProject
* @return the moduleName from configuration
*/
private String getGwtModuleShortName(MavenProject mavenProject) {
if (!isGwtMavenPlugin2(mavenProject)) {
return null;
}
Plugin gwtPlugin2 = getGwtMavenPlugin2(mavenProject);
if (gwtPlugin2 == null) {
return null;
}
Xpp3Dom gwtPluginConfig = (Xpp3Dom) gwtPlugin2.getConfiguration();
if (gwtPluginConfig == null) {
return null;
}
String moduleName = null;
for (Xpp3Dom child : gwtPluginConfig.getChildren()) {
if (child != null && GWT_MAVEN_MODULESHORTNAME.equals(child.getName())) {
moduleName = child.getValue().trim();
}
}
return moduleName;
}
/**
* Get the war output directory.
*
* @param project
* @param mavenProject
* @return returns the war output path
*/
private IPath getWarOutDir(IProject project, MavenProject mavenProject) {
String artifactId = mavenProject.getArtifactId();
String version = mavenProject.getVersion();
IPath locationOfProject = (project.getRawLocation() != null ? project.getRawLocation() : project.getLocation());
IPath warOut = null;
// Default directory target/artifact-version
if (locationOfProject != null && artifactId != null && version != null) {
warOut = locationOfProject.append("target").append(artifactId + "-" + version);
}
// Get the GWT Maven plugin 1 <hostedWebapp/> directory
if (isGwtMavenPlugin1(mavenProject) && getGwtMavenPluginHostedWebAppDirectory(mavenProject) != null) {
warOut = getGwtMavenPluginHostedWebAppDirectory(mavenProject);
}
// Get the Gwt Maven plugin 1 <webappDirectory/>
if (isGwtMavenPlugin2(mavenProject) && getGwtPlugin2WebAppDirectory(mavenProject) != null) {
warOut = getGwtPlugin2WebAppDirectory(mavenProject);
}
// Get the maven war plugin <webappDirectory/>
if (getMavenWarPluginWebAppDirectory(mavenProject) != null) {
warOut = getMavenWarPluginWebAppDirectory(mavenProject);
}
// make the directory if it doesn't exist
if (warOut != null) {
warOut.toFile().mkdirs();
}
return warOut;
}
/**
* Get the GWT Maven <hostedWebapp/> directory.
*
* @param mavenProject
* @return the webapp directory
*/
private IPath getGwtMavenPluginHostedWebAppDirectory(MavenProject mavenProject) {
Plugin warPlugin = getGwtMavenPlugin(mavenProject);
if (warPlugin == null) {
return null;
}
Xpp3Dom warPluginConfig = (Xpp3Dom) warPlugin.getConfiguration();
if (warPluginConfig == null) {
return null;
}
IPath warOut = null;
for (Xpp3Dom child : warPluginConfig.getChildren()) {
if (child != null && HOSTED_WEB_APP_DIRECTORY.equals(child.getName())) {
String path = child.getValue().trim();
if (!path.isEmpty()) {
warOut = new Path(path);
}
}
}
return warOut;
}
/**
* Return the war out directory via the Maven war plugin <webappDirectory/>.
*
* @param mavenProject
* @return path to web app direcotry
*/
protected IPath getMavenWarPluginWebAppDirectory(MavenProject mavenProject) {
Plugin warPlugin = getWarPlugin(mavenProject);
if (warPlugin == null) {
return null;
}
Xpp3Dom warPluginConfig = (Xpp3Dom) warPlugin.getConfiguration();
if (warPluginConfig == null) {
return null;
}
IPath warOut = null;
for (Xpp3Dom child : warPluginConfig.getChildren()) {
if (child != null && WEB_APP_DIRECTORY.equals(child.getName())) {
String path = child.getValue().trim();
if (!path.isEmpty()) {
warOut = new Path(path);
}
}
}
return warOut;
}
/**
* Returns the Gwt Maven Plugin 2 web app directory <webappDirectory/>.
*
* @param mavenProject
* @return path to web app direcotry
*/
protected IPath getGwtPlugin2WebAppDirectory(MavenProject mavenProject) {
Plugin warPlugin = getGwtMavenPlugin2(mavenProject);
if (warPlugin == null) {
return null;
}
Xpp3Dom warPluginConfig = (Xpp3Dom) warPlugin.getConfiguration();
if (warPluginConfig == null) {
return null;
}
IPath warOut = null;
for (Xpp3Dom child : warPluginConfig.getChildren()) {
if (child != null && WEB_APP_DIRECTORY.equals(child.getName())) {
String path = child.getValue().trim();
if (!path.isEmpty()) {
warOut = new Path(path);
}
}
}
return warOut;
}
/**
* Configure the GWT Nature.
*
* @param mavenProject
* @param monitor
*/
protected void configureGwtProject(MavenProject mavenProject, IProgressMonitor monitor) {
// Get the GWT version from the project pom
String gwtVersion = null;
List<Dependency> dependencies = mavenProject.getDependencies();
for (Dependency dependency : dependencies) {
boolean hasGwtGroupId = GWTMavenRuntime.MAVEN_GWT_GROUP_ID.equals(dependency.getGroupId());
boolean hasGwtUserArtivactId = GWTMavenRuntime.MAVEN_GWT_USER_ARTIFACT_ID.equals(dependency.getArtifactId());
boolean hasGwtUserServletId = GWTMavenRuntime.MAVEN_GWT_SERVLET_ARTIFACT_ID.equals(dependency.getArtifactId());
if (hasGwtGroupId && (hasGwtUserArtivactId || hasGwtUserServletId)) {
gwtVersion = dependency.getVersion();
Activator.log("MavenProjectConfigurator, Maven: Setting up Gwt Project. hasGwtGroupId=" + hasGwtGroupId
+ " hasGwtUser=" + hasGwtUserArtivactId + " hasGwtUserServletId=" + hasGwtUserServletId);
break;
}
}
Activator.log("MavenProjectConfigurator, Maven: gwtVersion=" + gwtVersion);
resolveGwtDevJar(mavenProject, monitor, gwtVersion);
}
private void resolveGwtDevJar(MavenProject mavenProject, IProgressMonitor monitor, String gwtVersion) {
// Check that the pom.xml has GWT dependencies
if (gwtVersion != null && !StringUtilities.isEmpty(gwtVersion)) {
try {
// Download and install the gwt-dev.jar into the local repository.
maven.resolve(GWTMavenRuntime.MAVEN_GWT_GROUP_ID, GWTMavenRuntime.MAVEN_GWT_DEV_JAR_ARTIFACT_ID, gwtVersion,
"jar", null, mavenProject.getRemoteArtifactRepositories(), monitor);
} catch (CoreException exception) {
Activator.logError(
"MavenProjectConfigurator: Problem configuring the maven project because it could not download the "
+ "gwt-dev.jar which is used to determine the version.",
exception);
}
}
}
/**
* Returns the war source directory such as src/main/webapp
*
* @param mavenProject
*
* @param config
* gwt-maven-maven config DOM
* @return the {@link #WAR_SRC_DIR_PROPERTY_KEY} value from the config if it exists, {@link #WAR_SRC_DIR_DEFAULT}
* otherwise or if config is null
*/
private static final IPath getWarSrcDir(MavenProject mavenProject, Xpp3Dom config) {
String spath = WAR_SRC_DIR_DEFAULT;
if (config != null) {
for (Xpp3Dom child : config.getChildren()) {
if (child != null && WAR_SRC_DIR_PROPERTY_KEY.equals(child.getName())) {
spath = child.getValue() == null ? WAR_SRC_DIR_DEFAULT : child.getValue().trim();
}
}
}
IPath path = null;
if (spath != null) {
path = new Path(spath);
String basePath = mavenProject.getBasedir().toPath().toAbsolutePath().toString();
String fullPath = basePath + "/" + spath;
java.io.File fullPathFile = new java.io.File(fullPath);
if (!fullPathFile.exists()) {
path = null;
}
}
return path;
}
/**
* Get the project launch locaiton
*
* @param config
* gwt-maven-maven config DOM
* @return the {@link #ECLIPSE_LAUNCH_SRC_DIR_PROPERTY_KEY} value from the config if it exists,
* {@link #ECLIPSE_LAUNCH_SRC_DIR_DEFAULT} otherwise or if config is null
*/
private final boolean getLaunchFromHere(Xpp3Dom config) {
if (config == null) {
return ECLIPSE_LAUNCH_SRC_DIR_DEFAULT;
}
for (Xpp3Dom child : config.getChildren()) {
if (child != null && ECLIPSE_LAUNCH_SRC_DIR_PROPERTY_KEY.equals(child.getName())) {
return child.getValue() == null ? ECLIPSE_LAUNCH_SRC_DIR_DEFAULT
: Boolean.parseBoolean(child.getValue().trim());
}
}
return ECLIPSE_LAUNCH_SRC_DIR_DEFAULT;
}
}