Java tutorial
package org.apache.maven.plugins.invoker; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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. */ import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Model; import org.apache.maven.model.Parent; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.shared.artifact.install.ArtifactInstaller; import org.apache.maven.shared.dependencies.DefaultDependableCoordinate; import org.apache.maven.shared.dependencies.resolve.DependencyResolver; import org.apache.maven.shared.dependencies.resolve.DependencyResolverException; import org.apache.maven.shared.repository.RepositoryManager; import org.codehaus.plexus.util.FileUtils; /** * Installs the project artifacts of the main build into the local repository as a preparation to run the sub projects. * More precisely, all artifacts of the project itself, all its locally reachable parent POMs and all its dependencies * from the reactor will be installed to the local repository. * * @since 1.2 * @author Paul Gier * @author Benjamin Bentmann * */ // CHECKSTYLE_OFF: LineLength @Mojo(name = "install", defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = true) // CHECKSTYLE_ON: LineLength public class InstallMojo extends AbstractMojo { /** * Maven artifact install component to copy artifacts to the local repository. */ @Component private ArtifactInstaller installer; @Component private RepositoryManager repositoryManager; /** * The component used to create artifacts. */ @Component private ArtifactFactory artifactFactory; /** */ @Parameter(property = "localRepository", required = true, readonly = true) private ArtifactRepository localRepository; /** * The path to the local repository into which the project artifacts should be installed for the integration tests. * If not set, the regular local repository will be used. To prevent soiling of your regular local repository with * possibly broken artifacts, it is strongly recommended to use an isolated repository for the integration tests * (e.g. <code>${project.build.directory}/it-repo</code>). */ @Parameter(property = "invoker.localRepositoryPath", defaultValue = "${session.localRepository.basedir}", required = true) private File localRepositoryPath; /** * The current Maven project. */ @Parameter(defaultValue = "${project}", readonly = true, required = true) private MavenProject project; @Parameter(defaultValue = "${session}", readonly = true, required = true) private MavenSession session; /** * The set of Maven projects in the reactor build. */ @Parameter(defaultValue = "${reactorProjects}", readonly = true) private Collection<MavenProject> reactorProjects; /** * A flag used to disable the installation procedure. This is primarily intended for usage from the command line to * occasionally adjust the build. * * @since 1.4 */ @Parameter(property = "invoker.skip", defaultValue = "false") private boolean skipInstallation; /** * The identifiers of already installed artifacts, used to avoid multiple installation of the same artifact. */ private Collection<String> installedArtifacts; /** * The identifiers of already copied artifacts, used to avoid multiple installation of the same artifact. */ private Collection<String> copiedArtifacts; /** * Extra dependencies that need to be installed on the local repository.<BR> * Format: * * <pre> * groupId:artifactId:version:type:classifier * </pre> * * Examples: * * <pre> * org.apache.maven.plugins:maven-clean-plugin:2.4:maven-plugin * org.apache.maven.plugins:maven-clean-plugin:2.4:jar:javadoc * </pre> * * If the type is 'maven-plugin' the plugin will try to resolve the artifact using plugin remote repositories, * instead of using artifact remote repositories. * * @since 1.6 */ @Parameter private String[] extraArtifacts; /** */ @Component private DependencyResolver resolver; private ProjectBuildingRequest projectBuildingRequest; /** * Performs this mojo's tasks. * * @throws MojoExecutionException If the artifacts could not be installed. */ public void execute() throws MojoExecutionException { if (skipInstallation) { getLog().info("Skipping artifact installation per configuration."); return; } createTestRepository(); installedArtifacts = new HashSet<>(); copiedArtifacts = new HashSet<>(); installProjectDependencies(project, reactorProjects); installProjectParents(project); installProjectArtifacts(project); installExtraArtifacts(extraArtifacts); } /** * Creates the local repository for the integration tests. If the user specified a custom repository location, the * custom repository will have the same identifier, layout and policies as the real local repository. That means * apart from the location, the custom repository will be indistinguishable from the real repository such that its * usage is transparent to the integration tests. * * @return The local repository for the integration tests, never <code>null</code>. * @throws MojoExecutionException If the repository could not be created. */ private void createTestRepository() throws MojoExecutionException { if (!localRepositoryPath.exists() && !localRepositoryPath.mkdirs()) { throw new MojoExecutionException("Failed to create directory: " + localRepositoryPath); } projectBuildingRequest = repositoryManager.setLocalRepositoryBasedir(session.getProjectBuildingRequest(), localRepositoryPath); } /** * Installs the specified artifact to the local repository. Note: This method should only be used for artifacts that * originate from the current (reactor) build. Artifacts that have been grabbed from the user's local repository * should be installed to the test repository via {@link #copyArtifact(File, Artifact)}. * * @param file The file associated with the artifact, must not be <code>null</code>. This is in most cases the value * of <code>artifact.getFile()</code> with the exception of the main artifact from a project with * packaging "pom". Projects with packaging "pom" have no main artifact file. They have however artifact * metadata (e.g. site descriptors) which needs to be installed. * @param artifact The artifact to install, must not be <code>null</code>. * @throws MojoExecutionException If the artifact could not be installed (e.g. has no associated file). */ private void installArtifact(File file, Artifact artifact) throws MojoExecutionException { try { if (file == null) { throw new IllegalStateException("Artifact has no associated file: " + artifact.getId()); } if (!file.isFile()) { throw new IllegalStateException("Artifact is not fully assembled: " + file); } if (installedArtifacts.add(artifact.getId())) { artifact.setFile(file); installer.install(projectBuildingRequest, localRepositoryPath, Collections.singletonList(artifact)); } else { getLog().debug("Not re-installing " + artifact + ", " + file); } } catch (Exception e) { throw new MojoExecutionException("Failed to install artifact: " + artifact, e); } } /** * Installs the specified artifact to the local repository. This method serves basically the same purpose as * {@link #installArtifact(File, Artifact)} but is meant for artifacts that have been resolved * from the user's local repository (and not the current build outputs). The subtle difference here is that * artifacts from the repository have already undergone transformations and these manipulations should not be redone * by the artifact installer. For this reason, this method performs plain copy operations to install the artifacts. * * @param file The file associated with the artifact, must not be <code>null</code>. * @param artifact The artifact to install, must not be <code>null</code>. * @throws MojoExecutionException If the artifact could not be installed (e.g. has no associated file). */ private void copyArtifact(File file, Artifact artifact) throws MojoExecutionException { try { if (file == null) { throw new IllegalStateException("Artifact has no associated file: " + artifact.getId()); } if (!file.isFile()) { throw new IllegalStateException("Artifact is not fully assembled: " + file); } if (copiedArtifacts.add(artifact.getId())) { File destination = new File(localRepositoryPath, repositoryManager.getPathForLocalArtifact(projectBuildingRequest, artifact)); getLog().debug("Installing " + file + " to " + destination); copyFileIfDifferent(file, destination); MetadataUtils.createMetadata(destination, artifact); } else { getLog().debug("Not re-installing " + artifact + ", " + file); } } catch (Exception e) { throw new MojoExecutionException("Failed to stage artifact: " + artifact, e); } } private void copyFileIfDifferent(File src, File dst) throws IOException { if (src.lastModified() != dst.lastModified() || src.length() != dst.length()) { FileUtils.copyFile(src, dst); dst.setLastModified(src.lastModified()); } } /** * Installs the main artifact and any attached artifacts of the specified project to the local repository. * * @param mvnProject The project whose artifacts should be installed, must not be <code>null</code>. * @throws MojoExecutionException If any artifact could not be installed. */ private void installProjectArtifacts(MavenProject mvnProject) throws MojoExecutionException { try { // Install POM (usually attached as metadata but that happens only as a side effect of the Install Plugin) installProjectPom(mvnProject); // Install the main project artifact (if the project has one, e.g. has no "pom" packaging) Artifact mainArtifact = mvnProject.getArtifact(); if (mainArtifact.getFile() != null) { installArtifact(mainArtifact.getFile(), mainArtifact); } // Install any attached project artifacts Collection<Artifact> attachedArtifacts = mvnProject.getAttachedArtifacts(); for (Artifact attachedArtifact : attachedArtifacts) { installArtifact(attachedArtifact.getFile(), attachedArtifact); } } catch (Exception e) { throw new MojoExecutionException("Failed to install project artifacts: " + mvnProject, e); } } /** * Installs the (locally reachable) parent POMs of the specified project to the local repository. The parent POMs * from the reactor must be installed or the forked IT builds will fail when using a clean repository. * * @param mvnProject The project whose parent POMs should be installed, must not be <code>null</code>. * @throws MojoExecutionException If any POM could not be installed. */ private void installProjectParents(MavenProject mvnProject) throws MojoExecutionException { try { for (MavenProject parent = mvnProject.getParent(); parent != null; parent = parent.getParent()) { if (parent.getFile() == null) { copyParentPoms(parent.getGroupId(), parent.getArtifactId(), parent.getVersion()); break; } installProjectPom(parent); } } catch (Exception e) { throw new MojoExecutionException("Failed to install project parents: " + mvnProject, e); } } /** * Installs the POM of the specified project to the local repository. * * @param mvnProject The project whose POM should be installed, must not be <code>null</code>. * @throws MojoExecutionException If the POM could not be installed. */ private void installProjectPom(MavenProject mvnProject) throws MojoExecutionException { try { Artifact pomArtifact = null; if ("pom".equals(mvnProject.getPackaging())) { pomArtifact = mvnProject.getArtifact(); } if (pomArtifact == null) { pomArtifact = artifactFactory.createProjectArtifact(mvnProject.getGroupId(), mvnProject.getArtifactId(), mvnProject.getVersion()); } installArtifact(mvnProject.getFile(), pomArtifact); } catch (Exception e) { throw new MojoExecutionException("Failed to install POM: " + mvnProject, e); } } /** * Installs the dependent projects from the reactor to the local repository. The dependencies on other modules from * the reactor must be installed or the forked IT builds will fail when using a clean repository. * * @param mvnProject The project whose dependent projects should be installed, must not be <code>null</code>. * @param reactorProjects The set of projects in the reactor build, must not be <code>null</code>. * @throws MojoExecutionException If any dependency could not be installed. */ private void installProjectDependencies(MavenProject mvnProject, Collection<MavenProject> reactorProjects) throws MojoExecutionException { // ... into dependencies that were resolved from reactor projects ... Collection<String> dependencyProjects = new LinkedHashSet<>(); collectAllProjectReferences(mvnProject, dependencyProjects); // index available reactor projects Map<String, MavenProject> projects = new HashMap<>(reactorProjects.size()); for (MavenProject reactorProject : reactorProjects) { String projectId = reactorProject.getGroupId() + ':' + reactorProject.getArtifactId() + ':' + reactorProject.getVersion(); projects.put(projectId, reactorProject); } // group transitive dependencies (even those that don't contribute to the class path like POMs) ... Collection<Artifact> artifacts = mvnProject.getArtifacts(); // ... and those that were resolved from the (local) repo Collection<Artifact> dependencyArtifacts = new LinkedHashSet<>(); for (Artifact artifact : artifacts) { // workaround for MNG-2961 to ensure the base version does not contain a timestamp artifact.isSnapshot(); String projectId = artifact.getGroupId() + ':' + artifact.getArtifactId() + ':' + artifact.getBaseVersion(); if (!projects.containsKey(projectId)) { dependencyArtifacts.add(artifact); } } // install dependencies try { // copy dependencies that where resolved from the local repo for (Artifact artifact : dependencyArtifacts) { copyArtifact(artifact); } // install dependencies that were resolved from the reactor for (String projectId : dependencyProjects) { MavenProject dependencyProject = projects.get(projectId); installProjectArtifacts(dependencyProject); installProjectParents(dependencyProject); } } catch (Exception e) { throw new MojoExecutionException("Failed to install project dependencies: " + mvnProject, e); } } protected void collectAllProjectReferences(MavenProject project, Collection<String> dependencyProjects) { for (MavenProject reactorProject : project.getProjectReferences().values()) { String projectId = reactorProject.getGroupId() + ':' + reactorProject.getArtifactId() + ':' + reactorProject.getVersion(); if (dependencyProjects.add(projectId)) { collectAllProjectReferences(reactorProject, dependencyProjects); } } } protected boolean isInProjectReferences(Collection<MavenProject> references, MavenProject project) { if (references == null || references.isEmpty()) { return false; } for (MavenProject mavenProject : references) { if (StringUtils.equals(mavenProject.getId(), project.getId())) { return true; } } return false; } private void copyArtifact(Artifact artifact) throws MojoExecutionException { copyPoms(artifact); Artifact depArtifact = artifactFactory.createArtifactWithClassifier(artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion(), artifact.getType(), artifact.getClassifier()); File artifactFile = artifact.getFile(); copyArtifact(artifactFile, depArtifact); } private void copyPoms(Artifact artifact) throws MojoExecutionException { Artifact pomArtifact = artifactFactory.createProjectArtifact(artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion()); File pomFile = new File(localRepository.getBasedir(), localRepository.pathOf(pomArtifact)); if (pomFile.isFile()) { copyArtifact(pomFile, pomArtifact); copyParentPoms(pomFile); } } /** * Installs all parent POMs of the specified POM file that are available in the local repository. * * @param pomFile The path to the POM file whose parents should be installed, must not be <code>null</code>. * @throws MojoExecutionException If any (existing) parent POM could not be installed. */ private void copyParentPoms(File pomFile) throws MojoExecutionException { Model model = PomUtils.loadPom(pomFile); Parent parent = model.getParent(); if (parent != null) { copyParentPoms(parent.getGroupId(), parent.getArtifactId(), parent.getVersion()); } } /** * Installs the specified POM and all its parent POMs to the local repository. * * @param groupId The group id of the POM which should be installed, must not be <code>null</code>. * @param artifactId The artifact id of the POM which should be installed, must not be <code>null</code>. * @param version The version of the POM which should be installed, must not be <code>null</code>. * @throws MojoExecutionException If any (existing) parent POM could not be installed. */ private void copyParentPoms(String groupId, String artifactId, String version) throws MojoExecutionException { Artifact pomArtifact = artifactFactory.createProjectArtifact(groupId, artifactId, version); if (installedArtifacts.contains(pomArtifact.getId()) || copiedArtifacts.contains(pomArtifact.getId())) { getLog().debug("Not re-installing " + pomArtifact); return; } File pomFile = new File(localRepository.getBasedir(), localRepository.pathOf(pomArtifact)); if (pomFile.isFile()) { copyArtifact(pomFile, pomArtifact); copyParentPoms(pomFile); } } private void installExtraArtifacts(String[] extraArtifacts) throws MojoExecutionException { if (extraArtifacts == null) { return; } for (String extraArtifact : extraArtifacts) { String[] gav = extraArtifact.split(":"); if (gav.length < 3 || gav.length > 5) { throw new MojoExecutionException("Invalid artifact " + extraArtifact); } String groupId = gav[0]; String artifactId = gav[1]; String version = gav[2]; String type = "jar"; if (gav.length > 3) { type = gav[3]; } String classifier = null; if (gav.length == 5) { classifier = gav[4]; } DefaultDependableCoordinate coordinate = new DefaultDependableCoordinate(); try { coordinate.setGroupId(groupId); coordinate.setArtifactId(artifactId); coordinate.setVersion(version); coordinate.setType(type); coordinate.setClassifier(classifier); resolver.resolveDependencies(projectBuildingRequest, coordinate, null); } catch (DependencyResolverException e) { throw new MojoExecutionException("Unable to resolve dependencies for: " + coordinate, e); } } } }