Java tutorial
/******************************************************************************* * Copyright (c) 2008-2010 Sonatype, 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: * Sonatype, Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.m2e.core.internal.project; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.eclipse.core.resources.ICommand; 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.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.osgi.util.NLS; import org.codehaus.plexus.util.StringUtils; import org.apache.maven.archetype.ArchetypeGenerationRequest; import org.apache.maven.archetype.ArchetypeGenerationResult; import org.apache.maven.archetype.catalog.Archetype; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.model.Model; import org.apache.maven.project.MavenProject; import org.eclipse.m2e.core.MavenPlugin; import org.eclipse.m2e.core.embedder.ICallable; import org.eclipse.m2e.core.embedder.IMaven; import org.eclipse.m2e.core.embedder.IMavenConfiguration; import org.eclipse.m2e.core.embedder.IMavenExecutionContext; import org.eclipse.m2e.core.embedder.MavenModelManager; import org.eclipse.m2e.core.internal.IMavenConstants; import org.eclipse.m2e.core.internal.MavenPluginActivator; import org.eclipse.m2e.core.internal.Messages; import org.eclipse.m2e.core.internal.archetype.ArchetypeCatalogFactory.RemoteCatalogFactory; import org.eclipse.m2e.core.internal.archetype.ArchetypeManager; import org.eclipse.m2e.core.internal.embedder.MavenExecutionContext; import org.eclipse.m2e.core.internal.lifecyclemapping.LifecycleMappingFactory; import org.eclipse.m2e.core.internal.markers.IMavenMarkerManager; import org.eclipse.m2e.core.internal.project.registry.ProjectRegistryManager; import org.eclipse.m2e.core.project.IMavenProjectChangedListener; import org.eclipse.m2e.core.project.IMavenProjectFacade; import org.eclipse.m2e.core.project.IMavenProjectImportResult; import org.eclipse.m2e.core.project.IProjectConfigurationManager; import org.eclipse.m2e.core.project.LocalProjectScanner; import org.eclipse.m2e.core.project.MavenProjectChangedEvent; import org.eclipse.m2e.core.project.MavenProjectInfo; import org.eclipse.m2e.core.project.MavenUpdateRequest; import org.eclipse.m2e.core.project.ProjectImportConfiguration; import org.eclipse.m2e.core.project.ResolverConfiguration; import org.eclipse.m2e.core.project.configurator.AbstractProjectConfigurator; import org.eclipse.m2e.core.project.configurator.ILifecycleMapping; import org.eclipse.m2e.core.project.configurator.ProjectConfigurationRequest; /** * import Maven projects update project configuration from Maven enable Maven nature create new project * * @author igor */ public class ProjectConfigurationManager implements IProjectConfigurationManager, IMavenProjectChangedListener, IResourceChangeListener { /*package*/static final Logger log = LoggerFactory.getLogger(ProjectConfigurationManager.class); final ProjectRegistryManager projectManager; final MavenModelManager mavenModelManager; final IMavenMarkerManager mavenMarkerManager; final IMaven maven; final IMavenConfiguration mavenConfiguration; public ProjectConfigurationManager(IMaven maven, ProjectRegistryManager projectManager, MavenModelManager mavenModelManager, IMavenMarkerManager mavenMarkerManager, IMavenConfiguration mavenConfiguration) { this.projectManager = projectManager; this.mavenModelManager = mavenModelManager; this.mavenMarkerManager = mavenMarkerManager; this.maven = maven; this.mavenConfiguration = mavenConfiguration; } public List<IMavenProjectImportResult> importProjects(final Collection<MavenProjectInfo> projectInfos, final ProjectImportConfiguration configuration, final IProgressMonitor monitor) throws CoreException { final SubMonitor progress = SubMonitor.convert(monitor, Messages.ProjectConfigurationManager_task_importing, 100); // overall execution context to share repository session data and cache for all projects return maven.execute(new ICallable<List<IMavenProjectImportResult>>() { public List<IMavenProjectImportResult> call(IMavenExecutionContext context, IProgressMonitor monitor) throws CoreException { long t1 = System.currentTimeMillis(); ArrayList<IMavenProjectImportResult> result = new ArrayList<IMavenProjectImportResult>(); ArrayList<IProject> projects = new ArrayList<IProject>(); // first, create all projects with basic configuration for (MavenProjectInfo projectInfo : projectInfos) { if (monitor.isCanceled()) { throw new OperationCanceledException(); } SubMonitor subProgress = SubMonitor.convert(progress.newChild(10), projectInfos.size() * 100); IProject project = create(projectInfo, configuration, subProgress.newChild(100)); result.add(new MavenProjectImportResult(projectInfo, project)); if (project != null) { projects.add(project); } } hideNestedProjectsFromParents(projects); // then configure maven for all projects configureNewMavenProjects(projects, progress.newChild(90)); long t2 = System.currentTimeMillis(); log.info("Project import completed " + ((t2 - t1) / 1000) + " sec"); return result; } }, monitor); } private void setHidden(IResource resource) { try { resource.setHidden(true); } catch (Exception ex) { log.error("Failed to hide resource; " + resource.getLocation().toOSString(), ex); } } /*package*/void hideNestedProjectsFromParents(List<IProject> projects) { if (!MavenPlugin.getMavenConfiguration().isHideFoldersOfNestedProjects()) { return; } // Prevent child project folders from showing up in parent project folders. HashMap<File, IProject> projectFileMap = new HashMap<File, IProject>(); for (IProject project : projects) { projectFileMap.put(project.getLocation().toFile(), project); } for (IProject project : projects) { File projectFile = project.getLocation().toFile(); IProject physicalParentProject = projectFileMap.get(projectFile.getParentFile()); if (physicalParentProject == null) { continue; } IFolder folder = physicalParentProject.getFolder(projectFile.getName()); if (folder.exists()) { setHidden(folder); } } } /*package*/void configureNewMavenProjects(final List<IProject> projects, IProgressMonitor monitor) throws CoreException { final SubMonitor progress = SubMonitor.convert(monitor, Messages.ProjectConfigurationManager_task_configuring, 100); //SubProgressMonitor sub = new SubProgressMonitor(monitor, projects.size()+1); // first, resolve maven dependencies for all projects Set<IFile> pomFiles = new LinkedHashSet<IFile>(); for (IProject project : projects) { pomFiles.add(project.getFile(IMavenConstants.POM_FILE_NAME)); } progress.subTask(Messages.ProjectConfigurationManager_task_refreshing); projectManager.refresh(pomFiles, progress.newChild(75)); // TODO this emits project change events, which may be premature at this point //Creating maven facades SubMonitor subProgress = SubMonitor.convert(progress.newChild(5), projects.size() * 100); List<IMavenProjectFacade> facades = new ArrayList<IMavenProjectFacade>(projects.size()); for (IProject project : projects) { if (progress.isCanceled()) { throw new OperationCanceledException(); } IMavenProjectFacade facade = projectManager.create(project, subProgress.newChild(100)); if (facade != null) { facades.add(facade); } } //MNGECLIPSE-1028 : Sort projects by build order here, //as dependent projects need to be configured before depending projects (in WTP integration for ex.) sortProjects(facades, progress.newChild(5)); //Then, perform detailed project configuration subProgress = SubMonitor.convert(progress.newChild(15), facades.size() * 100); for (IMavenProjectFacade facade : facades) { if (progress.isCanceled()) { throw new OperationCanceledException(); } progress.subTask( NLS.bind(Messages.ProjectConfigurationManager_task_updating, facade.getProject().getName())); MavenProject mavenProject = facade.getMavenProject(subProgress.newChild(5)); ProjectConfigurationRequest request = new ProjectConfigurationRequest(facade, mavenProject); updateProjectConfiguration(request, subProgress.newChild(90)); } } public void sortProjects(List<IMavenProjectFacade> facades, IProgressMonitor monitor) throws CoreException { HashMap<MavenProject, IMavenProjectFacade> mavenProjectToFacadeMap = new HashMap<MavenProject, IMavenProjectFacade>( facades.size()); for (IMavenProjectFacade facade : facades) { mavenProjectToFacadeMap.put(facade.getMavenProject(monitor), facade); } facades.clear(); for (MavenProject mavenProject : maven .getSortedProjects(new ArrayList<MavenProject>(mavenProjectToFacadeMap.keySet()))) { facades.add(mavenProjectToFacadeMap.get(mavenProject)); } } /** * A compatibility proxy stub */ private static interface A { public IAdaptable[] adaptElements(IAdaptable[] objects); } public void updateProjectConfiguration(IProject project, IProgressMonitor monitor) throws CoreException { updateProjectConfiguration(new MavenUpdateRequest(project, mavenConfiguration.isOffline(), false), monitor); } // TODO deprecate this method public void updateProjectConfiguration(MavenUpdateRequest request, IProgressMonitor monitor) throws CoreException { // for now, only allow one project per request. if (request.getPomFiles().size() != 1) { throw new IllegalArgumentException(); } Map<String, IStatus> updateStatus = updateProjectConfiguration(request, true, true, monitor); IStatus status = updateStatus.values().iterator().next(); // only one project if (!status.isOK()) { throw new CoreException(status); } } /** * Returns project name to update status map. * <p/> * TODO promote to API * * @since 1.1 */ public Map<String, IStatus> updateProjectConfiguration(final MavenUpdateRequest request, final boolean updateConfiguration, final boolean cleanProjects, final IProgressMonitor monitor) { return updateProjectConfiguration(request, updateConfiguration, cleanProjects, false/*refreshFromLocal*/, monitor); } /** * Returns project name to update status map. * <p/> * TODO promote to API. TODO decide if workspace or other lock is required during execution of this method. * * @since 1.4 */ public Map<String, IStatus> updateProjectConfiguration(final MavenUpdateRequest request, final boolean updateConfiguration, final boolean cleanProjects, final boolean refreshFromLocal, final IProgressMonitor monitor) { try { return maven.execute(request.isOffline(), request.isForceDependencyUpdate(), new ICallable<Map<String, IStatus>>() { public Map<String, IStatus> call(IMavenExecutionContext context, IProgressMonitor monitor) { return updateProjectConfiguration0(request.getPomFiles(), updateConfiguration, cleanProjects, refreshFromLocal, monitor); } }, monitor); } catch (CoreException ex) { Map<String, IStatus> result = new LinkedHashMap<String, IStatus>(); for (IFile pomFile : request.getPomFiles()) { result.put(pomFile.getProject().getName(), ex.getStatus()); } return result; } } /*package*/Map<String, IStatus> updateProjectConfiguration0(Collection<IFile> pomFiles, boolean updateConfiguration, boolean cleanProjects, boolean refreshFromLocal, IProgressMonitor monitor) { monitor.beginTask(Messages.ProjectConfigurationManager_task_updating_projects, pomFiles.size() * (1 + (updateConfiguration ? 1 : 0) + (cleanProjects ? 1 : 0) + (refreshFromLocal ? 1 : 0))); long l1 = System.currentTimeMillis(); log.info("Update started"); //$NON-NLS-1$ Map<IFile, IMavenProjectFacade> projects = new LinkedHashMap<IFile, IMavenProjectFacade>(); //project names to the errors encountered when updating them Map<String, IStatus> updateStatus = new HashMap<String, IStatus>(); // refresh projects and update all dependencies // this will ensure that project registry is up-to-date on GAV of all projects being updated // TODO this sends multiple update events, rework using low-level registry update methods for (IFile pom : pomFiles) { if (monitor.isCanceled()) { throw new OperationCanceledException(); } IProject project = pom.getProject(); monitor.subTask(project.getName()); try { if (refreshFromLocal) { project.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)); } projectManager.refresh(Collections.singleton(pom), new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)); IMavenProjectFacade facade = projectManager.getProject(project); if (facade != null) { // facade is null if pom.xml cannot be read projects.put(pom, facade); } updateStatus.put(project.getName(), Status.OK_STATUS); } catch (CoreException ex) { updateStatus.put(project.getName(), ex.getStatus()); } } // update project configuration if (updateConfiguration) { Iterator<Entry<IFile, IMavenProjectFacade>> iterator = projects.entrySet().iterator(); while (iterator.hasNext()) { if (monitor.isCanceled()) { throw new OperationCanceledException(); } IMavenProjectFacade facade = iterator.next().getValue(); monitor.subTask(facade.getProject().getName()); SubProgressMonitor submonitor = new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL); try { ProjectConfigurationRequest cfgRequest = new ProjectConfigurationRequest(facade, facade.getMavenProject(submonitor)); updateProjectConfiguration(cfgRequest, submonitor); } catch (CoreException ex) { iterator.remove(); updateStatus.put(facade.getProject().getName(), ex.getStatus()); } } } // rebuild if (cleanProjects) { Iterator<Entry<IFile, IMavenProjectFacade>> iterator = projects.entrySet().iterator(); while (iterator.hasNext()) { if (monitor.isCanceled()) { throw new OperationCanceledException(); } IMavenProjectFacade facade = iterator.next().getValue(); IProject project = facade.getProject(); monitor.subTask(project.getName()); SubProgressMonitor submonitor = new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL); try { // only rebuild projects that were successfully updated IStatus status = updateStatus.get(project.getName()); if (status == null || status.isOK()) { project.build(IncrementalProjectBuilder.CLEAN_BUILD, submonitor); // TODO provide an option to build projects if the workspace is not autobuilding } } catch (CoreException ex) { iterator.remove(); updateStatus.put(project.getName(), ex.getStatus()); } } } long l2 = System.currentTimeMillis(); log.info(NLS.bind("Update completed: {0} sec", ((l2 - l1) / 1000))); //$NON-NLS-1$ return updateStatus; } private void updateProjectConfiguration(final ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException { final IProject project = request.getProject(); long start = System.currentTimeMillis(); final IMavenProjectFacade mavenProjectFacade = request.getMavenProjectFacade(); log.debug("Updating project configuration for {}.", mavenProjectFacade.toString()); //$NON-NLS-1$ addMavenNature(project, monitor); // Configure project file encoding final MavenProject mavenProject = request.getMavenProject(); Properties mavenProperties = mavenProject.getProperties(); String sourceEncoding = mavenProperties.getProperty("project.build.sourceEncoding"); log.debug("Setting encoding for project {}: {}", project.getName(), sourceEncoding); //$NON-NLS-1$ project.setDefaultCharset(sourceEncoding, monitor); MavenExecutionContext executionContext = projectManager.createExecutionContext(mavenProjectFacade.getPom(), mavenProjectFacade.getResolverConfiguration()); executionContext.execute(mavenProject, new ICallable<Void>() { public Void call(IMavenExecutionContext context, IProgressMonitor monitor) throws CoreException { ILifecycleMapping lifecycleMapping = getLifecycleMapping(mavenProjectFacade); if (lifecycleMapping != null) { mavenMarkerManager.deleteMarkers(mavenProjectFacade.getProject(), IMavenConstants.MARKER_CONFIGURATION_ID); lifecycleMapping.configure(request, monitor); LifecycleMappingConfiguration.persist(request.getMavenProjectFacade(), monitor); } else { log.debug("LifecycleMapping is null for project {}", mavenProjectFacade.toString()); //$NON-NLS-1$ } return null; } }, monitor); log.debug("Updated project configuration for {} in {} ms.", mavenProjectFacade.toString(), //$NON-NLS-1$ System.currentTimeMillis() - start); } public void enableMavenNature(final IProject project, ResolverConfiguration configuration, final IProgressMonitor monitor) throws CoreException { monitor.subTask(Messages.ProjectConfigurationManager_task_enable_nature); enableBasicMavenNature(project, configuration, monitor); configureNewMavenProjects(Collections.singletonList(project), monitor); } private void enableBasicMavenNature(IProject project, ResolverConfiguration configuration, IProgressMonitor monitor) throws CoreException { ResolverConfigurationIO.saveResolverConfiguration(project, configuration); // add maven nature even for projects without valid pom.xml file addMavenNature(project, monitor); } private void addMavenNature(IProject project, IProgressMonitor monitor) throws CoreException { if (!project.hasNature(IMavenConstants.NATURE_ID)) { IProjectDescription description = project.getDescription(); String[] prevNatures = description.getNatureIds(); String[] newNatures = new String[prevNatures.length + 1]; System.arraycopy(prevNatures, 0, newNatures, 1, prevNatures.length); newNatures[0] = IMavenConstants.NATURE_ID; description.setNatureIds(newNatures); project.setDescription(description, monitor); } } public void disableMavenNature(IProject project, IProgressMonitor monitor) throws CoreException { monitor.subTask(Messages.ProjectConfigurationManager_task_disable_nature); IMavenProjectFacade facade = projectManager.create(project, monitor); if (facade != null) { ILifecycleMapping lifecycleMapping = getLifecycleMapping(facade); if (lifecycleMapping != null) { ProjectConfigurationRequest request = new ProjectConfigurationRequest(facade, facade.getMavenProject(monitor)); lifecycleMapping.unconfigure(request, monitor); } } // Delete all m2e markers project.deleteMarkers(IMavenConstants.MARKER_ID, true, IResource.DEPTH_INFINITE); // Remove the m2e nature IProjectDescription description = project.getDescription(); ArrayList<String> newNatures = new ArrayList<String>(); for (String natureId : description.getNatureIds()) { if (!IMavenConstants.NATURE_ID.equals(natureId)) { newNatures.add(natureId); } } description.setNatureIds(newNatures.toArray(new String[newNatures.size()])); // Remove the m2e builder removeMavenBuilder(project, description, monitor); project.setDescription(description, null); } public boolean addMavenBuilder(IProject project, IProjectDescription description, IProgressMonitor monitor) throws CoreException { boolean setProjectDescription = false; if (description == null) { description = project.getDescription(); setProjectDescription = true; } // ensure Maven builder is always the last one ICommand mavenBuilder = null; ArrayList<ICommand> newSpec = new ArrayList<ICommand>(); int i = 0; for (ICommand command : description.getBuildSpec()) { if (isMavenBuilderCommand(project, command)) { mavenBuilder = command; if (i == description.getBuildSpec().length - 1) { // This is the maven builder command and it is the last one in the list - there is nothing to change return false; } } else { newSpec.add(command); } i++; } if (mavenBuilder == null) { mavenBuilder = description.newCommand(); mavenBuilder.setBuilderName(IMavenConstants.BUILDER_ID); } newSpec.add(mavenBuilder); description.setBuildSpec(newSpec.toArray(new ICommand[newSpec.size()])); if (setProjectDescription) { project.setDescription(description, monitor); } return true; } public boolean removeMavenBuilder(IProject project, IProjectDescription description, IProgressMonitor monitor) throws CoreException { boolean setProjectDescription = false; if (description == null) { description = project.getDescription(); setProjectDescription = true; } boolean foundMavenBuilder = false; ArrayList<ICommand> newSpec = new ArrayList<ICommand>(); for (ICommand command : description.getBuildSpec()) { if (!isMavenBuilderCommand(project, command)) { newSpec.add(command); } else { foundMavenBuilder = true; } } if (!foundMavenBuilder) { return false; } description.setBuildSpec(newSpec.toArray(new ICommand[newSpec.size()])); if (setProjectDescription) { project.setDescription(description, monitor); } return true; } private boolean isMavenBuilderCommand(IProject project, ICommand command) { return IMavenConstants.BUILDER_ID.equals(command.getBuilderName()); } // project creation /** * Creates simple Maven project * <p> * The following steps are executed in the given order: * <ul> * <li>Creates the workspace project</li> * <li>Adds project to working set</li> * <li>Creates the required folders</li> * <li>Creates the POM</li> * <li>Configures project</li> * </ul> * </p> */ // XXX should use Maven plugin configurations instead of manually specifying folders public void createSimpleProject(IProject project, IPath location, Model model, String[] directories, ProjectImportConfiguration configuration, IProgressMonitor monitor) throws CoreException { String projectName = project.getName(); monitor.beginTask(NLS.bind(Messages.ProjectConfigurationManager_task_creating, projectName), 5); monitor.subTask(Messages.ProjectConfigurationManager_task_creating_workspace); IProjectDescription description = ResourcesPlugin.getWorkspace().newProjectDescription(projectName); description.setLocation(location); project.create(description, monitor); project.open(monitor); monitor.worked(1); hideNestedProjectsFromParents(Collections.singletonList(project)); monitor.worked(1); monitor.subTask(Messages.ProjectConfigurationManager_task_creating_pom); IFile pomFile = project.getFile(IMavenConstants.POM_FILE_NAME); mavenModelManager.createMavenModel(pomFile, model); monitor.worked(1); monitor.subTask(Messages.ProjectConfigurationManager_task_creating_folders); for (int i = 0; i < directories.length; i++) { createFolder(project.getFolder(directories[i]), false); } monitor.worked(1); monitor.subTask(Messages.ProjectConfigurationManager_task_creating_project); enableMavenNature(project, configuration.getResolverConfiguration(), monitor); monitor.worked(1); } /** * Helper method which creates a folder and, recursively, all its parent folders. * * @param folder The folder to create. * @param derived true if folder should be marked as derived * @throws CoreException if creating the given <code>folder</code> or any of its parents fails. */ public static void createFolder(IFolder folder, boolean derived) throws CoreException { // Recurse until we find a parent folder which already exists. if (!folder.exists()) { IContainer parent = folder.getParent(); // First, make sure that all parent folders exist. if (parent != null && !parent.exists()) { createFolder((IFolder) parent, false); } folder.create(true, true, null); } if (folder.isAccessible() && derived) { folder.setDerived(true); } } /** * Creates project structure using Archetype and then imports created project(s) * * @deprecated use * {@link #createArchetypeProjects(IPath, Archetype, String, String, String, String, Properties, ProjectImportConfiguration, IProgressMonitor)} */ @Deprecated public void createArchetypeProject(IProject project, IPath location, Archetype archetype, String groupId, String artifactId, String version, String javaPackage, Properties properties, ProjectImportConfiguration configuration, IProgressMonitor monitor) throws CoreException { createArchetypeProjects(location, archetype, groupId, artifactId, version, javaPackage, properties, configuration, monitor); } /** * Creates project structure using Archetype and then imports created project(s) * * @return an unmodifiable list of created projects. * @since 1.1 */ public List<IProject> createArchetypeProjects(final IPath location, final Archetype archetype, final String groupId, final String artifactId, final String version, final String javaPackage, final Properties properties, final ProjectImportConfiguration configuration, final IProgressMonitor monitor) throws CoreException { return maven.execute(new ICallable<List<IProject>>() { public List<IProject> call(IMavenExecutionContext context, IProgressMonitor monitor) throws CoreException { return createArchetypeProjects0(location, archetype, groupId, artifactId, version, javaPackage, properties, configuration, monitor); } }, monitor); } /*package*/List<IProject> createArchetypeProjects0(IPath location, Archetype archetype, String groupId, String artifactId, String version, String javaPackage, Properties properties, ProjectImportConfiguration configuration, IProgressMonitor monitor) throws CoreException { monitor.beginTask(NLS.bind(Messages.ProjectConfigurationManager_task_creating_project1, artifactId), 2); IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); monitor.subTask(NLS.bind(Messages.ProjectConfigurationManager_task_executing_archetype, archetype.getGroupId(), archetype.getArtifactId())); if (location == null) { // if the project should be created in the workspace, figure out the path location = workspaceRoot.getLocation(); } List<IProject> createdProjects = new ArrayList<IProject>(); try { Artifact artifact = resolveArchetype(archetype, monitor); ArchetypeGenerationRequest request = new ArchetypeGenerationRequest() // .setTransferListener(maven.createTransferListener(monitor)) // .setArchetypeGroupId(artifact.getGroupId()) // .setArchetypeArtifactId(artifact.getArtifactId()) // .setArchetypeVersion(artifact.getVersion()) // .setArchetypeRepository(archetype.getRepository()) // .setGroupId(groupId) // .setArtifactId(artifactId) // .setVersion(version) // .setPackage(javaPackage) // the model does not have a package field .setLocalRepository(maven.getLocalRepository()) // .setRemoteArtifactRepositories(maven.getArtifactRepositories(true)).setProperties(properties) .setOutputDirectory(location.toPortableString()); ArchetypeGenerationResult result = getArchetyper().generateProjectFromArchetype(request); Exception cause = result.getCause(); if (cause != null) { String msg = NLS.bind(Messages.ProjectConfigurationManager_error_unable_archetype, archetype.toString()); log.error(msg, cause); throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, msg, cause)); } monitor.worked(1); // XXX Archetyper don't allow to specify project folder String projectFolder = location.append(artifactId).toFile().getAbsolutePath(); LocalProjectScanner scanner = new LocalProjectScanner(workspaceRoot.getLocation().toFile(), // projectFolder, true, mavenModelManager); scanner.run(monitor); Set<MavenProjectInfo> projectSet = collectProjects(scanner.getProjects()); List<IMavenProjectImportResult> importResults = importProjects(projectSet, configuration, monitor); for (IMavenProjectImportResult r : importResults) { IProject p = r.getProject(); if (p != null && p.exists()) { createdProjects.add(p); } } monitor.worked(1); } catch (CoreException e) { throw e; } catch (InterruptedException e) { throw new CoreException(Status.CANCEL_STATUS); } catch (Exception ex) { throw new CoreException(new Status(IStatus.ERROR, "org.eclipse.m2e", //$NON-NLS-1$ Messages.ProjectConfigurationManager_error_failed, ex)); } return Collections.unmodifiableList(createdProjects); } /** * Apparently, Archetype#generateProjectFromArchetype 2.0-alpha-4 does not attempt to resolve archetype from * configured remote repositories. To compensate, we populate local repo with archetype pom/jar. */ private Artifact resolveArchetype(Archetype a, IProgressMonitor monitor) throws CoreException { ArrayList<ArtifactRepository> repos = new ArrayList<ArtifactRepository>(); repos.addAll(maven.getArtifactRepositories()); // see org.apache.maven.archetype.downloader.DefaultDownloader#download //MNGECLIPSE-1399 use archetype repository too, not just the default ones String artifactRemoteRepository = a.getRepository(); try { if (StringUtils.isBlank(artifactRemoteRepository)) { IMavenConfiguration mavenConfiguration = MavenPlugin.getMavenConfiguration(); if (!mavenConfiguration.isOffline()) { //Try to find the repository from remote catalog if needed final ArchetypeManager archetypeManager = MavenPluginActivator.getDefault() .getArchetypeManager(); RemoteCatalogFactory factory = archetypeManager.findParentCatalogFactory(a, RemoteCatalogFactory.class); if (factory != null) { //Grab the computed remote repository url artifactRemoteRepository = factory.getRepositoryUrl(); a.setRepository(artifactRemoteRepository);//Hopefully will prevent further lookups for the same archetype } } } if (StringUtils.isNotBlank(artifactRemoteRepository)) { ArtifactRepository archetypeRepository = maven.createArtifactRepository(a.getArtifactId() + "-repo", //$NON-NLS-1$ a.getRepository().trim()); repos.add(0, archetypeRepository);//If the archetype doesn't exist locally, this will be the first remote repo to be searched. } maven.resolve(a.getGroupId(), a.getArtifactId(), a.getVersion(), "pom", null, repos, monitor); //$NON-NLS-1$ return maven.resolve(a.getGroupId(), a.getArtifactId(), a.getVersion(), "jar", null, repos, monitor); //$NON-NLS-1$ } catch (CoreException e) { StringBuilder sb = new StringBuilder(); sb.append(Messages.ProjectConfigurationManager_error_resolve).append(a.getGroupId()).append(':') .append(a.getArtifactId()).append(':').append(a.getVersion()); sb.append(Messages.ProjectConfigurationManager_error_resolve2); throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, sb.toString(), e)); } } private org.apache.maven.archetype.Archetype getArchetyper() { return MavenPluginActivator.getDefault().getArchetype(); } public Set<MavenProjectInfo> collectProjects(Collection<MavenProjectInfo> projects) { // TODO what does this do? return new LinkedHashSet<MavenProjectInfo>() { private static final long serialVersionUID = 1L; public Set<MavenProjectInfo> collectProjects(Collection<MavenProjectInfo> projects) { for (MavenProjectInfo projectInfo : projects) { log.info("Collecting project info " + projectInfo); add(projectInfo); collectProjects(projectInfo.getProjects()); } return this; } }.collectProjects(projects); } public ISchedulingRule getRule() { return ResourcesPlugin.getWorkspace().getRuleFactory().buildRule(); } /*package*/IProject create(MavenProjectInfo projectInfo, ProjectImportConfiguration configuration, IProgressMonitor monitor) throws CoreException { IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspaceRoot root = workspace.getRoot(); File pomFile = projectInfo.getPomFile(); Model model = projectInfo.getModel(); if (model == null) { model = maven.readModel(pomFile); projectInfo.setModel(model); } String projectName = configuration.getProjectName(model); File projectDir = pomFile.getParentFile(); String projectParent = projectDir.getParentFile().getAbsolutePath(); if (projectInfo.getBasedirRename() == MavenProjectInfo.RENAME_REQUIRED) { File newProject = new File(projectDir.getParent(), projectName); if (!projectDir.equals(newProject)) { boolean renamed = projectDir.renameTo(newProject); if (!renamed) { StringBuilder msg = new StringBuilder(); msg.append(NLS.bind(Messages.ProjectConfigurationManager_error_rename, projectDir.getAbsolutePath())).append('.'); if (newProject.exists()) { msg.append(NLS.bind(Messages.ProjectConfigurationManager_error_targetDir, newProject.getAbsolutePath())); } throw new CoreException( new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, msg.toString(), null)); } projectInfo.setPomFile(getCanonicalPomFile(newProject)); projectDir = newProject; } } else { if (projectParent.equals(root.getLocation().toFile().getAbsolutePath())) { // immediately under workspace root, project name must match filesystem directory name projectName = projectDir.getName(); } } monitor.subTask(NLS.bind(Messages.ProjectConfigurationManager_task_importing2, projectName)); IProject project = root.getProject(projectName); if (project.exists()) { log.error("Project " + projectName + " already exists"); return null; } if (projectDir.equals(root.getLocation().toFile())) { log.error("Can't create project " + projectName + " at Workspace folder"); return null; } if (projectParent.equals(root.getLocation().toFile().getAbsolutePath())) { project.create(monitor); } else { IProjectDescription description = workspace.newProjectDescription(projectName); description.setLocation(new Path(projectDir.getAbsolutePath())); project.create(description, monitor); } if (!project.isOpen()) { project.open(monitor); } ResolverConfiguration resolverConfiguration = configuration.getResolverConfiguration(); enableBasicMavenNature(project, resolverConfiguration, monitor); // create empty/marker persistent configuration // 1 project with bad pom.xml gets imported in workspace // 1a empty/marker configuration is persisted here // 2 project's pom.xml gets fixed // 3 mavenProjectChanged below compares empty/marker with the real config and creates config marker LifecycleMappingConfiguration.persistEmpty(project); return project; } private File getCanonicalPomFile(File projectDir) throws CoreException { try { return new File(projectDir.getCanonicalFile(), IMavenConstants.POM_FILE_NAME); } catch (IOException ex) { throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, // NLS.bind(Messages.ProjectConfigurationManager_0, projectDir.getAbsolutePath()), null)); } } public void mavenProjectChanged(MavenProjectChangedEvent[] events, IProgressMonitor monitor) { for (MavenProjectChangedEvent event : events) { try { IMavenProjectFacade facade = event.getMavenProject(); ILifecycleMapping lifecycleMapping = getLifecycleMapping(facade); if (lifecycleMapping != null) { for (AbstractProjectConfigurator configurator : lifecycleMapping.getProjectConfigurators(facade, monitor)) { //MNGECLIPSE-2004 : only send the relevant event to the configurator configurator.mavenProjectChanged(event, monitor); } } if (facade != null) { LifecycleMappingConfiguration oldConfiguration = LifecycleMappingConfiguration.restore(facade, monitor); if (oldConfiguration != null && LifecycleMappingFactory.isLifecycleMappingChanged(facade, oldConfiguration, monitor)) { mavenMarkerManager.addMarker(facade.getProject(), IMavenConstants.MARKER_CONFIGURATION_ID, Messages.ProjectConfigurationUpdateRequired, -1, IMarker.SEVERITY_ERROR); } } else { IMavenProjectFacade oldFacade = event.getOldMavenProject(); if (oldFacade != null) { //LifecycleMappingConfiguration.remove(oldFacade); mavenMarkerManager.deleteMarkers(oldFacade.getPom(), IMavenConstants.MARKER_CONFIGURATION_ID); } } } catch (CoreException e) { log.error(e.getMessage(), e); } } } public ILifecycleMapping getLifecycleMapping(IMavenProjectFacade projectFacade) throws CoreException { if (projectFacade == null) { return null; } return LifecycleMappingFactory.getLifecycleMapping(projectFacade); } public void resourceChanged(IResourceChangeEvent event) { if (event.getType() == IResourceChangeEvent.PRE_DELETE && event.getResource() instanceof IProject) { LifecycleMappingConfiguration.remove((IProject) event.getResource()); } } public ResolverConfiguration getResolverConfiguration(IProject project) { return ResolverConfigurationIO.readResolverConfiguration(project); } public boolean setResolverConfiguration(IProject project, ResolverConfiguration configuration) { return ResolverConfigurationIO.saveResolverConfiguration(project, configuration); } }