001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2017-2019 microBean™. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 014 * implied. See the License for the specific language governing 015 * permissions and limitations under the License. 016 */ 017package org.microbean.maven.cdi; 018 019import java.io.BufferedInputStream; 020import java.io.File; 021import java.io.IOException; 022import java.io.InputStream; 023 024import java.net.JarURLConnection; 025import java.net.URI; 026import java.net.URISyntaxException; 027import java.net.URL; 028 029import java.nio.file.Files; 030import java.nio.file.Path; 031import java.nio.file.Paths; 032 033import java.security.CodeSource; 034import java.security.ProtectionDomain; 035 036import java.util.ArrayList; 037import java.util.Collection; 038import java.util.HashMap; 039import java.util.HashSet; 040import java.util.List; 041import java.util.Map; 042import java.util.Objects; 043import java.util.Properties; 044import java.util.Set; 045 046import java.util.jar.JarFile; 047 048import javax.enterprise.context.Dependent; 049 050import javax.enterprise.event.Observes; 051 052import javax.enterprise.inject.Any; 053import javax.enterprise.inject.Instance; 054import javax.enterprise.inject.Produces; 055import javax.enterprise.inject.Typed; 056 057import javax.enterprise.inject.literal.SingletonLiteral; 058 059import javax.enterprise.inject.spi.Bean; 060import javax.enterprise.inject.spi.BeanAttributes; 061import javax.enterprise.inject.spi.BeforeBeanDiscovery; 062import javax.enterprise.inject.spi.Extension; 063import javax.enterprise.inject.spi.ProcessBeanAttributes; 064import javax.inject.Named; 065import javax.inject.Singleton; 066 067import org.apache.maven.model.Model; 068 069import org.apache.maven.model.building.DefaultModelBuilder; 070import org.apache.maven.model.building.DefaultModelProcessor; 071import org.apache.maven.model.building.ModelBuildingRequest; 072import org.apache.maven.model.building.ModelProblemCollector; 073import org.apache.maven.model.building.ModelProcessor; 074 075import org.apache.maven.model.composition.DefaultDependencyManagementImporter; 076 077import org.apache.maven.model.inheritance.DefaultInheritanceAssembler; 078 079import org.apache.maven.model.interpolation.StringVisitorModelInterpolator; 080 081import org.apache.maven.model.io.DefaultModelReader; 082 083import org.apache.maven.model.locator.DefaultModelLocator; 084 085import org.apache.maven.model.management.DefaultDependencyManagementInjector; 086import org.apache.maven.model.management.DefaultPluginManagementInjector; 087 088import org.apache.maven.model.normalization.DefaultModelNormalizer; 089 090import org.apache.maven.model.path.DefaultModelPathTranslator; 091import org.apache.maven.model.path.DefaultModelUrlNormalizer; 092import org.apache.maven.model.path.DefaultPathTranslator; 093import org.apache.maven.model.path.DefaultUrlNormalizer; 094 095import org.apache.maven.model.plugin.DefaultPluginConfigurationExpander; 096import org.apache.maven.model.plugin.DefaultReportConfigurationExpander; 097import org.apache.maven.model.plugin.DefaultReportingConverter; 098import org.apache.maven.model.plugin.LifecycleBindingsInjector; 099 100import org.apache.maven.model.profile.DefaultProfileInjector; 101import org.apache.maven.model.profile.DefaultProfileSelector; 102import org.apache.maven.model.profile.ProfileSelector; 103 104import org.apache.maven.model.profile.activation.FileProfileActivator; 105import org.apache.maven.model.profile.activation.JdkVersionProfileActivator; 106import org.apache.maven.model.profile.activation.OperatingSystemProfileActivator; 107import org.apache.maven.model.profile.activation.ProfileActivator; 108import org.apache.maven.model.profile.activation.PropertyProfileActivator; 109 110import org.apache.maven.model.superpom.DefaultSuperPomProvider; 111 112import org.apache.maven.model.validation.DefaultModelValidator; 113 114import org.apache.maven.repository.internal.DefaultArtifactDescriptorReader; 115import org.apache.maven.repository.internal.DefaultVersionRangeResolver; 116import org.apache.maven.repository.internal.DefaultVersionResolver; 117import org.apache.maven.repository.internal.MavenRepositorySystemUtils; // for javadoc only 118import org.apache.maven.repository.internal.SnapshotMetadataGeneratorFactory; 119import org.apache.maven.repository.internal.VersionsMetadataGeneratorFactory; 120 121import org.apache.maven.settings.Mirror; 122import org.apache.maven.settings.Profile; 123import org.apache.maven.settings.Repository; 124import org.apache.maven.settings.Settings; 125 126import org.apache.maven.settings.building.DefaultSettingsBuilder; 127import org.apache.maven.settings.building.DefaultSettingsBuildingRequest; 128import org.apache.maven.settings.building.SettingsBuilder; 129import org.apache.maven.settings.building.SettingsBuildingException; 130import org.apache.maven.settings.building.SettingsBuildingResult; 131import org.apache.maven.settings.building.SettingsProblem; 132 133import org.apache.maven.settings.io.DefaultSettingsReader; 134import org.apache.maven.settings.io.DefaultSettingsWriter; 135 136import org.apache.maven.settings.merge.MavenSettingsMerger; 137 138import org.apache.maven.settings.validation.DefaultSettingsValidator; 139 140import org.eclipse.aether.DefaultRepositorySystemSession; 141import org.eclipse.aether.RepositoryListener; 142import org.eclipse.aether.RepositorySystem; 143import org.eclipse.aether.RepositorySystemSession; 144 145import org.eclipse.aether.artifact.ArtifactTypeRegistry; 146import org.eclipse.aether.artifact.DefaultArtifactType; 147 148import org.eclipse.aether.collection.DependencyGraphTransformer; 149import org.eclipse.aether.collection.DependencyManager; 150import org.eclipse.aether.collection.DependencySelector; 151import org.eclipse.aether.collection.DependencyTraverser; 152 153import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; 154 155import org.eclipse.aether.impl.LocalRepositoryProvider; 156import org.eclipse.aether.impl.MetadataGeneratorFactory; 157 158import org.eclipse.aether.internal.impl.DefaultArtifactResolver; 159import org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider; 160import org.eclipse.aether.internal.impl.DefaultDeployer; 161import org.eclipse.aether.internal.impl.DefaultFileProcessor; 162import org.eclipse.aether.internal.impl.DefaultInstaller; 163import org.eclipse.aether.internal.impl.DefaultLocalRepositoryProvider; 164import org.eclipse.aether.internal.impl.DefaultMetadataResolver; 165import org.eclipse.aether.internal.impl.DefaultOfflineController; 166import org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager; 167import org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider; 168import org.eclipse.aether.internal.impl.DefaultRepositoryEventDispatcher; 169import org.eclipse.aether.internal.impl.DefaultRepositoryLayoutProvider; 170import org.eclipse.aether.internal.impl.DefaultRepositorySystem; 171import org.eclipse.aether.internal.impl.DefaultSyncContextFactory; 172import org.eclipse.aether.internal.impl.DefaultTransporterProvider; 173import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager; 174import org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer; 175import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory; 176import org.eclipse.aether.internal.impl.Maven2RepositoryLayoutFactory; 177import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory; 178 179import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector; 180 181import org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory; 182 183import org.eclipse.aether.repository.LocalRepository; 184import org.eclipse.aether.repository.LocalRepositoryManager; 185import org.eclipse.aether.repository.MirrorSelector; 186import org.eclipse.aether.repository.NoLocalRepositoryManagerException; 187import org.eclipse.aether.repository.RemoteRepository; 188 189import org.eclipse.aether.resolution.ArtifactDescriptorPolicy; 190 191import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; 192 193import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory; 194 195import org.eclipse.aether.spi.connector.transport.TransporterFactory; 196 197import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory; 198 199import org.eclipse.aether.transfer.TransferListener; 200 201import org.eclipse.aether.transport.file.FileTransporterFactory; 202 203import org.eclipse.aether.transport.http.HttpTransporterFactory; 204 205import org.eclipse.aether.util.artifact.DefaultArtifactTypeRegistry; 206 207import org.eclipse.aether.util.graph.manager.ClassicDependencyManager; 208 209import org.eclipse.aether.util.graph.selector.AndDependencySelector; 210import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector; 211import org.eclipse.aether.util.graph.selector.OptionalDependencySelector; 212import org.eclipse.aether.util.graph.selector.ScopeDependencySelector; 213 214import org.eclipse.aether.util.graph.transformer.ChainedDependencyGraphTransformer; 215import org.eclipse.aether.util.graph.transformer.ConflictResolver; 216import org.eclipse.aether.util.graph.transformer.JavaDependencyContextRefiner; 217import org.eclipse.aether.util.graph.transformer.JavaScopeDeriver; 218import org.eclipse.aether.util.graph.transformer.JavaScopeSelector; 219import org.eclipse.aether.util.graph.transformer.NearestVersionSelector; 220import org.eclipse.aether.util.graph.transformer.SimpleOptionalitySelector; 221 222import org.eclipse.aether.util.graph.traverser.FatArtifactTraverser; 223 224import org.eclipse.aether.util.repository.DefaultMirrorSelector; 225import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy; 226 227import org.microbean.configuration.cdi.annotation.ConfigurationValue; 228 229import org.microbean.maven.cdi.annotation.Resolution; 230 231import org.slf4j.ILoggerFactory; 232import org.slf4j.LoggerFactory; 233 234/** 235 * A <a 236 * href="http://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#spi">CDI 237 * 2.0 portable extension</a> that exposes the <a 238 * href="https://maven.apache.org/resolver/">Maven Artifact Resolver 239 * components</a> as CDI beans, particularly for the purposes of 240 * dependency resolution. 241 * 242 * @author <a href="http://about.me/lairdnelson" 243 * target="_parent">Laird Nelson</a> 244 * 245 * @see RepositorySystem 246 * 247 * @see RepositorySystemSession 248 */ 249public class MavenExtension implements Extension { 250 251 252 /* 253 * Instance fields. 254 */ 255 256 257 /** 258 * A {@link Map} of Maven artifact coordinates represented as {@link 259 * Properties} objects indexed by {@link URI} objects representing 260 * their location. 261 * 262 * <p>This field is never {@code null}.</p> 263 * 264 * <p>This field is not safe for concurrent use by multiple threads. 265 * Threads should synchronize on its value to coordinate access.</p> 266 * 267 * @see #getGroupArtifactVersionCoordinates(URL) 268 */ 269 private final Map<URI, Properties> coordinates; 270 271 272 /* 273 * Constructors. 274 */ 275 276 277 /** 278 * Creates a new {@link MavenExtension}. 279 */ 280 public MavenExtension() { 281 super(); 282 this.coordinates = new HashMap<>(); 283 } 284 285 286 /* 287 * Instance methods. 288 */ 289 290 291 /** 292 * Registers certain Maven Resolver components as CDI beans in 293 * appropriate scopes. 294 * 295 * @param event the {@link BeforeBeanDiscovery} event indicating 296 * that bean discovery has started; may be {@code null} in which 297 * case no action will be taken 298 * 299 * @see BeforeBeanDiscovery#addAnnotatedType(Class, String) 300 * 301 * @see <a 302 * href="https://github.com/apache/maven-resolver/blob/9417310df326cd4a58b0ef534e6c0e29f7b4cb47/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java#L100-L151">Guice 303 * bindings for {@code maven-resolver-impl}</a> 304 * 305 * @see <a 306 * href="https://github.com/apache/maven-resolver/blob/9417310df326cd4a58b0ef534e6c0e29f7b4cb47/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/DefaultServiceLocator.java#L186-L215">{@code 307 * DefaultSerivceLocator} bindings</a> 308 */ 309 private final void beforeBeanDiscovery(@Observes final BeforeBeanDiscovery event) { 310 if (event != null) { 311 312 // 313 // Types effectively bound by DefaultServiceLocator 314 // 315 316 event.addAnnotatedType(DefaultArtifactResolver.class, "maven").add(SingletonLiteral.INSTANCE); 317 event.addAnnotatedType(DefaultChecksumPolicyProvider.class, "maven").add(SingletonLiteral.INSTANCE); 318 event.addAnnotatedType(DefaultDependencyCollector.class, "maven").add(SingletonLiteral.INSTANCE); 319 event.addAnnotatedType(DefaultDeployer.class, "maven").add(SingletonLiteral.INSTANCE); 320 event.addAnnotatedType(DefaultFileProcessor.class, "maven").add(SingletonLiteral.INSTANCE); 321 event.addAnnotatedType(DefaultInstaller.class, "maven").add(SingletonLiteral.INSTANCE); 322 event.addAnnotatedType(DefaultLocalRepositoryProvider.class, "maven").add(SingletonLiteral.INSTANCE); 323 event.addAnnotatedType(DefaultMetadataResolver.class, "maven").add(SingletonLiteral.INSTANCE); 324 event.addAnnotatedType(DefaultOfflineController.class, "maven").add(SingletonLiteral.INSTANCE); 325 event.addAnnotatedType(DefaultRemoteRepositoryManager.class, "maven").add(SingletonLiteral.INSTANCE); 326 event.addAnnotatedType(DefaultRepositoryConnectorProvider.class, "maven").add(SingletonLiteral.INSTANCE); 327 event.addAnnotatedType(DefaultRepositoryEventDispatcher.class, "maven").add(SingletonLiteral.INSTANCE); 328 event.addAnnotatedType(DefaultRepositoryLayoutProvider.class, "maven").add(SingletonLiteral.INSTANCE); 329 event.addAnnotatedType(DefaultRepositorySystem.class, "maven").add(SingletonLiteral.INSTANCE); 330 event.addAnnotatedType(DefaultSyncContextFactory.class, "maven").add(SingletonLiteral.INSTANCE); 331 event.addAnnotatedType(DefaultTransporterProvider.class, "maven").add(SingletonLiteral.INSTANCE); 332 event.addAnnotatedType(DefaultUpdateCheckManager.class, "maven").add(SingletonLiteral.INSTANCE); 333 event.addAnnotatedType(DefaultUpdatePolicyAnalyzer.class, "maven").add(SingletonLiteral.INSTANCE); 334 event.addAnnotatedType(EnhancedLocalRepositoryManagerFactory.class, "maven").add(SingletonLiteral.INSTANCE); 335 event.addAnnotatedType(Maven2RepositoryLayoutFactory.class, "maven").add(SingletonLiteral.INSTANCE); 336 event.addAnnotatedType(SimpleLocalRepositoryManagerFactory.class, "maven").add(SingletonLiteral.INSTANCE); 337 event.addAnnotatedType(Slf4jLoggerFactory.class, "maven"); 338 339 // 340 // Types effectively bound by MavenRepositorySystemUtils 341 // 342 343 event.addAnnotatedType(ClassicDependencyManager.class, "maven").add(SingletonLiteral.INSTANCE); 344 event.addAnnotatedType(DefaultArtifactDescriptorReader.class, "maven").add(SingletonLiteral.INSTANCE); 345 event.addAnnotatedType(DefaultVersionRangeResolver.class, "maven").add(SingletonLiteral.INSTANCE); 346 event.addAnnotatedType(DefaultVersionResolver.class, "maven").add(SingletonLiteral.INSTANCE); 347 event.addAnnotatedType(FatArtifactTraverser.class, "maven").add(SingletonLiteral.INSTANCE); 348 event.addAnnotatedType(SnapshotMetadataGeneratorFactory.class, "maven"); 349 event.addAnnotatedType(VersionsMetadataGeneratorFactory.class, "maven"); 350 351 // 352 // Types effectively bound by DefaultModelBuilderFactory. These 353 // all have @Singleton on them already. 354 // 355 356 event.addAnnotatedType(DefaultDependencyManagementImporter.class, "maven"); 357 event.addAnnotatedType(DefaultDependencyManagementInjector.class, "maven"); 358 event.addAnnotatedType(DefaultInheritanceAssembler.class, "maven"); 359 event.addAnnotatedType(DefaultModelBuilder.class, "maven"); 360 event.addAnnotatedType(DefaultModelLocator.class, "maven"); 361 event.addAnnotatedType(DefaultModelNormalizer.class, "maven"); 362 event.addAnnotatedType(DefaultModelPathTranslator.class, "maven"); 363 event.addAnnotatedType(DefaultModelProcessor.class, "maven").add(Typed.Literal.of(new Class<?>[] { ModelProcessor.class })); 364 event.addAnnotatedType(DefaultModelReader.class, "maven"); 365 event.addAnnotatedType(DefaultModelUrlNormalizer.class, "maven"); 366 event.addAnnotatedType(DefaultModelValidator.class, "maven"); 367 event.addAnnotatedType(DefaultPathTranslator.class, "maven"); 368 event.addAnnotatedType(DefaultPluginConfigurationExpander.class, "maven"); 369 event.addAnnotatedType(DefaultPluginManagementInjector.class, "maven"); 370 event.addAnnotatedType(DefaultProfileInjector.class, "maven"); 371 event.addAnnotatedType(DefaultReportConfigurationExpander.class, "maven"); 372 event.addAnnotatedType(DefaultReportingConverter.class, "maven"); 373 event.addAnnotatedType(DefaultSuperPomProvider.class, "maven"); 374 event.addAnnotatedType(DefaultUrlNormalizer.class, "maven"); 375 event.addAnnotatedType(FileProfileActivator.class, "maven"); 376 event.addAnnotatedType(JdkVersionProfileActivator.class, "maven"); 377 event.addAnnotatedType(OperatingSystemProfileActivator.class, "maven"); 378 event.addAnnotatedType(PropertyProfileActivator.class, "maven"); 379 event.addAnnotatedType(StringVisitorModelInterpolator.class, "maven"); 380 event.addAnnotatedType(StubLifecycleBindingsInjector.class, "maven"); 381 382 // 383 // Types bound by me :-) 384 // 385 386 // Somehow, the Producers nested class below is automatically 387 // discovered. I think this is a bug. If it is fixed, then 388 // uncomment this line. 389 // event.addAnnotatedType(Producers.class, "maven"); 390 event.addAnnotatedType(BasicRepositoryConnectorFactory.class, "maven").add(SingletonLiteral.INSTANCE); 391 event.addAnnotatedType(DefaultSettingsBuilder.class, "maven"); 392 event.addAnnotatedType(DefaultSettingsReader.class, "maven"); 393 event.addAnnotatedType(DefaultSettingsValidator.class, "maven"); 394 event.addAnnotatedType(DefaultSettingsWriter.class, "maven"); 395 event.addAnnotatedType(FileTransporterFactory.class, "maven").add(SingletonLiteral.INSTANCE); 396 event.addAnnotatedType(HttpTransporterFactory.class, "maven").add(SingletonLiteral.INSTANCE); 397 event.addAnnotatedType(MavenSettingsMerger.class, "maven").add(SingletonLiteral.INSTANCE); 398 } 399 } 400 401 /** 402 * A hack to work around the fact that Maven's {@link 403 * FileProfileActivator} class and {@code maven-resolver-api}'s 404 * {@link FileTransporterFactory} both end up with the same CDI <a 405 * href="https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#name_resolution">EL 406 * name</a>. 407 * 408 * <p>This method arbitrarily removes the {@code file} EL name from 409 * the {@link FileProfileActivator} managed bean.</p> 410 * 411 * @param event the event in question; may be {@code null} in which 412 * case no action will be taken 413 * 414 * @see FileProfileActivator 415 * 416 * @see FileTransporterFactory 417 */ 418 private final void removeBeanName(@Observes final ProcessBeanAttributes<FileProfileActivator> event) { 419 if (event != null) { 420 final BeanAttributes<FileProfileActivator> beanAttributes = event.getBeanAttributes(); 421 if (beanAttributes != null) { 422 if ("file".equals(beanAttributes.getName())) { 423 event.configureBeanAttributes().name(null); 424 } 425 } 426 } 427 } 428 429 /** 430 * Returns a {@link Properties} object containing the <a 431 * href="https://maven.apache.org/shared/maven-archiver/#pom-properties-content" 432 * target="_parent">contents of a {@code pom.properties} file as 433 * commonly installed in {@code .jar} files by Maven</a>. 434 * 435 * <p>This method may return {@code null}.</p> 436 * 437 * <p>This method is not {@code final} due to CDI specification 438 * restrictions only.</p> 439 * 440 * @param location the location of the classpath element (a {@code 441 * .jar} file, or, perhaps, a directory); may be {@code null} in 442 * which case {@code null} will be returned 443 * 444 * @return a {@link Properties} object, or {@code null} 445 * 446 * @exception IOException if an input/output error occurs 447 * 448 * @exception URISyntaxException if there was a problem constructing 449 * a {@link URI} 450 */ 451 public Properties getGroupArtifactVersionCoordinates(final URL location) throws IOException, URISyntaxException { 452 Properties returnValue = null; 453 if (location != null) { 454 final String path = location.getPath(); 455 456 URL beanArchiveRoot = null; 457 458 String scheme = location.getProtocol(); 459 if ("jar".equalsIgnoreCase(scheme)) { 460 beanArchiveRoot = new URL(location, "/"); // no jar entry, no matter what was passed in 461 } else if (path != null && path.endsWith(".jar")) { 462 beanArchiveRoot = new URL(new URL("jar", "", -1, location.toString() + "!/"), "/"); // normalize to jar URL with no jar entry 463 } else { 464 beanArchiveRoot = location; // no idea 465 } 466 assert beanArchiveRoot != null; 467 468 synchronized (this.coordinates) { 469 returnValue = this.coordinates.get(beanArchiveRoot.toURI()); 470 if (returnValue == null) { 471 472 scheme = beanArchiveRoot.getProtocol(); 473 if ("jar".equalsIgnoreCase(scheme)) { 474 final JarURLConnection urlConnection = (JarURLConnection)beanArchiveRoot.openConnection(); 475 if (urlConnection != null) { 476 try (final JarFile jarFile = urlConnection.getJarFile()) { 477 if (jarFile != null) { 478 returnValue = jarFile.stream() 479 .filter(e -> { 480 final String name = e.getName(); 481 return name != null && name.startsWith("META-INF/maven/") && name.endsWith("/pom.properties"); 482 }) 483 .findAny() // there should be only one 484 .map(jarEntry -> { 485 Properties p = null; 486 try (final InputStream inputStream = new BufferedInputStream(jarFile.getInputStream(jarEntry))) { 487 if (inputStream != null) { 488 p = new Properties(); 489 p.load(inputStream); 490 } 491 } catch (final IOException ioException) { 492 throw new RuntimeException(ioException); 493 } 494 return p; 495 }) 496 .orElse(null); 497 } 498 } 499 } 500 } else if ("file".equalsIgnoreCase(scheme)) { 501 File root = new File(beanArchiveRoot.toURI()); 502 while (root != null) { 503 if (root.isDirectory()) { 504 final File metaInfMaven = new File(root, "META-INF/maven"); 505 if (metaInfMaven.isDirectory()) { 506 507 File scanMe = metaInfMaven; 508 while (scanMe != null && scanMe.isDirectory()) { 509 510 final File[] subDirectories = scanMe.listFiles(f -> { 511 if (f == null || !f.isDirectory()) { 512 return false; 513 } 514 final String name = f.getName(); 515 return name != null && !name.startsWith("."); 516 }); 517 518 if (subDirectories == null || subDirectories.length <= 0) { 519 // We are looking for pom.properties in a 520 // directory that has no further subdirectories. 521 // We've found it. 522 final File pomPropertiesFile = new File(scanMe, "pom.properties"); 523 scanMe = null; 524 if (pomPropertiesFile.exists() && !pomPropertiesFile.isDirectory()) { 525 returnValue = new Properties(); 526 try (final InputStream stream = new BufferedInputStream(Files.newInputStream(pomPropertiesFile.toPath()))) { 527 returnValue.load(stream); 528 beanArchiveRoot = root.toURI().toURL(); 529 root = null; 530 } 531 } 532 } else if (subDirectories.length == 1) { 533 scanMe = subDirectories[0]; 534 } else { 535 scanMe = null; 536 } 537 } 538 539 } else { 540 // For common local development purposes, see if 541 // maven-archiver/pom.properties exists under our 542 // root; this will give us coordinates for testing 543 final File mavenArchiverPomProperties = new File(root, "maven-archiver/pom.properties"); 544 if (mavenArchiverPomProperties.exists() && !mavenArchiverPomProperties.isDirectory()) { 545 returnValue = new Properties(); 546 try (final InputStream stream = new BufferedInputStream(Files.newInputStream(mavenArchiverPomProperties.toPath()))) { 547 returnValue.load(stream); 548 beanArchiveRoot = root.toURI().toURL(); 549 root = null; 550 } 551 } 552 } 553 if (root != null) { 554 root = root.getParentFile(); 555 } 556 } else { 557 root = root.getParentFile(); 558 } 559 } 560 } else { 561 throw new IllegalStateException(); 562 } 563 564 if (returnValue == null || 565 !returnValue.containsKey("groupId") || 566 !returnValue.containsKey("artifactId") || 567 !returnValue.containsKey("version")) { 568 returnValue = null; 569 } else { 570 this.coordinates.put(beanArchiveRoot.toURI(), returnValue); 571 } 572 } 573 } 574 } 575 return returnValue; 576 } 577 578 /** 579 * Given a {@link Bean}, returns a {@link URL} representing the 580 * classpath root from which its {@linkplain Bean#getBeanClass() 581 * bean class} originates. 582 * 583 * <p>This method may return {@code null}.</p> 584 * 585 * @param bean the {@link Bean} whose classpath root should be 586 * returned; may be {@code null} in which case {@code null} will be 587 * returned 588 * 589 * @return a {@link URL} representing a classpath root from which 590 * the supplied {@link Bean}'s {@linkplain Bean#getBeanClass() bean 591 * class} originates, or {@code null} 592 * 593 * @see #getGroupArtifactVersionCoordinates(URL) 594 * 595 * @see Bean#getBeanClass() 596 * 597 * @see Class#getProtectionDomain() 598 * 599 * @see ProtectionDomain#getCodeSource() 600 * 601 * @see CodeSource#getLocation() 602 */ 603 public static final URL getBeanArchiveLocation(final Bean<?> bean) { 604 URL returnValue = null; 605 if (bean != null) { 606 final Class<?> beanClass = bean.getBeanClass(); 607 if (beanClass != null) { 608 final ProtectionDomain protectionDomain = beanClass.getProtectionDomain(); 609 if (protectionDomain != null) { 610 final CodeSource codeSource = protectionDomain.getCodeSource(); 611 if (codeSource != null) { 612 returnValue = codeSource.getLocation(); 613 } 614 } 615 } 616 } 617 return returnValue; 618 } 619 620 621 /* 622 * Inner and nested classes. 623 */ 624 625 626 /** 627 * A class housing several <a 628 * href="http://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#producer_method">producer 629 * methods</a> that produce certain <a 630 * href="https://maven.apache.org/resolver/">Maven Artifact Resolver 631 * components</a>. 632 * 633 * @author <a href="http://about.me/lairdnelson" 634 * target="_parent">Laird Nelson</a> 635 */ 636 private static final class Producers { 637 638 639 /* 640 * Static methods. 641 */ 642 643 644 /** 645 * Produces a {@link MirrorSelector} in {@link Singleton} scope 646 * from the contents of a {@link Settings} object. 647 * 648 * <p>This method never returns {@code null}.</p> 649 * 650 * @param settingsInstance an {@link Instance} of {@link Settings} 651 * that may be {@linkplain Instance#isUnsatisfied() unsatisfied} 652 * that contains information about mirrors; must not be {@code 653 * null} 654 * 655 * @return a {@link MirrorSelector}; never {@code null} 656 * 657 * @exception NullPointerException if {@code settingsInstance} is 658 * {@code null} 659 */ 660 @Produces 661 @Singleton 662 private static final MirrorSelector produceMirrorSelector(final Instance<Settings> settingsInstance) { 663 Objects.requireNonNull(settingsInstance); 664 final DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector(); 665 if (settingsInstance.isResolvable()) { 666 final Collection<? extends Mirror> mirrors = settingsInstance.get().getMirrors(); 667 if (mirrors != null && !mirrors.isEmpty()) { 668 for (final Mirror mirror : mirrors) { 669 assert mirror != null; 670 mirrorSelector.add(mirror.getId(), 671 mirror.getUrl(), 672 mirror.getLayout(), 673 false, /* not a repository manager; settings.xml does not encode this information */ 674 mirror.getMirrorOf(), 675 mirror.getMirrorOfLayouts()); 676 } 677 } 678 } 679 return mirrorSelector; 680 } 681 682 /** 683 * Produces a {@link Settings} object in {@link Singleton} scope 684 * from the supplied {@link SettingsBuilder} object. 685 * 686 * <p>This method never returns {@code null}.</p> 687 * 688 * @param settingsBuilder the {@link SettingsBuilder} that will 689 * ultimately be used to create this method's return value; must 690 * not be {@code null} 691 * 692 * @param mavenHomePath a {@link Path} describing a Maven home 693 * directory for the purposes of locating the global settings 694 * file; may be {@code null} 695 * 696 * @param mavenConfPath a {@link Path} describing a Maven global 697 * configuration directory for the purposes of locating the global 698 * settings file; may be {@code null} 699 * 700 * @param globalSettingsPath a {@link Path} representing where the 701 * global {@code settings.xml} file lives; may be {@code null} 702 * 703 * @param userSettingsPath a {@link Path} representing where the 704 * user's {@code settings.xml} file lives; may be {@code null} 705 * 706 * @return a {@link Settings} object; never {@code null} 707 * 708 * @exception NullPointerException if {@code settingsBuilder} is 709 * {@code null} 710 * 711 * @exception SettingsBuildingException if the {@link 712 * SettingsBuildingResult#getProblems()} method invoked on the 713 * return value of the {@link 714 * SettingsBuilder#build(SettingsBuildingRequest)} method returns 715 * a {@link List} of {@link SettingsProblem}s 716 */ 717 @Produces 718 @Singleton 719 private static final Settings produceSettings(final SettingsBuilder settingsBuilder, 720 721 @ConfigurationValue(value = { 722 "maven.home", 723 "M2_HOME" 724 }) 725 Path mavenHomePath, 726 727 @ConfigurationValue(value = { 728 "maven.conf" 729 }) 730 Path mavenConfPath, 731 732 @ConfigurationValue(value = { 733 "org.microbean.maven.cdi.globalSettingsPath", 734 "GLOBAL_SETTINGS_PATH" 735 }) 736 Path globalSettingsPath, 737 738 @ConfigurationValue(value = { 739 "org.microbean.maven.cdi.userSettingsPath", 740 "USER_SETTINGS_PATH" 741 }, 742 defaultValue = "${configurations[\"user.home\"]}/.m2/settings.xml") 743 final Path userSettingsPath) 744 throws SettingsBuildingException { 745 Objects.requireNonNull(settingsBuilder); 746 final DefaultSettingsBuildingRequest request = new DefaultSettingsBuildingRequest(); 747 request.setSystemProperties(System.getProperties()); 748 // request.setUserProperties(userProperties); // TODO: implement this 749 750 final File globalSettingsFile; 751 if (globalSettingsPath == null) { 752 if (mavenConfPath == null) { 753 if (mavenHomePath == null) { 754 String m2Home = System.getProperty("maven.home"); 755 if (m2Home == null) { 756 m2Home = System.getenv("M2_HOME"); 757 } 758 if (m2Home == null) { 759 globalSettingsFile = null; 760 } else { 761 mavenHomePath = Paths.get(m2Home); 762 mavenConfPath = mavenHomePath.resolve("conf"); 763 globalSettingsPath = mavenConfPath.resolve("settings.xml"); 764 globalSettingsFile = globalSettingsPath.toFile(); 765 } 766 } else { 767 mavenConfPath = mavenHomePath.resolve("conf"); 768 assert mavenConfPath != null; 769 globalSettingsPath = mavenConfPath.resolve("settings.xml"); 770 globalSettingsFile = globalSettingsPath.toFile(); 771 } 772 } else { 773 globalSettingsPath = mavenConfPath.resolve("settings.xml"); 774 globalSettingsFile = globalSettingsPath.toFile(); 775 } 776 } else { 777 globalSettingsFile = globalSettingsPath.toFile(); 778 } 779 request.setGlobalSettingsFile(globalSettingsFile); 780 781 final File userSettingsFile; 782 if (userSettingsPath == null) { 783 userSettingsFile = Paths.get(System.getProperty("user.home"), ".m2", "settings.xml").toFile(); 784 } else { 785 userSettingsFile = userSettingsPath.toFile(); 786 } 787 request.setUserSettingsFile(userSettingsFile); 788 final SettingsBuildingResult settingsBuildingResult = settingsBuilder.build(request); 789 assert settingsBuildingResult != null; 790 final List<SettingsProblem> settingsBuildingProblems = settingsBuildingResult.getProblems(); 791 if (settingsBuildingProblems != null && !settingsBuildingProblems.isEmpty()) { 792 // It is guaranteed that these problems will contain warnings 793 // only, but that's still a problem! 794 throw new SettingsBuildingException(settingsBuildingProblems); 795 } 796 final Settings returnValue = settingsBuildingResult.getEffectiveSettings(); 797 return returnValue; 798 } 799 800 /** 801 * Produces a {@link ProfileSelector} in {@link Singleton} scope 802 * that makes use of the supplied {@link ProfileActivator}s. 803 * 804 * <p>This method never returns {@code null}.</p> 805 * 806 * @param jdkVersionProfileActivator a {@link ProfileActivator} 807 * that can activate a Maven profile based on the version of the 808 * JDK; may be {@code null} 809 * 810 * @param operatingSystemProfileActivator a {@link 811 * ProfileActivator} that can activate a Maven profile based on 812 * the current operating system; may be {@code null} 813 * 814 * @param fileProfileActivator a {@link ProfileActivator} that can 815 * activate a Maven profile based on the presence of a file; may 816 * be {@code null} 817 * 818 * @param propertyProfileActivator a {@link ProfileActivator} that 819 * can activate a maven profile based on the value of a property; 820 * may be {@code null} 821 * 822 * @return a {@link ProfileSelector}; never {@code null} 823 * 824 * @see JdkVersionProfileActivator 825 * 826 * @see OperatingSystemProfileActivator 827 * 828 * @see FileProfileActivator 829 * 830 * @see PropertyProfileActivator 831 * 832 * @see DefaultProfileSelector 833 */ 834 @Produces 835 @Singleton 836 private static final ProfileSelector produceProfileSelector(@Named("jdk-version") final ProfileActivator jdkVersionProfileActivator, 837 @Named("os") final ProfileActivator operatingSystemProfileActivator, 838 @Named("property") final ProfileActivator fileProfileActivator, 839 @Named("file") final ProfileActivator propertyProfileActivator) { 840 final DefaultProfileSelector returnValue = new DefaultProfileSelector(); 841 returnValue.addProfileActivator(jdkVersionProfileActivator); 842 returnValue.addProfileActivator(operatingSystemProfileActivator); 843 returnValue.addProfileActivator(propertyProfileActivator); 844 returnValue.addProfileActivator(fileProfileActivator); // TODO: make sure fileProfileActivator.pathTranslator is non-null (i.e. injection worked) 845 return returnValue; 846 } 847 848 /** 849 * Produces an {@link ILoggerFactory} in {@link Singleton} scope. 850 * 851 * <p>This method never returns {@code null}.</p> 852 * 853 * @return an {@link ILoggerFactory}; never {@code null} 854 * 855 * @see LoggerFactory#getILoggerFactory() 856 */ 857 @Produces 858 @Singleton 859 private static final ILoggerFactory produceILoggerFactory() { 860 return LoggerFactory.getILoggerFactory(); 861 } 862 863 /** 864 * Produces a {@link LocalRepository} in {@link Singleton} scope. 865 * 866 * <p>This method never returns {@code null}.</p> 867 * 868 * @param mavenRepoLocal the value of the {@code maven.repo.local} 869 * configuration property; may be (and often is) {@code null} 870 * 871 * @param settingsInstance an {@link Instance} of {@link Settings} 872 * that may be {@linkplain Instance#isUnsatisfied() unsatisfied} 873 * that contains information about where a local Maven repository 874 * can be found; must not be {@code null} 875 * 876 * @return a {@link LocalRepository}; never {@code null} 877 * 878 * @exception NullPointerException if {@code settingsInstance} is 879 * {@code null} 880 * 881 * @see Settings#getLocalRepository() 882 */ 883 @Produces 884 @Singleton 885 private static final LocalRepository produceLocalRepository(@ConfigurationValue("maven.repo.local") 886 final String mavenRepoLocal, 887 final Instance<Settings> settingsInstance) { 888 // TODO: see https://github.com/apache/maven/blob/eb6b212b567c287734a2dbbef3c113fe650f1def/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java#L133 889 Objects.requireNonNull(settingsInstance); 890 String localRepositoryString = mavenRepoLocal; 891 if (localRepositoryString == null && settingsInstance.isResolvable()) { 892 localRepositoryString = settingsInstance.get().getLocalRepository(); 893 } 894 if (localRepositoryString == null) { 895 localRepositoryString = System.getProperty("user.home") + "/.m2/repository"; 896 } 897 final LocalRepository returnValue = new LocalRepository(localRepositoryString); 898 return returnValue; 899 } 900 901 /** 902 * Produces a {@link List} of {@link RemoteRepository} instances 903 * in {@link Dependent} scope {@linkplain Resolution suitable for 904 * artifact resolution} whose contents are inferred from reading 905 * the {@linkplain Settings#getActiveProfiles() active profiles 906 * contained in the supplied <code>Settings</code> object}. 907 * 908 * <p>This method will never return {@code null}.</p> 909 * 910 * @param settingsInstance an {@link Instance} of {@link Settings} 911 * that may be {@linkplain Instance#isUnsatisfied() unsatisfied} 912 * that contains information about where remote Maven repositories 913 * may be found; must not be {@code null} 914 * 915 * @param repositorySystem the {@link RepositorySystem} whose 916 * {@link 917 * RepositorySystem#newResolutionRepositories(RepositorySystemSession, 918 * List)} method will be called; must not be {@code null} 919 * 920 * @param session the {@link RepositorySystemSession} currently in 921 * effect; must not be {@code null} 922 * 923 * @return a {@link List} of {@link RemoteRepository} instances 924 * {@link Resolution suitable for artifact resolution}; never 925 * {@code null} 926 * 927 * @exception NullPointerException if either {@code 928 * settingsInstance}, {@code repositorySystem} or {@code session} 929 * is {@code null} 930 */ 931 @Produces 932 @Dependent 933 @Resolution 934 private static final List<RemoteRepository> produceRemoteRepositoryList(final Instance<Settings> settingsInstance, 935 final RepositorySystem repositorySystem, 936 final RepositorySystemSession session) { 937 Objects.requireNonNull(settingsInstance); 938 Objects.requireNonNull(repositorySystem); 939 Objects.requireNonNull(session); 940 List<RemoteRepository> remoteRepositories = new ArrayList<>(); 941 if (settingsInstance.isResolvable()) { 942 final Settings settings = settingsInstance.get(); 943 assert settings != null; 944 final Map<String, Profile> profiles = settings.getProfilesAsMap(); 945 if (profiles != null && !profiles.isEmpty()) { 946 final Collection<String> activeProfileKeys = settings.getActiveProfiles(); 947 if (activeProfileKeys != null && !activeProfileKeys.isEmpty()) { 948 for (final String activeProfileKey : activeProfileKeys) { 949 final Profile activeProfile = profiles.get(activeProfileKey); 950 if (activeProfile != null) { 951 final Collection<Repository> repositories = activeProfile.getRepositories(); 952 if (repositories != null && !repositories.isEmpty()) { 953 for (final Repository repository : repositories) { 954 if (repository != null) { 955 RemoteRepository.Builder builder = new RemoteRepository.Builder(repository.getId(), repository.getLayout(), repository.getUrl()); 956 957 final org.apache.maven.settings.RepositoryPolicy settingsReleasePolicy = repository.getReleases(); 958 if (settingsReleasePolicy != null) { 959 final org.eclipse.aether.repository.RepositoryPolicy releasePolicy = new org.eclipse.aether.repository.RepositoryPolicy(settingsReleasePolicy.isEnabled(), settingsReleasePolicy.getUpdatePolicy(), settingsReleasePolicy.getChecksumPolicy()); 960 builder = builder.setReleasePolicy(releasePolicy); 961 } 962 963 final org.apache.maven.settings.RepositoryPolicy settingsSnapshotPolicy = repository.getSnapshots(); 964 if (settingsSnapshotPolicy != null) { 965 final org.eclipse.aether.repository.RepositoryPolicy snapshotPolicy = new org.eclipse.aether.repository.RepositoryPolicy(settingsSnapshotPolicy.isEnabled(), settingsSnapshotPolicy.getUpdatePolicy(), settingsSnapshotPolicy.getChecksumPolicy()); 966 builder = builder.setSnapshotPolicy(snapshotPolicy); 967 } 968 969 final RemoteRepository remoteRepository = builder.build(); 970 assert remoteRepository != null; 971 remoteRepositories.add(remoteRepository); 972 } 973 } 974 } 975 } 976 } 977 } 978 } 979 } 980 final RemoteRepository mavenCentral = new RemoteRepository.Builder("central", "default", "http://central.maven.org/maven2/").build(); 981 assert mavenCentral != null; 982 remoteRepositories.add(mavenCentral); 983 remoteRepositories = repositorySystem.newResolutionRepositories(session, remoteRepositories); 984 assert remoteRepositories != null; 985 return remoteRepositories; 986 } 987 988 /** 989 * Produces a {@link RepositorySystemSession} in {@link Dependent} scope. 990 * 991 * <p>This method never returns {@code null}.</p> 992 * 993 * <h2>Implementation Notes</h2> 994 * 995 * <p>This method returns an {@link RepositorySystemSession} that 996 * is built in the same manner as that built by the {@link 997 * MavenRepositorySystemUtils#newSession()} method.</p> 998 * 999 * @param dependencyTraverser the {@link DependencyTraverser} that 1000 * helps in pruning the dependency graph; may be {@code null} 1001 * 1002 * @param dependencyManager the {@link DependencyManager} that 1003 * applies any overriding concerns with respect to particular 1004 * dependencies' versions and scopes (think {@code 1005 * <dependencyManagement>} in a Maven {@code pom.xml} file); may 1006 * be {@code null} 1007 * 1008 * @param dependencySelector a {@link DependencySelector} that 1009 * helps filter dependencies; may be {@code null} 1010 * 1011 * @param dependencyGraphTransformer a {@link 1012 * DependencyGraphTransformer} that helps with conflict 1013 * resolution; may be {@code null} 1014 * 1015 * @param artifactTypeRegistry an {@link ArtifactTypeRegistry} 1016 * that governs what artifacts will be looked at; may be {@code 1017 * null} 1018 * 1019 * @param artifactDescriptorPolicy an {@link 1020 * ArtifactDescriptorPolicy} that controls what to do with missing 1021 * or invalid artifacts; may be {@code null} 1022 * 1023 * @param settingsInstance an {@link Instance} of {@link Settings} 1024 * that may be {@linkplain Instance#isUnsatisfied() unsatisfied} 1025 * that may be consulted for offline status information; must not 1026 * be {@code null} 1027 * 1028 * @param mirrorSelector a {@link MirrorSelector} that will choose 1029 * the appropriate mirror for a given repository; may be {@code 1030 * null} 1031 * 1032 * @param localRepository a {@link LocalRepository} instance 1033 * representing the location where remote artifacts will be 1034 * cached; must not be {@code null} 1035 * 1036 * @param localRepositoryProvider a {@link 1037 * LocalRepositoryProvider} that will be {@linkplain 1038 * LocalRepositoryProvider#newLocalRepositoryManager(RepositorySystemSession, 1039 * LocalRepository) used to obtain a 1040 * <code>LocalRepositoryManager</code>}; must not be {@code null} 1041 * 1042 * @param transferListenerInstance an {@link Instance} 1043 * representing a {@link TransferListener}, which, {@linkplain 1044 * Instance#isResolvable() if resolvable}, will be installed on 1045 * the returned {@link RepositorySystemSession}; may be {@code 1046 * null} 1047 * 1048 * @return a {@link RepositorySystemSession}; never {@code null} 1049 * 1050 * @exception NullPointerException if any parameter described 1051 * above that must be non-{@code null} was {@code null} 1052 * 1053 * @exception NoLocalRepositoryManagerException if the supplied 1054 * {@link LocalRepositoryProvider} could not {@linkplain 1055 * LocalRepositoryProvider#newLocalRepositoryManager(RepositorySystemSession, 1056 * LocalRepository) provide a <code>LocalRepositoryManager</code>} 1057 * 1058 * @see MavenRepositorySystemUtils#newSession() 1059 * 1060 * @see FatArtifactTraverser 1061 * 1062 * @see ClassicDependencyManager 1063 * 1064 * @see ScopeDependencySelector 1065 * 1066 * @see OptionalDependencySelector 1067 * 1068 * @see ExclusionDependencySelector 1069 * 1070 * @see ConflictResolver 1071 * 1072 * @see NearestVersionSelector 1073 * 1074 * @see JavaScopeSelector 1075 * 1076 * @see SimpleOptionalitySelector 1077 * 1078 * @see JavaScopeDeriver 1079 * 1080 * @see #produceArtifactTypeRegistry() 1081 * 1082 * @see #produceArtifactDescriptorPolicy() 1083 * 1084 * @see Settings#isOffline() 1085 * 1086 * @see DefaultRepositorySystemSession#setOffline(boolean) 1087 * 1088 * @see #produceMirrorSelector(Instance) 1089 * 1090 * @see #produceLocalRepository(String, Instance) 1091 * 1092 * @see 1093 * LocalRepositoryProvider#newLocalRepositoryManager(RepositorySystemSession, 1094 * LocalRepository) 1095 * 1096 * @see TransferListener 1097 * 1098 * @see 1099 * DefaultRepositorySystemSession#setTransferListener(TransferListener) 1100 */ 1101 @Produces 1102 @Dependent 1103 private static final RepositorySystemSession produceRepositorySystemSession(final DependencyTraverser dependencyTraverser, 1104 final DependencyManager dependencyManager, 1105 final DependencySelector dependencySelector, 1106 final DependencyGraphTransformer dependencyGraphTransformer, 1107 final ArtifactTypeRegistry artifactTypeRegistry, 1108 final ArtifactDescriptorPolicy artifactDescriptorPolicy, 1109 final Instance<Settings> settingsInstance, 1110 final MirrorSelector mirrorSelector, 1111 final LocalRepository localRepository, 1112 final LocalRepositoryProvider localRepositoryProvider, 1113 final Instance<TransferListener> transferListenerInstance) 1114 throws NoLocalRepositoryManagerException { 1115 Objects.requireNonNull(settingsInstance); 1116 final DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(); 1117 session.setDependencyTraverser(dependencyTraverser); 1118 session.setDependencyManager(dependencyManager); 1119 session.setDependencySelector(dependencySelector); 1120 session.setDependencyGraphTransformer(dependencyGraphTransformer); 1121 session.setArtifactTypeRegistry(artifactTypeRegistry); 1122 session.setArtifactDescriptorPolicy(artifactDescriptorPolicy); 1123 final Properties sessionSystemProperties = new Properties(); 1124 final Properties systemProperties = System.getProperties(); 1125 synchronized (systemProperties) { 1126 final Set<String> keys = systemProperties.stringPropertyNames(); 1127 if (keys != null) { 1128 for (final String key : keys) { 1129 assert key != null; 1130 sessionSystemProperties.setProperty(key, systemProperties.getProperty(key)); 1131 } 1132 } 1133 } 1134 session.setSystemProperties(sessionSystemProperties); 1135 session.setConfigProperties(sessionSystemProperties); 1136 if (settingsInstance.isResolvable()) { 1137 session.setOffline(settingsInstance.get().isOffline()); 1138 } 1139 session.setMirrorSelector(mirrorSelector); 1140 final LocalRepositoryManager localRepositoryManager = localRepositoryProvider.newLocalRepositoryManager(session, localRepository); 1141 session.setLocalRepositoryManager(localRepositoryManager); 1142 if (transferListenerInstance != null && transferListenerInstance.isResolvable()) { 1143 session.setTransferListener(transferListenerInstance.get()); 1144 } 1145 return session; 1146 } 1147 1148 /** 1149 * Produces a {@link DependencySelector} in {@link Singleton} 1150 * scope. 1151 * 1152 * <p>This method never returns {@code null}.</p> 1153 * 1154 * <h2>Implementation Notes</h2> 1155 * 1156 * <p>This method returns an {@link AndDependencySelector} that is 1157 * built in the same manner as that built by the {@link 1158 * MavenRepositorySystemUtils#newSession()} method.</p> 1159 * 1160 * @return a {@link DependencySelector}; never {@code null} 1161 * 1162 * @see MavenRepositorySystemUtils#newSession() 1163 */ 1164 @Produces 1165 @Singleton 1166 private static final DependencySelector produceDependencySelector() { 1167 return new AndDependencySelector(new ScopeDependencySelector("test", "provided"), // excludes test and provided scopes 1168 new OptionalDependencySelector(), 1169 new ExclusionDependencySelector()); 1170 } 1171 1172 /** 1173 * Produces a {@link DependencyGraphTransformer} in {@link 1174 * Singleton} scope. 1175 * 1176 * <p>This method never returns {@code null}.</p> 1177 * 1178 * <h2>Implementation Notes</h2> 1179 * 1180 * <p>This method returns a {@link 1181 * ChainedDependencyGraphTransformer} that is built in the same 1182 * manner as that built by the {@link 1183 * MavenRepositorySystemUtils#newSession()} method.</p> 1184 * 1185 * @return a {@link DependencyGraphTransformer}; never {@code 1186 * null} 1187 * 1188 * @see MavenRepositorySystemUtils#newSession() 1189 */ 1190 @Produces 1191 @Singleton 1192 private static final DependencyGraphTransformer produceDependencyGraphTransformer() { 1193 return new ChainedDependencyGraphTransformer(new ConflictResolver(new NearestVersionSelector(), 1194 new JavaScopeSelector(), 1195 new SimpleOptionalitySelector(), 1196 new JavaScopeDeriver()), 1197 new JavaDependencyContextRefiner()); 1198 } 1199 1200 /** 1201 * Produces an {@link ArtifactTypeRegistry} in {@link Singleton} 1202 * scope. 1203 * 1204 * <p>This method never returns {@code null}.</p> 1205 * 1206 * <h2>Implementation Notes</h2> 1207 * 1208 * <p>This method returns a {@link DefaultArtifactTypeRegistry} 1209 * that is built in the same manner as that built by the {@link 1210 * MavenRepositorySystemUtils#newSession()} method.</p> 1211 * 1212 * @return an {@link ArtifactTypeRegistry}; never {@code null} 1213 * 1214 * @see MavenRepositorySystemUtils#newSession() 1215 */ 1216 @Produces 1217 @Singleton 1218 private static final ArtifactTypeRegistry produceArtifactTypeRegistry() { 1219 final DefaultArtifactTypeRegistry stereotypes = new DefaultArtifactTypeRegistry(); 1220 stereotypes.add(new DefaultArtifactType("pom")); 1221 stereotypes.add(new DefaultArtifactType("maven-plugin", "jar", "", "java")); 1222 stereotypes.add(new DefaultArtifactType("jar", "jar", "", "java")); 1223 stereotypes.add(new DefaultArtifactType("ejb", "jar", "", "java")); 1224 stereotypes.add(new DefaultArtifactType("ejb-client", "jar", "client", "java")); 1225 stereotypes.add(new DefaultArtifactType("test-jar", "jar", "tests", "java")); 1226 stereotypes.add(new DefaultArtifactType("javadoc", "jar", "javadoc", "java")); 1227 stereotypes.add(new DefaultArtifactType("java-source", "jar", "sources", "java", false, false)); 1228 stereotypes.add(new DefaultArtifactType("war", "war", "", "java", false, true)); 1229 stereotypes.add(new DefaultArtifactType("ear", "ear", "", "java", false, true)); 1230 stereotypes.add(new DefaultArtifactType("rar", "rar", "", "java", false, true)); 1231 stereotypes.add(new DefaultArtifactType("par", "par", "", "java", false, true)); 1232 return stereotypes; 1233 } 1234 1235 /** 1236 * Produces an {@link ArtifactDescriptorPolicy} in {@link 1237 * Singleton} scope. 1238 * 1239 * <p>This method never returns {@code null}.</p> 1240 * 1241 * <h2>Implementation Notes</h2> 1242 * 1243 * <p>This method returns a {@link SimpleArtifactDescriptorPolicy} 1244 * that is built in the same manner as that built by the {@link 1245 * MavenRepositorySystemUtils#newSession()} method.</p> 1246 * 1247 * @return an {@link ArtifactDescriptorPolicy}; never {@code null} 1248 * 1249 * @see MavenRepositorySystemUtils#newSession() 1250 */ 1251 @Produces 1252 @Singleton 1253 private static final ArtifactDescriptorPolicy produceArtifactDescriptorPolicy() { 1254 return new SimpleArtifactDescriptorPolicy(true /* ignoreMissing */, true /* ignoreInvalid */); 1255 } 1256 1257 1258 /* 1259 * Sets of things. 1260 */ 1261 1262 1263 /** 1264 * Converts an {@link Instance} of {@link 1265 * LocalRepositoryManagerFactory} instances into a {@link Set} of 1266 * such instances in {@link Singleton} scope. 1267 * 1268 * <p>This method never returns {@code null}.</p> 1269 * 1270 * @param localRepositoryManagerFactories an {@link Instance} of 1271 * {@link LocalRepositoryManagerFactory} instances; may be {@code 1272 * null} 1273 * 1274 * @return a {@link Set} of {@link LocalRepositoryManagerFactory} 1275 * instances; never {@code null} 1276 * 1277 * @see #produceSet(Instance) 1278 */ 1279 @Produces 1280 @Singleton 1281 private static final Set<LocalRepositoryManagerFactory> produceLocalRepositoryManagerFactorySet(@Any final Instance<LocalRepositoryManagerFactory> localRepositoryManagerFactories) { 1282 final Set<LocalRepositoryManagerFactory> returnValue = produceSet(localRepositoryManagerFactories); 1283 return returnValue; 1284 } 1285 1286 /** 1287 * Converts an {@link Instance} of {@link RepositoryLayoutFactory} 1288 * instances into a {@link Set} of such instances in {@link 1289 * Singleton} scope. 1290 * 1291 * <p>This method never returns {@code null}.</p> 1292 * 1293 * @param repositoryLayoutFactories an {@link Instance} of {@link 1294 * RepositoryLayoutFactory} instances; may be {@code null} 1295 * 1296 * @return a {@link Set} of {@link RepositoryLayoutFactory} 1297 * instances; never {@code null} 1298 * 1299 * @see #produceSet(Instance) 1300 */ 1301 @Produces 1302 @Singleton 1303 private static final Set<RepositoryLayoutFactory> produceRepositoryLayoutFactorySet(@Any final Instance<RepositoryLayoutFactory> repositoryLayoutFactories) { 1304 return produceSet(repositoryLayoutFactories); 1305 } 1306 1307 /** 1308 * Converts an {@link Instance} of {@link TransporterFactory} 1309 * instances into a {@link Set} of such instances in {@link 1310 * Singleton} scope. 1311 * 1312 * <p>This method never returns {@code null}.</p> 1313 * 1314 * @param transporterFactories an {@link Instance} of {@link 1315 * TransporterFactory} instances; may be {@code null} 1316 * 1317 * @return a {@link Set} of {@link TransporterFactory} instances; 1318 * never {@code null} 1319 * 1320 * @see #produceSet(Instance) 1321 */ 1322 @Produces 1323 @Singleton 1324 private static final Set<TransporterFactory> produceTransporterFactorySet(@Any final Instance<TransporterFactory> transporterFactories) { 1325 return produceSet(transporterFactories); 1326 } 1327 1328 /** 1329 * Converts an {@link Instance} of {@link RepositoryListener} 1330 * instances into a {@link Set} of such instances in {@link 1331 * Singleton} scope. 1332 * 1333 * <p>This method never returns {@code null}.</p> 1334 * 1335 * @param repositoryListeners an {@link Instance} of {@link 1336 * RepositoryListener} instances; may be {@code null} 1337 * 1338 * @return a {@link Set} of {@link RepositoryListener} instances; 1339 * never {@code null} 1340 * 1341 * @see #produceSet(Instance) 1342 */ 1343 @Produces 1344 @Dependent 1345 private static final Set<RepositoryListener> produceRepositoryListenerSet(@Any final Instance<RepositoryListener> repositoryListeners) { 1346 return produceSet(repositoryListeners); 1347 } 1348 1349 /** 1350 * Converts an {@link Instance} of {@link 1351 * RepositoryConnectorFactory} instances into a {@link Set} of 1352 * such instances in {@link Singleton} scope. 1353 * 1354 * <p>This method never returns {@code null}.</p> 1355 * 1356 * @param repositoryConnectorFactories an {@link Instance} of 1357 * {@link RepositoryConnectorFactory} instances; may be {@code 1358 * null} 1359 * 1360 * @return a {@link Set} of {@link RepositoryConnectorFactory} 1361 * instances; never {@code null} 1362 * 1363 * @see #produceSet(Instance) 1364 */ 1365 @Produces 1366 @Singleton 1367 private static final Set<RepositoryConnectorFactory> produceRepositoryConnectorFactorySet(@Any final Instance<RepositoryConnectorFactory> repositoryConnectorFactories) { 1368 return produceSet(repositoryConnectorFactories); 1369 } 1370 1371 /** 1372 * Converts an {@link Instance} of {@link 1373 * MetadataGeneratorFactory} instances into a {@link Set} of such 1374 * instances in {@link Singleton} scope. 1375 * 1376 * <p>This method never returns {@code null}.</p> 1377 * 1378 * @param metadataGeneratorFactories an {@link Instance} of {@link 1379 * MetadataGeneratorFactory} instances; may be {@code null} 1380 * 1381 * @return a {@link Set} of {@link MetadataGeneratorFactory} 1382 * instances; never {@code null} 1383 * 1384 * @see #produceSet(Instance) 1385 */ 1386 @Produces 1387 @Singleton 1388 private static final Set<MetadataGeneratorFactory> produceMetadataGeneratorFactorySet(@Any final Instance<MetadataGeneratorFactory> metadataGeneratorFactories) { 1389 return produceSet(metadataGeneratorFactories); 1390 } 1391 1392 /** 1393 * Returns a {@link Set} of the objects represented by the 1394 * supplied {@link Instance}. 1395 * 1396 * <p>This method never returns {@code null}.</p> 1397 * 1398 * @param <T> the type of object the returned {@link Set} will 1399 * contain 1400 * 1401 * @param things the {@link Instance} whose instances should be 1402 * returned as a {@link Set}; may be {@code null} 1403 * 1404 * @return a non-{@code null} {@link Set} 1405 */ 1406 private static final <T> Set<T> produceSet(final Instance<? extends T> things) { 1407 final Set<T> returnValue = new HashSet<>(); 1408 if (things != null) { 1409 for (final T thing : things) { 1410 returnValue.add(thing); 1411 } 1412 } 1413 return returnValue; 1414 } 1415 1416 } 1417 1418 /** 1419 * A {@link LifecycleBindingsInjector} that does nothing. 1420 * 1421 * @author <a href="http://about.me/lairdnelson/" 1422 * target="_parent">Laird Nelson</a> 1423 * 1424 * @see LifecycleBindingsInjector 1425 */ 1426 private static final class StubLifecycleBindingsInjector implements LifecycleBindingsInjector { 1427 1428 1429 /* 1430 * Instance methods. 1431 */ 1432 1433 1434 /** 1435 * Does nothing when invoked. 1436 * 1437 * @param model ignored 1438 * 1439 * @param modelBuildingRequest ignored 1440 * 1441 * @param modelProblemCollector ignored 1442 */ 1443 @Override 1444 public final void injectLifecycleBindings(final Model model, final ModelBuildingRequest modelBuildingRequest, final ModelProblemCollector modelProblemCollector) { 1445 1446 } 1447 1448 } 1449 1450}