diff options
13 files changed, 729 insertions, 2 deletions
diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/wizards/MavenPomWizard.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/wizards/MavenPomWizard.java index 20baff1e..dc287fe0 100644 --- a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/wizards/MavenPomWizard.java +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/wizards/MavenPomWizard.java @@ -132,6 +132,10 @@ public class MavenPomWizard extends Wizard implements INewWizard { final File pom = file.getLocation().toFile(); try { + //#359340 : Convert existing Eclipse config into Maven model config + //TODO We could let the user choose which conversion participants to run (in case of conflicts?) + MavenPlugin.getProjectConversionManager().convert(resource.getProject(), model, monitor); + MavenModelManager modelManager = MavenPlugin.getMavenModelManager(); modelManager.createMavenModel(file, model); diff --git a/org.eclipse.m2e.core/META-INF/MANIFEST.MF b/org.eclipse.m2e.core/META-INF/MANIFEST.MF index f1ee8591..b259c881 100644 --- a/org.eclipse.m2e.core/META-INF/MANIFEST.MF +++ b/org.eclipse.m2e.core/META-INF/MANIFEST.MF @@ -41,6 +41,7 @@ Export-Package: org.eclipse.m2e.core, org.eclipse.m2e.core.lifecyclemapping.model, org.eclipse.m2e.core.project, org.eclipse.m2e.core.project.configurator, + org.eclipse.m2e.core.project.conversion, org.eclipse.m2e.core.repository MavenArtifact-GroupId: org.eclipse.m2e MavenArtifact-ArtifactId: org.eclipse.m2e.core diff --git a/org.eclipse.m2e.core/plugin.properties b/org.eclipse.m2e.core/plugin.properties index 871699c8..eb2ba31e 100644 --- a/org.eclipse.m2e.core/plugin.properties +++ b/org.eclipse.m2e.core/plugin.properties @@ -38,3 +38,4 @@ extension-point.mappingdefault.name = Default Maven Lifecycle Mappings extension-point.component.name = Maven Core Component Contributor extension-point.changed.name = mavenProjectChangedListeners extension-point.lifecycleMappingMetadataSource.name = Lifecycle Mapping Metadata Source +extension-point.projectConversionParticipants.name= Project conversion participants
\ No newline at end of file diff --git a/org.eclipse.m2e.core/plugin.xml b/org.eclipse.m2e.core/plugin.xml index 0492809a..cd08c47d 100644 --- a/org.eclipse.m2e.core/plugin.xml +++ b/org.eclipse.m2e.core/plugin.xml @@ -16,6 +16,7 @@ <extension-point id="mavenProjectChangedListeners" name="%extension-point.changed.name" schema="schema/mavenProjectChangedListeners.exsd"/> <extension-point id="lifecycleMappingMetadataSource" name="%extension-point.lifecycleMappingMetadataSource.name" schema="schema/lifecycleMappingMetadataSource.exsd"/> <extension-point id="artifactFilters" name="%extension-point.artifactFilters-name" schema="schema/artifactFilters.exsd"/> + <extension-point id="projectConversionParticipants" name="%extension-point.projectConversionParticipants.name" schema="schema/projectConversionParticipants.exsd"/> <extension point="org.eclipse.core.runtime.contentTypes"> <content-type id="pomFile" name="%content-type.name" diff --git a/org.eclipse.m2e.core/schema/projectConversionParticipants.exsd b/org.eclipse.m2e.core/schema/projectConversionParticipants.exsd new file mode 100644 index 00000000..fb219cea --- /dev/null +++ b/org.eclipse.m2e.core/schema/projectConversionParticipants.exsd @@ -0,0 +1,130 @@ +<?xml version='1.0' encoding='UTF-8'?> +<schema targetNamespace="org.eclipse.m2e.core" xmlns="http://www.w3.org/2001/XMLSchema"> +<annotation> + <appInfo> + <meta.schema plugin="org.eclipse.m2e.core" id="projectConversionParticipants" name="org.eclipse.m2e.core.project.conversionParticipants"/> + </appInfo> + <documentation> + [Enter description of this extension point.] + </documentation> + </annotation> + + <element name="extension"> + <annotation> + <appInfo> + <meta.element /> + </appInfo> + </annotation> + <complexType> + <sequence minOccurs="1" maxOccurs="unbounded"> + <element ref="projectConversionParticipant"/> + </sequence> + <attribute name="point" type="string" use="required"> + <annotation> + <documentation> + + </documentation> + </annotation> + </attribute> + <attribute name="id" type="string"> + <annotation> + <documentation> + + </documentation> + </annotation> + </attribute> + <attribute name="name" type="string"> + <annotation> + <documentation> + + </documentation> + <appInfo> + <meta.attribute translatable="true"/> + </appInfo> + </annotation> + </attribute> + </complexType> + </element> + + <element name="projectConversionParticipant"> + <complexType> + <attribute name="id" type="string" use="required"> + <annotation> + <documentation> + Unique project conversion participant Id + </documentation> + </annotation> + </attribute> + <attribute name="class" type="string" use="required"> + <annotation> + <documentation> + + </documentation> + <appInfo> + <meta.attribute kind="java" basedOn="org.eclipse.m2e.core.project.conversion.AbstractProjectConversionParticipant:"/> + </appInfo> + </annotation> + </attribute> + <attribute name="name" type="string"> + <annotation> + <documentation> + Translatable name of this conversion participant. Ex. "JDT project converter" + </documentation> + <appInfo> + <meta.attribute translatable="true"/> + </appInfo> + </annotation> + </attribute> + </complexType> + </element> + + <annotation> + <appInfo> + <meta.section type="since"/> + </appInfo> + <documentation> + 1.1 + </documentation> + </annotation> + + <annotation> + <appInfo> + <meta.section type="examples"/> + </appInfo> + <documentation> + [Enter extension point usage example here.] + </documentation> + </annotation> + + <annotation> + <appInfo> + <meta.section type="apiinfo"/> + </appInfo> + <documentation> + [Enter API information here.] + </documentation> + </annotation> + + <annotation> + <appInfo> + <meta.section type="implementation"/> + </appInfo> + <documentation> + [Enter information about supplied implementation of this extension point.] + </documentation> + </annotation> + + <annotation> + <appInfo> + <meta.section type="copyright"/> + </appInfo> + <documentation> + Copyright (c) 2012 Red Hat, Inc. +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 + </documentation> + </annotation> + +</schema> diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/MavenPlugin.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/MavenPlugin.java index 907c29b7..3be53e36 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/MavenPlugin.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/MavenPlugin.java @@ -17,8 +17,10 @@ import org.eclipse.m2e.core.embedder.MavenModelManager; import org.eclipse.m2e.core.embedder.MavenRuntimeManager; import org.eclipse.m2e.core.internal.MavenPluginActivator; import org.eclipse.m2e.core.internal.index.IndexManager; +import org.eclipse.m2e.core.internal.project.conversion.ProjectConversionManager; import org.eclipse.m2e.core.project.IProjectConfigurationManager; import org.eclipse.m2e.core.project.IMavenProjectRegistry; +import org.eclipse.m2e.core.project.conversion.IProjectConversionManager; import org.eclipse.m2e.core.repository.IRepositoryRegistry; @@ -69,4 +71,8 @@ public final class MavenPlugin { return MavenPluginActivator.getDefault().getMavenModelManager(); } + public static IProjectConversionManager getProjectConversionManager() { + return MavenPluginActivator.getDefault().getProjectConversionManager(); + } + } diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/MavenPluginActivator.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/MavenPluginActivator.java index 87593448..13433db2 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/MavenPluginActivator.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/MavenPluginActivator.java @@ -71,12 +71,14 @@ import org.eclipse.m2e.core.internal.markers.MavenMarkerManager; import org.eclipse.m2e.core.internal.preferences.MavenConfigurationImpl; import org.eclipse.m2e.core.internal.project.ProjectConfigurationManager; import org.eclipse.m2e.core.internal.project.WorkspaceStateWriter; +import org.eclipse.m2e.core.internal.project.conversion.ProjectConversionManager; import org.eclipse.m2e.core.internal.project.registry.MavenProjectManager; import org.eclipse.m2e.core.internal.project.registry.ProjectRegistryManager; import org.eclipse.m2e.core.internal.project.registry.ProjectRegistryRefreshJob; import org.eclipse.m2e.core.internal.repository.RepositoryRegistry; import org.eclipse.m2e.core.project.IProjectConfigurationManager; import org.eclipse.m2e.core.project.MavenUpdateRequest; +import org.eclipse.m2e.core.project.conversion.IProjectConversionManager; import org.eclipse.m2e.core.repository.IRepositoryRegistry; @@ -133,6 +135,8 @@ public class MavenPluginActivator extends Plugin { private MavenImpl maven; + private IProjectConversionManager projectConversionManager; + public MavenPluginActivator() { plugin = this; @@ -239,6 +243,8 @@ public class MavenPluginActivator extends Plugin { // fork repository registry update. must after index manager registered as a listener this.repositoryRegistry.updateRegistry(); + + this.projectConversionManager = new ProjectConversionManager(); } private static ArchetypeManager newArchetypeManager(File stateLocationDir) { @@ -287,6 +293,8 @@ public class MavenPluginActivator extends Plugin { this.configurationManager = null; LifecycleMappingFactory.setBundleMetadataSources(null); + this.projectConversionManager = null; + plugin = null; } @@ -431,4 +439,11 @@ public class MavenPluginActivator extends Plugin { public ArtifactFilterManager getArifactFilterManager() { return artifactFilterManager; } + + /** + * @return + */ + public IProjectConversionManager getProjectConversionManager() { + return projectConversionManager; + } } diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/conversion/ProjectConversionManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/conversion/ProjectConversionManager.java new file mode 100644 index 00000000..4aca4e07 --- /dev/null +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/conversion/ProjectConversionManager.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2012 Red Hat, Inc. + * 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: + * Red Hat, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.core.internal.project.conversion; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Platform; + +import org.apache.maven.model.Model; + +import org.eclipse.m2e.core.project.conversion.AbstractProjectConversionParticipant; +import org.eclipse.m2e.core.project.conversion.IProjectConversionManager; + +/** + * Manages conversion of existing Eclipse projects into Maven ones. <br/> + * Looks up for {@link AbstractProjectConversionParticipant} contributed by 3rd party eclipse plugins. + * + * @author Fred Bricon + */ +public class ProjectConversionManager implements IProjectConversionManager { + + private static final String CONVERSION_PARTICIPANTS_EXTENSION_POINT = "org.eclipse.m2e.core.projectConversionParticipants"; + + private static final Logger log = LoggerFactory.getLogger(ProjectConversionManager.class); + + private List<AbstractProjectConversionParticipant> allParticipants; + + public List<AbstractProjectConversionParticipant> getAllConversionParticipants() { + if (allParticipants == null) { + allParticipants = lookupConversionParticipants(); + } + return Collections.unmodifiableList(allParticipants); + } + + private static List<AbstractProjectConversionParticipant> lookupConversionParticipants() { + + List<AbstractProjectConversionParticipant> participants = new ArrayList<AbstractProjectConversionParticipant>(); + + IExtensionRegistry registry = Platform.getExtensionRegistry(); + IExtensionPoint conversionExtensionPoint = registry.getExtensionPoint(CONVERSION_PARTICIPANTS_EXTENSION_POINT); + if(conversionExtensionPoint != null) { + IExtension[] archetypesExtensions = conversionExtensionPoint.getExtensions(); + for(IExtension extension : archetypesExtensions) { + IConfigurationElement[] elements = extension.getConfigurationElements(); + for(IConfigurationElement element : elements) { + AbstractProjectConversionParticipant participant = readProjectConversionParticipant(element); + if (participant != null) { + participants.add(participant); + } + } + } + } + return Collections.unmodifiableList(participants); + } + + private static AbstractProjectConversionParticipant readProjectConversionParticipant(IConfigurationElement element) { + AbstractProjectConversionParticipant participant = null; + try { + participant = (AbstractProjectConversionParticipant) element.createExecutableExtension("class"); + } catch(CoreException ex) { + log.error("Can not load IProjectConversionParticipant", ex); + } + return participant; + } + + public void convert(IProject project, Model model, IProgressMonitor monitor) throws CoreException { + if (model == null) { + return; + } + List<AbstractProjectConversionParticipant> participants = getConversionParticipants(project); + if (participants != null) { + for (AbstractProjectConversionParticipant participant : participants) { + participant.convert(project, model, monitor); + } + } + } + + public List<AbstractProjectConversionParticipant> getConversionParticipants(IProject project) throws CoreException { + List<AbstractProjectConversionParticipant> allParticipants = getAllConversionParticipants(); + List<AbstractProjectConversionParticipant> participants = new ArrayList<AbstractProjectConversionParticipant>(); + if (allParticipants != null) { + for (AbstractProjectConversionParticipant participant : allParticipants) { + if (participant.accept(project)) { + participants.add(participant); + } + } + } + return participants; + } + +} diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/conversion/AbstractProjectConversionParticipant.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/conversion/AbstractProjectConversionParticipant.java new file mode 100644 index 00000000..64553a9b --- /dev/null +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/conversion/AbstractProjectConversionParticipant.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2012 Red Hat, Inc. + * 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: + * Red Hat, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.core.project.conversion; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExecutableExtension; +import org.eclipse.core.runtime.IProgressMonitor; + +import org.apache.maven.model.Model; + +/** + * Used to convert existing Eclipse project configuration to the corresponding Maven Model. + * + * @author Fred Bricon + */ +public abstract class AbstractProjectConversionParticipant implements IExecutableExtension { + + public static final String ATTR_ID = "id"; //$NON-NLS-1$ + + public static final String ATTR_NAME = "name"; //$NON-NLS-1$ + + private String name; + private String id; + + public String getName() { + return name; + } + + public String getId() { + if (id == null) { + id = getClass().getName(); + } + return id; + } + + public void setInitializationData(IConfigurationElement config, String propertyName, Object data) { + this.id = config.getAttribute(ATTR_ID); + this.name = config.getAttribute(ATTR_NAME); + } + + /** + * Checks if this participant can change the Maven Model from this Eclipse project configuration + */ + public abstract boolean accept(IProject project) throws CoreException; + + /** + * Converts existing Eclipse project configuration to Maven model + */ + public abstract void convert(IProject project, Model model, IProgressMonitor monitor) throws CoreException; + + + public String toString() { + return (name == null)?getId():name; + } +} diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/conversion/IProjectConversionManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/conversion/IProjectConversionManager.java new file mode 100644 index 00000000..ca48e5cc --- /dev/null +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/conversion/IProjectConversionManager.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2012 Red Hat, Inc. + * 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: + * Red Hat, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.core.project.conversion; + +import java.util.List; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; + +import org.apache.maven.model.Model; + +/** + * Manages conversion of existing Eclipse projects into Maven ones. + * + * @author Fred Bricon + */ +public interface IProjectConversionManager { + + /** + * Converts an existing Eclipse project configuration to its Maven Model counterpart + */ + void convert(IProject project, Model model, IProgressMonitor monitor) throws CoreException; + + /** + * Returns an unmodifiable list of all known {@link AbstractProjectConversionParticipant}s + */ + List<AbstractProjectConversionParticipant> getAllConversionParticipants(); + + /** + * Returns an unmodifiable list of all {@link AbstractProjectConversionParticipant}s applying to this project + */ + List<AbstractProjectConversionParticipant> getConversionParticipants(IProject project) throws CoreException; + +} diff --git a/org.eclipse.m2e.jdt/plugin.properties b/org.eclipse.m2e.jdt/plugin.properties index 38c6fe23..97d642b6 100644 --- a/org.eclipse.m2e.jdt/plugin.properties +++ b/org.eclipse.m2e.jdt/plugin.properties @@ -30,4 +30,5 @@ action.javadoc.label = Open JavaDoc action.javadoc2.label = Open JavaDoc action.javadoc3.label = Open JavaDoc action.javadoc4.label = Open JavaDoc -lifecycleMapping.jar.name = Jar Lifecycle Mapping
\ No newline at end of file +lifecycleMapping.jar.name = Jar Lifecycle Mapping +java.conversion.participant.name = Java project converter
\ No newline at end of file diff --git a/org.eclipse.m2e.jdt/plugin.xml b/org.eclipse.m2e.jdt/plugin.xml index e861244c..6ca863de 100644 --- a/org.eclipse.m2e.jdt/plugin.xml +++ b/org.eclipse.m2e.jdt/plugin.xml @@ -358,5 +358,12 @@ <extension point="org.eclipse.m2e.core.lifecycleMappingMetadataSource"> </extension> - + <extension + point="org.eclipse.m2e.core.projectConversionParticipants"> + <projectConversionParticipant + class="org.eclipse.m2e.jdt.internal.JavaProjectConversionParticipant" + id="org.eclipse.m2e.jdt.javaProjectConversionParticipant" + name="%java.conversion.participant.name" > + </projectConversionParticipant> + </extension> </plugin> diff --git a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/JavaProjectConversionParticipant.java b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/JavaProjectConversionParticipant.java new file mode 100644 index 00000000..88ad5986 --- /dev/null +++ b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/JavaProjectConversionParticipant.java @@ -0,0 +1,342 @@ +/******************************************************************************* + * Copyright (c) 2012 Red Hat, Inc. + * 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: + * Red Hat, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.jdt.internal; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceVisitor; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; + +import org.codehaus.plexus.util.xml.Xpp3Dom; + +import org.apache.maven.model.Build; +import org.apache.maven.model.Model; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.Resource; + +import org.eclipse.m2e.core.project.conversion.AbstractProjectConversionParticipant; + +/** + * Converts existing Eclipse Java projects by setting the maven compiler source and target values. + * It also tries to best match existing Java source directories with the corresponding + * source, test source, resource and test resource directories of the Maven model. + * + * @author Fred Bricon + */ +public class JavaProjectConversionParticipant extends AbstractProjectConversionParticipant { + + private static final Logger log = LoggerFactory.getLogger(JavaProjectConversionParticipant.class); + + private static final String DEFAULT_JAVA_SOURCE = "src/main/java"; //$NON-NLS-1$ + + private static final String DEFAULT_RESOURCES = "src/main/resources"; //$NON-NLS-1$ + + private static final String DEFAULT_JAVA_TEST_SOURCE = "src/test/java"; //$NON-NLS-1$ + + private static final String DEFAULT_TEST_RESOURCES = "src/test/resources"; //$NON-NLS-1$ + + private static final String DEFAULT_JAVA_VERSION = "1.5"; //$NON-NLS-1$ + + private static final String COMPILER_GROUP_ID = "org.apache.maven.plugins"; //$NON-NLS-1$ + + private static final String COMPILER_ARTIFACT_ID = "maven-compiler-plugin"; //$NON-NLS-1$ + + private static final String COMPILER_VERSION = "2.3.2"; //$NON-NLS-1$ + + private static final String TARGET_KEY = "target"; //$NON-NLS-1$ + + private static final String SOURCE_KEY = "source"; //$NON-NLS-1$ + + private static final String CONFIGURATION_KEY = "configuration"; //$NON-NLS-1$ + + public boolean accept(IProject project) throws CoreException { + boolean accepts = project != null && project.isAccessible() + && project.hasNature(JavaCore.NATURE_ID); + return accepts; + } + + public void convert(IProject project, Model model, IProgressMonitor monitor) throws CoreException { + if (!accept(project)) { + return; + } + IJavaProject javaProject = JavaCore.create(project); + if (javaProject == null) { + return; + } + + log.debug("Applying Java conversion to " + project.getName()); //$NON-NLS-1$ + + configureBuildSourceDirectories(model, javaProject); + + //Read existing Eclipse compiler settings + String source = javaProject.getOption(JavaCore.COMPILER_SOURCE, false); + String target= javaProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, false); + + //We want to keep pom.xml configuration to a minimum so we rely on convention. If the java version == 1.5, + //we shouldn't need to add anything as recent maven-compiler-plugin versions target Java 1.5 by default + if (DEFAULT_JAVA_VERSION.equals(source) && DEFAULT_JAVA_VERSION.equals(target)) { + return; + } + + //Configure Java version + boolean useProperties = false;//TODO Use preferences + if (useProperties) { + configureProperties(model, source, target); + } else { + configureCompilerPlugin(model, source, target); + } + + } + + private void configureProperties(Model model, String source, String target) { + Properties properties = model.getProperties(); + if (properties == null) { + properties = new Properties(); + model.setProperties(properties); + } + properties.setProperty("maven.compiler.source", source); //$NON-NLS-1$ + properties.setProperty("maven.compiler.target", target); //$NON-NLS-1$ + } + + private void configureCompilerPlugin(Model model, String source, String target) { + Build build= getOrCreateBuild(model); + model.setBuild(build); + + Plugin compiler = getOrCreateCompilerPlugin(build); + + Xpp3Dom configuration = (Xpp3Dom)compiler.getConfiguration(); + if (configuration == null) { + configuration = new Xpp3Dom(CONFIGURATION_KEY); + compiler.setConfiguration(configuration); + } + + Xpp3Dom sourceDom = configuration.getChild(SOURCE_KEY); + if (sourceDom == null) { + sourceDom = new Xpp3Dom(SOURCE_KEY); + configuration.addChild(sourceDom); + } + sourceDom.setValue(source); + + Xpp3Dom targetDom = configuration.getChild(TARGET_KEY); + if (targetDom == null) { + targetDom = new Xpp3Dom(TARGET_KEY); + configuration.addChild(targetDom); + } + targetDom.setValue(target); + compiler.setConfiguration(configuration); + } + + private Plugin getOrCreateCompilerPlugin(Build build) { + build.flushPluginMap();//We need to force the re-generation of the plugin map as it may be stale + Plugin compiler = build.getPluginsAsMap().get(COMPILER_GROUP_ID+":"+COMPILER_ARTIFACT_ID); //$NON-NLS-1$ + if (compiler == null) { + compiler = build.getPluginsAsMap().get(COMPILER_ARTIFACT_ID); + } + if (compiler == null) { + compiler = new Plugin(); + compiler.setGroupId(COMPILER_GROUP_ID); + compiler.setArtifactId(COMPILER_ARTIFACT_ID); + compiler.setVersion(COMPILER_VERSION); + build.addPlugin(compiler); + } + + return compiler; + } + + private void configureBuildSourceDirectories(Model model, IJavaProject javaProject) throws CoreException { + IClasspathEntry[] entries = javaProject.getRawClasspath(); + Set<String> sources = new LinkedHashSet<String>(); + Set<String> potentialTestSources = new LinkedHashSet<String>(); + Set<String> potentialResourceDirectories = new LinkedHashSet<String>(); + Set<String> potentialTestResourceDirectories = new LinkedHashSet<String>(); + IPath projectPath = javaProject.getPath(); + + for (int i = 0; i < entries.length; i++) { + if (entries[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) { + IPath path = entries[i].getPath().makeRelativeTo(projectPath); + if (path.isAbsolute()) { + //We only support paths relative to the project root, so we skip this one + continue; + } + String portablePath = path.toPortableString(); + boolean isPotentialTestSource = isPotentialTestSource(path); + boolean isResource = false; + if (isPotentialTestSource) { + if (DEFAULT_TEST_RESOURCES.equals(portablePath)) { + isResource = potentialTestResourceDirectories.add(portablePath); + } else { + potentialTestSources.add(portablePath); + } + } else { + if (DEFAULT_RESOURCES.equals(portablePath)) { + isResource = potentialResourceDirectories.add(portablePath); + } else { + sources.add(portablePath); + } + } + + if (!isResource) { + //For source folders not already flagged as resource folder, check if + // they contain non-java sources, so we can add them as resources too + IFolder folder = javaProject.getProject().getFolder(path); + NonJavaResourceVisitor nonJavaResourceVisitor = new NonJavaResourceVisitor(); + boolean hasNonJavaResources = false; + try { + folder.accept(nonJavaResourceVisitor); + } catch(NonJavaResourceFoundException ex) { + //Expected + hasNonJavaResources = true; + } + + if (hasNonJavaResources) { + if (isPotentialTestSource) { + potentialTestResourceDirectories.add(portablePath); + } else { + potentialResourceDirectories.add(portablePath); + } + } + } + } + } + + Build build = getOrCreateBuild(model); + + if (!sources.isEmpty()) { + if (sources.size() > 1) { + //We don't know how to handle multiple sources, i.e. how to map to a resource or test source directory + //That should be dealt by setting the build-helper-plugin config (http://mojo.codehaus.org/build-helper-maven-plugin/usage.html) + log.warn("{} has multiple source entries, this is not supported yet", model.getArtifactId()); //$NON-NLS-1$ + } + String sourceDirectory = sources.iterator().next(); + if (!DEFAULT_JAVA_SOURCE.equals(sourceDirectory)) { + build.setSourceDirectory(sourceDirectory); + } + + for (String resourceDirectory : potentialResourceDirectories) { + if (!DEFAULT_RESOURCES.equals(resourceDirectory) || potentialResourceDirectories.size() > 1) { + build.addResource(createResource(resourceDirectory)); + } + } + } + + if (!potentialTestSources.isEmpty()) { + if (potentialTestSources.size() > 1) { + log.warn("{} has multiple test source entries, this is not supported yet", model.getArtifactId()); //$NON-NLS-1$ + } + String testSourceDirectory = potentialTestSources.iterator().next(); + if (!DEFAULT_JAVA_TEST_SOURCE.equals(testSourceDirectory)) { + build.setTestSourceDirectory(testSourceDirectory); + } + for (String resourceDirectory : potentialTestResourceDirectories) { + if (!DEFAULT_TEST_RESOURCES.equals(resourceDirectory) || potentialTestResourceDirectories.size() > 1) { + build.addTestResource(createResource(resourceDirectory)); + } + } + } + + //Ensure we don't attach a new empty build definition to the model + if (build.getSourceDirectory() != null || build.getTestSourceDirectory() != null + || !build.getResources().isEmpty() || !build.getTestResources().isEmpty()) { + model.setBuild(build); + } + } + + private Resource createResource(String resourceDirectory) { + Resource r = new Resource(); + r.setDirectory(resourceDirectory); + r.addExclude("**/*.java"); //$NON-NLS-1$ + return r; + } + + /** + * Checks if a given path has one of its segment ending with test or tests + */ + private boolean isPotentialTestSource(IPath path) { + for (String segment : path.segments()) { + String folderName = segment.toLowerCase(); + if (folderName.matches(".*tests?")) { //$NON-NLS-1$ + return true; + } + } + return false; + //TODO Maybe check if the folder has java files with a Test or TestSuite suffix? + } + + private Build getOrCreateBuild(Model model) { + Build build = model.getBuild(); + if (build == null) { + build = new Build(); + } + return build; + } + + + /** + * Visitor implementation looking for non-Java resources. as soon as such resource is found, + * a {@link NonJavaResourceFoundException} is thrown. + */ + private static class NonJavaResourceVisitor implements IResourceVisitor { + + //TODO either declare a complete list of extensions or switch to + // a different "ignore resource" strategy + private static final List<String> IGNORED_EXTENSIONS = Arrays.asList(".svn"); //$NON-NLS-1$ + + public NonJavaResourceVisitor() { + } + + @SuppressWarnings("unused") + public boolean visit(IResource resource) throws CoreException { + String resourceName = resource.getProjectRelativePath().lastSegment(); + if (resource.isHidden() || isIgnored(resourceName)) { + return false; + } + if(resource instanceof IFile) { + IFile file = (IFile) resource; + if (!"java".equals(file.getFileExtension())) { + throw new NonJavaResourceFoundException(); + } + } + return true; + } + + private boolean isIgnored(String resourceName) { + for (String extension : IGNORED_EXTENSIONS) { + if (resourceName.endsWith(extension)) { + return true; + } + } + return false; + } + } + + private static class NonJavaResourceFoundException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public NonJavaResourceFoundException() {} + } +} |