Java tutorial
/* * Copyright 2000-2009 JetBrains s.r.o. * * 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.jetbrains.maven.embedder; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.annotation.Nonnull; import org.apache.maven.DefaultMaven; import org.apache.maven.Maven; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.handler.ArtifactHandler; import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; import org.apache.maven.artifact.manager.DefaultWagonManager; import org.apache.maven.artifact.manager.WagonManager; import org.apache.maven.artifact.metadata.ArtifactMetadataSource; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.ArtifactRepositoryFactory; import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; import org.apache.maven.artifact.repository.DefaultArtifactRepository; import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; import org.apache.maven.artifact.resolver.ArtifactNotFoundException; import org.apache.maven.artifact.resolver.ArtifactResolutionException; import org.apache.maven.artifact.resolver.ArtifactResolutionResult; import org.apache.maven.artifact.resolver.ArtifactResolver; import org.apache.maven.artifact.resolver.DefaultArtifactResolver; import org.apache.maven.artifact.resolver.ResolutionListener; import org.apache.maven.execution.DefaultMavenExecutionRequest; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.ReactorManager; import org.apache.maven.extension.ExtensionManager; import org.apache.maven.model.Extension; import org.apache.maven.model.Plugin; import org.apache.maven.monitor.event.DefaultEventDispatcher; import org.apache.maven.monitor.event.DefaultEventMonitor; import org.apache.maven.monitor.event.EventDispatcher; import org.apache.maven.plugin.PluginManager; import org.apache.maven.profiles.DefaultProfileManager; import org.apache.maven.profiles.ProfileManager; import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProjectBuilder; import org.apache.maven.project.ProjectBuilderConfiguration; import org.apache.maven.project.interpolation.ModelInterpolationException; import org.apache.maven.settings.MavenSettingsBuilder; import org.apache.maven.settings.Mirror; import org.apache.maven.settings.Proxy; import org.apache.maven.settings.RuntimeInfo; import org.apache.maven.settings.Server; import org.apache.maven.settings.Settings; import org.codehaus.classworlds.ClassWorld; import org.codehaus.plexus.DefaultPlexusContainer; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.PlexusContainerException; import org.codehaus.plexus.component.repository.ComponentDescriptor; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.codehaus.plexus.logging.BaseLoggerManager; import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException; public class MavenEmbedder { private static final String PROP_MAVEN_HOME = "maven.home"; private final DefaultPlexusContainer myContainer; private final Settings mySettings; private final Logger myLogger; private final MavenEmbedderSettings myEmbedderSettings; private final ArtifactRepository myLocalRepository; private MavenEmbedder(@Nonnull DefaultPlexusContainer container, @Nonnull Settings settings, @Nonnull Logger logger, @Nonnull MavenEmbedderSettings embedderSettings) { myContainer = container; mySettings = settings; myLogger = logger; myEmbedderSettings = embedderSettings; myLocalRepository = createLocalRepository(embedderSettings); loadSettings(); } private void loadSettings() { // copied from DefaultMaven.resolveParameters // copied because using original code spoils something in the container and configuration are get messed and not picked up. WagonManager wagonManager = getComponent(WagonManager.class); wagonManager.setOnline(!mySettings.isOffline()); if (wagonManager instanceof DefaultWagonManager) { ((DefaultWagonManager) wagonManager).setHttpUserAgent("Apache-Maven/2.2"); } Proxy proxy = mySettings.getActiveProxy(); if (proxy != null && proxy.getHost() != null) { String pass = decrypt(proxy.getPassword()); wagonManager.addProxy(proxy.getProtocol(), proxy.getHost(), proxy.getPort(), proxy.getUsername(), pass, proxy.getNonProxyHosts()); } for (Object each : mySettings.getServers()) { Server server = (Server) each; String passWord = decrypt(server.getPassword()); String passPhrase = decrypt(server.getPassphrase()); wagonManager.addAuthenticationInfo(server.getId(), server.getUsername(), passWord, server.getPrivateKey(), passPhrase); wagonManager.addPermissionInfo(server.getId(), server.getFilePermissions(), server.getDirectoryPermissions()); if (server.getConfiguration() != null) { wagonManager.addConfiguration(server.getId(), (Xpp3Dom) server.getConfiguration()); } } for (Object each : mySettings.getMirrors()) { Mirror mirror = (Mirror) each; if (mirror.getUrl() == null) { continue; } wagonManager.addMirror(mirror.getId(), mirror.getMirrorOf(), mirror.getUrl()); } // end copied from DefaultMaven.resolveParameters } private String decrypt(String pass) { try { pass = getComponent(SecDispatcher.class, "maven").decrypt(pass); } catch (SecDispatcherException e) { MavenEmbedderLog.LOG.warn(e); } return pass; } private ArtifactRepository createLocalRepository(MavenEmbedderSettings generalSettings) { ArtifactRepositoryLayout layout = getComponent(ArtifactRepositoryLayout.class, "default"); ArtifactRepositoryFactory factory = getComponent(ArtifactRepositoryFactory.class); String url = mySettings.getLocalRepository(); if (!url.startsWith("file:")) { url = "file://" + url; } ArtifactRepository localRepository = new DefaultArtifactRepository("local", url, layout); boolean snapshotPolicySet = mySettings.isOffline(); if (!snapshotPolicySet && generalSettings.getSnapshotUpdatePolicy() == MavenEmbedderSettings.UpdatePolicy.ALWAYS_UPDATE) { factory.setGlobalUpdatePolicy(ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS); } factory.setGlobalChecksumPolicy(ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN); return localRepository; } @Nonnull public ArtifactRepository getLocalRepository() { return myLocalRepository; } @Nonnull public File getLocalRepositoryFile() { return new File(myLocalRepository.getBasedir()); } public Settings getSettings() { return mySettings; } @Nonnull public MavenExecutionResult resolveProject(@Nonnull final File file, @Nonnull final List<String> activeProfiles, @Nonnull final List<String> inactiveProfiles) { return resolveProject(file, activeProfiles, inactiveProfiles, Collections.<ResolutionListener>emptyList()); } @Nonnull public MavenExecutionResult resolveProject(@Nonnull final File file, @Nonnull final List<String> activeProfiles, @Nonnull final List<String> inactiveProfiles, List<ResolutionListener> listeners) { MavenExecutionRequest request = createRequest(file, activeProfiles, inactiveProfiles, Collections.<String>emptyList()); ProjectBuilderConfiguration config = request.getProjectBuilderConfiguration(); request.getGlobalProfileManager().loadSettingsProfiles(mySettings); ProfileManager globalProfileManager = request.getGlobalProfileManager(); globalProfileManager.loadSettingsProfiles(request.getSettings()); List<Exception> exceptions = new ArrayList<Exception>(); MavenProject project = null; try { // copied from DefaultMavenProjectBuilder.buildWithDependencies MavenProjectBuilder builder = getComponent(MavenProjectBuilder.class); project = builder.build(new File(file.getPath()), config); builder.calculateConcreteState(project, config, false); // copied from DefaultLifecycleExecutor.execute findExtensions(project); // end copied from DefaultLifecycleExecutor.execute Artifact projectArtifact = project.getArtifact(); Map managedVersions = project.getManagedVersionMap(); ArtifactMetadataSource metadataSource = getComponent(ArtifactMetadataSource.class); project.setDependencyArtifacts( project.createArtifacts(getComponent(ArtifactFactory.class), null, null)); ArtifactResolver resolver = getComponent(ArtifactResolver.class); ArtifactResolutionResult result = resolver.resolveTransitively(project.getDependencyArtifacts(), projectArtifact, managedVersions, myLocalRepository, project.getRemoteArtifactRepositories(), metadataSource, null, listeners); project.setArtifacts(result.getArtifacts()); // end copied from DefaultMavenProjectBuilder.buildWithDependencies } catch (Exception e) { return handleException(e); } return new MavenExecutionResult(project, exceptions); } private void findExtensions(MavenProject project) { // end copied from DefaultLifecycleExecutor.findExtensions ExtensionManager extensionManager = getComponent(ExtensionManager.class); for (Object each : project.getBuildExtensions()) { try { extensionManager.addExtension((Extension) each, project, myLocalRepository); } catch (PlexusContainerException e) { MavenEmbedderLog.LOG.error(e); } catch (ArtifactResolutionException e) { MavenEmbedderLog.LOG.error(e); } catch (ArtifactNotFoundException e) { MavenEmbedderLog.LOG.error(e); } } extensionManager.registerWagons(); Map handlers = findArtifactTypeHandlers(project); getComponent(ArtifactHandlerManager.class).addHandlers(handlers); } @SuppressWarnings({ "unchecked" }) private Map findArtifactTypeHandlers(MavenProject project) { // end copied from DefaultLifecycleExecutor.findExtensions Map result = new HashMap(); for (Object each : project.getBuildPlugins()) { Plugin eachPlugin = (Plugin) each; if (eachPlugin.isExtensions()) { try { PluginManager pluginManager = getComponent(PluginManager.class); pluginManager.verifyPlugin(eachPlugin, project, mySettings, myLocalRepository); result.putAll(pluginManager.getPluginComponents(eachPlugin, ArtifactHandler.ROLE)); } catch (Exception e) { MavenEmbedderLog.LOG.info(e); continue; } for (Object o : result.values()) { ArtifactHandler handler = (ArtifactHandler) o; if (project.getPackaging().equals(handler.getPackaging())) { project.getArtifact().setArtifactHandler(handler); } } } } return result; } public void resolve(@Nonnull final Artifact artifact, @Nonnull final List<ArtifactRepository> repos) throws ArtifactResolutionException, ArtifactNotFoundException { getComponent(ArtifactResolver.class).resolve(artifact, repos, myLocalRepository); } public Set<Artifact> resolveTransitively(@Nonnull Set<Artifact> toResolve, @Nonnull List<ArtifactRepository> repos) throws ArtifactResolutionException, ArtifactNotFoundException { Artifact project = getComponent(ArtifactFactory.class).createBuildArtifact("temp", "temp", "666", "pom"); return getComponent(ArtifactResolver.class).resolveTransitively(toResolve, project, Collections.EMPTY_MAP, myLocalRepository, repos, getComponent(ArtifactMetadataSource.class)).getArtifacts(); } @Nonnull public MavenExecutionResult execute(@Nonnull final File file, @Nonnull final List<String> activeProfiles, @Nonnull final List<String> inactiveProfiles, @Nonnull final List<String> goals, @Nonnull final List<String> selectedProjects, boolean alsoMake, boolean alsoMakeDependents) { try { MavenExecutionRequest request = createRequest(file, activeProfiles, inactiveProfiles, goals); if (!selectedProjects.isEmpty()) { request.setRecursive(true); request.setSelectedProjects(selectedProjects); if (alsoMake && alsoMakeDependents) { request.setMakeBehavior(ReactorManager.MAKE_BOTH_MODE); } else if (alsoMake) { request.setMakeBehavior(ReactorManager.MAKE_MODE); } else if (alsoMakeDependents) { request.setMakeBehavior(ReactorManager.MAKE_DEPENDENTS_MODE); } } Maven maven = getComponent(Maven.class); Method method = maven.getClass().getDeclaredMethod("doExecute", MavenExecutionRequest.class, EventDispatcher.class); method.setAccessible(true); ReactorManager reactor = (ReactorManager) method.invoke(maven, request, request.getEventDispatcher()); return new MavenExecutionResult(reactor.getTopLevelProject(), Collections.<Exception>emptyList()); } catch (InvocationTargetException e) { return handleException(e.getTargetException()); } catch (NoSuchMethodException e) { throw new RuntimeException(e); // should never happen } catch (IllegalAccessException e) { throw new RuntimeException(e); // should never happen } } @Nonnull public MavenExecutionResult readProjectWithModules(@Nonnull final File file, List<String> activeProfiles, List<String> inactiveProfiles) { MavenExecutionRequest request = createRequest(file, activeProfiles, inactiveProfiles, Collections.<String>emptyList()); request.getGlobalProfileManager().loadSettingsProfiles(mySettings); request.setRecursive(true); return readProject(request); } @Nonnull private MavenExecutionResult readProject(@Nonnull final MavenExecutionRequest request) { ProfileManager globalProfileManager = request.getGlobalProfileManager(); globalProfileManager.loadSettingsProfiles(request.getSettings()); MavenProject rootProject = null; final List<Exception> exceptions = new ArrayList<Exception>(); Object result = null; try { final File pomFile = new File(request.getPomFile()); if (!pomFile.exists()) { throw new FileNotFoundException("File doesn't exist: " + pomFile.getPath()); } final Method getProjectsMethod = DefaultMaven.class.getDeclaredMethod("getProjects", MavenExecutionRequest.class); getProjectsMethod.setAccessible(true); Maven maven = getComponent(Maven.class); result = getProjectsMethod.invoke(maven, request); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { return handleException(e.getTargetException()); } catch (Exception e) { return handleException(e); } if (result != null) { MavenProjectBuilder builder = getComponent(MavenProjectBuilder.class); for (Object p : (List) result) { MavenProject project = (MavenProject) p; try { builder.calculateConcreteState(project, request.getProjectBuilderConfiguration(), false); } catch (ModelInterpolationException e) { exceptions.add(e); } if (project.isExecutionRoot()) { rootProject = project; } } if (rootProject == null && exceptions.isEmpty()) { throw new RuntimeException("Could't build project for unknown reason"); } } return new MavenExecutionResult(rootProject, exceptions); } @Nonnull public MavenExecutionResult readProject(@Nonnull final File file, @Nonnull final List<String> activeProfiles, @Nonnull final List<String> inactiveProfiles) { MavenExecutionRequest request = createRequest(file, activeProfiles, inactiveProfiles, Collections.<String>emptyList()); request.getGlobalProfileManager().loadSettingsProfiles(mySettings); request.setRecursive(false); return readProject(request); } private MavenExecutionRequest createRequest(File file, List<String> activeProfiles, List<String> inactiveProfiles, List<String> goals) { Properties executionProperties = myEmbedderSettings.getProperties(); if (executionProperties == null) { executionProperties = new Properties(); } DefaultEventDispatcher dispatcher = new DefaultEventDispatcher(); dispatcher.addEventMonitor(new DefaultEventMonitor(myLogger)); // subclassing because in DefaultMavenExecutionRequest field isRecursive is always false MavenExecutionRequest result = new DefaultMavenExecutionRequest(myLocalRepository, mySettings, dispatcher, goals, file.getParent(), createProfileManager(activeProfiles, inactiveProfiles, executionProperties), executionProperties, new Properties(), true) { private boolean myIsRecursive; @Override public boolean isRecursive() { return myIsRecursive; } @Override public void setRecursive(final boolean recursive) { myIsRecursive = recursive; } }; result.setPomFile(file.getPath()); result.setRecursive(myEmbedderSettings.isRecursive()); return result; } private MavenExecutionResult handleException(Throwable e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } if (e instanceof Error) { throw (Error) e; } return new MavenExecutionResult(null, Collections.singletonList((Exception) e)); } private ProfileManager createProfileManager(List<String> activeProfiles, List<String> inactiveProfiles, Properties executionProperties) { ProfileManager profileManager = new DefaultProfileManager(getContainer(), executionProperties); profileManager.explicitlyActivate(activeProfiles); profileManager.explicitlyDeactivate(inactiveProfiles); return profileManager; } @SuppressWarnings({ "unchecked" }) public <T> T getComponent(Class<T> clazz) { try { return (T) getContainer().lookup(clazz.getName()); } catch (ComponentLookupException e) { throw new RuntimeException(e); } } @SuppressWarnings({ "unchecked" }) public <T> T getComponent(Class<T> clazz, String roleHint) { try { return (T) getContainer().lookup(clazz.getName(), roleHint); } catch (ComponentLookupException e) { throw new RuntimeException(e); } } public PlexusContainer getContainer() { return myContainer; } public void release() { releaseResolverThreadExecutor(); myContainer.dispose(); } private void releaseResolverThreadExecutor() { ArtifactResolver resolver = getComponent(ArtifactResolver.class); @SuppressWarnings({ "unchecked" }) FieldAccessor pool = new FieldAccessor(DefaultArtifactResolver.class, resolver, "resolveArtifactPool"); try { final Object threadPool = pool.getField(); // an instance of a hidden copy of ThreadPoolExecutor threadPool.getClass().getMethod("shutdown").invoke(threadPool); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } @Nonnull public static MavenEmbedder create(@Nonnull final MavenEmbedderSettings embedderSettings) { @Nonnull final Logger logger = getLogger(embedderSettings); DefaultPlexusContainer container = new DefaultPlexusContainer(); container.setClassWorld(new ClassWorld("plexus.core", embedderSettings.getClass().getClassLoader())); container.setLoggerManager(new BaseLoggerManager() { @Override protected Logger createLogger(final String s) { return logger; } }); try { container.initialize(); container.start(); } catch (PlexusContainerException e) { MavenEmbedderLog.LOG.error(e); throw new RuntimeException(e); } final PlexusComponentConfigurator configurator = embedderSettings.getConfigurator(); if (configurator != null) { configurator.configureComponents(container); } File mavenHome = embedderSettings.getMavenHome(); if (mavenHome != null) { System.setProperty(PROP_MAVEN_HOME, mavenHome.getPath()); } Settings nativeSettings = buildSettings(container, embedderSettings); return new MavenEmbedder(container, nativeSettings, logger, embedderSettings); } @Nonnull private static Logger getLogger(@Nonnull final MavenEmbedderSettings embedderSettings) { final Logger logger = embedderSettings.getLogger(); return logger != null ? logger : new NullMavenLogger(); } public static Settings buildSettings(PlexusContainer container, MavenEmbedderSettings embedderSettings) { File file = embedderSettings.getGlobalSettingsFile(); if (file != null) { System.setProperty(MavenSettingsBuilder.ALT_GLOBAL_SETTINGS_XML_LOCATION, file.getPath()); } Settings settings = null; try { MavenSettingsBuilder builder = (MavenSettingsBuilder) container.lookup(MavenSettingsBuilder.ROLE); File userSettingsFile = embedderSettings.getUserSettingsFile(); if (userSettingsFile != null && userSettingsFile.exists() && !userSettingsFile.isDirectory()) { settings = builder.buildSettings(userSettingsFile, false); } if (settings == null) { settings = builder.buildSettings(); } } catch (ComponentLookupException e) { MavenEmbedderLog.LOG.error(e); } catch (IOException e) { MavenEmbedderLog.LOG.warn(e); } catch (XmlPullParserException e) { MavenEmbedderLog.LOG.warn(e); } if (settings == null) { settings = new Settings(); } if (embedderSettings.getLocalRepository() != null) { settings.setLocalRepository(embedderSettings.getLocalRepository().getPath()); } if (settings.getLocalRepository() == null) { settings.setLocalRepository(System.getProperty("user.home") + "/.m2/repository"); } settings.setOffline(embedderSettings.isWorkOffline()); settings.setInteractiveMode(false); settings.setUsePluginRegistry(embedderSettings.isUsePluginRegistry()); RuntimeInfo runtimeInfo = new RuntimeInfo(settings); runtimeInfo.setPluginUpdateOverride( embedderSettings.getPluginUpdatePolicy() == MavenEmbedderSettings.UpdatePolicy.ALWAYS_UPDATE); settings.setRuntimeInfo(runtimeInfo); return settings; } public static <T> void setImplementation(PlexusContainer container, Class<T> componentClass, Class<? extends T> implementationClass) { ComponentDescriptor d = container.getComponentDescriptor(componentClass.getName()); d.setImplementation(implementationClass.getName()); } }