/* * Copyright 2001-2005 The Apache Software Foundation. * * 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.kie.scanner.embedder; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map.Entry; import java.util.Properties; import org.apache.maven.DefaultMaven; import org.apache.maven.Maven; import org.apache.maven.artifact.InvalidRepositoryException; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.execution.DefaultMavenExecutionRequest; import org.apache.maven.execution.DefaultMavenExecutionResult; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenExecutionRequestPopulationException; import org.apache.maven.execution.MavenExecutionRequestPopulator; import org.apache.maven.execution.MavenExecutionResult; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Profile; import org.apache.maven.model.building.ModelSource; import org.apache.maven.plugin.LegacySupport; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuilder; import org.apache.maven.project.ProjectBuildingException; import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.project.ProjectBuildingResult; import org.apache.maven.repository.RepositorySystem; import org.apache.maven.settings.Settings; import org.apache.maven.settings.building.DefaultSettingsBuildingRequest; import org.apache.maven.settings.building.FileSettingsSource; 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.SettingsSource; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.util.Os; import org.eclipse.aether.RepositorySystemSession; import org.kie.scanner.MavenRepositoryConfiguration; import org.slf4j.LoggerFactory; import static org.drools.core.util.IoUtils.*; public class MavenEmbedder { private static final org.slf4j.Logger log = LoggerFactory.getLogger( MavenEmbedder.class ); public static final File DEFAULT_GLOBAL_SETTINGS_FILE = new File( System.getProperty( "maven.home", System.getProperty( "user.dir", "" ) ), "conf/settings.xml" ); private final MavenRequest mavenRequest; private final ComponentProvider componentProvider; private MavenExecutionRequest mavenExecutionRequest; private MavenSession mavenSession; public MavenEmbedder( MavenRequest mavenRequest ) throws MavenEmbedderException { this( Thread.currentThread().getContextClassLoader(), null, mavenRequest ); } public MavenEmbedder( ClassLoader mavenClassLoader, ClassLoader parent, MavenRequest mavenRequest ) throws MavenEmbedderException { this( mavenRequest, MavenEmbedderUtils.buildComponentProvider( mavenClassLoader, parent, mavenRequest ) ); } private MavenEmbedder( MavenRequest mavenRequest, ComponentProvider componentProvider ) throws MavenEmbedderException { this.mavenRequest = mavenRequest; this.componentProvider = componentProvider; try { this.mavenExecutionRequest = this.buildMavenExecutionRequest( mavenRequest ); RepositorySystemSession rss = ( (DefaultMaven) componentProvider.lookup( Maven.class ) ).newRepositorySession( mavenExecutionRequest ); mavenSession = new MavenSession( componentProvider.getPlexusContainer(), rss, mavenExecutionRequest, new DefaultMavenExecutionResult() ); componentProvider.lookup( LegacySupport.class ).setSession( mavenSession ); } catch ( MavenEmbedderException e ) { log.error( "Unable to build MavenEmbedder", e ); throw e; } catch ( ComponentLookupException e ) { log.error( "Unable to build MavenEmbedder", e ); throw new MavenEmbedderException( e.getMessage(), e ); } } protected MavenExecutionRequest buildMavenExecutionRequest( MavenRequest mavenRequest ) throws MavenEmbedderException, ComponentLookupException { MavenExecutionRequest mavenExecutionRequest = new DefaultMavenExecutionRequest(); if ( mavenRequest.getGlobalSettingsFile() != null ) { mavenExecutionRequest.setGlobalSettingsFile( new File( mavenRequest.getGlobalSettingsFile() ) ); } SettingsSource userSettings = mavenRequest.getUserSettingsSource(); if ( userSettings != null ) { if ( userSettings instanceof FileSettingsSource ) { mavenExecutionRequest.setUserSettingsFile( ( (FileSettingsSource) userSettings ).getSettingsFile() ); } else { try { mavenExecutionRequest.setUserSettingsFile( copyInTempFile( userSettings.getInputStream(), "xml" ) ); } catch ( IOException ioe ) { log.warn( "Unable to use maven settings defined in " + userSettings, ioe ); } } } try { componentProvider.lookup( MavenExecutionRequestPopulator.class ).populateFromSettings( mavenExecutionRequest, getSettings() ); componentProvider.lookup( MavenExecutionRequestPopulator.class ).populateDefaults( mavenExecutionRequest ); } catch ( MavenExecutionRequestPopulationException e ) { throw new MavenEmbedderException( e.getMessage(), e ); } ArtifactRepository localRepository = getLocalRepository(); mavenExecutionRequest.setLocalRepository( localRepository ); mavenExecutionRequest.setLocalRepositoryPath( localRepository.getBasedir() ); mavenExecutionRequest.setOffline( mavenRequest.isOffline() ); mavenExecutionRequest.setUpdateSnapshots( mavenRequest.isUpdateSnapshots() ); // TODO check null and create a console one ? mavenExecutionRequest.setTransferListener( mavenRequest.getTransferListener() ); mavenExecutionRequest.setCacheNotFound( mavenRequest.isCacheNotFound() ); mavenExecutionRequest.setCacheTransferError( true ); mavenExecutionRequest.setUserProperties( mavenRequest.getUserProperties() ); mavenExecutionRequest.getSystemProperties().putAll( System.getProperties() ); if ( mavenRequest.getSystemProperties() != null ) { mavenExecutionRequest.getSystemProperties().putAll( mavenRequest.getSystemProperties() ); } mavenExecutionRequest.getSystemProperties().putAll( getEnvVars() ); if ( mavenRequest.getProfiles() != null && !mavenRequest.getProfiles().isEmpty() ) { for ( String id : mavenRequest.getProfiles() ) { Profile p = new Profile(); p.setId( id ); p.setSource( "cli" ); mavenExecutionRequest.addProfile( p ); mavenExecutionRequest.addActiveProfile( id ); } } MavenRepositoryConfiguration mavenRepoConf = getMavenRepositoryConfiguration(); //DROOLS-899: Copy repositories defined in settings to execution request for ( ArtifactRepository artifactRepository : mavenRepoConf.getArtifactRepositoriesForRequest() ) { mavenExecutionRequest.addRemoteRepository( artifactRepository ); } mavenExecutionRequest.setProxies( mavenRepoConf.getProxies() ); mavenExecutionRequest.setLoggingLevel( mavenRequest.getLoggingLevel() ); componentProvider.lookup( Logger.class ).setThreshold( mavenRequest.getLoggingLevel() ); mavenExecutionRequest.setExecutionListener( mavenRequest.getExecutionListener() ) .setInteractiveMode( mavenRequest.isInteractive() ) .setGlobalChecksumPolicy( mavenRequest.getGlobalChecksumPolicy() ) .setGoals( mavenRequest.getGoals() ); if ( mavenRequest.getPom() != null ) { mavenExecutionRequest.setPom( new File( mavenRequest.getPom() ) ); } if ( mavenRequest.getWorkspaceReader() != null ) { mavenExecutionRequest.setWorkspaceReader( mavenRequest.getWorkspaceReader() ); } return mavenExecutionRequest; } protected MavenRepositoryConfiguration getMavenRepositoryConfiguration() { return MavenSettings.getMavenRepositoryConfiguration(); } private Properties getEnvVars() { Properties envVars = new Properties(); boolean caseSensitive = !Os.isFamily( Os.FAMILY_WINDOWS ); for ( Entry<String, String> entry : System.getenv().entrySet() ) { String key = "env." + ( caseSensitive ? entry.getKey() : entry.getKey().toUpperCase( Locale.ENGLISH ) ); envVars.setProperty( key, entry.getValue() ); } return envVars; } public Settings getSettings() throws MavenEmbedderException, ComponentLookupException { SettingsBuildingRequest settingsBuildingRequest = new DefaultSettingsBuildingRequest(); if ( this.mavenRequest.getGlobalSettingsFile() != null ) { settingsBuildingRequest.setGlobalSettingsFile( new File( this.mavenRequest.getGlobalSettingsFile() ) ); } else { settingsBuildingRequest.setGlobalSettingsFile( DEFAULT_GLOBAL_SETTINGS_FILE ); } if ( this.mavenRequest.getUserSettingsSource() != null ) { settingsBuildingRequest.setUserSettingsSource( this.mavenRequest.getUserSettingsSource() ); } else { SettingsSource userSettingsSource = MavenSettings.getUserSettingsSource(); if ( userSettingsSource != null ) { settingsBuildingRequest.setUserSettingsSource( userSettingsSource ); } } settingsBuildingRequest.setUserProperties( this.mavenRequest.getUserProperties() ); settingsBuildingRequest.getSystemProperties().putAll( System.getProperties() ); settingsBuildingRequest.getSystemProperties().putAll( this.mavenRequest.getSystemProperties() ); settingsBuildingRequest.getSystemProperties().putAll( getEnvVars() ); try { return componentProvider.lookup( SettingsBuilder.class ).build( settingsBuildingRequest ).getEffectiveSettings(); } catch ( SettingsBuildingException e ) { throw new MavenEmbedderException( e.getMessage(), e ); } } public ArtifactRepository getLocalRepository() throws ComponentLookupException { try { String localRepositoryPath = getLocalRepositoryPath(); if ( localRepositoryPath != null ) { return componentProvider.lookup( RepositorySystem.class ).createLocalRepository( new File( localRepositoryPath ) ); } return componentProvider.lookup( RepositorySystem.class ).createLocalRepository( RepositorySystem.defaultUserLocalRepository ); } catch ( InvalidRepositoryException e ) { // never happened throw new IllegalStateException( e ); } } public String getLocalRepositoryPath() { String path = null; try { Settings settings = getSettings(); path = settings.getLocalRepository(); } catch ( MavenEmbedderException e ) { // ignore } catch ( ComponentLookupException e ) { // ignore } if ( this.mavenRequest.getLocalRepositoryPath() != null ) { path = this.mavenRequest.getLocalRepositoryPath(); } if ( path == null ) { path = RepositorySystem.defaultUserLocalRepository.getAbsolutePath(); } return path; } // ---------------------------------------------------------------------- // Project // ---------------------------------------------------------------------- public MavenProject readProject( final InputStream mavenProjectStream ) throws ProjectBuildingException, MavenEmbedderException { ModelSource modelSource = new ModelSource() { @Override public InputStream getInputStream() throws IOException { return mavenProjectStream; } @Override public String getLocation() { return ""; } }; ClassLoader originalCl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( componentProvider.getSystemClassLoader() ); ProjectBuilder projectBuilder = componentProvider.lookup( ProjectBuilder.class ); // BZ-1007894: Check if added dependencies are resolvable. ProjectBuildingResult result = projectBuilder.build( modelSource, getProjectBuildingRequest() ); if ( result != null && result.getDependencyResolutionResult() != null && !result.getDependencyResolutionResult().getCollectionErrors().isEmpty() ) { // A dependency resolution error has been produced. It can contains some error. Throw the first one to the client, so the user will fix every one sequentially. Exception depedencyResolutionException = result.getDependencyResolutionResult().getCollectionErrors().get( 0 ); if ( depedencyResolutionException != null ) { throw new MavenEmbedderException( depedencyResolutionException.getMessage(), depedencyResolutionException ); } } return result.getProject(); } catch ( ComponentLookupException e ) { throw new MavenEmbedderException( e.getMessage(), e ); } finally { Thread.currentThread().setContextClassLoader( originalCl ); try { mavenProjectStream.close(); } catch ( IOException e ) { } } } public MavenProject readProject( File mavenProject ) throws ProjectBuildingException, MavenEmbedderException { List<MavenProject> projects = readProjects( mavenProject, false ); return projects == null || projects.isEmpty() ? null : projects.get( 0 ); } public List<MavenProject> readProjects( File mavenProject, boolean recursive ) throws ProjectBuildingException, MavenEmbedderException { ClassLoader originalCl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( componentProvider.getSystemClassLoader() ); List<ProjectBuildingResult> results = buildProjects( mavenProject, recursive ); List<MavenProject> projects = new ArrayList<MavenProject>( results.size() ); for ( ProjectBuildingResult result : results ) { projects.add( result.getProject() ); } return projects; } finally { Thread.currentThread().setContextClassLoader( originalCl ); } } public List<ProjectBuildingResult> buildProjects( File mavenProject, boolean recursive ) throws ProjectBuildingException, MavenEmbedderException { ClassLoader originalCl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( componentProvider.getSystemClassLoader() ); ProjectBuilder projectBuilder = componentProvider.lookup( ProjectBuilder.class ); return projectBuilder.build( Collections.singletonList( mavenProject ), recursive, getProjectBuildingRequest() ); } catch ( ComponentLookupException e ) { throw new MavenEmbedderException( e.getMessage(), e ); } finally { Thread.currentThread().setContextClassLoader( originalCl ); } } private ProjectBuildingRequest getProjectBuildingRequest() throws ComponentLookupException { ProjectBuildingRequest projectBuildingRequest = this.mavenExecutionRequest.getProjectBuildingRequest(); projectBuildingRequest.setValidationLevel( this.mavenRequest.getValidationLevel() ); RepositorySystemSession repositorySystemSession = componentProvider.getRepositorySystemSession( mavenExecutionRequest ); projectBuildingRequest.setRepositorySession( repositorySystemSession ); projectBuildingRequest.setProcessPlugins( this.mavenRequest.isProcessPlugins() ); projectBuildingRequest.setResolveDependencies( this.mavenRequest.isResolveDependencies() ); return projectBuildingRequest; } public MavenSession getMavenSession() { return mavenSession; } public MavenExecutionRequest getMavenExecutionRequest() { return mavenExecutionRequest; } public void dispose() { PlexusContainer plexusContainer = componentProvider.getPlexusContainer(); if ( plexusContainer != null ) { plexusContainer.dispose(); } } public MavenExecutionResult execute( final MavenRequest mavenRequest ) throws MavenEmbedderException { final ClassLoader originalCl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( componentProvider.getSystemClassLoader() ); final Maven maven = componentProvider.lookup( Maven.class ); return maven.execute( buildMavenExecutionRequest( mavenRequest ) ); } catch ( final MavenEmbedderException e ) { log.error( "An MavenEmbedderException occurred during maven execution.", e ); throw e; } catch ( final Throwable e ) { log.error( "An exception occurred during maven execution.", e ); throw new MavenEmbedderException( e.getMessage(), e ); } finally { Thread.currentThread().setContextClassLoader( originalCl ); } } }