]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.support.maven/src/main/java/org/argeo/slc/maven/SlcMavenEmbedder.java
Upgrade to Maven 2.0.9 (in order to support import id DependencyManagement)
[gpl/argeo-slc.git] / runtime / org.argeo.slc.support.maven / src / main / java / org / argeo / slc / maven / SlcMavenEmbedder.java
1 package org.argeo.slc.maven;
2
3 /*
4 * Copyright 2001-2005 The Apache Software Foundation.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 import java.io.File;
20 import java.io.FileNotFoundException;
21 import java.io.FileReader;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.io.Writer;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.Date;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Properties;
32
33 import org.apache.maven.BuildFailureException;
34 import org.apache.maven.artifact.Artifact;
35 import org.apache.maven.artifact.factory.ArtifactFactory;
36 import org.apache.maven.artifact.manager.WagonManager;
37 import org.apache.maven.artifact.repository.ArtifactRepository;
38 import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
39 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
40 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
41 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
42 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
43 import org.apache.maven.artifact.resolver.ArtifactResolver;
44 import org.apache.maven.execution.MavenSession;
45 import org.apache.maven.execution.ReactorManager;
46 import org.apache.maven.lifecycle.LifecycleExecutionException;
47 import org.apache.maven.lifecycle.LifecycleExecutor;
48 import org.apache.maven.model.Model;
49 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
50 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
51 import org.apache.maven.monitor.event.DefaultEventDispatcher;
52 import org.apache.maven.monitor.event.EventDispatcher;
53 import org.apache.maven.monitor.event.EventMonitor;
54 import org.apache.maven.plugin.MojoExecutionException;
55 import org.apache.maven.plugin.descriptor.PluginDescriptor;
56 import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
57 import org.apache.maven.profiles.DefaultProfileManager;
58 import org.apache.maven.profiles.ProfileManager;
59 import org.apache.maven.project.DuplicateProjectException;
60 import org.apache.maven.project.MavenProject;
61 import org.apache.maven.project.MavenProjectBuilder;
62 import org.apache.maven.project.ProjectBuildingException;
63 import org.apache.maven.settings.MavenSettingsBuilder;
64 import org.apache.maven.settings.RuntimeInfo;
65 import org.apache.maven.settings.Settings;
66 import org.apache.maven.wagon.events.TransferListener;
67 import org.argeo.slc.maven.embedder.MavenEmbedderException;
68 import org.argeo.slc.maven.embedder.MavenEmbedderLogger;
69 import org.argeo.slc.maven.embedder.MavenEmbedderLoggerManager;
70 import org.argeo.slc.maven.embedder.PlexusLoggerAdapter;
71 import org.argeo.slc.maven.embedder.SummaryPluginDescriptor;
72 import org.codehaus.classworlds.ClassWorld;
73 import org.codehaus.classworlds.DuplicateRealmException;
74 import org.codehaus.plexus.PlexusContainerException;
75 import org.codehaus.plexus.component.repository.ComponentDescriptor;
76 import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
77 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
78 import org.codehaus.plexus.configuration.PlexusConfiguration;
79 import org.codehaus.plexus.configuration.PlexusConfigurationException;
80 import org.codehaus.plexus.embed.Embedder;
81 import org.codehaus.plexus.util.DirectoryScanner;
82 import org.codehaus.plexus.util.dag.CycleDetectedException;
83 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
84
85 /**
86 * Class intended to be used by clients who wish to embed Maven into their
87 * applications
88 *
89 * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
90 */
91 public class SlcMavenEmbedder {
92 public static final String userHome = System.getProperty("user.home");
93
94 // ----------------------------------------------------------------------
95 // Embedder
96 // ----------------------------------------------------------------------
97
98 private Embedder embedder;
99
100 // ----------------------------------------------------------------------
101 // Components
102 // ----------------------------------------------------------------------
103
104 private MavenProjectBuilder mavenProjectBuilder;
105
106 private ArtifactRepositoryFactory artifactRepositoryFactory;
107
108 private MavenSettingsBuilder settingsBuilder;
109
110 private LifecycleExecutor lifecycleExecutor;
111
112 private WagonManager wagonManager;
113
114 private MavenXpp3Reader modelReader;
115
116 private MavenXpp3Writer modelWriter;
117
118 private ProfileManager profileManager;
119
120 private PluginDescriptorBuilder pluginDescriptorBuilder;
121
122 private ArtifactFactory artifactFactory;
123
124 private ArtifactResolver artifactResolver;
125
126 private ArtifactRepositoryLayout defaultArtifactRepositoryLayout;
127
128 // ----------------------------------------------------------------------
129 // Configuration
130 // ----------------------------------------------------------------------
131
132 private Settings settings;
133
134 private ArtifactRepository localRepository;
135
136 private File localRepositoryDirectory;
137
138 private ClassLoader classLoader;
139
140 private MavenEmbedderLogger logger;
141
142 // ----------------------------------------------------------------------
143 // User options
144 // ----------------------------------------------------------------------
145
146 // release plugin uses this but in IDE there will probably always be some
147 // form of interaction.
148 private boolean interactiveMode;
149
150 private boolean offline;
151
152 private String globalChecksumPolicy;
153
154 /**
155 * This option determines whether the embedder is to be aligned to the user
156 * installation.
157 */
158 private boolean alignWithUserInstallation;
159
160 // ----------------------------------------------------------------------
161 // Accessors
162 // ----------------------------------------------------------------------
163
164 public void setInteractiveMode(boolean interactiveMode) {
165 this.interactiveMode = interactiveMode;
166 }
167
168 public boolean isInteractiveMode() {
169 return interactiveMode;
170 }
171
172 public void setOffline(boolean offline) {
173 this.offline = offline;
174 }
175
176 public boolean isOffline() {
177 return offline;
178 }
179
180 public void setGlobalChecksumPolicy(String globalChecksumPolicy) {
181 this.globalChecksumPolicy = globalChecksumPolicy;
182 }
183
184 public String getGlobalChecksumPolicy() {
185 return globalChecksumPolicy;
186 }
187
188 public boolean isAlignWithUserInstallation() {
189 return alignWithUserInstallation;
190 }
191
192 public void setAlignWithUserInstallation(boolean alignWithUserInstallation) {
193 this.alignWithUserInstallation = alignWithUserInstallation;
194 }
195
196 /**
197 * Set the classloader to use with the maven embedder.
198 *
199 * @param classLoader
200 */
201 public void setClassLoader(ClassLoader classLoader) {
202 this.classLoader = classLoader;
203 }
204
205 public ClassLoader getClassLoader() {
206 return classLoader;
207 }
208
209 public void setLocalRepositoryDirectory(File localRepositoryDirectory) {
210 this.localRepositoryDirectory = localRepositoryDirectory;
211 }
212
213 public File getLocalRepositoryDirectory() {
214 return localRepositoryDirectory;
215 }
216
217 public ArtifactRepository getLocalRepository() {
218 return localRepository;
219 }
220
221 public MavenEmbedderLogger getLogger() {
222 return logger;
223 }
224
225 public void setLogger(MavenEmbedderLogger logger) {
226 this.logger = logger;
227 }
228
229 // ----------------------------------------------------------------------
230 // Embedder Client Contract
231 // ----------------------------------------------------------------------
232
233 // ----------------------------------------------------------------------
234 // Model
235 // ----------------------------------------------------------------------
236
237 public Model readModel(File model) throws XmlPullParserException,
238 FileNotFoundException, IOException {
239 return modelReader.read(new FileReader(model));
240 }
241
242 public void writeModel(Writer writer, Model model) throws IOException {
243 modelWriter.write(writer, model);
244 }
245
246 // ----------------------------------------------------------------------
247 // Project
248 // ----------------------------------------------------------------------
249
250 public MavenProject readProject(File mavenProject)
251 throws ProjectBuildingException {
252 return mavenProjectBuilder.build(mavenProject, localRepository,
253 profileManager);
254 }
255
256 public MavenProject readProjectWithDependencies(File mavenProject,
257 TransferListener transferListener) throws ProjectBuildingException,
258 ArtifactResolutionException, ArtifactNotFoundException {
259 return mavenProjectBuilder.buildWithDependencies(mavenProject,
260 localRepository, profileManager, transferListener);
261 }
262
263 public MavenProject readProjectWithDependencies(File mavenProject)
264 throws ProjectBuildingException, ArtifactResolutionException,
265 ArtifactNotFoundException {
266 return mavenProjectBuilder.buildWithDependencies(mavenProject,
267 localRepository, profileManager);
268 }
269
270 public List collectProjects(File basedir, String[] includes,
271 String[] excludes) throws MojoExecutionException {
272 List projects = new ArrayList();
273
274 List poms = getPomFiles(basedir, includes, excludes);
275
276 for (Iterator i = poms.iterator(); i.hasNext();) {
277 File pom = (File) i.next();
278
279 try {
280 MavenProject p = readProject(pom);
281
282 projects.add(p);
283
284 } catch (ProjectBuildingException e) {
285 throw new MojoExecutionException("Error loading " + pom, e);
286 }
287 }
288
289 return projects;
290 }
291
292 // ----------------------------------------------------------------------
293 // Artifacts
294 // ----------------------------------------------------------------------
295
296 public Artifact createArtifact(String groupId, String artifactId,
297 String version, String scope, String type) {
298 return artifactFactory.createArtifact(groupId, artifactId, version,
299 scope, type);
300 }
301
302 public Artifact createArtifactWithClassifier(String groupId,
303 String artifactId, String version, String type, String classifier) {
304 return artifactFactory.createArtifactWithClassifier(groupId,
305 artifactId, version, type, classifier);
306 }
307
308 public void resolve(Artifact artifact, List remoteRepositories,
309 ArtifactRepository localRepository)
310 throws ArtifactResolutionException, ArtifactNotFoundException {
311 artifactResolver.resolve(artifact, remoteRepositories, localRepository);
312 }
313
314 // ----------------------------------------------------------------------
315 // Plugins
316 // ----------------------------------------------------------------------
317
318 public List getAvailablePlugins() {
319 List plugins = new ArrayList();
320
321 plugins.add(makeMockPlugin("org.apache.maven.plugins",
322 "maven-jar-plugin", "Maven Jar Plug-in"));
323
324 plugins.add(makeMockPlugin("org.apache.maven.plugins",
325 "maven-compiler-plugin", "Maven Compiler Plug-in"));
326
327 return plugins;
328 }
329
330 public PluginDescriptor getPluginDescriptor(
331 SummaryPluginDescriptor summaryPluginDescriptor)
332 throws MavenEmbedderException {
333 PluginDescriptor pluginDescriptor;
334
335 try {
336 InputStream is = classLoader.getResourceAsStream("/plugins/"
337 + summaryPluginDescriptor.getArtifactId() + ".xml");
338
339 pluginDescriptor = pluginDescriptorBuilder
340 .build(new InputStreamReader(is));
341 } catch (PlexusConfigurationException e) {
342 throw new MavenEmbedderException(
343 "Error retrieving plugin descriptor.", e);
344 }
345
346 return pluginDescriptor;
347 }
348
349 private SummaryPluginDescriptor makeMockPlugin(String groupId,
350 String artifactId, String name) {
351 return new SummaryPluginDescriptor(groupId, artifactId, name);
352 }
353
354 // ----------------------------------------------------------------------
355 // Execution of phases/goals
356 // ----------------------------------------------------------------------
357
358 // TODO: should we allow the passing in of a settings object so that
359 // everything can be taken from the client env
360 // TODO: transfer listener
361 // TODO: logger
362
363 public void execute(MavenProject project, List goals,
364 EventMonitor eventMonitor, TransferListener transferListener,
365 Properties properties, File executionRootDirectory)
366 throws CycleDetectedException, LifecycleExecutionException,
367 BuildFailureException, DuplicateProjectException {
368 execute(Collections.singletonList(project), goals, eventMonitor,
369 transferListener, properties, executionRootDirectory);
370 }
371
372 public void execute(List projects, List goals, EventMonitor eventMonitor,
373 TransferListener transferListener, Properties properties,
374 File executionRootDirectory) throws CycleDetectedException,
375 LifecycleExecutionException, BuildFailureException,
376 DuplicateProjectException {
377 ReactorManager rm = new ReactorManager(projects);
378
379 EventDispatcher eventDispatcher = new DefaultEventDispatcher();
380
381 eventDispatcher.addEventMonitor(eventMonitor);
382
383 // If this option is set the exception seems to be hidden ...
384
385 // rm.setFailureBehavior( ReactorManager.FAIL_AT_END );
386
387 rm.setFailureBehavior(ReactorManager.FAIL_FAST);
388
389 MavenSession session = new MavenSession(embedder.getContainer(),
390 settings, localRepository, eventDispatcher, rm, goals,
391 executionRootDirectory.getAbsolutePath(), properties,
392 new Date());
393
394 session.setUsingPOMsFromFilesystem(true);
395
396 if (transferListener != null) {
397 wagonManager.setDownloadMonitor(transferListener);
398 }
399
400 // ----------------------------------------------------------------------
401 // Maven should not be using system properties internally but because
402 // it does for now I'll just take properties that are handed to me
403 // and set them so that the plugin expression evaluator will work
404 // as expected.
405 // ----------------------------------------------------------------------
406
407 if (properties != null) {
408 for (Iterator i = properties.keySet().iterator(); i.hasNext();) {
409 String key = (String) i.next();
410
411 String value = properties.getProperty(key);
412
413 System.setProperty(key, value);
414 }
415 }
416
417 lifecycleExecutor.execute(session, rm, session.getEventDispatcher());
418 }
419
420 // ----------------------------------------------------------------------
421 // Lifecycle information
422 // ----------------------------------------------------------------------
423
424 public List getLifecyclePhases() throws MavenEmbedderException {
425 List phases = new ArrayList();
426
427 ComponentDescriptor descriptor = embedder.getContainer()
428 .getComponentDescriptor(LifecycleExecutor.ROLE);
429
430 PlexusConfiguration configuration = descriptor.getConfiguration();
431
432 PlexusConfiguration[] phasesConfigurations = configuration.getChild(
433 "lifecycles").getChild(0).getChild("phases").getChildren(
434 "phase");
435
436 try {
437 for (int i = 0; i < phasesConfigurations.length; i++) {
438 phases.add(phasesConfigurations[i].getValue());
439 }
440 } catch (PlexusConfigurationException e) {
441 throw new MavenEmbedderException(
442 "Cannot retrieve default lifecycle phasesConfigurations.",
443 e);
444 }
445
446 return phases;
447 }
448
449 // ----------------------------------------------------------------------
450 // Remote Repository
451 // ----------------------------------------------------------------------
452
453 // ----------------------------------------------------------------------
454 // Local Repository
455 // ----------------------------------------------------------------------
456
457 public static final String DEFAULT_LOCAL_REPO_ID = "local";
458
459 public static final String DEFAULT_LAYOUT_ID = "default";
460
461 public ArtifactRepository createLocalRepository(File localRepository)
462 throws ComponentLookupException {
463 return createLocalRepository(localRepository.getAbsolutePath(),
464 DEFAULT_LOCAL_REPO_ID);
465 }
466
467 public ArtifactRepository createLocalRepository(Settings settings)
468 throws ComponentLookupException {
469 return createLocalRepository(settings.getLocalRepository(),
470 DEFAULT_LOCAL_REPO_ID);
471 }
472
473 public ArtifactRepository createLocalRepository(String url,
474 String repositoryId) throws ComponentLookupException {
475 if (!url.startsWith("file:")) {
476 url = "file://" + url;
477 }
478
479 return createRepository(url, repositoryId);
480 }
481
482 public ArtifactRepository createRepository(String url, String repositoryId)
483 throws ComponentLookupException {
484 // snapshots vs releases
485 // offline = to turning the update policy off
486
487 // TODO: we'll need to allow finer grained creation of repositories but
488 // this will do for now
489
490 String updatePolicyFlag = ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS;
491
492 String checksumPolicyFlag = ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN;
493
494 ArtifactRepositoryPolicy snapshotsPolicy = new ArtifactRepositoryPolicy(
495 true, updatePolicyFlag, checksumPolicyFlag);
496
497 ArtifactRepositoryPolicy releasesPolicy = new ArtifactRepositoryPolicy(
498 true, updatePolicyFlag, checksumPolicyFlag);
499
500 return artifactRepositoryFactory.createArtifactRepository(repositoryId,
501 url, defaultArtifactRepositoryLayout, snapshotsPolicy,
502 releasesPolicy);
503 }
504
505 // ----------------------------------------------------------------------
506 // Internal utility code
507 // ----------------------------------------------------------------------
508
509 private RuntimeInfo createRuntimeInfo(Settings settings) {
510 RuntimeInfo runtimeInfo = new RuntimeInfo(settings);
511
512 runtimeInfo.setPluginUpdateOverride(Boolean.FALSE);
513
514 return runtimeInfo;
515 }
516
517 private List getPomFiles(File basedir, String[] includes, String[] excludes) {
518 DirectoryScanner scanner = new DirectoryScanner();
519
520 scanner.setBasedir(basedir);
521
522 scanner.setIncludes(includes);
523
524 scanner.setExcludes(excludes);
525
526 scanner.scan();
527
528 List poms = new ArrayList();
529
530 for (int i = 0; i < scanner.getIncludedFiles().length; i++) {
531 poms.add(new File(basedir, scanner.getIncludedFiles()[i]));
532 }
533
534 return poms;
535 }
536
537 // ----------------------------------------------------------------------
538 // Lifecycle
539 // ----------------------------------------------------------------------
540
541 public void start() throws MavenEmbedderException {
542 detectUserInstallation();
543
544 // ----------------------------------------------------------------------
545 // Set the maven.home system property which is need by components like
546 // the plugin registry builder.
547 // ----------------------------------------------------------------------
548
549 if (classLoader == null) {
550 throw new IllegalStateException(
551 "A classloader must be specified using setClassLoader(ClassLoader).");
552 }
553
554 embedder = new Embedder();
555
556 if (logger != null) {
557 embedder.setLoggerManager(new MavenEmbedderLoggerManager(
558 new PlexusLoggerAdapter(logger)));
559 }
560
561 try {
562 ClassWorld classWorld = new ClassWorld();
563
564 classWorld.newRealm("plexus.core", classLoader);
565
566 embedder.start(classWorld);
567
568 // ----------------------------------------------------------------------
569 // Lookup each of the components we need to provide the desired
570 // client interface.
571 // ----------------------------------------------------------------------
572
573 modelReader = new MavenXpp3Reader();
574
575 modelWriter = new MavenXpp3Writer();
576
577 pluginDescriptorBuilder = new PluginDescriptorBuilder();
578
579 profileManager = new DefaultProfileManager(embedder.getContainer());
580
581 mavenProjectBuilder = (MavenProjectBuilder) embedder
582 .lookup(MavenProjectBuilder.ROLE);
583
584 // ----------------------------------------------------------------------
585 // Artifact related components
586 // ----------------------------------------------------------------------
587
588 artifactRepositoryFactory = (ArtifactRepositoryFactory) embedder
589 .lookup(ArtifactRepositoryFactory.ROLE);
590
591 artifactFactory = (ArtifactFactory) embedder
592 .lookup(ArtifactFactory.ROLE);
593
594 artifactResolver = (ArtifactResolver) embedder
595 .lookup(ArtifactResolver.ROLE);
596
597 defaultArtifactRepositoryLayout = (ArtifactRepositoryLayout) embedder
598 .lookup(ArtifactRepositoryLayout.ROLE, DEFAULT_LAYOUT_ID);
599
600 lifecycleExecutor = (LifecycleExecutor) embedder
601 .lookup(LifecycleExecutor.ROLE);
602
603 wagonManager = (WagonManager) embedder.lookup(WagonManager.ROLE);
604
605 createMavenSettings();
606
607 profileManager.loadSettingsProfiles(settings);
608
609 localRepository = createLocalRepository(settings);
610 } catch (PlexusContainerException e) {
611 throw new MavenEmbedderException("Cannot start Plexus embedder.", e);
612 } catch (DuplicateRealmException e) {
613 throw new MavenEmbedderException(
614 "Cannot create Classworld realm for the embedder.", e);
615 } catch (ComponentLookupException e) {
616 throw new MavenEmbedderException(
617 "Cannot lookup required component.", e);
618 }
619 }
620
621 // ----------------------------------------------------------------------
622 //
623 // ----------------------------------------------------------------------
624
625 private void detectUserInstallation() {
626 if (new File(userHome, ".m2").exists()) {
627 alignWithUserInstallation = true;
628 }
629 }
630
631 /**
632 * Create the Settings that will be used with the embedder. If we are
633 * aligning with the user installation then we lookup the standard settings
634 * builder and use that to create our settings. Otherwise we constructs a
635 * settings object and populate the information ourselves.
636 *
637 * @throws MavenEmbedderException
638 * @throws ComponentLookupException
639 */
640 private void createMavenSettings() throws MavenEmbedderException,
641 ComponentLookupException {
642 if (alignWithUserInstallation) {
643 // ----------------------------------------------------------------------
644 // We will use the standard method for creating the settings. This
645 // method reproduces the method of building the settings from the
646 // CLI
647 // mode of operation.
648 // ----------------------------------------------------------------------
649
650 settingsBuilder = (MavenSettingsBuilder) embedder
651 .lookup(MavenSettingsBuilder.ROLE);
652
653 try {
654 settings = settingsBuilder.buildSettings();
655 } catch (IOException e) {
656 throw new MavenEmbedderException("Error creating settings.", e);
657 } catch (XmlPullParserException e) {
658 throw new MavenEmbedderException("Error creating settings.", e);
659 }
660 } else {
661 if (localRepository == null) {
662 throw new IllegalArgumentException(
663 "When not aligning with a user install you must specify a local repository location using the setLocalRepositoryDirectory( File ) method.");
664 }
665
666 settings = new Settings();
667
668 settings.setLocalRepository(localRepositoryDirectory
669 .getAbsolutePath());
670
671 settings.setRuntimeInfo(createRuntimeInfo(settings));
672
673 settings.setOffline(offline);
674
675 settings.setInteractiveMode(interactiveMode);
676 }
677 }
678
679 // ----------------------------------------------------------------------
680 // Lifecycle
681 // ----------------------------------------------------------------------
682
683 public void stop() throws MavenEmbedderException {
684 try {
685 embedder.release(mavenProjectBuilder);
686
687 embedder.release(artifactRepositoryFactory);
688
689 embedder.release(settingsBuilder);
690
691 embedder.release(lifecycleExecutor);
692 } catch (ComponentLifecycleException e) {
693 throw new MavenEmbedderException("Cannot stop the embedder.", e);
694 }
695 }
696
697 public Embedder getEmbedder() {
698 return embedder;
699 }
700
701 }