Java tutorial
/* * Copyright 2014 Andrew Schurman * * Licensed 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. */ package org.debian.dependency.builders; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Model; import org.apache.maven.model.building.DefaultModelBuildingRequest; import org.apache.maven.model.building.ModelBuilder; import org.apache.maven.model.building.ModelBuildingException; import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.repository.RepositorySystem; import org.apache.maven.shared.invoker.DefaultInvocationRequest; import org.apache.maven.shared.invoker.InvocationOutputHandler; import org.apache.maven.shared.invoker.InvocationRequest; import org.apache.maven.shared.invoker.InvocationResult; import org.apache.maven.shared.invoker.Invoker; import org.apache.maven.shared.invoker.MavenInvocationException; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.StringUtils; import org.debian.dependency.ServicePackage; import org.debian.dependency.sources.Source; /** * Builds a Maven project using an embedded (forked) version of Maven. */ @Component(role = SourceBuilder.class, hint = "maven2") public class ForkedMavenBuilder extends AbstractBuildFileSourceBuilder implements SourceBuilder { private static final String POM_INCLUDES = "**/pom.xml"; private static final String POM_EXCLUDES = "**/src/**"; private static final Pattern ARTIFACT_PATTERN = Pattern .compile("^(?<groupId>[^:]*):(?<artifactId>[^:]*):(?<type>[^:]*)" + "(?::(?<classifier>[^:]*))?:(?<version>[^:]*)$"); @Requirement private ModelBuilder modelBuilder; @Requirement private Invoker invoker; @Requirement private RepositorySystem repositorySystem; @Override public Set<Artifact> build(final Artifact artifact, final Source source, final File localRepository) throws ArtifactBuildException { Properties properties = new Properties(); properties.setProperty("maven.ext.class.path", getOriginClassPath(ServicePackage.class).toString()); Model model = findProjectModel(artifact, source.getLocation()); InvocationRequest request = new DefaultInvocationRequest().setPomFile(model.getPomFile()) .setGoals(Arrays.asList("verify")).setOffline(true).setRecursive(false) // in case we are dealing with a pom packaging .setProperties(properties).setOutputHandler(new InvocationOutputHandler() { @Override public void consumeLine(final String line) { getLogger().info(line); } }).setErrorHandler(new InvocationOutputHandler() { @Override public void consumeLine(final String line) { getLogger().error(line); } }).setLocalRepositoryDirectory(localRepository); try { InvocationResult result = invoker.execute(request); if (result.getExecutionException() == null && result.getExitCode() == 0) { return getBuiltArtifacts( new File(model.getBuild().getDirectory(), ServicePackage.PROJECT_ARTIFACT_REPORT_NAME)); } else if (result.getExecutionException() != null) { throw new ArtifactBuildException("Unable to build proejct", result.getExecutionException()); } throw new ArtifactBuildException("Execution did not complete successfully"); } catch (MavenInvocationException e) { throw new ArtifactBuildException("Unable to build project", e); } catch (IOException e) { throw new ArtifactBuildException(e); } } @SuppressWarnings("PMD.PreserveStackTrace") private static File getOriginClassPath(final Class<?> clazz) throws ArtifactBuildException { try { URL sourceUrl; try { sourceUrl = clazz.getProtectionDomain().getCodeSource().getLocation(); } catch (SecurityException e) { URL location = clazz.getResource(clazz.getSimpleName() + ".class"); if ("file".equals(location.getProtocol())) { File file = new File(location.toURI()).getParentFile(); for (int i = 0; i < StringUtils.countMatches(clazz.getPackage().getName(), ".") + 1; ++i) { file = file.getParentFile(); } return file; } else if ("jar".equals(location.getProtocol())) { sourceUrl = new URL(location.toExternalForm().substring("jar".length(), location.toExternalForm().lastIndexOf('!'))); } else { // this exception has nothing to do with the security exception throw new IllegalStateException("Unhandled location: " + location); } } if (!"file".equals(sourceUrl.getProtocol())) { throw new IllegalStateException("Not local location: " + sourceUrl); } return new File(sourceUrl.toURI().getPath()); } catch (URISyntaxException e) { throw new ArtifactBuildException(e); } catch (MalformedURLException e) { throw new ArtifactBuildException(e); } } private Set<Artifact> getBuiltArtifacts(final File reportFile) throws IOException, ArtifactBuildException { if (!reportFile.exists()) { return Collections.emptySet(); } Properties artifacts = new Properties(); FileInputStream stream = new FileInputStream(reportFile); try { artifacts.load(stream); } finally { IOUtil.close(stream); } Set<Artifact> result = new HashSet<Artifact>(); for (String specifier : artifacts.stringPropertyNames()) { Matcher matcher = ARTIFACT_PATTERN.matcher(specifier); if (!matcher.find()) { throw new ArtifactBuildException("Illegal artifact specifier: " + specifier); } String groupId = matcher.group("groupId"); String artifactId = matcher.group("artifactId"); String version = matcher.group("version"); String type = matcher.group("type"); String classifier = matcher.group("classifier"); Artifact artifact; if (classifier == null) { artifact = repositorySystem.createArtifact(groupId, artifactId, version, type); } else { artifact = repositorySystem.createArtifactWithClassifier(groupId, artifactId, version, type, classifier); } artifact.setFile(new File(artifacts.getProperty(specifier))); result.add(artifact); } return result; } private Model findProjectModel(final Artifact artifact, final File basedir) throws ArtifactBuildException { return findProjectModel(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), basedir); } private Model findProjectModel(final String groupId, final String artifactId, final String version, final File basedir) throws ArtifactBuildException { try { for (File pom : findBuildFiles(basedir)) { try { ModelBuildingRequest request = new DefaultModelBuildingRequest().setPomFile(pom) .setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL); Model model = modelBuilder.build(request).getEffectiveModel(); if (model.getGroupId().equals(groupId) && model.getArtifactId().equals(artifactId) && model.getVersion().equals(version)) { return model; } } catch (ModelBuildingException e) { getLogger().debug("Ignoring unreadable pom file:" + pom, e); } } } catch (IOException e) { throw new ArtifactBuildException(e); } throw new ArtifactBuildException("Unable to find reactor containing " + groupId + ":" + artifactId + ":" + version + " under " + basedir); } @Override protected List<String> getIncludes() { return Arrays.asList(POM_INCLUDES); } @Override protected List<String> getExcludes() { List<String> result = new ArrayList<String>(super.getExcludes()); result.add(POM_EXCLUDES); return result; } @Override protected int getPriorityOffset() { return PRIORITY_STEP / 2; } }