Java tutorial
/* * Copyright (c) 2011, Olivier Lamy, Talend * 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. */ package org.jvnet.hudson.plugins.mavendepsupdate; import hudson.FilePath; import hudson.PluginFirstClassLoader; import hudson.remoting.Callable; import org.apache.commons.lang.StringUtils; import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.artifact.InvalidRepositoryException; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.execution.DefaultMavenExecutionRequest; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenExecutionRequestPopulationException; import org.apache.maven.execution.MavenExecutionRequestPopulator; import org.apache.maven.model.Plugin; import org.apache.maven.model.Profile; import org.apache.maven.plugin.MavenPluginManager; import org.apache.maven.project.DefaultDependencyResolutionRequest; import org.apache.maven.project.DependencyResolutionException; import org.apache.maven.project.DependencyResolutionResult; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuilder; import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.project.ProjectBuildingResult; import org.apache.maven.project.ProjectDependenciesResolver; import org.apache.maven.project.ProjectSorter; import org.apache.maven.repository.RepositorySystem; import org.apache.maven.repository.internal.MavenRepositorySystemSession; import org.apache.maven.settings.building.DefaultSettingsBuildingRequest; import org.apache.maven.settings.building.SettingsBuilder; import org.apache.maven.settings.building.SettingsBuildingException; import org.apache.maven.settings.building.SettingsBuildingRequest; import org.apache.maven.settings.building.SettingsBuildingResult; import org.codehaus.plexus.DefaultContainerConfiguration; import org.codehaus.plexus.DefaultPlexusContainer; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.PlexusContainerException; import org.codehaus.plexus.classworlds.ClassWorld; import org.codehaus.plexus.classworlds.realm.ClassRealm; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.jvnet.hudson.plugins.mavendepsupdate.util.Maven3Utils; import org.jvnet.hudson.plugins.mavendepsupdate.util.ReactorReader; import org.jvnet.hudson.plugins.mavendepsupdate.util.SnapshotTransfertListener; import org.sonatype.aether.repository.LocalRepository; import org.sonatype.aether.repository.RepositoryPolicy; import org.sonatype.aether.repository.WorkspaceReader; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.logging.Logger; /** * @author Olivier Lamy * @since 1.1 */ public class MavenUpdateChecker implements Callable<MavenUpdateCheckerResult, IOException> { private static final Logger LOGGER = Logger.getLogger(MavenUpdateChecker.class.getName()); //private final FilePath mavenShadedJarPath; private final String rootPomPath; private final String localRepoPath; private final boolean checkPlugins; private final String projectWorkspace; private final boolean masterRun; private final Long lastBuildTime; //--------------------------------------- // optionnal parameters //--------------------------------------- // use for master run private PluginFirstClassLoader classLoaderParent; private FilePath alternateSettings; private FilePath globalSettings; private Properties userProperties; private List<String> activeProfiles = new ArrayList<String>(); private String jdkHome; private MavenUpdateCheckerResult mavenUpdateCheckerResult = new MavenUpdateCheckerResult(); private String mavenHome; public MavenUpdateChecker(String rootPomPath, String localRepoPath, boolean checkPlugins, String projectWorkspace, boolean masterRun, String mavenHome, String jdkHome, long lastBuildTime) { this.rootPomPath = rootPomPath; this.localRepoPath = localRepoPath; this.checkPlugins = checkPlugins; this.projectWorkspace = projectWorkspace; this.masterRun = masterRun; this.mavenHome = mavenHome; this.jdkHome = jdkHome; this.lastBuildTime = lastBuildTime; } public MavenUpdateCheckerResult call() throws IOException { ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); try { PluginFirstClassLoader pluginFirstClassLoader = getPluginFirstClassLoader(); Thread.currentThread().setContextClassLoader(pluginFirstClassLoader); String classLoaderName = getClass().getClassLoader().toString(); mavenUpdateCheckerResult.addDebugLine(classLoaderName); PlexusContainer plexusContainer = getPlexusContainer(pluginFirstClassLoader); Thread.currentThread().setContextClassLoader(plexusContainer.getContainerRealm()); mavenUpdateCheckerResult.addDebugLine("ok for new DefaultPlexusContainer( conf ) "); mavenUpdateCheckerResult.addDebugLine("Thread.currentThread().getContextClassLoader() " + Thread.currentThread().getContextClassLoader()); mavenUpdateCheckerResult.addDebugLine("Thread.currentThread().getContextClassLoader().parent " + (Thread.currentThread().getContextClassLoader().getParent() == null ? "null" : Thread.currentThread().getContextClassLoader().getParent().toString())); mavenUpdateCheckerResult.addDebugLine( "classLoader urls " + Arrays.asList(plexusContainer.getContainerRealm().getURLs())); ProjectBuilder projectBuilder = plexusContainer.lookup(ProjectBuilder.class); // FIXME load userProperties from the job Properties userProperties = this.userProperties == null ? new Properties() : this.userProperties; userProperties.put("java.home", jdkHome); ProjectBuildingRequest projectBuildingRequest = getProjectBuildingRequest(userProperties, plexusContainer); // check plugins too projectBuildingRequest.setProcessPlugins(true); // force snapshots update projectBuildingRequest.setResolveDependencies(true); List<ProjectBuildingResult> projectBuildingResults = projectBuilder .build(Arrays.asList(new File(rootPomPath)), true, projectBuildingRequest); ProjectDependenciesResolver projectDependenciesResolver = plexusContainer .lookup(ProjectDependenciesResolver.class); List<MavenProject> mavenProjects = new ArrayList<MavenProject>(projectBuildingResults.size()); for (ProjectBuildingResult projectBuildingResult : projectBuildingResults) { mavenProjects.add(projectBuildingResult.getProject()); } ProjectSorter projectSorter = new ProjectSorter(mavenProjects); // use the projects reactor model as a workspaceReader // if reactors are not available remotely dependencies resolve will failed // due to artifact not found final Map<String, MavenProject> projectMap = getProjectMap(mavenProjects); WorkspaceReader reactorRepository = new ReactorReader(projectMap); MavenRepositorySystemSession mavenRepositorySystemSession = (MavenRepositorySystemSession) projectBuildingRequest .getRepositorySession(); mavenRepositorySystemSession.setUpdatePolicy(RepositoryPolicy.UPDATE_POLICY_ALWAYS); mavenRepositorySystemSession.setWorkspaceReader(reactorRepository); MavenPluginManager mavenPluginManager = plexusContainer.lookup(MavenPluginManager.class); for (MavenProject mavenProject : projectSorter.getSortedProjects()) { LOGGER.info("resolve dependencies for project " + mavenProject.getId()); DefaultDependencyResolutionRequest dependencyResolutionRequest = new DefaultDependencyResolutionRequest( mavenProject, mavenRepositorySystemSession); try { DependencyResolutionResult dependencyResolutionResult = projectDependenciesResolver .resolve(dependencyResolutionRequest); } catch (DependencyResolutionException e) { mavenUpdateCheckerResult.addDebugLine(e.getMessage()); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); mavenUpdateCheckerResult.addDebugLine("skip:" + sw.toString()); } if (checkPlugins) { for (Plugin plugin : mavenProject.getBuildPlugins()) { // only for SNAPSHOT if (StringUtils.endsWith(plugin.getVersion(), "SNAPSHOT")) { mavenPluginManager.getPluginDescriptor(plugin, mavenProject.getRemotePluginRepositories(), mavenRepositorySystemSession); } } } } SnapshotTransfertListener snapshotTransfertListener = (SnapshotTransfertListener) projectBuildingRequest .getRepositorySession().getTransferListener(); if (snapshotTransfertListener.isSnapshotDownloaded()) { mavenUpdateCheckerResult.addFilesUpdatedNames(snapshotTransfertListener.getSnapshots()); } } catch (Exception e) { mavenUpdateCheckerResult.addDebugLine(e.getMessage()); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); mavenUpdateCheckerResult.addDebugLine("skip:" + sw.toString()); } finally { Thread.currentThread().setContextClassLoader(originalClassLoader); } return mavenUpdateCheckerResult; } private PlexusContainer getPlexusContainer(PluginFirstClassLoader pluginFirstClassLoader) throws MalformedURLException, IOException, InterruptedException, PlexusContainerException { if (this.masterRun) { return Maven3Utils.getPlexusContainer(this.classLoaderParent); } DefaultContainerConfiguration conf = new DefaultContainerConfiguration(); ClassWorld world = new ClassWorld(); ClassRealm classRealm = new ClassRealm(world, "project-building", pluginFirstClassLoader); // olamy yup hackish but it's needed for plexus-shim for (URL url : pluginFirstClassLoader.getURLs()) { classRealm.addURL(url); mavenUpdateCheckerResult.addDebugLine("add url " + url.toExternalForm()); } conf.setRealm(classRealm); mavenUpdateCheckerResult.addDebugLine("before return new DefaultPlexusContainer( conf ) "); return new DefaultPlexusContainer(conf); } PluginFirstClassLoader getPluginFirstClassLoader() throws MalformedURLException, IOException, InterruptedException { PluginFirstClassLoader pluginFirstClassLoader = new PluginFirstClassLoader(); pluginFirstClassLoader.setParent( this.masterRun ? this.classLoaderParent : Thread.currentThread().getContextClassLoader()); // parent first as jenkins classes must be loaded first in a remote env pluginFirstClassLoader.setParentFirst(!this.masterRun); //pluginFirstClassLoader.addPathFiles( new ArrayList<File>( 0 ) ); mavenUpdateCheckerResult.addDebugLine("pluginFirstClassLoader end"); return pluginFirstClassLoader; } ProjectBuildingRequest getProjectBuildingRequest(Properties userProperties, PlexusContainer plexusContainer) throws ComponentLookupException, SettingsBuildingException, MavenExecutionRequestPopulationException, InvalidRepositoryException { MavenExecutionRequest request = new DefaultMavenExecutionRequest(); request.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_DEBUG); request.setWorkspaceReader(new ReactorReader(new HashMap<String, MavenProject>(0))); SettingsBuilder settingsBuilder = plexusContainer.lookup(SettingsBuilder.class); RepositorySystem repositorySystem = plexusContainer.lookup(RepositorySystem.class); org.sonatype.aether.RepositorySystem repoSystem = plexusContainer .lookup(org.sonatype.aether.RepositorySystem.class); SettingsBuildingRequest settingsRequest = new DefaultSettingsBuildingRequest(); if (globalSettings != null) { mavenUpdateCheckerResult.addDebugLine("globalSettings " + globalSettings.getRemote()); settingsRequest.setGlobalSettingsFile(new File(globalSettings.getRemote())); } else { File globalSettings = new File(mavenHome, "conf/settings.xml"); if (globalSettings.exists()) { settingsRequest.setGlobalSettingsFile(globalSettings); } } if (alternateSettings != null) { mavenUpdateCheckerResult.addDebugLine("alternateSettings " + alternateSettings.getRemote()); settingsRequest.setUserSettingsFile(new File(alternateSettings.getRemote())); request.setUserSettingsFile(new File(alternateSettings.getRemote())); } else { File defaultUserSettings = new File(new File(System.getProperty("user.home"), ".m2"), "settings.xml"); settingsRequest.setUserSettingsFile(defaultUserSettings); request.setUserSettingsFile(defaultUserSettings); } settingsRequest.setSystemProperties(System.getProperties()); settingsRequest.setUserProperties(userProperties); SettingsBuildingResult settingsBuildingResult = settingsBuilder.build(settingsRequest); MavenExecutionRequestPopulator executionRequestPopulator = plexusContainer .lookup(MavenExecutionRequestPopulator.class); executionRequestPopulator.populateFromSettings(request, settingsBuildingResult.getEffectiveSettings()); executionRequestPopulator.populateDefaults(request); MavenRepositorySystemSession session = new MavenRepositorySystemSession(); session.setUpdatePolicy(RepositoryPolicy.UPDATE_POLICY_ALWAYS); SnapshotTransfertListener snapshotTransfertListener = new SnapshotTransfertListener(this.lastBuildTime); session.setTransferListener(snapshotTransfertListener); LocalRepository localRepo = getLocalRepo(settingsBuildingResult); session.setLocalRepositoryManager(repoSystem.newLocalRepositoryManager(localRepo)); ArtifactRepository localArtifactRepository = getLocalArtifactRepo(settingsBuildingResult, repositorySystem); request.setLocalRepository(localArtifactRepository); if (this.activeProfiles != null && !this.activeProfiles.isEmpty()) { for (String id : this.activeProfiles) { Profile p = new Profile(); p.setId(id); p.setSource("cli"); request.addProfile(p); request.addActiveProfile(id); } } ProjectBuildingRequest projectBuildingRequest = request.getProjectBuildingRequest(); return projectBuildingRequest.setRepositorySession(session); } private ArtifactRepository getLocalArtifactRepo(SettingsBuildingResult settingsBuildingResult, RepositorySystem repositorySystem) throws InvalidRepositoryException { ArtifactRepository localArtifactRepository = null; if (StringUtils.isEmpty(localRepoPath)) { if (settingsBuildingResult.getEffectiveSettings().getLocalRepository() == null) { localArtifactRepository = repositorySystem .createLocalRepository(new File(System.getProperty("user.home"), ".m2/repository")); } else { localArtifactRepository = repositorySystem.createLocalRepository( new File(settingsBuildingResult.getEffectiveSettings().getLocalRepository())); } } else { localArtifactRepository = repositorySystem.createLocalRepository(new File(localRepoPath)); } return localArtifactRepository; } private LocalRepository getLocalRepo(SettingsBuildingResult settingsBuildingResult) { LocalRepository localRepo = null; if (StringUtils.isEmpty(localRepoPath)) { localRepo = new LocalRepository(settingsBuildingResult.getEffectiveSettings().getLocalRepository()); if (localRepo.getBasedir() == null) { localRepo = new LocalRepository(new File(System.getProperty("user.home"), ".m2").getAbsolutePath()); } } else { localRepo = new LocalRepository(localRepoPath); } if (localRepo == null || localRepo.getBasedir() == null) { LOGGER.warning("could not locate local repo"); } return localRepo; } private Map<String, MavenProject> getProjectMap(List<MavenProject> projects) { Map<String, MavenProject> index = new LinkedHashMap<String, MavenProject>(); for (MavenProject project : projects) { String projectId = ArtifactUtils.key(project.getGroupId(), project.getArtifactId(), project.getVersion()); index.put(projectId, project); } return index; } public void setClassLoaderParent(PluginFirstClassLoader classLoaderParent) { this.classLoaderParent = classLoaderParent; } public void setAlternateSettings(FilePath alternateSettings) { this.alternateSettings = alternateSettings; } public void setGlobalSettings(FilePath globalSettings) { this.globalSettings = globalSettings; } public void setUserProperties(Properties userProperties) { this.userProperties = userProperties; } public void setActiveProfiles(List<String> activeProfiles) { this.activeProfiles = activeProfiles; } }