From b182eb6c94fc5a5f942091a57d8ec6fd9a782a58 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Mon, 13 Nov 2017 14:05:37 +0100 Subject: [PATCH] Deal with the deprecation of Eclipse Aether --- demo/slc_localrepo.properties | 4 +- dist/pom.xml | 2 +- .../dist/commands/NormalizeDistribution.java | 2 +- org.argeo.slc.repo/.classpath | 3 +- org.argeo.slc.repo/.gitignore | 1 + org.argeo.slc.repo/bnd.bnd | 3 + org.argeo.slc.repo/build.properties | 1 + .../slc/repo/internal}/AetherUtilsTest.java | 4 +- .../test/org/argeo/slc/repo/internal/pom.xml | 209 +++++ .../org/argeo/slc/repo/ArtifactIndexer.java | 2 +- .../slc/repo/ModularDistributionIndexer.java | 4 +- .../org/argeo/slc/repo/PdeSourcesIndexer.java | 2 +- .../src/org/argeo/slc/repo/RepoUtils.java | 2 +- .../argeo/slc/repo/maven}/AetherUtils.java | 2 +- .../slc/repo/maven}/ArtifactIdComparator.java | 2 +- .../slc/repo/maven/GenerateBinaries.java | 1 - .../repo/maven/ImportMavenDependencies.java | 374 -------- .../slc/repo/maven/MavenConventionsUtils.java | 130 ++- .../argeo/slc/repo/osgi/ArchiveWrapper.java | 2 +- .../org/argeo/slc/repo/osgi/MavenWrapper.java | 1 - .../argeo/slc/repo/osgi/NormalizeGroup.java | 2 +- .../org/argeo/slc/repo/osgi/SubArtifact.java | 214 +++++ ...ractForwardingRepositorySystemSession.java | 180 ++++ .../aether/AbstractRepositoryListener.java | 103 +++ .../aether/ConfigurationProperties.java | 165 ++++ .../aether/DefaultRepositoryCache.java | 43 + .../DefaultRepositorySystemSession.java | 825 ++++++++++++++++++ .../eclipse/aether/DefaultSessionData.java | 82 ++ .../org/eclipse/aether/RepositoryCache.java | 50 ++ .../org/eclipse/aether/RepositoryEvent.java | 433 +++++++++ .../eclipse/aether/RepositoryException.java | 63 ++ .../eclipse/aether/RepositoryListener.java | 213 +++++ .../org/eclipse/aether/RepositorySystem.java | 268 ++++++ .../aether/RepositorySystemSession.java | 254 ++++++ .../src/org/eclipse/aether/RequestTrace.java | 108 +++ .../src/org/eclipse/aether/SessionData.java | 57 ++ .../src/org/eclipse/aether/SyncContext.java | 67 ++ .../aether/artifact/AbstractArtifact.java | 221 +++++ .../org/eclipse/aether/artifact/Artifact.java | 134 +++ .../aether/artifact/ArtifactProperties.java | 65 ++ .../eclipse/aether/artifact/ArtifactType.java | 58 ++ .../aether/artifact/ArtifactTypeRegistry.java | 29 + .../aether/artifact/DefaultArtifact.java | 276 ++++++ .../aether/artifact/DefaultArtifactType.java | 137 +++ .../eclipse/aether/artifact/package-info.java | 15 + .../aether/collection/CollectRequest.java | 347 ++++++++ .../aether/collection/CollectResult.java | 150 ++++ .../DependencyCollectionContext.java | 66 ++ .../DependencyCollectionException.java | 102 +++ .../DependencyGraphTransformationContext.java | 49 ++ .../DependencyGraphTransformer.java | 42 + .../collection/DependencyManagement.java | 168 ++++ .../aether/collection/DependencyManager.java | 48 + .../aether/collection/DependencySelector.java | 49 ++ .../collection/DependencyTraverser.java | 50 ++ .../UnsolvableVersionConflictException.java | 133 +++ .../aether/collection/VersionFilter.java | 126 +++ .../aether/collection/package-info.java | 16 + .../aether/deployment/DeployRequest.java | 193 ++++ .../aether/deployment/DeployResult.java | 165 ++++ .../deployment/DeploymentException.java | 43 + .../aether/deployment/package-info.java | 15 + .../aether/graph/DefaultDependencyNode.java | 359 ++++++++ .../org/eclipse/aether/graph/Dependency.java | 321 +++++++ .../eclipse/aether/graph/DependencyCycle.java | 44 + .../aether/graph/DependencyFilter.java | 33 + .../eclipse/aether/graph/DependencyNode.java | 223 +++++ .../aether/graph/DependencyVisitor.java | 38 + .../org/eclipse/aether/graph/Exclusion.java | 122 +++ .../eclipse/aether/graph/package-info.java | 15 + .../aether/installation/InstallRequest.java | 168 ++++ .../aether/installation/InstallResult.java | 165 ++++ .../installation/InstallationException.java | 43 + .../aether/installation/package-info.java | 15 + .../aether/metadata/AbstractMetadata.java | 151 ++++ .../aether/metadata/DefaultMetadata.java | 183 ++++ .../aether/metadata/MergeableMetadata.java | 42 + .../org/eclipse/aether/metadata/Metadata.java | 129 +++ .../eclipse/aether/metadata/package-info.java | 15 + .../src/org/eclipse/aether/package-info.java | 15 + .../aether/repository/ArtifactRepository.java | 36 + .../aether/repository/Authentication.java | 46 + .../repository/AuthenticationContext.java | 380 ++++++++ .../repository/AuthenticationDigest.java | 210 +++++ .../repository/AuthenticationSelector.java | 29 + .../repository/LocalArtifactRegistration.java | 140 +++ .../repository/LocalArtifactRequest.java | 136 +++ .../repository/LocalArtifactResult.java | 138 +++ .../repository/LocalMetadataRegistration.java | 139 +++ .../repository/LocalMetadataRequest.java | 124 +++ .../repository/LocalMetadataResult.java | 105 +++ .../aether/repository/LocalRepository.java | 123 +++ .../repository/LocalRepositoryManager.java | 118 +++ .../aether/repository/MirrorSelector.java | 30 + .../NoLocalRepositoryManagerException.java | 93 ++ .../org/eclipse/aether/repository/Proxy.java | 149 ++++ .../aether/repository/ProxySelector.java | 29 + .../aether/repository/RemoteRepository.java | 573 ++++++++++++ .../aether/repository/RepositoryPolicy.java | 152 ++++ .../aether/repository/WorkspaceReader.java | 49 ++ .../repository/WorkspaceRepository.java | 113 +++ .../aether/repository/package-info.java | 15 + .../ArtifactDescriptorException.java | 82 ++ .../resolution/ArtifactDescriptorPolicy.java | 52 ++ .../ArtifactDescriptorPolicyRequest.java | 97 ++ .../resolution/ArtifactDescriptorRequest.java | 181 ++++ .../resolution/ArtifactDescriptorResult.java | 457 ++++++++++ .../aether/resolution/ArtifactRequest.java | 223 +++++ .../ArtifactResolutionException.java | 164 ++++ .../aether/resolution/ArtifactResult.java | 179 ++++ .../aether/resolution/DependencyRequest.java | 178 ++++ .../DependencyResolutionException.java | 74 ++ .../aether/resolution/DependencyResult.java | 186 ++++ .../aether/resolution/MetadataRequest.java | 223 +++++ .../aether/resolution/MetadataResult.java | 157 ++++ .../resolution/ResolutionErrorPolicy.java | 73 ++ .../ResolutionErrorPolicyRequest.java | 98 +++ .../resolution/VersionRangeRequest.java | 181 ++++ .../VersionRangeResolutionException.java | 96 ++ .../aether/resolution/VersionRangeResult.java | 231 +++++ .../aether/resolution/VersionRequest.java | 181 ++++ .../VersionResolutionException.java | 96 ++ .../aether/resolution/VersionResult.java | 141 +++ .../aether/resolution/package-info.java | 15 + .../transfer/AbstractTransferListener.java | 55 ++ .../transfer/ArtifactNotFoundException.java | 95 ++ .../transfer/ArtifactTransferException.java | 131 +++ .../transfer/ChecksumFailureException.java | 122 +++ .../transfer/MetadataNotFoundException.java | 97 ++ .../transfer/MetadataTransferException.java | 131 +++ .../NoRepositoryConnectorException.java | 94 ++ .../transfer/NoRepositoryLayoutException.java | 93 ++ .../transfer/NoTransporterException.java | 93 ++ .../transfer/RepositoryOfflineException.java | 70 ++ .../transfer/TransferCancelledException.java | 51 ++ .../aether/transfer/TransferEvent.java | 423 +++++++++ .../aether/transfer/TransferListener.java | 91 ++ .../aether/transfer/TransferResource.java | 192 ++++ .../eclipse/aether/transfer/package-info.java | 16 + .../InvalidVersionSpecificationException.java | 71 ++ .../org/eclipse/aether/version/Version.java | 27 + .../aether/version/VersionConstraint.java | 45 + .../eclipse/aether/version/VersionRange.java | 122 +++ .../eclipse/aether/version/VersionScheme.java | 50 ++ .../eclipse/aether/version/package-info.java | 15 + .../META-INF/spring/maven.xml | 18 - .../META-INF/spring/repo-osgi.xml | 25 +- .../META-INF/spring/services.xml | 33 +- org.argeo.slc.server.repo/repository-h2.xml | 73 -- .../repository-localfs.xml | 60 -- .../repository-pg-dist.xml | 78 -- .../repository-pg-docs.xml | 78 -- .../repository-pg-java.xml | 78 -- .../repository-pg-rpm.xml | 78 -- .../org/argeo/slc/aether/AetherTemplate.java | 117 --- .../slc/aether/ConsoleRepositoryListener.java | 127 --- .../slc/aether/ConsoleTransferListener.java | 154 ---- .../SimpleArtifactDescriptorReader.java | 33 - .../aether/SimpleVersionRangeResolver.java | 37 - .../slc/aether/SimpleVersionResolver.java | 33 - .../argeo/slc/aether/osgi/OsgiVersion.java | 41 - .../spring/RemoteRepositoryFactory.java | 79 -- pom.xml | 2 +- 163 files changed, 16589 insertions(+), 1587 deletions(-) create mode 100644 org.argeo.slc.repo/build.properties rename {org.argeo.slc.support/ext/test/org/argeo/slc/aether => org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal}/AetherUtilsTest.java (97%) create mode 100644 org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal/pom.xml rename {org.argeo.slc.support/src/org/argeo/slc/aether => org.argeo.slc.repo/src/org/argeo/slc/repo/maven}/AetherUtils.java (99%) rename {org.argeo.slc.support/src/org/argeo/slc/aether => org.argeo.slc.repo/src/org/argeo/slc/repo/maven}/ArtifactIdComparator.java (97%) delete mode 100644 org.argeo.slc.repo/src/org/argeo/slc/repo/maven/ImportMavenDependencies.java create mode 100644 org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/SubArtifact.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/AbstractRepositoryListener.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/ConfigurationProperties.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositoryCache.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositorySystemSession.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/DefaultSessionData.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/RepositoryCache.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/RepositoryEvent.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/RepositoryException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/RepositoryListener.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystem.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystemSession.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/RequestTrace.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/SessionData.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/SyncContext.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/artifact/AbstractArtifact.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/artifact/Artifact.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactProperties.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactType.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactTypeRegistry.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifact.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifactType.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/artifact/package-info.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectRequest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectResult.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionContext.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformationContext.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformer.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManagement.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManager.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencySelector.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyTraverser.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/collection/UnsolvableVersionConflictException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/collection/VersionFilter.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/collection/package-info.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployRequest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployResult.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeploymentException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/deployment/package-info.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/graph/DefaultDependencyNode.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/graph/Dependency.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyCycle.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyFilter.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyNode.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyVisitor.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/graph/Exclusion.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/graph/package-info.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallRequest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallResult.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallationException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/installation/package-info.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/metadata/AbstractMetadata.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/metadata/DefaultMetadata.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/metadata/MergeableMetadata.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/metadata/Metadata.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/metadata/package-info.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/package-info.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/ArtifactRepository.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/Authentication.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationContext.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationDigest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationSelector.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRegistration.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRequest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactResult.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRegistration.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRequest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataResult.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepository.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepositoryManager.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/MirrorSelector.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/NoLocalRepositoryManagerException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/Proxy.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/ProxySelector.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/RemoteRepository.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/RepositoryPolicy.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceReader.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceRepository.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/repository/package-info.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicy.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicyRequest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorRequest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorResult.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactRequest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResolutionException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResult.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyRequest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResolutionException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResult.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataRequest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataResult.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicy.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicyRequest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeRequest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResolutionException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResult.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRequest.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResolutionException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResult.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/resolution/package-info.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/AbstractTransferListener.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactNotFoundException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactTransferException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/ChecksumFailureException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataNotFoundException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataTransferException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryConnectorException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryLayoutException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoTransporterException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/RepositoryOfflineException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferCancelledException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferEvent.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferListener.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferResource.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/transfer/package-info.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/version/InvalidVersionSpecificationException.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/version/Version.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/version/VersionConstraint.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/version/VersionRange.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/version/VersionScheme.java create mode 100644 org.argeo.slc.repo/src/org/eclipse/aether/version/package-info.java delete mode 100644 org.argeo.slc.server.repo/META-INF/spring/maven.xml delete mode 100644 org.argeo.slc.server.repo/repository-h2.xml delete mode 100644 org.argeo.slc.server.repo/repository-localfs.xml delete mode 100644 org.argeo.slc.server.repo/repository-pg-dist.xml delete mode 100644 org.argeo.slc.server.repo/repository-pg-docs.xml delete mode 100644 org.argeo.slc.server.repo/repository-pg-java.xml delete mode 100644 org.argeo.slc.server.repo/repository-pg-rpm.xml delete mode 100644 org.argeo.slc.support/src/org/argeo/slc/aether/AetherTemplate.java delete mode 100644 org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleRepositoryListener.java delete mode 100644 org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleTransferListener.java delete mode 100644 org.argeo.slc.support/src/org/argeo/slc/aether/SimpleArtifactDescriptorReader.java delete mode 100644 org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionRangeResolver.java delete mode 100644 org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionResolver.java delete mode 100644 org.argeo.slc.support/src/org/argeo/slc/aether/osgi/OsgiVersion.java delete mode 100644 org.argeo.slc.support/src/org/argeo/slc/aether/spring/RemoteRepositoryFactory.java diff --git a/demo/slc_localrepo.properties b/demo/slc_localrepo.properties index 9e34647a0..a89763302 100644 --- a/demo/slc_localrepo.properties +++ b/demo/slc_localrepo.properties @@ -22,8 +22,8 @@ slc.executionModules=org.argeo.tp.factory.core,\ org.argeo.tp.factory.extras,\ org.argeo.tp.factory.rcp -argeo.node.repo.type=localfs -argeo.node.useradmin.uris=ipa:/// +argeo.node.repo.type=h2 +#argeo.node.useradmin.uris=ipa:/// #org.osgi.framework.security=osgi java.security.manager= diff --git a/dist/pom.xml b/dist/pom.xml index 8cb68dce6..2abac18a0 100644 --- a/dist/pom.xml +++ b/dist/pom.xml @@ -12,7 +12,7 @@ SLC Distribution slc - slc-maven + diff --git a/org.argeo.slc.client.ui.dist/src/org/argeo/slc/client/ui/dist/commands/NormalizeDistribution.java b/org.argeo.slc.client.ui.dist/src/org/argeo/slc/client/ui/dist/commands/NormalizeDistribution.java index ab4f33303..57aa1edec 100644 --- a/org.argeo.slc.client.ui.dist/src/org/argeo/slc/client/ui/dist/commands/NormalizeDistribution.java +++ b/org.argeo.slc.client.ui.dist/src/org/argeo/slc/client/ui/dist/commands/NormalizeDistribution.java @@ -39,12 +39,12 @@ import org.argeo.slc.NameVersion; import org.argeo.slc.SlcException; import org.argeo.slc.SlcNames; import org.argeo.slc.SlcTypes; -import org.argeo.slc.aether.AetherUtils; import org.argeo.slc.client.ui.dist.DistPlugin; import org.argeo.slc.repo.ArtifactIndexer; import org.argeo.slc.repo.JarFileIndexer; import org.argeo.slc.repo.RepoConstants; import org.argeo.slc.repo.RepoUtils; +import org.argeo.slc.repo.maven.AetherUtils; import org.argeo.slc.repo.maven.MavenConventionsUtils; import org.argeo.slc.repo.osgi.NormalizeGroup; import org.eclipse.aether.artifact.Artifact; diff --git a/org.argeo.slc.repo/.classpath b/org.argeo.slc.repo/.classpath index bc86c4239..70b08e830 100644 --- a/org.argeo.slc.repo/.classpath +++ b/org.argeo.slc.repo/.classpath @@ -1,7 +1,8 @@ + - >> + diff --git a/org.argeo.slc.repo/.gitignore b/org.argeo.slc.repo/.gitignore index b83d22266..0f630157f 100644 --- a/org.argeo.slc.repo/.gitignore +++ b/org.argeo.slc.repo/.gitignore @@ -1 +1,2 @@ /target/ +/bin/ diff --git a/org.argeo.slc.repo/bnd.bnd b/org.argeo.slc.repo/bnd.bnd index d40b307f8..6ead58491 100644 --- a/org.argeo.slc.repo/bnd.bnd +++ b/org.argeo.slc.repo/bnd.bnd @@ -3,8 +3,11 @@ org.xml.sax.*,\ javax.xml.transform.*,\ javax.xml.parsers.*,\ javax.jcr.nodetype,\ +org.eclipse.aether.*;version=1.0.1,\ * +Private-Package: org.eclipse.aether.* + Require-Capability: cms.datamodel; filter:="(name=node)",\ cms.datamodel; filter:="(name=slc)" Provide-Capability: cms.datamodel; name=java,\ diff --git a/org.argeo.slc.repo/build.properties b/org.argeo.slc.repo/build.properties new file mode 100644 index 000000000..31b02d2fa --- /dev/null +++ b/org.argeo.slc.repo/build.properties @@ -0,0 +1 @@ +additional.bundles = org.junit diff --git a/org.argeo.slc.support/ext/test/org/argeo/slc/aether/AetherUtilsTest.java b/org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal/AetherUtilsTest.java similarity index 97% rename from org.argeo.slc.support/ext/test/org/argeo/slc/aether/AetherUtilsTest.java rename to org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal/AetherUtilsTest.java index 6f1370187..61824e4ed 100644 --- a/org.argeo.slc.support/ext/test/org/argeo/slc/aether/AetherUtilsTest.java +++ b/org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal/AetherUtilsTest.java @@ -1,3 +1,4 @@ +package org.argeo.slc.repo.internal; /* * Copyright (C) 2007-2012 Argeo GmbH * @@ -13,10 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.argeo.slc.aether; + import junit.framework.TestCase; +import org.argeo.slc.repo.maven.AetherUtils; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; diff --git a/org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal/pom.xml b/org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal/pom.xml new file mode 100644 index 000000000..b12659b2d --- /dev/null +++ b/org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal/pom.xml @@ -0,0 +1,209 @@ + + 4.0.0 + + org.argeo.commons + argeo-commons + 2.1.70-SNAPSHOT + + org.argeo.slc + argeo-slc + pom + Argeo SLC + 2.1.10-SNAPSHOT + + 2.1 + 2015-02-12 + 2.1.15 + 2.1.10-SNAPSHOT + 3.11.1.v20160708-1632 + + 3.2.5 + + + + org.argeo.slc.api + org.argeo.slc.core + org.argeo.slc.unit + org.argeo.slc.support + org.argeo.slc.support.maven + org.argeo.slc.repo + org.argeo.slc.factory + org.argeo.slc.launcher + + + org.argeo.slc.agent + org.argeo.slc.agent.jcr + org.argeo.slc.server.repo + + + org.argeo.slc.client.ui + org.argeo.slc.client.ui.dist + org.argeo.slc.client.rap + + + lib + dep + dist + demo + + http://projects.argeo.org/slc/ + + scm:git:http://git.argeo.org/apache2/argeo-slc.git + http://git.argeo.org/?p=apache2/argeo-slc.git;a=summary + scm:git:https://code.argeo.org/git/apache2/argeo-slc.git + HEAD + + 2007 + + + Apache 2 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + + mbaudier + Mathieu Baudier + + Argeo + http://www.argeo.org + + architect + developer + QA + + + + ocapillo + Olivier Capillon + + Argeo + http://www.argeo.org + + developer + + + + bsinou + Bruno Sinou + + Argeo + http://www.argeo.org + + developer + + + + + + + maven-site-plugin + false + + false + + + + maven-javadoc-plugin + + true + + + + + + + argeo + http://forge.argeo.org/data/java/argeo-2.1/ + + true + daily + warn + + + + argeo-rcp + http://forge.argeo.org/data/java/argeo-rcp-2.1 + + true + daily + warn + + + + + + central + http://repo1.maven.org/maven2 + + false + + + false + + + + + + localrepo + + + argeo-tp + http://localhost:7070/data/java/argeo-${developmentCycle.argeo-commons} + + true + daily + warn + + + + + + + + + + + + + argeo-commons + http://localhost:7070/data/java/argeo-${developmentCycle.argeo-commons} + + true + daily + warn + + + + + + staging + dav:http://localhost:7070/data/java/argeo-slc-${developmentCycle.slc} + + + staging + dav:http://localhost:7070/data/docs/argeo-slc-${developmentCycle.slc} + + + + + diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/ArtifactIndexer.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/ArtifactIndexer.java index 214269c5f..a3c1b5d4d 100644 --- a/org.argeo.slc.repo/src/org/argeo/slc/repo/ArtifactIndexer.java +++ b/org.argeo.slc.repo/src/org/argeo/slc/repo/ArtifactIndexer.java @@ -24,9 +24,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.jcr.JcrUtils; import org.argeo.slc.SlcException; -import org.argeo.slc.aether.AetherUtils; import org.argeo.slc.SlcNames; import org.argeo.slc.SlcTypes; +import org.argeo.slc.repo.maven.AetherUtils; import org.eclipse.aether.artifact.Artifact; import org.osgi.framework.Constants; diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/ModularDistributionIndexer.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/ModularDistributionIndexer.java index 594168d51..65238df55 100644 --- a/org.argeo.slc.repo/src/org/argeo/slc/repo/ModularDistributionIndexer.java +++ b/org.argeo.slc.repo/src/org/argeo/slc/repo/ModularDistributionIndexer.java @@ -24,10 +24,10 @@ import org.argeo.slc.CategorizedNameVersion; import org.argeo.slc.DefaultNameVersion; import org.argeo.slc.NameVersion; import org.argeo.slc.SlcException; -import org.argeo.slc.aether.AetherUtils; -import org.argeo.slc.build.Distribution; import org.argeo.slc.SlcNames; import org.argeo.slc.SlcTypes; +import org.argeo.slc.build.Distribution; +import org.argeo.slc.repo.maven.AetherUtils; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; import org.osgi.framework.Constants; diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/PdeSourcesIndexer.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/PdeSourcesIndexer.java index bcaa7302e..793f9bd9e 100644 --- a/org.argeo.slc.repo/src/org/argeo/slc/repo/PdeSourcesIndexer.java +++ b/org.argeo.slc.repo/src/org/argeo/slc/repo/PdeSourcesIndexer.java @@ -27,7 +27,7 @@ import org.apache.commons.logging.LogFactory; import org.argeo.jcr.JcrUtils; import org.argeo.slc.NameVersion; import org.argeo.slc.SlcException; -import org.argeo.slc.aether.AetherUtils; +import org.argeo.slc.repo.maven.AetherUtils; import org.argeo.slc.repo.maven.MavenConventionsUtils; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/RepoUtils.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/RepoUtils.java index 056d7164c..13ad7583d 100644 --- a/org.argeo.slc.repo/src/org/argeo/slc/repo/RepoUtils.java +++ b/org.argeo.slc.repo/src/org/argeo/slc/repo/RepoUtils.java @@ -60,9 +60,9 @@ import org.argeo.node.security.Keyring; import org.argeo.slc.DefaultNameVersion; import org.argeo.slc.NameVersion; import org.argeo.slc.SlcException; -import org.argeo.slc.aether.ArtifactIdComparator; import org.argeo.slc.SlcNames; import org.argeo.slc.SlcTypes; +import org.argeo.slc.repo.maven.ArtifactIdComparator; import org.argeo.slc.repo.maven.MavenConventionsUtils; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/AetherUtils.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/AetherUtils.java similarity index 99% rename from org.argeo.slc.support/src/org/argeo/slc/aether/AetherUtils.java rename to org.argeo.slc.repo/src/org/argeo/slc/repo/maven/AetherUtils.java index 873ddcbfd..fcc9b05b1 100644 --- a/org.argeo.slc.support/src/org/argeo/slc/aether/AetherUtils.java +++ b/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/AetherUtils.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.argeo.slc.aether; +package org.argeo.slc.repo.maven; import java.util.regex.Pattern; diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/ArtifactIdComparator.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/ArtifactIdComparator.java similarity index 97% rename from org.argeo.slc.support/src/org/argeo/slc/aether/ArtifactIdComparator.java rename to org.argeo.slc.repo/src/org/argeo/slc/repo/maven/ArtifactIdComparator.java index 6aa0ec69a..98d2d1d46 100644 --- a/org.argeo.slc.support/src/org/argeo/slc/aether/ArtifactIdComparator.java +++ b/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/ArtifactIdComparator.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.argeo.slc.aether; +package org.argeo.slc.repo.maven; import java.util.Comparator; import java.util.TreeMap; diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/GenerateBinaries.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/GenerateBinaries.java index 063b408c7..83335e9a5 100644 --- a/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/GenerateBinaries.java +++ b/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/GenerateBinaries.java @@ -33,7 +33,6 @@ import org.apache.commons.logging.LogFactory; import org.argeo.jcr.JcrMonitor; import org.argeo.jcr.JcrUtils; import org.argeo.slc.SlcException; -import org.argeo.slc.aether.ArtifactIdComparator; import org.argeo.slc.SlcNames; import org.argeo.slc.SlcTypes; import org.argeo.slc.repo.ArtifactIndexer; diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/ImportMavenDependencies.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/ImportMavenDependencies.java deleted file mode 100644 index 009d1f9ed..000000000 --- a/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/ImportMavenDependencies.java +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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.argeo.slc.repo.maven; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Properties; -import java.util.Set; -import java.util.TreeSet; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.Repository; -import javax.jcr.Session; -import javax.jcr.nodetype.NodeType; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.jcr.JcrUtils; -import org.argeo.slc.NameVersion; -import org.argeo.slc.SlcException; -import org.argeo.slc.aether.AetherTemplate; -import org.argeo.slc.aether.ArtifactIdComparator; -import org.argeo.slc.repo.ArtifactIndexer; -import org.argeo.slc.repo.JarFileIndexer; -import org.argeo.slc.repo.RepoConstants; -import org.argeo.slc.repo.RepoUtils; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.graph.DependencyNode; - -/** - * Import all the dependencies listed in a POM and their dependency graphs to a - * workspace. - */ -public class ImportMavenDependencies implements Runnable { - private final static Log log = LogFactory - .getLog(ImportMavenDependencies.class); - - private AetherTemplate aetherTemplate; - private String rootCoordinates = "org.argeo.dep:versions-all:pom:1.2.0"; - private String distCoordinates = "org.argeo.tp:dist:pom:1.3.0"; - private String parentPomCoordinates = "org.argeo:parent:1.2.0"; - private Set excludedArtifacts = new HashSet(); - - private Repository repository; - private String workspace; - - private String artifactBasePath = RepoConstants.DEFAULT_ARTIFACTS_BASE_PATH; - - private ArtifactIndexer artifactIndexer = new ArtifactIndexer(); - private JarFileIndexer jarFileIndexer = new JarFileIndexer(); - private Comparator artifactComparator = new ArtifactIdComparator(); - - public void run() { - // resolve - Set artifacts = resolveDistribution(); - - // sync - sync(artifacts); - } - - void sync(Set artifacts) { - Session session = null; - try { - session = JcrUtils.loginOrCreateWorkspace(repository, workspace); - // clear - NodeIterator nit = session.getNode(artifactBasePath).getNodes(); - while (nit.hasNext()) { - Node node = nit.nextNode(); - if (node.isNodeType(NodeType.NT_FOLDER) - || node.isNodeType(NodeType.NT_UNSTRUCTURED)) - node.remove(); - } - session.save(); - - // sync - syncDistribution(session, artifacts); - } catch (Exception e) { - throw new SlcException("Cannot import distribution", e); - } finally { - JcrUtils.logoutQuietly(session); - } - } - - /** - * Generate a POM with all the artifacts declared in root coordinates as - * dependencies AND in dependency management. - */ - void createDistPom() { - try { - Artifact pomArtifact = new DefaultArtifact(rootCoordinates); - - Set registeredArtifacts = new TreeSet( - artifactComparator); - MavenConventionsUtils.gatherPomDependencies(aetherTemplate, - registeredArtifacts, pomArtifact); - Artifact sdkArtifact = new DefaultArtifact(distCoordinates); - String sdkPom = MavenConventionsUtils.artifactsAsDependencyPom( - sdkArtifact, registeredArtifacts, new DefaultArtifact( - parentPomCoordinates)); - if (log.isDebugEnabled()) - log.debug("Gathered " + registeredArtifacts.size() - + " artifacts:\n" + sdkPom); - } catch (Exception e) { - throw new SlcException("Cannot resolve distribution", e); - } - } - - /** Returns all transitive dependencies of dist POM */ - private Set resolveDistribution() { - try { - Artifact distArtifact = new DefaultArtifact(distCoordinates); - Set artifacts = new TreeSet(artifactComparator); - - DependencyNode node = aetherTemplate - .resolveDependencies(distArtifact); - addDependencies(artifacts, node, null); - - if (log.isDebugEnabled()) { - log.debug("Resolved " + artifacts.size() + " artifacts"); - - // Properties distributionDescriptor = - // generateDistributionDescriptor(artifacts); - // ByteArrayOutputStream out = new ByteArrayOutputStream(); - // distributionDescriptor.store(out, ""); - // log.debug(new String(out.toByteArray())); - // out.close(); - } - - /* - * for (Artifact artifact : registeredArtifacts) { try { Boolean - * wasAdded = addArtifact(artifacts, artifact); if (wasAdded) { - * DependencyNode node = aetherTemplate - * .resolveDependencies(artifact); addDependencies(artifacts, node, - * null); } } catch (Exception e) { - * log.error("Could not resolve dependencies of " + artifact + ": " - * + e.getCause().getMessage()); } - * - * } - * - * if (log.isDebugEnabled()) log.debug("Resolved " + - * artifacts.size() + " artifacts"); - * - * // distribution descriptor // Properties distributionDescriptor = - * // generateDistributionDescriptor(artifacts); // - * ByteArrayOutputStream out = new ByteArrayOutputStream(); // - * distributionDescriptor.store(out, ""); // log.debug(new - * String(out.toByteArray())); // out.close(); - */ - return artifacts; - } catch (Exception e) { - throw new SlcException("Cannot resolve distribution", e); - } - } - - protected Properties generateDistributionDescriptor(Set artifacts) { - Properties distributionDescriptor = new Properties(); - for (Artifact artifact : artifacts) { - log.debug(artifact.getArtifactId() + " [" + artifact.getVersion() - + "]\t(" + artifact + ")"); - distributionDescriptor.setProperty(artifact.getArtifactId() + ":" - + artifact.getVersion(), artifact.toString()); - } - return distributionDescriptor; - } - - /** Write artifacts to the target workspace, skipping excluded ones */ - protected void syncDistribution(Session jcrSession, Set artifacts) { - Set artifactsWithoutSources = new TreeSet( - artifactComparator); - Long begin = System.currentTimeMillis(); - try { - JcrUtils.mkfolders(jcrSession, artifactBasePath); - artifacts: for (Artifact artifact : artifacts) { - // skip excluded - if (excludedArtifacts.contains(artifact.getGroupId() + ":" - + artifact.getArtifactId())) { - if (log.isDebugEnabled()) - log.debug("Exclude " + artifact); - continue artifacts; - } - - File jarFile = MavenConventionsUtils.artifactToFile(artifact); - if (!jarFile.exists()) { - log.warn("Generated file " + jarFile + " for " + artifact - + " does not exist"); - continue artifacts; - } - artifact.setFile(jarFile); - - try { - String parentPath = MavenConventionsUtils - .artifactParentPath(artifactBasePath, artifact); - Node parentNode; - if (!jcrSession.itemExists(parentPath)) - parentNode = JcrUtils.mkfolders(jcrSession, parentPath); - else - parentNode = jcrSession.getNode(parentPath); - - Node fileNode; - if (!parentNode.hasNode(jarFile.getName())) { - fileNode = createFileNode(parentNode, jarFile); - } else { - fileNode = parentNode.getNode(jarFile.getName()); - } - - if (artifactIndexer.support(fileNode.getPath())) - artifactIndexer.index(fileNode); - if (jarFileIndexer.support(fileNode.getPath())) - jarFileIndexer.index(fileNode); - jcrSession.save(); - - addPdeSource(jcrSession, artifact, jarFile, - artifactsWithoutSources); - jcrSession.save(); - - if (log.isDebugEnabled()) - log.debug("Synchronized " + fileNode); - } catch (Exception e) { - log.error("Could not synchronize " + artifact, e); - jcrSession.refresh(false); - throw e; - } - } - - Long duration = (System.currentTimeMillis() - begin) / 1000; - if (log.isDebugEnabled()) { - log.debug("Synchronized distribution in " + duration + "s"); - log.debug("The following artifacts have no sources:"); - for (Artifact artifact : artifactsWithoutSources) { - log.debug(artifact); - } - } - } catch (Exception e) { - throw new SlcException("Cannot synchronize distribution", e); - } - } - - /** Try to add PDE sources */ - private void addPdeSource(Session session, Artifact artifact, - File artifactFile, Set artifactsWithoutSources) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - File origSourceFile = null; - Artifact origSourceArtifact = new DefaultArtifact( - artifact.getGroupId(), artifact.getArtifactId(), "sources", - artifact.getExtension(), artifact.getVersion()); - Artifact newSourceArtifact = new DefaultArtifact( - artifact.getGroupId(), - artifact.getArtifactId() + ".source", - artifact.getExtension(), artifact.getVersion()); - try { - origSourceFile = aetherTemplate - .getResolvedFile(origSourceArtifact); - } catch (Exception e) { - // also try artifact following the conventions - origSourceArtifact = newSourceArtifact; - origSourceFile = aetherTemplate - .getResolvedFile(origSourceArtifact); - } - - String newSourceParentPath = MavenConventionsUtils - .artifactParentPath(artifactBasePath, newSourceArtifact); - Node newSourceParentNode = JcrUtils.mkfolders(session, - newSourceParentPath); - NameVersion bundleNameVersion = RepoUtils - .readNameVersion(artifactFile); - RepoUtils.packagesAsPdeSource(origSourceFile, bundleNameVersion, - out); - String newSourceFileName = MavenConventionsUtils - .artifactFileName(newSourceArtifact); - JcrUtils.copyBytesAsFile(newSourceParentNode, newSourceFileName, - out.toByteArray()); - } catch (Exception e) { - log.error("Cannot add PDE source for " + artifact + ": " + e); - artifactsWithoutSources.add(artifact); - } finally { - IOUtils.closeQuietly(out); - } - } - - private Node createFileNode(Node parentNode, File file) { - return JcrUtils.copyFile(parentNode, file); - } - - /** Recursively adds non optional dependencies */ - private void addDependencies(Set artifacts, DependencyNode node, - String ancestors) { - // if (artifacts.contains(node.getDependency().getArtifact())) - // return; - String currentArtifactId = node.getDependency().getArtifact() - .getArtifactId(); - if (log.isDebugEnabled()) { - log.debug("# Add dependency for " + currentArtifactId); - if (ancestors != null) - log.debug(ancestors); - } - for (DependencyNode child : node.getChildren()) { - if (!child.getDependency().isOptional()) { - if (willAdd(child.getDependency().getArtifact())) { - addArtifact(artifacts, child.getDependency().getArtifact()); - addDependencies(artifacts, child, currentArtifactId + "\n" - + (ancestors != null ? ancestors : "")); - } - } - } - } - - /** @return whether it was added */ - private Boolean addArtifact(Set artifacts, Artifact artifact) { - Boolean willAdd = willAdd(artifact); - if (willAdd) - artifacts.add(artifact); - else - log.info("Skip " + artifact); - return willAdd; - } - - private Boolean willAdd(Artifact artifact) { - Boolean willAdd = true; - if (excludedArtifacts.contains(artifact.getGroupId() + ":" - + artifact.getArtifactId())) - willAdd = false; - else if (excludedArtifacts.contains(artifact.getGroupId() + ":*")) - willAdd = false; - return willAdd; - } - - public void setAetherTemplate(AetherTemplate aetherTemplate) { - this.aetherTemplate = aetherTemplate; - } - - public void setExcludedArtifacts(Set excludedArtifactIds) { - this.excludedArtifacts = excludedArtifactIds; - } - - public void setRootCoordinates(String rootCoordinates) { - this.rootCoordinates = rootCoordinates; - } - - public void setRepository(Repository repository) { - this.repository = repository; - } - - public void setWorkspace(String workspace) { - this.workspace = workspace; - } - - public void setDistCoordinates(String distCoordinates) { - this.distCoordinates = distCoordinates; - } - - public void setArtifactBasePath(String artifactBasePath) { - this.artifactBasePath = artifactBasePath; - } - -} diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/MavenConventionsUtils.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/MavenConventionsUtils.java index 09827885c..c25e3fb7f 100644 --- a/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/MavenConventionsUtils.java +++ b/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/MavenConventionsUtils.java @@ -16,21 +16,11 @@ package org.argeo.slc.repo.maven; import java.io.File; -import java.util.Properties; import java.util.Set; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.aether.AetherTemplate; import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; /** * Static utilities around Maven which are NOT using the Maven APIs (conventions @@ -162,66 +152,66 @@ public class MavenConventionsUtils { return p.toString(); } - /** - * Directly parses Maven POM XML format in order to find all artifacts - * references under the dependency and dependencyManagement tags. This is - * meant to migrate existing pom registering a lot of artifacts, not to - * replace Maven resolving. - */ - public static void gatherPomDependencies(AetherTemplate aetherTemplate, Set artifacts, - Artifact pomArtifact) { - if (log.isDebugEnabled()) - log.debug("Gather dependencies for " + pomArtifact); - - try { - File file = aetherTemplate.getResolvedFile(pomArtifact); - DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - Document doc = documentBuilder.parse(file); - - // properties - Properties props = new Properties(); - props.setProperty("project.version", pomArtifact.getBaseVersion()); - NodeList properties = doc.getElementsByTagName("properties"); - if (properties.getLength() > 0) { - NodeList propertiesElems = properties.item(0).getChildNodes(); - for (int i = 0; i < propertiesElems.getLength(); i++) { - if (propertiesElems.item(i) instanceof Element) { - Element property = (Element) propertiesElems.item(i); - props.put(property.getNodeName(), property.getTextContent()); - } - } - } - - // dependencies (direct and dependencyManagement) - NodeList dependencies = doc.getElementsByTagName("dependency"); - for (int i = 0; i < dependencies.getLength(); i++) { - Element dependency = (Element) dependencies.item(i); - String groupId = dependency.getElementsByTagName("groupId").item(0).getTextContent().trim(); - String artifactId = dependency.getElementsByTagName("artifactId").item(0).getTextContent().trim(); - String version = dependency.getElementsByTagName("version").item(0).getTextContent().trim(); - if (version.startsWith("${")) { - String versionKey = version.substring(0, version.length() - 1).substring(2); - if (!props.containsKey(versionKey)) - throw new SlcException("Cannot interpret version " + version); - version = props.getProperty(versionKey); - } - NodeList scopes = dependency.getElementsByTagName("scope"); - if (scopes.getLength() > 0 && scopes.item(0).getTextContent().equals("import")) { - // recurse - gatherPomDependencies(aetherTemplate, artifacts, - new DefaultArtifact(groupId, artifactId, "pom", version)); - } else { - // TODO: deal with scope? - // TODO: deal with type - String type = "jar"; - Artifact artifact = new DefaultArtifact(groupId, artifactId, type, version); - artifacts.add(artifact); - } - } - } catch (Exception e) { - throw new SlcException("Cannot process " + pomArtifact, e); - } - } +// /** +// * Directly parses Maven POM XML format in order to find all artifacts +// * references under the dependency and dependencyManagement tags. This is +// * meant to migrate existing pom registering a lot of artifacts, not to +// * replace Maven resolving. +// */ +// public static void gatherPomDependencies(AetherTemplate aetherTemplate, Set artifacts, +// Artifact pomArtifact) { +// if (log.isDebugEnabled()) +// log.debug("Gather dependencies for " + pomArtifact); +// +// try { +// File file = aetherTemplate.getResolvedFile(pomArtifact); +// DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); +// Document doc = documentBuilder.parse(file); +// +// // properties +// Properties props = new Properties(); +// props.setProperty("project.version", pomArtifact.getBaseVersion()); +// NodeList properties = doc.getElementsByTagName("properties"); +// if (properties.getLength() > 0) { +// NodeList propertiesElems = properties.item(0).getChildNodes(); +// for (int i = 0; i < propertiesElems.getLength(); i++) { +// if (propertiesElems.item(i) instanceof Element) { +// Element property = (Element) propertiesElems.item(i); +// props.put(property.getNodeName(), property.getTextContent()); +// } +// } +// } +// +// // dependencies (direct and dependencyManagement) +// NodeList dependencies = doc.getElementsByTagName("dependency"); +// for (int i = 0; i < dependencies.getLength(); i++) { +// Element dependency = (Element) dependencies.item(i); +// String groupId = dependency.getElementsByTagName("groupId").item(0).getTextContent().trim(); +// String artifactId = dependency.getElementsByTagName("artifactId").item(0).getTextContent().trim(); +// String version = dependency.getElementsByTagName("version").item(0).getTextContent().trim(); +// if (version.startsWith("${")) { +// String versionKey = version.substring(0, version.length() - 1).substring(2); +// if (!props.containsKey(versionKey)) +// throw new SlcException("Cannot interpret version " + version); +// version = props.getProperty(versionKey); +// } +// NodeList scopes = dependency.getElementsByTagName("scope"); +// if (scopes.getLength() > 0 && scopes.item(0).getTextContent().equals("import")) { +// // recurse +// gatherPomDependencies(aetherTemplate, artifacts, +// new DefaultArtifact(groupId, artifactId, "pom", version)); +// } else { +// // TODO: deal with scope? +// // TODO: deal with type +// String type = "jar"; +// Artifact artifact = new DefaultArtifact(groupId, artifactId, type, version); +// artifacts.add(artifact); +// } +// } +// } catch (Exception e) { +// throw new SlcException("Cannot process " + pomArtifact, e); +// } +// } /** Prevent instantiation */ private MavenConventionsUtils() { diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/ArchiveWrapper.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/ArchiveWrapper.java index 9a9e96f01..badbbc1e8 100644 --- a/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/ArchiveWrapper.java +++ b/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/ArchiveWrapper.java @@ -30,11 +30,11 @@ import org.argeo.slc.DefaultNameVersion; import org.argeo.slc.ModuleSet; import org.argeo.slc.NameVersion; import org.argeo.slc.SlcException; -import org.argeo.slc.aether.ArtifactIdComparator; import org.argeo.slc.build.Distribution; import org.argeo.slc.build.License; import org.argeo.slc.repo.OsgiFactory; import org.argeo.slc.repo.RepoUtils; +import org.argeo.slc.repo.maven.ArtifactIdComparator; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; import org.springframework.util.AntPathMatcher; diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/MavenWrapper.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/MavenWrapper.java index a5b6ec934..40a7a8ac9 100644 --- a/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/MavenWrapper.java +++ b/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/MavenWrapper.java @@ -17,7 +17,6 @@ import org.argeo.slc.repo.OsgiFactory; import org.argeo.slc.repo.RepoUtils; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.util.artifact.SubArtifact; /** * BND wrapper based on a Maven artifact available from one of the configured diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/NormalizeGroup.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/NormalizeGroup.java index 82657b29f..1d2503799 100644 --- a/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/NormalizeGroup.java +++ b/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/NormalizeGroup.java @@ -35,12 +35,12 @@ import org.apache.commons.logging.LogFactory; import org.argeo.jcr.JcrMonitor; import org.argeo.jcr.JcrUtils; import org.argeo.slc.SlcException; -import org.argeo.slc.aether.ArtifactIdComparator; import org.argeo.slc.SlcNames; import org.argeo.slc.SlcTypes; import org.argeo.slc.repo.ArtifactIndexer; import org.argeo.slc.repo.RepoConstants; import org.argeo.slc.repo.RepoUtils; +import org.argeo.slc.repo.maven.ArtifactIdComparator; import org.argeo.slc.repo.maven.MavenConventionsUtils; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/SubArtifact.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/SubArtifact.java new file mode 100644 index 000000000..9ce84555d --- /dev/null +++ b/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/SubArtifact.java @@ -0,0 +1,214 @@ +package org.argeo.slc.repo.osgi; + +import java.io.File; +import java.util.Map; + +import org.eclipse.aether.artifact.AbstractArtifact; +import org.eclipse.aether.artifact.Artifact; + +/** + * An artifact whose identity is derived from another artifact. Note: Instances of this class are immutable and + * the exposed mutators return new objects rather than changing the current instance. + */ +final class SubArtifact + extends AbstractArtifact +{ + + private final Artifact mainArtifact; + + private final String classifier; + + private final String extension; + + private final File file; + + private final Map properties; + + /** + * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk + * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier + * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be + * used to refer to the GPG signature of an artifact. + * + * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}. + * @param classifier The classifier for this artifact, may be {@code null} if none. + * @param extension The extension for this artifact, may be {@code null} if none. + */ + public SubArtifact( Artifact mainArtifact, String classifier, String extension ) + { + this( mainArtifact, classifier, extension, (File) null ); + } + + /** + * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk + * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier + * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be + * used to refer to the GPG signature of an artifact. + * + * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}. + * @param classifier The classifier for this artifact, may be {@code null} if none. + * @param extension The extension for this artifact, may be {@code null} if none. + * @param file The file for this artifact, may be {@code null} if unresolved. + */ + public SubArtifact( Artifact mainArtifact, String classifier, String extension, File file ) + { + this( mainArtifact, classifier, extension, null, file ); + } + + /** + * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk + * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier + * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be + * used to refer to the GPG signature of an artifact. + * + * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}. + * @param classifier The classifier for this artifact, may be {@code null} if none. + * @param extension The extension for this artifact, may be {@code null} if none. + * @param properties The properties of the artifact, may be {@code null}. + */ + public SubArtifact( Artifact mainArtifact, String classifier, String extension, Map properties ) + { + this( mainArtifact, classifier, extension, properties, null ); + } + + /** + * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk + * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier + * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be + * used to refer to the GPG signature of an artifact. + * + * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}. + * @param classifier The classifier for this artifact, may be {@code null} if none. + * @param extension The extension for this artifact, may be {@code null} if none. + * @param properties The properties of the artifact, may be {@code null}. + * @param file The file for this artifact, may be {@code null} if unresolved. + */ + public SubArtifact( Artifact mainArtifact, String classifier, String extension, Map properties, + File file ) + { + if ( mainArtifact == null ) + { + throw new IllegalArgumentException( "no artifact specified" ); + } + this.mainArtifact = mainArtifact; + this.classifier = classifier; + this.extension = extension; + this.file = file; + this.properties = copyProperties( properties ); + } + + private SubArtifact( Artifact mainArtifact, String classifier, String extension, File file, + Map properties ) + { + // NOTE: This constructor assumes immutability of the provided properties, for internal use only + this.mainArtifact = mainArtifact; + this.classifier = classifier; + this.extension = extension; + this.file = file; + this.properties = properties; + } + + public String getGroupId() + { + return mainArtifact.getGroupId(); + } + + public String getArtifactId() + { + return mainArtifact.getArtifactId(); + } + + public String getVersion() + { + return mainArtifact.getVersion(); + } + + public String getBaseVersion() + { + return mainArtifact.getBaseVersion(); + } + + public boolean isSnapshot() + { + return mainArtifact.isSnapshot(); + } + + public String getClassifier() + { + return expand( classifier, mainArtifact.getClassifier() ); + } + + public String getExtension() + { + return expand( extension, mainArtifact.getExtension() ); + } + + public File getFile() + { + return file; + } + + public Artifact setFile( File file ) + { + if ( ( this.file == null ) ? file == null : this.file.equals( file ) ) + { + return this; + } + return new SubArtifact( mainArtifact, classifier, extension, file, properties ); + } + + public Map getProperties() + { + return properties; + } + + public Artifact setProperties( Map properties ) + { + if ( this.properties.equals( properties ) || ( properties == null && this.properties.isEmpty() ) ) + { + return this; + } + return new SubArtifact( mainArtifact, classifier, extension, properties, file ); + } + + private static String expand( String pattern, String replacement ) + { + String result = ""; + if ( pattern != null ) + { + result = pattern.replace( "*", replacement ); + + if ( replacement.length() <= 0 ) + { + if ( pattern.startsWith( "*" ) ) + { + int i = 0; + for ( ; i < result.length(); i++ ) + { + char c = result.charAt( i ); + if ( c != '-' && c != '.' ) + { + break; + } + } + result = result.substring( i ); + } + if ( pattern.endsWith( "*" ) ) + { + int i = result.length() - 1; + for ( ; i >= 0; i-- ) + { + char c = result.charAt( i ); + if ( c != '-' && c != '.' ) + { + break; + } + } + result = result.substring( 0, i + 1 ); + } + } + } + return result; + } + +} \ No newline at end of file diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java b/org.argeo.slc.repo/src/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java new file mode 100644 index 000000000..590ad28e0 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java @@ -0,0 +1,180 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +import java.util.Map; + +import org.eclipse.aether.artifact.ArtifactTypeRegistry; +import org.eclipse.aether.collection.DependencyGraphTransformer; +import org.eclipse.aether.collection.DependencyManager; +import org.eclipse.aether.collection.DependencySelector; +import org.eclipse.aether.collection.DependencyTraverser; +import org.eclipse.aether.collection.VersionFilter; +import org.eclipse.aether.repository.AuthenticationSelector; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.LocalRepositoryManager; +import org.eclipse.aether.repository.MirrorSelector; +import org.eclipse.aether.repository.ProxySelector; +import org.eclipse.aether.repository.WorkspaceReader; +import org.eclipse.aether.resolution.ArtifactDescriptorPolicy; +import org.eclipse.aether.resolution.ResolutionErrorPolicy; +import org.eclipse.aether.transfer.TransferListener; + +/** + * A special repository system session to enable decorating or proxying another session. To do so, clients have to + * create a subclass and implement {@link #getSession()}. + */ +public abstract class AbstractForwardingRepositorySystemSession + implements RepositorySystemSession +{ + + /** + * Creates a new forwarding session. + */ + protected AbstractForwardingRepositorySystemSession() + { + } + + /** + * Gets the repository system session to which this instance forwards calls. It's worth noting that this class does + * not save/cache the returned reference but queries this method before each forwarding. Hence, the session + * forwarded to may change over time or depending on the context (e.g. calling thread). + * + * @return The repository system session to forward calls to, never {@code null}. + */ + protected abstract RepositorySystemSession getSession(); + + public boolean isOffline() + { + return getSession().isOffline(); + } + + public boolean isIgnoreArtifactDescriptorRepositories() + { + return getSession().isIgnoreArtifactDescriptorRepositories(); + } + + public ResolutionErrorPolicy getResolutionErrorPolicy() + { + return getSession().getResolutionErrorPolicy(); + } + + public ArtifactDescriptorPolicy getArtifactDescriptorPolicy() + { + return getSession().getArtifactDescriptorPolicy(); + } + + public String getChecksumPolicy() + { + return getSession().getChecksumPolicy(); + } + + public String getUpdatePolicy() + { + return getSession().getUpdatePolicy(); + } + + public LocalRepository getLocalRepository() + { + return getSession().getLocalRepository(); + } + + public LocalRepositoryManager getLocalRepositoryManager() + { + return getSession().getLocalRepositoryManager(); + } + + public WorkspaceReader getWorkspaceReader() + { + return getSession().getWorkspaceReader(); + } + + public RepositoryListener getRepositoryListener() + { + return getSession().getRepositoryListener(); + } + + public TransferListener getTransferListener() + { + return getSession().getTransferListener(); + } + + public Map getSystemProperties() + { + return getSession().getSystemProperties(); + } + + public Map getUserProperties() + { + return getSession().getUserProperties(); + } + + public Map getConfigProperties() + { + return getSession().getConfigProperties(); + } + + public MirrorSelector getMirrorSelector() + { + return getSession().getMirrorSelector(); + } + + public ProxySelector getProxySelector() + { + return getSession().getProxySelector(); + } + + public AuthenticationSelector getAuthenticationSelector() + { + return getSession().getAuthenticationSelector(); + } + + public ArtifactTypeRegistry getArtifactTypeRegistry() + { + return getSession().getArtifactTypeRegistry(); + } + + public DependencyTraverser getDependencyTraverser() + { + return getSession().getDependencyTraverser(); + } + + public DependencyManager getDependencyManager() + { + return getSession().getDependencyManager(); + } + + public DependencySelector getDependencySelector() + { + return getSession().getDependencySelector(); + } + + public VersionFilter getVersionFilter() + { + return getSession().getVersionFilter(); + } + + public DependencyGraphTransformer getDependencyGraphTransformer() + { + return getSession().getDependencyGraphTransformer(); + } + + public SessionData getData() + { + return getSession().getData(); + } + + public RepositoryCache getCache() + { + return getSession().getCache(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/AbstractRepositoryListener.java b/org.argeo.slc.repo/src/org/eclipse/aether/AbstractRepositoryListener.java new file mode 100644 index 000000000..eaaffc198 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/AbstractRepositoryListener.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +/** + * A skeleton implementation for custom repository listeners. The callback methods in this class do nothing. + */ +public abstract class AbstractRepositoryListener + implements RepositoryListener +{ + + /** + * Enables subclassing. + */ + protected AbstractRepositoryListener() + { + } + + public void artifactDeployed( RepositoryEvent event ) + { + } + + public void artifactDeploying( RepositoryEvent event ) + { + } + + public void artifactDescriptorInvalid( RepositoryEvent event ) + { + } + + public void artifactDescriptorMissing( RepositoryEvent event ) + { + } + + public void artifactDownloaded( RepositoryEvent event ) + { + } + + public void artifactDownloading( RepositoryEvent event ) + { + } + + public void artifactInstalled( RepositoryEvent event ) + { + } + + public void artifactInstalling( RepositoryEvent event ) + { + } + + public void artifactResolved( RepositoryEvent event ) + { + } + + public void artifactResolving( RepositoryEvent event ) + { + } + + public void metadataDeployed( RepositoryEvent event ) + { + } + + public void metadataDeploying( RepositoryEvent event ) + { + } + + public void metadataDownloaded( RepositoryEvent event ) + { + } + + public void metadataDownloading( RepositoryEvent event ) + { + } + + public void metadataInstalled( RepositoryEvent event ) + { + } + + public void metadataInstalling( RepositoryEvent event ) + { + } + + public void metadataInvalid( RepositoryEvent event ) + { + } + + public void metadataResolved( RepositoryEvent event ) + { + } + + public void metadataResolving( RepositoryEvent event ) + { + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/ConfigurationProperties.java b/org.argeo.slc.repo/src/org/eclipse/aether/ConfigurationProperties.java new file mode 100644 index 000000000..3cbd59c23 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/ConfigurationProperties.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +/** + * The keys and defaults for common configuration properties. + * + * @see RepositorySystemSession#getConfigProperties() + */ +public final class ConfigurationProperties +{ + + private static final String PREFIX_AETHER = "aether."; + + private static final String PREFIX_CONNECTOR = PREFIX_AETHER + "connector."; + + /** + * The prefix for properties that control the priority of pluggable extensions like transporters. For example, for + * an extension with the fully qualified class name "org.eclipse.MyExtensionFactory", the configuration properties + * "aether.priority.org.eclipse.MyExtensionFactory", "aether.priority.MyExtensionFactory" and + * "aether.priority.MyExtension" will be consulted for the priority, in that order (obviously, the last key is only + * tried if the class name ends with "Factory"). The corresponding value is a float and the special value + * {@link Float#NaN} or "NaN" (case-sensitive) can be used to disable the extension. + */ + public static final String PREFIX_PRIORITY = PREFIX_AETHER + "priority."; + + /** + * A flag indicating whether the priorities of pluggable extensions are implicitly given by their iteration order + * such that the first extension has the highest priority. If set, an extension's built-in priority as well as any + * corresponding {@code aether.priority.*} configuration properties are ignored when searching for a suitable + * implementation among the available extensions. This priority mode is meant for cases where the application will + * present/inject extensions in the desired search order. + * + * @see #DEFAULT_IMPLICIT_PRIORITIES + */ + public static final String IMPLICIT_PRIORITIES = PREFIX_PRIORITY + "implicit"; + + /** + * The default extension priority mode if {@link #IMPLICIT_PRIORITIES} isn't set. + */ + public static final boolean DEFAULT_IMPLICIT_PRIORITIES = false; + + /** + * A flag indicating whether interaction with the user is allowed. + * + * @see #DEFAULT_INTERACTIVE + */ + public static final String INTERACTIVE = PREFIX_AETHER + "interactive"; + + /** + * The default interactive mode if {@link #INTERACTIVE} isn't set. + */ + public static final boolean DEFAULT_INTERACTIVE = false; + + /** + * The user agent that repository connectors should report to servers. + * + * @see #DEFAULT_USER_AGENT + */ + public static final String USER_AGENT = PREFIX_CONNECTOR + "userAgent"; + + /** + * The default user agent to use if {@link #USER_AGENT} isn't set. + */ + public static final String DEFAULT_USER_AGENT = "Aether"; + + /** + * The maximum amount of time (in milliseconds) to wait for a successful connection to a remote server. Non-positive + * values indicate no timeout. + * + * @see #DEFAULT_CONNECT_TIMEOUT + */ + public static final String CONNECT_TIMEOUT = PREFIX_CONNECTOR + "connectTimeout"; + + /** + * The default connect timeout to use if {@link #CONNECT_TIMEOUT} isn't set. + */ + public static final int DEFAULT_CONNECT_TIMEOUT = 10 * 1000; + + /** + * The maximum amount of time (in milliseconds) to wait for remaining data to arrive from a remote server. Note that + * this timeout does not restrict the overall duration of a request, it only restricts the duration of inactivity + * between consecutive data packets. Non-positive values indicate no timeout. + * + * @see #DEFAULT_REQUEST_TIMEOUT + */ + public static final String REQUEST_TIMEOUT = PREFIX_CONNECTOR + "requestTimeout"; + + /** + * The default request timeout to use if {@link #REQUEST_TIMEOUT} isn't set. + */ + public static final int DEFAULT_REQUEST_TIMEOUT = 1800 * 1000; + + /** + * The request headers to use for HTTP-based repository connectors. The headers are specified using a + * {@code Map}, mapping a header name to its value. Besides this general key, clients may also + * specify headers for a specific remote repository by appending the suffix {@code .} to this key when + * storing the headers map. The repository-specific headers map is supposed to be complete, i.e. is not merged with + * the general headers map. + */ + public static final String HTTP_HEADERS = PREFIX_CONNECTOR + "http.headers"; + + /** + * The encoding/charset to use when exchanging credentials with HTTP servers. Besides this general key, clients may + * also specify the encoding for a specific remote repository by appending the suffix {@code .} to this key + * when storing the charset name. + * + * @see #DEFAULT_HTTP_CREDENTIAL_ENCODING + */ + public static final String HTTP_CREDENTIAL_ENCODING = PREFIX_CONNECTOR + "http.credentialEncoding"; + + /** + * The default encoding/charset to use if {@link #HTTP_CREDENTIAL_ENCODING} isn't set. + */ + public static final String DEFAULT_HTTP_CREDENTIAL_ENCODING = "ISO-8859-1"; + + /** + * An option indicating whether authentication configured for a HTTP repository should also be used with any host + * that the original server might redirect requests to. Unless enabled, credentials are only exchanged with the + * original host from the repository URL and not supplied to different hosts encountered during redirects. The + * option value can either be a boolean flag or a comma-separated list of host names denoting the whitelist of + * original hosts whose redirects can be trusted and should use the configured authentication no matter the + * destination host(s). Alternatively, the suffix {@code .} can be appended to this configuration key to + * control the behavior for a specific repository id. + * + * @see #DEFAULT_HTTP_REDIRECTED_AUTHENTICATION + * @since 1.1.0 + */ + public static final String HTTP_REDIRECTED_AUTHENTICATION = PREFIX_CONNECTOR + "http.redirectedAuthentication"; + + /** + * The default handling of authentication during HTTP redirects if {@link #HTTP_REDIRECTED_AUTHENTICATION} isn't + * set. + * + * @since 1.1.0 + */ + public static final String DEFAULT_HTTP_REDIRECTED_AUTHENTICATION = "false"; + + /** + * A flag indicating whether checksums which are retrieved during checksum validation should be persisted in the + * local filesystem next to the file they provide the checksum for. + * + * @see #DEFAULT_PERSISTED_CHECKSUMS + */ + public static final String PERSISTED_CHECKSUMS = PREFIX_CONNECTOR + "persistedChecksums"; + + /** + * The default checksum persistence mode if {@link #PERSISTED_CHECKSUMS} isn't set. + */ + public static final boolean DEFAULT_PERSISTED_CHECKSUMS = true; + + private ConfigurationProperties() + { + // hide constructor + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositoryCache.java b/org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositoryCache.java new file mode 100644 index 000000000..12d278921 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositoryCache.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * A simplistic repository cache backed by a thread-safe map. The simplistic nature of this cache makes it only suitable + * for use with short-lived repository system sessions where pruning of cache data is not required. + */ +public final class DefaultRepositoryCache + implements RepositoryCache +{ + + private final Map cache = new ConcurrentHashMap( 256 ); + + public Object get( RepositorySystemSession session, Object key ) + { + return cache.get( key ); + } + + public void put( RepositorySystemSession session, Object key, Object data ) + { + if ( data != null ) + { + cache.put( key, data ); + } + else + { + cache.remove( key ); + } + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositorySystemSession.java b/org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositorySystemSession.java new file mode 100644 index 000000000..363ede643 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositorySystemSession.java @@ -0,0 +1,825 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.aether.artifact.ArtifactType; +import org.eclipse.aether.artifact.ArtifactTypeRegistry; +import org.eclipse.aether.collection.DependencyGraphTransformer; +import org.eclipse.aether.collection.DependencyManager; +import org.eclipse.aether.collection.DependencySelector; +import org.eclipse.aether.collection.DependencyTraverser; +import org.eclipse.aether.collection.VersionFilter; +import org.eclipse.aether.repository.Authentication; +import org.eclipse.aether.repository.AuthenticationSelector; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.LocalRepositoryManager; +import org.eclipse.aether.repository.MirrorSelector; +import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.ProxySelector; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.repository.RepositoryPolicy; +import org.eclipse.aether.repository.WorkspaceReader; +import org.eclipse.aether.resolution.ArtifactDescriptorPolicy; +import org.eclipse.aether.resolution.ResolutionErrorPolicy; +import org.eclipse.aether.transfer.TransferListener; + +/** + * A simple repository system session. + *

+ * Note: This class is not thread-safe. It is assumed that the mutators get only called during an + * initialization phase and that the session itself is not changed once initialized and being used by the repository + * system. It is recommended to call {@link #setReadOnly()} once the session has been fully initialized to prevent + * accidental manipulation of it afterwards. + */ +public final class DefaultRepositorySystemSession + implements RepositorySystemSession +{ + + private boolean readOnly; + + private boolean offline; + + private boolean ignoreArtifactDescriptorRepositories; + + private ResolutionErrorPolicy resolutionErrorPolicy; + + private ArtifactDescriptorPolicy artifactDescriptorPolicy; + + private String checksumPolicy; + + private String updatePolicy; + + private LocalRepositoryManager localRepositoryManager; + + private WorkspaceReader workspaceReader; + + private RepositoryListener repositoryListener; + + private TransferListener transferListener; + + private Map systemProperties; + + private Map systemPropertiesView; + + private Map userProperties; + + private Map userPropertiesView; + + private Map configProperties; + + private Map configPropertiesView; + + private MirrorSelector mirrorSelector; + + private ProxySelector proxySelector; + + private AuthenticationSelector authenticationSelector; + + private ArtifactTypeRegistry artifactTypeRegistry; + + private DependencyTraverser dependencyTraverser; + + private DependencyManager dependencyManager; + + private DependencySelector dependencySelector; + + private VersionFilter versionFilter; + + private DependencyGraphTransformer dependencyGraphTransformer; + + private SessionData data; + + private RepositoryCache cache; + + /** + * Creates an uninitialized session. Note: The new session is not ready to use, as a bare minimum, + * {@link #setLocalRepositoryManager(LocalRepositoryManager)} needs to be called but usually other settings also + * need to be customized to achieve meaningful behavior. + */ + public DefaultRepositorySystemSession() + { + systemProperties = new HashMap(); + systemPropertiesView = Collections.unmodifiableMap( systemProperties ); + userProperties = new HashMap(); + userPropertiesView = Collections.unmodifiableMap( userProperties ); + configProperties = new HashMap(); + configPropertiesView = Collections.unmodifiableMap( configProperties ); + mirrorSelector = NullMirrorSelector.INSTANCE; + proxySelector = NullProxySelector.INSTANCE; + authenticationSelector = NullAuthenticationSelector.INSTANCE; + artifactTypeRegistry = NullArtifactTypeRegistry.INSTANCE; + data = new DefaultSessionData(); + } + + /** + * Creates a shallow copy of the specified session. Actually, the copy is not completely shallow, all maps holding + * system/user/config properties are copied as well. In other words, invoking any mutator on the new session itself + * has no effect on the original session. Other mutable objects like the session data and cache (if any) are not + * copied and will be shared with the original session unless reconfigured. + * + * @param session The session to copy, must not be {@code null}. + */ + public DefaultRepositorySystemSession( RepositorySystemSession session ) + { + if ( session == null ) + { + throw new IllegalArgumentException( "repository system session not specified" ); + } + + setOffline( session.isOffline() ); + setIgnoreArtifactDescriptorRepositories( session.isIgnoreArtifactDescriptorRepositories() ); + setResolutionErrorPolicy( session.getResolutionErrorPolicy() ); + setArtifactDescriptorPolicy( session.getArtifactDescriptorPolicy() ); + setChecksumPolicy( session.getChecksumPolicy() ); + setUpdatePolicy( session.getUpdatePolicy() ); + setLocalRepositoryManager( session.getLocalRepositoryManager() ); + setWorkspaceReader( session.getWorkspaceReader() ); + setRepositoryListener( session.getRepositoryListener() ); + setTransferListener( session.getTransferListener() ); + setSystemProperties( session.getSystemProperties() ); + setUserProperties( session.getUserProperties() ); + setConfigProperties( session.getConfigProperties() ); + setMirrorSelector( session.getMirrorSelector() ); + setProxySelector( session.getProxySelector() ); + setAuthenticationSelector( session.getAuthenticationSelector() ); + setArtifactTypeRegistry( session.getArtifactTypeRegistry() ); + setDependencyTraverser( session.getDependencyTraverser() ); + setDependencyManager( session.getDependencyManager() ); + setDependencySelector( session.getDependencySelector() ); + setVersionFilter( session.getVersionFilter() ); + setDependencyGraphTransformer( session.getDependencyGraphTransformer() ); + setData( session.getData() ); + setCache( session.getCache() ); + } + + public boolean isOffline() + { + return offline; + } + + /** + * Controls whether the repository system operates in offline mode and avoids/refuses any access to remote + * repositories. + * + * @param offline {@code true} if the repository system is in offline mode, {@code false} otherwise. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setOffline( boolean offline ) + { + failIfReadOnly(); + this.offline = offline; + return this; + } + + public boolean isIgnoreArtifactDescriptorRepositories() + { + return ignoreArtifactDescriptorRepositories; + } + + /** + * Controls whether repositories declared in artifact descriptors should be ignored during transitive dependency + * collection. If enabled, only the repositories originally provided with the collect request will be considered. + * + * @param ignoreArtifactDescriptorRepositories {@code true} to ignore additional repositories from artifact + * descriptors, {@code false} to merge those with the originally specified repositories. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setIgnoreArtifactDescriptorRepositories( boolean ignoreArtifactDescriptorRepositories ) + { + failIfReadOnly(); + this.ignoreArtifactDescriptorRepositories = ignoreArtifactDescriptorRepositories; + return this; + } + + public ResolutionErrorPolicy getResolutionErrorPolicy() + { + return resolutionErrorPolicy; + } + + /** + * Sets the policy which controls whether resolutions errors from remote repositories should be cached. + * + * @param resolutionErrorPolicy The resolution error policy for this session, may be {@code null} if resolution + * errors should generally not be cached. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setResolutionErrorPolicy( ResolutionErrorPolicy resolutionErrorPolicy ) + { + failIfReadOnly(); + this.resolutionErrorPolicy = resolutionErrorPolicy; + return this; + } + + public ArtifactDescriptorPolicy getArtifactDescriptorPolicy() + { + return artifactDescriptorPolicy; + } + + /** + * Sets the policy which controls how errors related to reading artifact descriptors should be handled. + * + * @param artifactDescriptorPolicy The descriptor error policy for this session, may be {@code null} if descriptor + * errors should generally not be tolerated. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setArtifactDescriptorPolicy( ArtifactDescriptorPolicy artifactDescriptorPolicy ) + { + failIfReadOnly(); + this.artifactDescriptorPolicy = artifactDescriptorPolicy; + return this; + } + + public String getChecksumPolicy() + { + return checksumPolicy; + } + + /** + * Sets the global checksum policy. If set, the global checksum policy overrides the checksum policies of the remote + * repositories being used for resolution. + * + * @param checksumPolicy The global checksum policy, may be {@code null}/empty to apply the per-repository policies. + * @return This session for chaining, never {@code null}. + * @see RepositoryPolicy#CHECKSUM_POLICY_FAIL + * @see RepositoryPolicy#CHECKSUM_POLICY_IGNORE + * @see RepositoryPolicy#CHECKSUM_POLICY_WARN + */ + public DefaultRepositorySystemSession setChecksumPolicy( String checksumPolicy ) + { + failIfReadOnly(); + this.checksumPolicy = checksumPolicy; + return this; + } + + public String getUpdatePolicy() + { + return updatePolicy; + } + + /** + * Sets the global update policy. If set, the global update policy overrides the update policies of the remote + * repositories being used for resolution. + * + * @param updatePolicy The global update policy, may be {@code null}/empty to apply the per-repository policies. + * @return This session for chaining, never {@code null}. + * @see RepositoryPolicy#UPDATE_POLICY_ALWAYS + * @see RepositoryPolicy#UPDATE_POLICY_DAILY + * @see RepositoryPolicy#UPDATE_POLICY_NEVER + */ + public DefaultRepositorySystemSession setUpdatePolicy( String updatePolicy ) + { + failIfReadOnly(); + this.updatePolicy = updatePolicy; + return this; + } + + public LocalRepository getLocalRepository() + { + LocalRepositoryManager lrm = getLocalRepositoryManager(); + return ( lrm != null ) ? lrm.getRepository() : null; + } + + public LocalRepositoryManager getLocalRepositoryManager() + { + return localRepositoryManager; + } + + /** + * Sets the local repository manager used during this session. Note: Eventually, a valid session must have + * a local repository manager set. + * + * @param localRepositoryManager The local repository manager used during this session, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setLocalRepositoryManager( LocalRepositoryManager localRepositoryManager ) + { + failIfReadOnly(); + this.localRepositoryManager = localRepositoryManager; + return this; + } + + public WorkspaceReader getWorkspaceReader() + { + return workspaceReader; + } + + /** + * Sets the workspace reader used during this session. If set, the workspace reader will usually be consulted first + * to resolve artifacts. + * + * @param workspaceReader The workspace reader for this session, may be {@code null} if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setWorkspaceReader( WorkspaceReader workspaceReader ) + { + failIfReadOnly(); + this.workspaceReader = workspaceReader; + return this; + } + + public RepositoryListener getRepositoryListener() + { + return repositoryListener; + } + + /** + * Sets the listener being notified of actions in the repository system. + * + * @param repositoryListener The repository listener, may be {@code null} if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setRepositoryListener( RepositoryListener repositoryListener ) + { + failIfReadOnly(); + this.repositoryListener = repositoryListener; + return this; + } + + public TransferListener getTransferListener() + { + return transferListener; + } + + /** + * Sets the listener being notified of uploads/downloads by the repository system. + * + * @param transferListener The transfer listener, may be {@code null} if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setTransferListener( TransferListener transferListener ) + { + failIfReadOnly(); + this.transferListener = transferListener; + return this; + } + + private Map copySafe( Map table, Class valueType ) + { + Map map; + if ( table == null || table.isEmpty() ) + { + map = new HashMap(); + } + else + { + map = new HashMap( (int) ( table.size() / 0.75f ) + 1 ); + for ( Map.Entry entry : table.entrySet() ) + { + Object key = entry.getKey(); + if ( key instanceof String ) + { + Object value = entry.getValue(); + if ( valueType.isInstance( value ) ) + { + map.put( key.toString(), valueType.cast( value ) ); + } + } + } + } + return map; + } + + public Map getSystemProperties() + { + return systemPropertiesView; + } + + /** + * Sets the system properties to use, e.g. for processing of artifact descriptors. System properties are usually + * collected from the runtime environment like {@link System#getProperties()} and environment variables. + *

+ * Note: System properties are of type {@code Map} and any key-value pair in the input map + * that doesn't match this type will be silently ignored. + * + * @param systemProperties The system properties, may be {@code null} or empty if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setSystemProperties( Map systemProperties ) + { + failIfReadOnly(); + this.systemProperties = copySafe( systemProperties, String.class ); + systemPropertiesView = Collections.unmodifiableMap( this.systemProperties ); + return this; + } + + /** + * Sets the specified system property. + * + * @param key The property key, must not be {@code null}. + * @param value The property value, may be {@code null} to remove/unset the property. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setSystemProperty( String key, String value ) + { + failIfReadOnly(); + if ( value != null ) + { + systemProperties.put( key, value ); + } + else + { + systemProperties.remove( key ); + } + return this; + } + + public Map getUserProperties() + { + return userPropertiesView; + } + + /** + * Sets the user properties to use, e.g. for processing of artifact descriptors. User properties are similar to + * system properties but are set on the discretion of the user and hence are considered of higher priority than + * system properties in case of conflicts. + *

+ * Note: User properties are of type {@code Map} and any key-value pair in the input map + * that doesn't match this type will be silently ignored. + * + * @param userProperties The user properties, may be {@code null} or empty if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setUserProperties( Map userProperties ) + { + failIfReadOnly(); + this.userProperties = copySafe( userProperties, String.class ); + userPropertiesView = Collections.unmodifiableMap( this.userProperties ); + return this; + } + + /** + * Sets the specified user property. + * + * @param key The property key, must not be {@code null}. + * @param value The property value, may be {@code null} to remove/unset the property. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setUserProperty( String key, String value ) + { + failIfReadOnly(); + if ( value != null ) + { + userProperties.put( key, value ); + } + else + { + userProperties.remove( key ); + } + return this; + } + + public Map getConfigProperties() + { + return configPropertiesView; + } + + /** + * Sets the configuration properties used to tweak internal aspects of the repository system (e.g. thread pooling, + * connector-specific behavior, etc.). + *

+ * Note: Configuration properties are of type {@code Map} and any key-value pair in the + * input map that doesn't match this type will be silently ignored. + * + * @param configProperties The configuration properties, may be {@code null} or empty if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setConfigProperties( Map configProperties ) + { + failIfReadOnly(); + this.configProperties = copySafe( configProperties, Object.class ); + configPropertiesView = Collections.unmodifiableMap( this.configProperties ); + return this; + } + + /** + * Sets the specified configuration property. + * + * @param key The property key, must not be {@code null}. + * @param value The property value, may be {@code null} to remove/unset the property. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setConfigProperty( String key, Object value ) + { + failIfReadOnly(); + if ( value != null ) + { + configProperties.put( key, value ); + } + else + { + configProperties.remove( key ); + } + return this; + } + + public MirrorSelector getMirrorSelector() + { + return mirrorSelector; + } + + /** + * Sets the mirror selector to use for repositories discovered in artifact descriptors. Note that this selector is + * not used for remote repositories which are passed as request parameters to the repository system, those + * repositories are supposed to denote the effective repositories. + * + * @param mirrorSelector The mirror selector to use, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setMirrorSelector( MirrorSelector mirrorSelector ) + { + failIfReadOnly(); + this.mirrorSelector = mirrorSelector; + if ( this.mirrorSelector == null ) + { + this.mirrorSelector = NullMirrorSelector.INSTANCE; + } + return this; + } + + public ProxySelector getProxySelector() + { + return proxySelector; + } + + /** + * Sets the proxy selector to use for repositories discovered in artifact descriptors. Note that this selector is + * not used for remote repositories which are passed as request parameters to the repository system, those + * repositories are supposed to have their proxy (if any) already set. + * + * @param proxySelector The proxy selector to use, may be {@code null}. + * @return This session for chaining, never {@code null}. + * @see org.eclipse.aether.repository.RemoteRepository#getProxy() + */ + public DefaultRepositorySystemSession setProxySelector( ProxySelector proxySelector ) + { + failIfReadOnly(); + this.proxySelector = proxySelector; + if ( this.proxySelector == null ) + { + this.proxySelector = NullProxySelector.INSTANCE; + } + return this; + } + + public AuthenticationSelector getAuthenticationSelector() + { + return authenticationSelector; + } + + /** + * Sets the authentication selector to use for repositories discovered in artifact descriptors. Note that this + * selector is not used for remote repositories which are passed as request parameters to the repository system, + * those repositories are supposed to have their authentication (if any) already set. + * + * @param authenticationSelector The authentication selector to use, may be {@code null}. + * @return This session for chaining, never {@code null}. + * @see org.eclipse.aether.repository.RemoteRepository#getAuthentication() + */ + public DefaultRepositorySystemSession setAuthenticationSelector( AuthenticationSelector authenticationSelector ) + { + failIfReadOnly(); + this.authenticationSelector = authenticationSelector; + if ( this.authenticationSelector == null ) + { + this.authenticationSelector = NullAuthenticationSelector.INSTANCE; + } + return this; + } + + public ArtifactTypeRegistry getArtifactTypeRegistry() + { + return artifactTypeRegistry; + } + + /** + * Sets the registry of artifact types recognized by this session. + * + * @param artifactTypeRegistry The artifact type registry, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setArtifactTypeRegistry( ArtifactTypeRegistry artifactTypeRegistry ) + { + failIfReadOnly(); + this.artifactTypeRegistry = artifactTypeRegistry; + if ( this.artifactTypeRegistry == null ) + { + this.artifactTypeRegistry = NullArtifactTypeRegistry.INSTANCE; + } + return this; + } + + public DependencyTraverser getDependencyTraverser() + { + return dependencyTraverser; + } + + /** + * Sets the dependency traverser to use for building dependency graphs. + * + * @param dependencyTraverser The dependency traverser to use for building dependency graphs, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setDependencyTraverser( DependencyTraverser dependencyTraverser ) + { + failIfReadOnly(); + this.dependencyTraverser = dependencyTraverser; + return this; + } + + public DependencyManager getDependencyManager() + { + return dependencyManager; + } + + /** + * Sets the dependency manager to use for building dependency graphs. + * + * @param dependencyManager The dependency manager to use for building dependency graphs, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setDependencyManager( DependencyManager dependencyManager ) + { + failIfReadOnly(); + this.dependencyManager = dependencyManager; + return this; + } + + public DependencySelector getDependencySelector() + { + return dependencySelector; + } + + /** + * Sets the dependency selector to use for building dependency graphs. + * + * @param dependencySelector The dependency selector to use for building dependency graphs, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setDependencySelector( DependencySelector dependencySelector ) + { + failIfReadOnly(); + this.dependencySelector = dependencySelector; + return this; + } + + public VersionFilter getVersionFilter() + { + return versionFilter; + } + + /** + * Sets the version filter to use for building dependency graphs. + * + * @param versionFilter The version filter to use for building dependency graphs, may be {@code null} to not filter + * versions. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setVersionFilter( VersionFilter versionFilter ) + { + failIfReadOnly(); + this.versionFilter = versionFilter; + return this; + } + + public DependencyGraphTransformer getDependencyGraphTransformer() + { + return dependencyGraphTransformer; + } + + /** + * Sets the dependency graph transformer to use for building dependency graphs. + * + * @param dependencyGraphTransformer The dependency graph transformer to use for building dependency graphs, may be + * {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setDependencyGraphTransformer( DependencyGraphTransformer dependencyGraphTransformer ) + { + failIfReadOnly(); + this.dependencyGraphTransformer = dependencyGraphTransformer; + return this; + } + + public SessionData getData() + { + return data; + } + + /** + * Sets the custom data associated with this session. + * + * @param data The session data, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setData( SessionData data ) + { + failIfReadOnly(); + this.data = data; + if ( this.data == null ) + { + this.data = new DefaultSessionData(); + } + return this; + } + + public RepositoryCache getCache() + { + return cache; + } + + /** + * Sets the cache the repository system may use to save data for future reuse during the session. + * + * @param cache The repository cache, may be {@code null} if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultRepositorySystemSession setCache( RepositoryCache cache ) + { + failIfReadOnly(); + this.cache = cache; + return this; + } + + /** + * Marks this session as read-only such that any future attempts to call its mutators will fail with an exception. + * Marking an already read-only session as read-only has no effect. The session's data and cache remain writable + * though. + */ + public void setReadOnly() + { + readOnly = true; + } + + private void failIfReadOnly() + { + if ( readOnly ) + { + throw new IllegalStateException( "repository system session is read-only" ); + } + } + + static class NullProxySelector + implements ProxySelector + { + + public static final ProxySelector INSTANCE = new NullProxySelector(); + + public Proxy getProxy( RemoteRepository repository ) + { + return repository.getProxy(); + } + + } + + static class NullMirrorSelector + implements MirrorSelector + { + + public static final MirrorSelector INSTANCE = new NullMirrorSelector(); + + public RemoteRepository getMirror( RemoteRepository repository ) + { + return null; + } + + } + + static class NullAuthenticationSelector + implements AuthenticationSelector + { + + public static final AuthenticationSelector INSTANCE = new NullAuthenticationSelector(); + + public Authentication getAuthentication( RemoteRepository repository ) + { + return repository.getAuthentication(); + } + + } + + static final class NullArtifactTypeRegistry + implements ArtifactTypeRegistry + { + + public static final ArtifactTypeRegistry INSTANCE = new NullArtifactTypeRegistry(); + + public ArtifactType get( String typeId ) + { + return null; + } + + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/DefaultSessionData.java b/org.argeo.slc.repo/src/org/eclipse/aether/DefaultSessionData.java new file mode 100644 index 000000000..738cebc02 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/DefaultSessionData.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * A simple session data storage backed by a thread-safe map. + */ +public final class DefaultSessionData + implements SessionData +{ + + private final ConcurrentMap data; + + public DefaultSessionData() + { + data = new ConcurrentHashMap(); + } + + public void set( Object key, Object value ) + { + if ( key == null ) + { + throw new IllegalArgumentException( "key must not be null" ); + } + + if ( value != null ) + { + data.put( key, value ); + } + else + { + data.remove( key ); + } + } + + public boolean set( Object key, Object oldValue, Object newValue ) + { + if ( key == null ) + { + throw new IllegalArgumentException( "key must not be null" ); + } + + if ( newValue != null ) + { + if ( oldValue == null ) + { + return data.putIfAbsent( key, newValue ) == null; + } + return data.replace( key, oldValue, newValue ); + } + else + { + if ( oldValue == null ) + { + return !data.containsKey( key ); + } + return data.remove( key, oldValue ); + } + } + + public Object get( Object key ) + { + if ( key == null ) + { + throw new IllegalArgumentException( "key must not be null" ); + } + + return data.get( key ); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryCache.java b/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryCache.java new file mode 100644 index 000000000..736384414 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryCache.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +/** + * Caches auxiliary data used during repository access like already processed metadata. The data in the cache is meant + * for exclusive consumption by the repository system and is opaque to the cache implementation. Note: + * Actual cache implementations must be thread-safe. + * + * @see RepositorySystemSession#getCache() + */ +public interface RepositoryCache +{ + + /** + * Puts the specified data into the cache. It is entirely up to the cache implementation how long this data will be + * kept before being purged, i.e. callers must not make any assumptions about the lifetime of cached data. + *

+ * Warning: The cache will directly save the provided reference. If the cached data is mutable, i.e. could + * be modified after being put into the cache, the caller is responsible for creating a copy of the original data + * and store the copy in the cache. + * + * @param session The repository session during which the cache is accessed, must not be {@code null}. + * @param key The key to use for lookup of the data, must not be {@code null}. + * @param data The data to store in the cache, may be {@code null}. + */ + void put( RepositorySystemSession session, Object key, Object data ); + + /** + * Gets the specified data from the cache. + *

+ * Warning: The cache will directly return the saved reference. If the cached data is to be modified after + * its retrieval, the caller is responsible to create a copy of the returned data and use this instead of the cache + * record. + * + * @param session The repository session during which the cache is accessed, must not be {@code null}. + * @param key The key to use for lookup of the data, must not be {@code null}. + * @return The requested data or {@code null} if none was present in the cache. + */ + Object get( RepositorySystemSession session, Object key ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryEvent.java b/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryEvent.java new file mode 100644 index 000000000..2abd80009 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryEvent.java @@ -0,0 +1,433 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +import java.io.File; +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.ArtifactRepository; + +/** + * An event describing an action performed by the repository system. Note that events which indicate the end of an + * action like {@link EventType#ARTIFACT_RESOLVED} are generally fired in both the success and the failure case. Use + * {@link #getException()} to check whether an event denotes success or failure. + * + * @see RepositoryListener + * @see RepositoryEvent.Builder + */ +public final class RepositoryEvent +{ + + /** + * The type of the repository event. + */ + public enum EventType + { + + /** + * @see RepositoryListener#artifactDescriptorInvalid(RepositoryEvent) + */ + ARTIFACT_DESCRIPTOR_INVALID, + + /** + * @see RepositoryListener#artifactDescriptorMissing(RepositoryEvent) + */ + ARTIFACT_DESCRIPTOR_MISSING, + + /** + * @see RepositoryListener#metadataInvalid(RepositoryEvent) + */ + METADATA_INVALID, + + /** + * @see RepositoryListener#artifactResolving(RepositoryEvent) + */ + ARTIFACT_RESOLVING, + + /** + * @see RepositoryListener#artifactResolved(RepositoryEvent) + */ + ARTIFACT_RESOLVED, + + /** + * @see RepositoryListener#metadataResolving(RepositoryEvent) + */ + METADATA_RESOLVING, + + /** + * @see RepositoryListener#metadataResolved(RepositoryEvent) + */ + METADATA_RESOLVED, + + /** + * @see RepositoryListener#artifactDownloading(RepositoryEvent) + */ + ARTIFACT_DOWNLOADING, + + /** + * @see RepositoryListener#artifactDownloaded(RepositoryEvent) + */ + ARTIFACT_DOWNLOADED, + + /** + * @see RepositoryListener#metadataDownloading(RepositoryEvent) + */ + METADATA_DOWNLOADING, + + /** + * @see RepositoryListener#metadataDownloaded(RepositoryEvent) + */ + METADATA_DOWNLOADED, + + /** + * @see RepositoryListener#artifactInstalling(RepositoryEvent) + */ + ARTIFACT_INSTALLING, + + /** + * @see RepositoryListener#artifactInstalled(RepositoryEvent) + */ + ARTIFACT_INSTALLED, + + /** + * @see RepositoryListener#metadataInstalling(RepositoryEvent) + */ + METADATA_INSTALLING, + + /** + * @see RepositoryListener#metadataInstalled(RepositoryEvent) + */ + METADATA_INSTALLED, + + /** + * @see RepositoryListener#artifactDeploying(RepositoryEvent) + */ + ARTIFACT_DEPLOYING, + + /** + * @see RepositoryListener#artifactDeployed(RepositoryEvent) + */ + ARTIFACT_DEPLOYED, + + /** + * @see RepositoryListener#metadataDeploying(RepositoryEvent) + */ + METADATA_DEPLOYING, + + /** + * @see RepositoryListener#metadataDeployed(RepositoryEvent) + */ + METADATA_DEPLOYED + + } + + private final EventType type; + + private final RepositorySystemSession session; + + private final Artifact artifact; + + private final Metadata metadata; + + private final ArtifactRepository repository; + + private final File file; + + private final List exceptions; + + private final RequestTrace trace; + + RepositoryEvent( Builder builder ) + { + type = builder.type; + session = builder.session; + artifact = builder.artifact; + metadata = builder.metadata; + repository = builder.repository; + file = builder.file; + exceptions = builder.exceptions; + trace = builder.trace; + } + + /** + * Gets the type of the event. + * + * @return The type of the event, never {@code null}. + */ + public EventType getType() + { + return type; + } + + /** + * Gets the repository system session during which the event occurred. + * + * @return The repository system session during which the event occurred, never {@code null}. + */ + public RepositorySystemSession getSession() + { + return session; + } + + /** + * Gets the artifact involved in the event (if any). + * + * @return The involved artifact or {@code null} if none. + */ + public Artifact getArtifact() + { + return artifact; + } + + /** + * Gets the metadata involved in the event (if any). + * + * @return The involved metadata or {@code null} if none. + */ + public Metadata getMetadata() + { + return metadata; + } + + /** + * Gets the file involved in the event (if any). + * + * @return The involved file or {@code null} if none. + */ + public File getFile() + { + return file; + } + + /** + * Gets the repository involved in the event (if any). + * + * @return The involved repository or {@code null} if none. + */ + public ArtifactRepository getRepository() + { + return repository; + } + + /** + * Gets the exception that caused the event (if any). As a rule of thumb, an event accompanied by an exception + * indicates a failure of the corresponding action. If multiple exceptions occurred, this method returns the first + * exception. + * + * @return The exception or {@code null} if none. + */ + public Exception getException() + { + return exceptions.isEmpty() ? null : exceptions.get( 0 ); + } + + /** + * Gets the exceptions that caused the event (if any). As a rule of thumb, an event accompanied by exceptions + * indicates a failure of the corresponding action. + * + * @return The exceptions, never {@code null}. + */ + public List getExceptions() + { + return exceptions; + } + + /** + * Gets the trace information about the request during which the event occurred. + * + * @return The trace information or {@code null} if none. + */ + public RequestTrace getTrace() + { + return trace; + } + + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder( 256 ); + buffer.append( getType() ); + if ( getArtifact() != null ) + { + buffer.append( " " ).append( getArtifact() ); + } + if ( getMetadata() != null ) + { + buffer.append( " " ).append( getMetadata() ); + } + if ( getFile() != null ) + { + buffer.append( " (" ).append( getFile() ).append( ")" ); + } + if ( getRepository() != null ) + { + buffer.append( " @ " ).append( getRepository() ); + } + return buffer.toString(); + } + + /** + * A builder to create events. + */ + public static final class Builder + { + + EventType type; + + RepositorySystemSession session; + + Artifact artifact; + + Metadata metadata; + + ArtifactRepository repository; + + File file; + + List exceptions = Collections.emptyList(); + + RequestTrace trace; + + /** + * Creates a new event builder for the specified session and event type. + * + * @param session The repository system session, must not be {@code null}. + * @param type The type of the event, must not be {@code null}. + */ + public Builder( RepositorySystemSession session, EventType type ) + { + if ( session == null ) + { + throw new IllegalArgumentException( "session not specified" ); + } + this.session = session; + if ( type == null ) + { + throw new IllegalArgumentException( "event type not specified" ); + } + this.type = type; + } + + /** + * Sets the artifact involved in the event. + * + * @param artifact The involved artifact, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setArtifact( Artifact artifact ) + { + this.artifact = artifact; + return this; + } + + /** + * Sets the metadata involved in the event. + * + * @param metadata The involved metadata, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setMetadata( Metadata metadata ) + { + this.metadata = metadata; + return this; + } + + /** + * Sets the repository involved in the event. + * + * @param repository The involved repository, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setRepository( ArtifactRepository repository ) + { + this.repository = repository; + return this; + } + + /** + * Sets the file involved in the event. + * + * @param file The involved file, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setFile( File file ) + { + this.file = file; + return this; + } + + /** + * Sets the exception causing the event. + * + * @param exception The exception causing the event, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setException( Exception exception ) + { + if ( exception != null ) + { + this.exceptions = Collections.singletonList( exception ); + } + else + { + this.exceptions = Collections.emptyList(); + } + return this; + } + + /** + * Sets the exceptions causing the event. + * + * @param exceptions The exceptions causing the event, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setExceptions( List exceptions ) + { + if ( exceptions != null ) + { + this.exceptions = exceptions; + } + else + { + this.exceptions = Collections.emptyList(); + } + return this; + } + + /** + * Sets the trace information about the request during which the event occurred. + * + * @param trace The trace information, may be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setTrace( RequestTrace trace ) + { + this.trace = trace; + return this; + } + + /** + * Builds a new event from the current values of this builder. The state of the builder itself remains + * unchanged. + * + * @return The event, never {@code null}. + */ + public RepositoryEvent build() + { + return new RepositoryEvent( this ); + } + + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryException.java b/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryException.java new file mode 100644 index 000000000..35f0cfd1a --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryException.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +/** + * The base class for exceptions thrown by the repository system. Note: Unless otherwise noted, instances of + * this class and its subclasses will not persist fields carrying extended error information during serialization. + */ +public class RepositoryException + extends Exception +{ + + /** + * Creates a new exception with the specified detail message. + * + * @param message The detail message, may be {@code null}. + */ + public RepositoryException( String message ) + { + super( message ); + } + + /** + * Creates a new exception with the specified detail message and cause. + * + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public RepositoryException( String message, Throwable cause ) + { + super( message, cause ); + } + + /** + * @noreference This method is not intended to be used by clients. + * @param prefix A message prefix for the cause. + * @param cause The error cause. + * @return The error message for the cause. + */ + protected static String getMessage( String prefix, Throwable cause ) + { + String msg = ""; + if ( cause != null ) + { + msg = cause.getMessage(); + if ( msg == null || msg.length() <= 0 ) + { + msg = cause.getClass().getSimpleName(); + } + msg = prefix + msg; + } + return msg; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryListener.java b/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryListener.java new file mode 100644 index 000000000..5f8392368 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryListener.java @@ -0,0 +1,213 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +/** + * A listener being notified of events from the repository system. In general, the system sends events upon termination + * of an operation like {@link #artifactResolved(RepositoryEvent)} regardless whether it succeeded or failed so + * listeners need to inspect the event details carefully. Also, the listener may be called from an arbitrary thread. + * Note: Implementors are strongly advised to inherit from {@link AbstractRepositoryListener} instead of + * directly implementing this interface. + * + * @see org.eclipse.aether.RepositorySystemSession#getRepositoryListener() + * @see org.eclipse.aether.transfer.TransferListener + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface RepositoryListener +{ + + /** + * Notifies the listener of a syntactically or semantically invalid artifact descriptor. + * {@link RepositoryEvent#getArtifact()} indicates the artifact whose descriptor is invalid and + * {@link RepositoryEvent#getExceptions()} carries the encountered errors. Depending on the session's + * {@link org.eclipse.aether.resolution.ArtifactDescriptorPolicy}, the underlying repository operation might abort + * with an exception or ignore the invalid descriptor. + * + * @param event The event details, must not be {@code null}. + */ + void artifactDescriptorInvalid( RepositoryEvent event ); + + /** + * Notifies the listener of a missing artifact descriptor. {@link RepositoryEvent#getArtifact()} indicates the + * artifact whose descriptor is missing. Depending on the session's + * {@link org.eclipse.aether.resolution.ArtifactDescriptorPolicy}, the underlying repository operation might abort + * with an exception or ignore the missing descriptor. + * + * @param event The event details, must not be {@code null}. + */ + void artifactDescriptorMissing( RepositoryEvent event ); + + /** + * Notifies the listener of syntactically or semantically invalid metadata. {@link RepositoryEvent#getMetadata()} + * indicates the invalid metadata and {@link RepositoryEvent#getExceptions()} carries the encountered errors. The + * underlying repository operation might still succeed, depending on whether the metadata in question is actually + * needed to carry out the resolution process. + * + * @param event The event details, must not be {@code null}. + */ + void metadataInvalid( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact that is about to be resolved. {@link RepositoryEvent#getArtifact()} denotes + * the artifact in question. Unlike the {@link #artifactDownloading(RepositoryEvent)} event, this event is fired + * regardless whether the artifact already exists locally or not. + * + * @param event The event details, must not be {@code null}. + */ + void artifactResolving( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact whose resolution has been completed, either successfully or not. + * {@link RepositoryEvent#getArtifact()} denotes the artifact in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the resolution succeeded or failed. Unlike the + * {@link #artifactDownloaded(RepositoryEvent)} event, this event is fired regardless whether the artifact already + * exists locally or not. + * + * @param event The event details, must not be {@code null}. + */ + void artifactResolved( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata that is about to be resolved. {@link RepositoryEvent#getMetadata()} + * denotes the metadata in question. Unlike the {@link #metadataDownloading(RepositoryEvent)} event, this event is + * fired regardless whether the metadata already exists locally or not. + * + * @param event The event details, must not be {@code null}. + */ + void metadataResolving( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata whose resolution has been completed, either successfully or not. + * {@link RepositoryEvent#getMetadata()} denotes the metadata in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the resolution succeeded or failed. Unlike the + * {@link #metadataDownloaded(RepositoryEvent)} event, this event is fired regardless whether the metadata already + * exists locally or not. + * + * @param event The event details, must not be {@code null}. + */ + void metadataResolved( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact that is about to be downloaded from a remote repository. + * {@link RepositoryEvent#getArtifact()} denotes the artifact in question and + * {@link RepositoryEvent#getRepository()} the source repository. Unlike the + * {@link #artifactResolving(RepositoryEvent)} event, this event is only fired when the artifact does not already + * exist locally. + * + * @param event The event details, must not be {@code null}. + */ + void artifactDownloading( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact whose download has been completed, either successfully or not. + * {@link RepositoryEvent#getArtifact()} denotes the artifact in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the download succeeded or failed. Unlike the + * {@link #artifactResolved(RepositoryEvent)} event, this event is only fired when the artifact does not already + * exist locally. + * + * @param event The event details, must not be {@code null}. + */ + void artifactDownloaded( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata that is about to be downloaded from a remote repository. + * {@link RepositoryEvent#getMetadata()} denotes the metadata in question and + * {@link RepositoryEvent#getRepository()} the source repository. Unlike the + * {@link #metadataResolving(RepositoryEvent)} event, this event is only fired when the metadata does not already + * exist locally. + * + * @param event The event details, must not be {@code null}. + */ + void metadataDownloading( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata whose download has been completed, either successfully or not. + * {@link RepositoryEvent#getMetadata()} denotes the metadata in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the download succeeded or failed. Unlike the + * {@link #metadataResolved(RepositoryEvent)} event, this event is only fired when the metadata does not already + * exist locally. + * + * @param event The event details, must not be {@code null}. + */ + void metadataDownloaded( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact that is about to be installed to the local repository. + * {@link RepositoryEvent#getArtifact()} denotes the artifact in question. + * + * @param event The event details, must not be {@code null}. + */ + void artifactInstalling( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact whose installation to the local repository has been completed, either + * successfully or not. {@link RepositoryEvent#getArtifact()} denotes the artifact in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the installation succeeded or failed. + * + * @param event The event details, must not be {@code null}. + */ + void artifactInstalled( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata that is about to be installed to the local repository. + * {@link RepositoryEvent#getMetadata()} denotes the metadata in question. + * + * @param event The event details, must not be {@code null}. + */ + void metadataInstalling( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata whose installation to the local repository has been completed, either + * successfully or not. {@link RepositoryEvent#getMetadata()} denotes the metadata in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the installation succeeded or failed. + * + * @param event The event details, must not be {@code null}. + */ + void metadataInstalled( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact that is about to be uploaded to a remote repository. + * {@link RepositoryEvent#getArtifact()} denotes the artifact in question and + * {@link RepositoryEvent#getRepository()} the destination repository. + * + * @param event The event details, must not be {@code null}. + */ + void artifactDeploying( RepositoryEvent event ); + + /** + * Notifies the listener of an artifact whose upload to a remote repository has been completed, either successfully + * or not. {@link RepositoryEvent#getArtifact()} denotes the artifact in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the upload succeeded or failed. + * + * @param event The event details, must not be {@code null}. + */ + void artifactDeployed( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata that is about to be uploaded to a remote repository. + * {@link RepositoryEvent#getMetadata()} denotes the metadata in question and + * {@link RepositoryEvent#getRepository()} the destination repository. + * + * @param event The event details, must not be {@code null}. + */ + void metadataDeploying( RepositoryEvent event ); + + /** + * Notifies the listener of some metadata whose upload to a remote repository has been completed, either + * successfully or not. {@link RepositoryEvent#getMetadata()} denotes the metadata in question and + * {@link RepositoryEvent#getExceptions()} indicates whether the upload succeeded or failed. + * + * @param event The event details, must not be {@code null}. + */ + void metadataDeployed( RepositoryEvent event ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystem.java b/org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystem.java new file mode 100644 index 000000000..debdb7d19 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystem.java @@ -0,0 +1,268 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +import java.util.Collection; +import java.util.List; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.collection.CollectResult; +import org.eclipse.aether.collection.DependencyCollectionException; +import org.eclipse.aether.deployment.DeployRequest; +import org.eclipse.aether.deployment.DeployResult; +import org.eclipse.aether.deployment.DeploymentException; +import org.eclipse.aether.installation.InstallRequest; +import org.eclipse.aether.installation.InstallResult; +import org.eclipse.aether.installation.InstallationException; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.LocalRepositoryManager; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.ArtifactDescriptorException; +import org.eclipse.aether.resolution.ArtifactDescriptorRequest; +import org.eclipse.aether.resolution.ArtifactDescriptorResult; +import org.eclipse.aether.resolution.ArtifactRequest; +import org.eclipse.aether.resolution.ArtifactResolutionException; +import org.eclipse.aether.resolution.ArtifactResult; +import org.eclipse.aether.resolution.DependencyRequest; +import org.eclipse.aether.resolution.DependencyResolutionException; +import org.eclipse.aether.resolution.DependencyResult; +import org.eclipse.aether.resolution.MetadataRequest; +import org.eclipse.aether.resolution.MetadataResult; +import org.eclipse.aether.resolution.VersionRangeRequest; +import org.eclipse.aether.resolution.VersionRangeResolutionException; +import org.eclipse.aether.resolution.VersionRangeResult; +import org.eclipse.aether.resolution.VersionRequest; +import org.eclipse.aether.resolution.VersionResolutionException; +import org.eclipse.aether.resolution.VersionResult; + +/** + * The main entry point to the repository system and its functionality. Note that obtaining a concrete implementation of + * this interface (e.g. via dependency injection, service locator, etc.) is dependent on the application and its + * specific needs, please consult the online documentation for examples and directions on booting the system. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface RepositorySystem +{ + + /** + * Expands a version range to a list of matching versions, in ascending order. For example, resolves "[3.8,4.0)" to + * "3.8", "3.8.1", "3.8.2". Note that the returned list of versions is only dependent on the configured repositories + * and their contents, the list is not processed by the {@link RepositorySystemSession#getVersionFilter() session's + * version filter}. + *

+ * The supplied request may also refer to a single concrete version rather than a version range. In this case + * though, the result contains simply the (parsed) input version, regardless of the repositories and their contents. + * + * @param session The repository session, must not be {@code null}. + * @param request The version range request, must not be {@code null}. + * @return The version range result, never {@code null}. + * @throws VersionRangeResolutionException If the requested range could not be parsed. Note that an empty range does + * not raise an exception. + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + VersionRangeResult resolveVersionRange( RepositorySystemSession session, VersionRangeRequest request ) + throws VersionRangeResolutionException; + + /** + * Resolves an artifact's meta version (if any) to a concrete version. For example, resolves "1.0-SNAPSHOT" to + * "1.0-20090208.132618-23". + * + * @param session The repository session, must not be {@code null}. + * @param request The version request, must not be {@code null}. + * @return The version result, never {@code null}. + * @throws VersionResolutionException If the metaversion could not be resolved. + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + VersionResult resolveVersion( RepositorySystemSession session, VersionRequest request ) + throws VersionResolutionException; + + /** + * Gets information about an artifact like its direct dependencies and potential relocations. + * + * @param session The repository session, must not be {@code null}. + * @param request The descriptor request, must not be {@code null}. + * @return The descriptor result, never {@code null}. + * @throws ArtifactDescriptorException If the artifact descriptor could not be read. + * @see RepositorySystemSession#getArtifactDescriptorPolicy() + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session, ArtifactDescriptorRequest request ) + throws ArtifactDescriptorException; + + /** + * Collects the transitive dependencies of an artifact and builds a dependency graph. Note that this operation is + * only concerned about determining the coordinates of the transitive dependencies. To also resolve the actual + * artifact files, use {@link #resolveDependencies(RepositorySystemSession, DependencyRequest)}. + * + * @param session The repository session, must not be {@code null}. + * @param request The collection request, must not be {@code null}. + * @return The collection result, never {@code null}. + * @throws DependencyCollectionException If the dependency tree could not be built. + * @see RepositorySystemSession#getDependencyTraverser() + * @see RepositorySystemSession#getDependencyManager() + * @see RepositorySystemSession#getDependencySelector() + * @see RepositorySystemSession#getVersionFilter() + * @see RepositorySystemSession#getDependencyGraphTransformer() + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + CollectResult collectDependencies( RepositorySystemSession session, CollectRequest request ) + throws DependencyCollectionException; + + /** + * Collects and resolves the transitive dependencies of an artifact. This operation is essentially a combination of + * {@link #collectDependencies(RepositorySystemSession, CollectRequest)} and + * {@link #resolveArtifacts(RepositorySystemSession, Collection)}. + * + * @param session The repository session, must not be {@code null}. + * @param request The dependency request, must not be {@code null}. + * @return The dependency result, never {@code null}. + * @throws DependencyResolutionException If the dependency tree could not be built or any dependency artifact could + * not be resolved. + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + DependencyResult resolveDependencies( RepositorySystemSession session, DependencyRequest request ) + throws DependencyResolutionException; + + /** + * Resolves the path for an artifact. The artifact will be downloaded to the local repository if necessary. An + * artifact that is already resolved will be skipped and is not re-resolved. In general, callers must not assume any + * relationship between an artifact's resolved filename and its coordinates. Note that this method assumes that any + * relocations have already been processed. + * + * @param session The repository session, must not be {@code null}. + * @param request The resolution request, must not be {@code null}. + * @return The resolution result, never {@code null}. + * @throws ArtifactResolutionException If the artifact could not be resolved. + * @see Artifact#getFile() + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + ArtifactResult resolveArtifact( RepositorySystemSession session, ArtifactRequest request ) + throws ArtifactResolutionException; + + /** + * Resolves the paths for a collection of artifacts. Artifacts will be downloaded to the local repository if + * necessary. Artifacts that are already resolved will be skipped and are not re-resolved. In general, callers must + * not assume any relationship between an artifact's filename and its coordinates. Note that this method assumes + * that any relocations have already been processed. + * + * @param session The repository session, must not be {@code null}. + * @param requests The resolution requests, must not be {@code null}. + * @return The resolution results (in request order), never {@code null}. + * @throws ArtifactResolutionException If any artifact could not be resolved. + * @see Artifact#getFile() + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + List resolveArtifacts( RepositorySystemSession session, + Collection requests ) + throws ArtifactResolutionException; + + /** + * Resolves the paths for a collection of metadata. Metadata will be downloaded to the local repository if + * necessary, e.g. because it hasn't been cached yet or the cache is deemed outdated. + * + * @param session The repository session, must not be {@code null}. + * @param requests The resolution requests, must not be {@code null}. + * @return The resolution results (in request order), never {@code null}. + * @see Metadata#getFile() + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + List resolveMetadata( RepositorySystemSession session, + Collection requests ); + + /** + * Installs a collection of artifacts and their accompanying metadata to the local repository. + * + * @param session The repository session, must not be {@code null}. + * @param request The installation request, must not be {@code null}. + * @return The installation result, never {@code null}. + * @throws InstallationException If any artifact/metadata from the request could not be installed. + */ + InstallResult install( RepositorySystemSession session, InstallRequest request ) + throws InstallationException; + + /** + * Uploads a collection of artifacts and their accompanying metadata to a remote repository. + * + * @param session The repository session, must not be {@code null}. + * @param request The deployment request, must not be {@code null}. + * @return The deployment result, never {@code null}. + * @throws DeploymentException If any artifact/metadata from the request could not be deployed. + * @see #newDeploymentRepository(RepositorySystemSession, RemoteRepository) + */ + DeployResult deploy( RepositorySystemSession session, DeployRequest request ) + throws DeploymentException; + + /** + * Creates a new manager for the specified local repository. If the specified local repository has no type, the + * default local repository type of the system will be used. Note: It is expected that this method + * invocation is one of the last steps of setting up a new session, in particular any configuration properties + * should have been set already. + * + * @param session The repository system session from which to configure the manager, must not be {@code null}. + * @param localRepository The local repository to create a manager for, must not be {@code null}. + * @return The local repository manager, never {@code null}. + * @throws IllegalArgumentException If the specified repository type is not recognized or no base directory is + * given. + */ + LocalRepositoryManager newLocalRepositoryManager( RepositorySystemSession session, LocalRepository localRepository ); + + /** + * Creates a new synchronization context. + * + * @param session The repository session during which the context will be used, must not be {@code null}. + * @param shared A flag indicating whether access to the artifacts/metadata associated with the new context can be + * shared among concurrent readers or whether access needs to be exclusive to the calling thread. + * @return The synchronization context, never {@code null}. + */ + SyncContext newSyncContext( RepositorySystemSession session, boolean shared ); + + /** + * Forms remote repositories suitable for artifact resolution by applying the session's authentication selector and + * similar network configuration to the given repository prototypes. As noted for + * {@link RepositorySystemSession#getAuthenticationSelector()} etc. the remote repositories passed to e.g. + * {@link #resolveArtifact(RepositorySystemSession, ArtifactRequest) resolveArtifact()} are used as is and expected + * to already carry any required authentication or proxy configuration. This method can be used to apply the + * authentication/proxy configuration from a session to a bare repository definition to obtain the complete + * repository definition for use in the resolution request. + * + * @param session The repository system session from which to configure the repositories, must not be {@code null}. + * @param repositories The repository prototypes from which to derive the resolution repositories, must not be + * {@code null} or contain {@code null} elements. + * @return The resolution repositories, never {@code null}. Note that there is generally no 1:1 relationship of the + * obtained repositories to the original inputs due to mirror selection potentially aggregating multiple + * repositories. + * @see #newDeploymentRepository(RepositorySystemSession, RemoteRepository) + */ + List newResolutionRepositories( RepositorySystemSession session, + List repositories ); + + /** + * Forms a remote repository suitable for artifact deployment by applying the session's authentication selector and + * similar network configuration to the given repository prototype. As noted for + * {@link RepositorySystemSession#getAuthenticationSelector()} etc. the remote repository passed to + * {@link #deploy(RepositorySystemSession, DeployRequest) deploy()} is used as is and expected to already carry any + * required authentication or proxy configuration. This method can be used to apply the authentication/proxy + * configuration from a session to a bare repository definition to obtain the complete repository definition for use + * in the deploy request. + * + * @param session The repository system session from which to configure the repository, must not be {@code null}. + * @param repository The repository prototype from which to derive the deployment repository, must not be + * {@code null}. + * @return The deployment repository, never {@code null}. + * @see #newResolutionRepositories(RepositorySystemSession, List) + */ + RemoteRepository newDeploymentRepository( RepositorySystemSession session, RemoteRepository repository ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystemSession.java b/org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystemSession.java new file mode 100644 index 000000000..96f51c156 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystemSession.java @@ -0,0 +1,254 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +import java.util.Map; + +import org.eclipse.aether.artifact.ArtifactTypeRegistry; +import org.eclipse.aether.collection.DependencyGraphTransformer; +import org.eclipse.aether.collection.DependencyManager; +import org.eclipse.aether.collection.DependencySelector; +import org.eclipse.aether.collection.DependencyTraverser; +import org.eclipse.aether.collection.VersionFilter; +import org.eclipse.aether.repository.AuthenticationSelector; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.LocalRepositoryManager; +import org.eclipse.aether.repository.MirrorSelector; +import org.eclipse.aether.repository.ProxySelector; +import org.eclipse.aether.repository.RepositoryPolicy; +import org.eclipse.aether.repository.WorkspaceReader; +import org.eclipse.aether.resolution.ArtifactDescriptorPolicy; +import org.eclipse.aether.resolution.ResolutionErrorPolicy; +import org.eclipse.aether.transfer.TransferListener; + +/** + * Defines settings and components that control the repository system. Once initialized, the session object itself is + * supposed to be immutable and hence can safely be shared across an entire application and any concurrent threads + * reading it. Components that wish to tweak some aspects of an existing session should use the copy constructor of + * {@link DefaultRepositorySystemSession} and its mutators to derive a custom session. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface RepositorySystemSession +{ + + /** + * Indicates whether the repository system operates in offline mode and avoids/refuses any access to remote + * repositories. + * + * @return {@code true} if the repository system is in offline mode, {@code false} otherwise. + */ + boolean isOffline(); + + /** + * Indicates whether repositories declared in artifact descriptors should be ignored during transitive dependency + * collection. If enabled, only the repositories originally provided with the collect request will be considered. + * + * @return {@code true} if additional repositories from artifact descriptors are ignored, {@code false} to merge + * those with the originally specified repositories. + */ + boolean isIgnoreArtifactDescriptorRepositories(); + + /** + * Gets the policy which controls whether resolutions errors from remote repositories should be cached. + * + * @return The resolution error policy for this session or {@code null} if resolution errors should generally not be + * cached. + */ + ResolutionErrorPolicy getResolutionErrorPolicy(); + + /** + * Gets the policy which controls how errors related to reading artifact descriptors should be handled. + * + * @return The descriptor error policy for this session or {@code null} if descriptor errors should generally not be + * tolerated. + */ + ArtifactDescriptorPolicy getArtifactDescriptorPolicy(); + + /** + * Gets the global checksum policy. If set, the global checksum policy overrides the checksum policies of the remote + * repositories being used for resolution. + * + * @return The global checksum policy or {@code null}/empty if not set and the per-repository policies apply. + * @see RepositoryPolicy#CHECKSUM_POLICY_FAIL + * @see RepositoryPolicy#CHECKSUM_POLICY_IGNORE + * @see RepositoryPolicy#CHECKSUM_POLICY_WARN + */ + String getChecksumPolicy(); + + /** + * Gets the global update policy. If set, the global update policy overrides the update policies of the remote + * repositories being used for resolution. + * + * @return The global update policy or {@code null}/empty if not set and the per-repository policies apply. + * @see RepositoryPolicy#UPDATE_POLICY_ALWAYS + * @see RepositoryPolicy#UPDATE_POLICY_DAILY + * @see RepositoryPolicy#UPDATE_POLICY_NEVER + */ + String getUpdatePolicy(); + + /** + * Gets the local repository used during this session. This is a convenience method for + * {@link LocalRepositoryManager#getRepository()}. + * + * @return The local repository being during this session, never {@code null}. + */ + LocalRepository getLocalRepository(); + + /** + * Gets the local repository manager used during this session. + * + * @return The local repository manager used during this session, never {@code null}. + */ + LocalRepositoryManager getLocalRepositoryManager(); + + /** + * Gets the workspace reader used during this session. If set, the workspace reader will usually be consulted first + * to resolve artifacts. + * + * @return The workspace reader for this session or {@code null} if none. + */ + WorkspaceReader getWorkspaceReader(); + + /** + * Gets the listener being notified of actions in the repository system. + * + * @return The repository listener or {@code null} if none. + */ + RepositoryListener getRepositoryListener(); + + /** + * Gets the listener being notified of uploads/downloads by the repository system. + * + * @return The transfer listener or {@code null} if none. + */ + TransferListener getTransferListener(); + + /** + * Gets the system properties to use, e.g. for processing of artifact descriptors. System properties are usually + * collected from the runtime environment like {@link System#getProperties()} and environment variables. + * + * @return The (read-only) system properties, never {@code null}. + */ + Map getSystemProperties(); + + /** + * Gets the user properties to use, e.g. for processing of artifact descriptors. User properties are similar to + * system properties but are set on the discretion of the user and hence are considered of higher priority than + * system properties. + * + * @return The (read-only) user properties, never {@code null}. + */ + Map getUserProperties(); + + /** + * Gets the configuration properties used to tweak internal aspects of the repository system (e.g. thread pooling, + * connector-specific behavior, etc.) + * + * @return The (read-only) configuration properties, never {@code null}. + * @see ConfigurationProperties + */ + Map getConfigProperties(); + + /** + * Gets the mirror selector to use for repositories discovered in artifact descriptors. Note that this selector is + * not used for remote repositories which are passed as request parameters to the repository system, those + * repositories are supposed to denote the effective repositories. + * + * @return The mirror selector to use, never {@code null}. + * @see RepositorySystem#newResolutionRepositories(RepositorySystemSession, java.util.List) + */ + MirrorSelector getMirrorSelector(); + + /** + * Gets the proxy selector to use for repositories discovered in artifact descriptors. Note that this selector is + * not used for remote repositories which are passed as request parameters to the repository system, those + * repositories are supposed to have their proxy (if any) already set. + * + * @return The proxy selector to use, never {@code null}. + * @see org.eclipse.aether.repository.RemoteRepository#getProxy() + * @see RepositorySystem#newResolutionRepositories(RepositorySystemSession, java.util.List) + */ + ProxySelector getProxySelector(); + + /** + * Gets the authentication selector to use for repositories discovered in artifact descriptors. Note that this + * selector is not used for remote repositories which are passed as request parameters to the repository system, + * those repositories are supposed to have their authentication (if any) already set. + * + * @return The authentication selector to use, never {@code null}. + * @see org.eclipse.aether.repository.RemoteRepository#getAuthentication() + * @see RepositorySystem#newResolutionRepositories(RepositorySystemSession, java.util.List) + */ + AuthenticationSelector getAuthenticationSelector(); + + /** + * Gets the registry of artifact types recognized by this session, for instance when processing artifact + * descriptors. + * + * @return The artifact type registry, never {@code null}. + */ + ArtifactTypeRegistry getArtifactTypeRegistry(); + + /** + * Gets the dependency traverser to use for building dependency graphs. + * + * @return The dependency traverser to use for building dependency graphs or {@code null} if dependencies are + * unconditionally traversed. + */ + DependencyTraverser getDependencyTraverser(); + + /** + * Gets the dependency manager to use for building dependency graphs. + * + * @return The dependency manager to use for building dependency graphs or {@code null} if dependency management is + * not performed. + */ + DependencyManager getDependencyManager(); + + /** + * Gets the dependency selector to use for building dependency graphs. + * + * @return The dependency selector to use for building dependency graphs or {@code null} if dependencies are + * unconditionally included. + */ + DependencySelector getDependencySelector(); + + /** + * Gets the version filter to use for building dependency graphs. + * + * @return The version filter to use for building dependency graphs or {@code null} if versions aren't filtered. + */ + VersionFilter getVersionFilter(); + + /** + * Gets the dependency graph transformer to use for building dependency graphs. + * + * @return The dependency graph transformer to use for building dependency graphs or {@code null} if none. + */ + DependencyGraphTransformer getDependencyGraphTransformer(); + + /** + * Gets the custom data associated with this session. + * + * @return The session data, never {@code null}. + */ + SessionData getData(); + + /** + * Gets the cache the repository system may use to save data for future reuse during the session. + * + * @return The repository cache or {@code null} if none. + */ + RepositoryCache getCache(); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RequestTrace.java b/org.argeo.slc.repo/src/org/eclipse/aether/RequestTrace.java new file mode 100644 index 000000000..c6afa8e81 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/RequestTrace.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +/** + * A trace of nested requests that are performed by the repository system. This trace information can be used to + * correlate repository events with higher level operations in the application code that eventually caused the events. A + * single trace can carry an arbitrary object as data which is meant to describe a request/operation that is currently + * executed. For call hierarchies within the repository system itself, this data will usually be the {@code *Request} + * object that is currently processed. When invoking methods on the repository system, client code may provide a request + * trace that has been prepopulated with whatever data is useful for the application to indicate its state for later + * evaluation when processing the repository events. + * + * @see RepositoryEvent#getTrace() + */ +public class RequestTrace +{ + + private final RequestTrace parent; + + private final Object data; + + /** + * Creates a child of the specified request trace. This method is basically a convenience that will invoke + * {@link RequestTrace#newChild(Object) parent.newChild()} when the specified parent trace is not {@code null} or + * otherwise instantiante a new root trace. + * + * @param parent The parent request trace, may be {@code null}. + * @param data The data to associate with the child trace, may be {@code null}. + * @return The child trace, never {@code null}. + */ + public static RequestTrace newChild( RequestTrace parent, Object data ) + { + if ( parent == null ) + { + return new RequestTrace( data ); + } + return parent.newChild( data ); + } + + /** + * Creates a new root trace with the specified data. + * + * @param data The data to associate with the trace, may be {@code null}. + */ + public RequestTrace( Object data ) + { + this( null, data ); + } + + /** + * Creates a new trace with the specified data and parent + * + * @param parent The parent trace, may be {@code null} for a root trace. + * @param data The data to associate with the trace, may be {@code null}. + */ + protected RequestTrace( RequestTrace parent, Object data ) + { + this.parent = parent; + this.data = data; + } + + /** + * Gets the data associated with this trace. + * + * @return The data associated with this trace or {@code null} if none. + */ + public final Object getData() + { + return data; + } + + /** + * Gets the parent of this trace. + * + * @return The parent of this trace or {@code null} if this is the root of the trace stack. + */ + public final RequestTrace getParent() + { + return parent; + } + + /** + * Creates a new child of this trace. + * + * @param data The data to associate with the child, may be {@code null}. + * @return The child trace, never {@code null}. + */ + public RequestTrace newChild( Object data ) + { + return new RequestTrace( this, data ); + } + + @Override + public String toString() + { + return String.valueOf( getData() ); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/SessionData.java b/org.argeo.slc.repo/src/org/eclipse/aether/SessionData.java new file mode 100644 index 000000000..92930e76e --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/SessionData.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +/** + * A container for data that is specific to a repository system session. Both components within the repository system + * and clients of the system may use this storage to associate arbitrary data with a session. + *

+ * Unlike a cache, this session data is not subject to purging. For this same reason, session data should also not be + * abused as a cache (i.e. for storing values that can be re-calculated) to avoid memory exhaustion. + *

+ * Note: Actual implementations must be thread-safe. + * + * @see RepositorySystemSession#getData() + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface SessionData +{ + + /** + * Associates the specified session data with the given key. + * + * @param key The key under which to store the session data, must not be {@code null}. + * @param value The data to associate with the key, may be {@code null} to remove the mapping. + */ + void set( Object key, Object value ); + + /** + * Associates the specified session data with the given key if the key is currently mapped to the given value. This + * method provides an atomic compare-and-update of some key's value. + * + * @param key The key under which to store the session data, must not be {@code null}. + * @param oldValue The expected data currently associated with the key, may be {@code null}. + * @param newValue The data to associate with the key, may be {@code null} to remove the mapping. + * @return {@code true} if the key mapping was successfully updated from the old value to the new value, + * {@code false} if the current key mapping didn't match the expected value and was not updated. + */ + boolean set( Object key, Object oldValue, Object newValue ); + + /** + * Gets the session data associated with the specified key. + * + * @param key The key for which to retrieve the session data, must not be {@code null}. + * @return The session data associated with the key or {@code null} if none. + */ + Object get( Object key ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/SyncContext.java b/org.argeo.slc.repo/src/org/eclipse/aether/SyncContext.java new file mode 100644 index 000000000..a05d512fd --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/SyncContext.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether; + +import java.io.Closeable; +import java.util.Collection; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.metadata.Metadata; + +/** + * A synchronization context used to coordinate concurrent access to artifacts or metadatas. The typical usage of a + * synchronization context looks like this: + * + *

+ * SyncContext syncContext = repositorySystem.newSyncContext( ... );
+ * try {
+ *     syncContext.acquire( artifacts, metadatas );
+ *     // work with the artifacts and metadatas
+ * } finally {
+ *     syncContext.close();
+ * }
+ * 
+ * + * Within one thread, synchronization contexts may be nested which can naturally happen in a hierarchy of method calls. + * The nested synchronization contexts may also acquire overlapping sets of artifacts/metadatas as long as the following + * conditions are met. If the outer-most context holding a particular resource is exclusive, that resource can be + * reacquired in any nested context. If however the outer-most context is shared, the resource may only be reacquired by + * nested contexts if these are also shared. + *

+ * A synchronization context is meant to be utilized by only one thread and as such is not thread-safe. + *

+ * Note that the level of actual synchronization is subject to the implementation and might range from OS-wide to none. + * + * @see RepositorySystem#newSyncContext(RepositorySystemSession, boolean) + */ +public interface SyncContext + extends Closeable +{ + + /** + * Acquires synchronized access to the specified artifacts and metadatas. The invocation will potentially block + * until all requested resources can be acquired by the calling thread. Acquiring resources that are already + * acquired by this synchronization context has no effect. Please also see the class-level documentation for + * information regarding reentrancy. The method may be invoked multiple times on a synchronization context until all + * desired resources have been acquired. + * + * @param artifacts The artifacts to acquire, may be {@code null} or empty if none. + * @param metadatas The metadatas to acquire, may be {@code null} or empty if none. + */ + void acquire( Collection artifacts, Collection metadatas ); + + /** + * Releases all previously acquired artifacts/metadatas. If no resources have been acquired before or if this + * synchronization context has already been closed, this method does nothing. + */ + void close(); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/AbstractArtifact.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/AbstractArtifact.java new file mode 100644 index 000000000..2944ff889 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/AbstractArtifact.java @@ -0,0 +1,221 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.artifact; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A skeleton class for artifacts. + */ +public abstract class AbstractArtifact + implements Artifact +{ + + private static final String SNAPSHOT = "SNAPSHOT"; + + private static final Pattern SNAPSHOT_TIMESTAMP = Pattern.compile( "^(.*-)?([0-9]{8}\\.[0-9]{6}-[0-9]+)$" ); + + public boolean isSnapshot() + { + return isSnapshot( getVersion() ); + } + + private static boolean isSnapshot( String version ) + { + return version.endsWith( SNAPSHOT ) || SNAPSHOT_TIMESTAMP.matcher( version ).matches(); + } + + public String getBaseVersion() + { + return toBaseVersion( getVersion() ); + } + + private static String toBaseVersion( String version ) + { + String baseVersion; + + if ( version == null ) + { + baseVersion = version; + } + else if ( version.startsWith( "[" ) || version.startsWith( "(" ) ) + { + baseVersion = version; + } + else + { + Matcher m = SNAPSHOT_TIMESTAMP.matcher( version ); + if ( m.matches() ) + { + if ( m.group( 1 ) != null ) + { + baseVersion = m.group( 1 ) + SNAPSHOT; + } + else + { + baseVersion = SNAPSHOT; + } + } + else + { + baseVersion = version; + } + } + + return baseVersion; + } + + /** + * Creates a new artifact with the specified coordinates, properties and file. + * + * @param version The version of the artifact, may be {@code null}. + * @param properties The properties of the artifact, may be {@code null} if none. The method may assume immutability + * of the supplied map, i.e. need not copy it. + * @param file The resolved file of the artifact, may be {@code null}. + * @return The new artifact instance, never {@code null}. + */ + private Artifact newInstance( String version, Map properties, File file ) + { + return new DefaultArtifact( getGroupId(), getArtifactId(), getClassifier(), getExtension(), version, file, + properties ); + } + + public Artifact setVersion( String version ) + { + String current = getVersion(); + if ( current.equals( version ) || ( version == null && current.length() <= 0 ) ) + { + return this; + } + return newInstance( version, getProperties(), getFile() ); + } + + public Artifact setFile( File file ) + { + File current = getFile(); + if ( ( current == null ) ? file == null : current.equals( file ) ) + { + return this; + } + return newInstance( getVersion(), getProperties(), file ); + } + + public Artifact setProperties( Map properties ) + { + Map current = getProperties(); + if ( current.equals( properties ) || ( properties == null && current.isEmpty() ) ) + { + return this; + } + return newInstance( getVersion(), copyProperties( properties ), getFile() ); + } + + public String getProperty( String key, String defaultValue ) + { + String value = getProperties().get( key ); + return ( value != null ) ? value : defaultValue; + } + + /** + * Copies the specified artifact properties. This utility method should be used when creating new artifact instances + * with caller-supplied properties. + * + * @param properties The properties to copy, may be {@code null}. + * @return The copied and read-only properties, never {@code null}. + */ + protected static Map copyProperties( Map properties ) + { + if ( properties != null && !properties.isEmpty() ) + { + return Collections.unmodifiableMap( new HashMap( properties ) ); + } + else + { + return Collections.emptyMap(); + } + } + + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder( 128 ); + buffer.append( getGroupId() ); + buffer.append( ':' ).append( getArtifactId() ); + buffer.append( ':' ).append( getExtension() ); + if ( getClassifier().length() > 0 ) + { + buffer.append( ':' ).append( getClassifier() ); + } + buffer.append( ':' ).append( getVersion() ); + return buffer.toString(); + } + + /** + * Compares this artifact with the specified object. + * + * @param obj The object to compare this artifact against, may be {@code null}. + * @return {@code true} if and only if the specified object is another {@link Artifact} with equal coordinates, + * properties and file, {@code false} otherwise. + */ + @Override + public boolean equals( Object obj ) + { + if ( obj == this ) + { + return true; + } + else if ( !( obj instanceof Artifact ) ) + { + return false; + } + + Artifact that = (Artifact) obj; + + return getArtifactId().equals( that.getArtifactId() ) && getGroupId().equals( that.getGroupId() ) + && getVersion().equals( that.getVersion() ) && getExtension().equals( that.getExtension() ) + && getClassifier().equals( that.getClassifier() ) && eq( getFile(), that.getFile() ) + && getProperties().equals( that.getProperties() ); + } + + private static boolean eq( T s1, T s2 ) + { + return s1 != null ? s1.equals( s2 ) : s2 == null; + } + + /** + * Returns a hash code for this artifact. + * + * @return A hash code for the artifact. + */ + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + getGroupId().hashCode(); + hash = hash * 31 + getArtifactId().hashCode(); + hash = hash * 31 + getExtension().hashCode(); + hash = hash * 31 + getClassifier().hashCode(); + hash = hash * 31 + getVersion().hashCode(); + hash = hash * 31 + hash( getFile() ); + return hash; + } + + private static int hash( Object obj ) + { + return ( obj != null ) ? obj.hashCode() : 0; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/Artifact.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/Artifact.java new file mode 100644 index 000000000..5eef695d0 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/Artifact.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.artifact; + +import java.io.File; +import java.util.Map; + +/** + * A specific artifact. In a nutshell, an artifact has identifying coordinates and optionally a file that denotes its + * data. Note: Artifact instances are supposed to be immutable, e.g. any exposed mutator method returns a new + * artifact instance and leaves the original instance unchanged. Note: Implementors are strongly advised to + * inherit from {@link AbstractArtifact} instead of directly implementing this interface. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface Artifact +{ + + /** + * Gets the group identifier of this artifact, for example "org.apache.maven". + * + * @return The group identifier, never {@code null}. + */ + String getGroupId(); + + /** + * Gets the artifact identifier of this artifact, for example "maven-model". + * + * @return The artifact identifier, never {@code null}. + */ + String getArtifactId(); + + /** + * Gets the version of this artifact, for example "1.0-20100529-1213". Note that in case of meta versions like + * "1.0-SNAPSHOT", the artifact's version depends on the state of the artifact. Artifacts that have been resolved or + * deployed will usually have the meta version expanded. + * + * @return The version, never {@code null}. + */ + String getVersion(); + + /** + * Sets the version of the artifact. + * + * @param version The version of this artifact, may be {@code null} or empty. + * @return The new artifact, never {@code null}. + */ + Artifact setVersion( String version ); + + /** + * Gets the base version of this artifact, for example "1.0-SNAPSHOT". In contrast to the {@link #getVersion()}, the + * base version will always refer to the unresolved meta version. + * + * @return The base version, never {@code null}. + */ + String getBaseVersion(); + + /** + * Determines whether this artifact uses a snapshot version. + * + * @return {@code true} if the artifact is a snapshot, {@code false} otherwise. + */ + boolean isSnapshot(); + + /** + * Gets the classifier of this artifact, for example "sources". + * + * @return The classifier or an empty string if none, never {@code null}. + */ + String getClassifier(); + + /** + * Gets the (file) extension of this artifact, for example "jar" or "tar.gz". + * + * @return The file extension (without leading period), never {@code null}. + */ + String getExtension(); + + /** + * Gets the file of this artifact. Note that only resolved artifacts have a file associated with them. In general, + * callers must not assume any relationship between an artifact's filename and its coordinates. + * + * @return The file or {@code null} if the artifact isn't resolved. + */ + File getFile(); + + /** + * Sets the file of the artifact. + * + * @param file The file of the artifact, may be {@code null} + * @return The new artifact, never {@code null}. + */ + Artifact setFile( File file ); + + /** + * Gets the specified property. + * + * @param key The name of the property, must not be {@code null}. + * @param defaultValue The default value to return in case the property is not set, may be {@code null}. + * @return The requested property value or {@code null} if the property is not set and no default value was + * provided. + * @see ArtifactProperties + */ + String getProperty( String key, String defaultValue ); + + /** + * Gets the properties of this artifact. Clients may use these properties to associate non-persistent values with an + * artifact that help later processing when the artifact gets passed around within the application. + * + * @return The (read-only) properties, never {@code null}. + * @see ArtifactProperties + */ + Map getProperties(); + + /** + * Sets the properties for the artifact. Note that these properties exist merely in memory and are not persisted + * when the artifact gets installed/deployed to a repository. + * + * @param properties The properties for the artifact, may be {@code null}. + * @return The new artifact, never {@code null}. + * @see ArtifactProperties + */ + Artifact setProperties( Map properties ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactProperties.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactProperties.java new file mode 100644 index 000000000..7fbea0447 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactProperties.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.artifact; + +/** + * The keys for common properties of artifacts. + * + * @see Artifact#getProperties() + */ +public final class ArtifactProperties +{ + + /** + * A high-level characterization of the artifact, e.g. "maven-plugin" or "test-jar". + * + * @see ArtifactType#getId() + */ + public static final String TYPE = "type"; + + /** + * The programming language this artifact is relevant for, e.g. "java" or "none". + */ + public static final String LANGUAGE = "language"; + + /** + * The (expected) path to the artifact on the local filesystem. An artifact which has this property set is assumed + * to be not present in any regular repository and likewise has no artifact descriptor. Artifact resolution will + * verify the path and resolve the artifact if the path actually denotes an existing file. If the path isn't valid, + * resolution will fail and no attempts to search local/remote repositories are made. + */ + public static final String LOCAL_PATH = "localPath"; + + /** + * A boolean flag indicating whether the artifact presents some kind of bundle that physically includes its + * dependencies, e.g. a fat WAR. + */ + public static final String INCLUDES_DEPENDENCIES = "includesDependencies"; + + /** + * A boolean flag indicating whether the artifact is meant to be used for the compile/runtime/test build path of a + * consumer project. + */ + public static final String CONSTITUTES_BUILD_PATH = "constitutesBuildPath"; + + /** + * The URL to a web page from which the artifact can be manually downloaded. This URL is not contacted by the + * repository system but serves as a pointer for the end user to assist in getting artifacts that are not published + * in a proper repository. + */ + public static final String DOWNLOAD_URL = "downloadUrl"; + + private ArtifactProperties() + { + // hide constructor + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactType.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactType.java new file mode 100644 index 000000000..174c3c5a5 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactType.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.artifact; + +import java.util.Map; + +/** + * An artifact type describing artifact characteristics/properties that are common for certain artifacts. Artifact types + * are a means to simplify the description of an artifact by referring to an artifact type instead of specifying the + * various properties individually. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + * @see ArtifactTypeRegistry + * @see DefaultArtifact#DefaultArtifact(String, String, String, String, String, ArtifactType) + */ +public interface ArtifactType +{ + + /** + * Gets the identifier of this type, e.g. "maven-plugin" or "test-jar". + * + * @return The identifier of this type, never {@code null}. + * @see ArtifactProperties#TYPE + */ + String getId(); + + /** + * Gets the file extension to use for artifacts of this type (unless explicitly overridden by the artifact). + * + * @return The usual file extension, never {@code null}. + */ + String getExtension(); + + /** + * Gets the classifier to use for artifacts of this type (unless explicitly overridden by the artifact). + * + * @return The usual classifier or an empty string if none, never {@code null}. + */ + String getClassifier(); + + /** + * Gets the properties to use for artifacts of this type (unless explicitly overridden by the artifact). + * + * @return The (read-only) properties, never {@code null}. + * @see ArtifactProperties + */ + Map getProperties(); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactTypeRegistry.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactTypeRegistry.java new file mode 100644 index 000000000..2addff1ea --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactTypeRegistry.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.artifact; + +/** + * A registry of known artifact types. + * + * @see org.eclipse.aether.RepositorySystemSession#getArtifactTypeRegistry() + */ +public interface ArtifactTypeRegistry +{ + + /** + * Gets the artifact type with the specified identifier. + * + * @param typeId The identifier of the type, must not be {@code null}. + * @return The artifact type or {@code null} if no type with the requested identifier exists. + */ + ArtifactType get( String typeId ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifact.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifact.java new file mode 100644 index 000000000..997103419 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifact.java @@ -0,0 +1,276 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.artifact; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A simple artifact. Note: Instances of this class are immutable and the exposed mutators return new objects + * rather than changing the current instance. + */ +public final class DefaultArtifact + extends AbstractArtifact +{ + + private final String groupId; + + private final String artifactId; + + private final String version; + + private final String classifier; + + private final String extension; + + private final File file; + + private final Map properties; + + /** + * Creates a new artifact with the specified coordinates. If not specified in the artifact coordinates, the + * artifact's extension defaults to {@code jar} and classifier to an empty string. + * + * @param coords The artifact coordinates in the format + * {@code :[:[:]]:}, must not be {@code null}. + */ + public DefaultArtifact( String coords ) + { + this( coords, Collections. emptyMap() ); + } + + /** + * Creates a new artifact with the specified coordinates and properties. If not specified in the artifact + * coordinates, the artifact's extension defaults to {@code jar} and classifier to an empty string. + * + * @param coords The artifact coordinates in the format + * {@code :[:[:]]:}, must not be {@code null}. + * @param properties The artifact properties, may be {@code null}. + */ + public DefaultArtifact( String coords, Map properties ) + { + Pattern p = Pattern.compile( "([^: ]+):([^: ]+)(:([^: ]*)(:([^: ]+))?)?:([^: ]+)" ); + Matcher m = p.matcher( coords ); + if ( !m.matches() ) + { + throw new IllegalArgumentException( "Bad artifact coordinates " + coords + + ", expected format is :[:[:]]:" ); + } + groupId = m.group( 1 ); + artifactId = m.group( 2 ); + extension = get( m.group( 4 ), "jar" ); + classifier = get( m.group( 6 ), "" ); + version = m.group( 7 ); + file = null; + this.properties = copyProperties( properties ); + } + + private static String get( String value, String defaultValue ) + { + return ( value == null || value.length() <= 0 ) ? defaultValue : value; + } + + /** + * Creates a new artifact with the specified coordinates and no classifier. Passing {@code null} for any of the + * coordinates is equivalent to specifying an empty string. + * + * @param groupId The group identifier of the artifact, may be {@code null}. + * @param artifactId The artifact identifier of the artifact, may be {@code null}. + * @param extension The file extension of the artifact, may be {@code null}. + * @param version The version of the artifact, may be {@code null}. + */ + public DefaultArtifact( String groupId, String artifactId, String extension, String version ) + { + this( groupId, artifactId, "", extension, version ); + } + + /** + * Creates a new artifact with the specified coordinates. Passing {@code null} for any of the coordinates is + * equivalent to specifying an empty string. + * + * @param groupId The group identifier of the artifact, may be {@code null}. + * @param artifactId The artifact identifier of the artifact, may be {@code null}. + * @param classifier The classifier of the artifact, may be {@code null}. + * @param extension The file extension of the artifact, may be {@code null}. + * @param version The version of the artifact, may be {@code null}. + */ + public DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version ) + { + this( groupId, artifactId, classifier, extension, version, null, (File) null ); + } + + /** + * Creates a new artifact with the specified coordinates. Passing {@code null} for any of the coordinates is + * equivalent to specifying an empty string. The optional artifact type provided to this constructor will be used to + * determine the artifact's classifier and file extension if the corresponding arguments for this constructor are + * {@code null}. + * + * @param groupId The group identifier of the artifact, may be {@code null}. + * @param artifactId The artifact identifier of the artifact, may be {@code null}. + * @param classifier The classifier of the artifact, may be {@code null}. + * @param extension The file extension of the artifact, may be {@code null}. + * @param version The version of the artifact, may be {@code null}. + * @param type The artifact type from which to query classifier, file extension and properties, may be {@code null}. + */ + public DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version, + ArtifactType type ) + { + this( groupId, artifactId, classifier, extension, version, null, type ); + } + + /** + * Creates a new artifact with the specified coordinates and properties. Passing {@code null} for any of the + * coordinates is equivalent to specifying an empty string. The optional artifact type provided to this constructor + * will be used to determine the artifact's classifier and file extension if the corresponding arguments for this + * constructor are {@code null}. If the artifact type specifies properties, those will get merged with the + * properties passed directly into the constructor, with the latter properties taking precedence. + * + * @param groupId The group identifier of the artifact, may be {@code null}. + * @param artifactId The artifact identifier of the artifact, may be {@code null}. + * @param classifier The classifier of the artifact, may be {@code null}. + * @param extension The file extension of the artifact, may be {@code null}. + * @param version The version of the artifact, may be {@code null}. + * @param properties The properties of the artifact, may be {@code null} if none. + * @param type The artifact type from which to query classifier, file extension and properties, may be {@code null}. + */ + public DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version, + Map properties, ArtifactType type ) + { + this.groupId = emptify( groupId ); + this.artifactId = emptify( artifactId ); + if ( classifier != null || type == null ) + { + this.classifier = emptify( classifier ); + } + else + { + this.classifier = emptify( type.getClassifier() ); + } + if ( extension != null || type == null ) + { + this.extension = emptify( extension ); + } + else + { + this.extension = emptify( type.getExtension() ); + } + this.version = emptify( version ); + this.file = null; + this.properties = merge( properties, ( type != null ) ? type.getProperties() : null ); + } + + private static Map merge( Map dominant, Map recessive ) + { + Map properties; + + if ( ( dominant == null || dominant.isEmpty() ) && ( recessive == null || recessive.isEmpty() ) ) + { + properties = Collections.emptyMap(); + } + else + { + properties = new HashMap(); + if ( recessive != null ) + { + properties.putAll( recessive ); + } + if ( dominant != null ) + { + properties.putAll( dominant ); + } + properties = Collections.unmodifiableMap( properties ); + } + + return properties; + } + + /** + * Creates a new artifact with the specified coordinates, properties and file. Passing {@code null} for any of the + * coordinates is equivalent to specifying an empty string. + * + * @param groupId The group identifier of the artifact, may be {@code null}. + * @param artifactId The artifact identifier of the artifact, may be {@code null}. + * @param classifier The classifier of the artifact, may be {@code null}. + * @param extension The file extension of the artifact, may be {@code null}. + * @param version The version of the artifact, may be {@code null}. + * @param properties The properties of the artifact, may be {@code null} if none. + * @param file The resolved file of the artifact, may be {@code null}. + */ + public DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version, + Map properties, File file ) + { + this.groupId = emptify( groupId ); + this.artifactId = emptify( artifactId ); + this.classifier = emptify( classifier ); + this.extension = emptify( extension ); + this.version = emptify( version ); + this.file = file; + this.properties = copyProperties( properties ); + } + + DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version, File file, + Map properties ) + { + // NOTE: This constructor assumes immutability of the provided properties, for internal use only + this.groupId = emptify( groupId ); + this.artifactId = emptify( artifactId ); + this.classifier = emptify( classifier ); + this.extension = emptify( extension ); + this.version = emptify( version ); + this.file = file; + this.properties = properties; + } + + private static String emptify( String str ) + { + return ( str == null ) ? "" : str; + } + + public String getGroupId() + { + return groupId; + } + + public String getArtifactId() + { + return artifactId; + } + + public String getVersion() + { + return version; + } + + public String getClassifier() + { + return classifier; + } + + public String getExtension() + { + return extension; + } + + public File getFile() + { + return file; + } + + public Map getProperties() + { + return properties; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifactType.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifactType.java new file mode 100644 index 000000000..b30cd12ef --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifactType.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.artifact; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * A simple artifact type. + */ +public final class DefaultArtifactType + implements ArtifactType +{ + + private final String id; + + private final String extension; + + private final String classifier; + + private final Map properties; + + /** + * Creates a new artifact type with the specified identifier. This constructor assumes the usual file extension + * equals the given type id and that the usual classifier is empty. Additionally, the properties + * {@link ArtifactProperties#LANGUAGE}, {@link ArtifactProperties#CONSTITUTES_BUILD_PATH} and + * {@link ArtifactProperties#INCLUDES_DEPENDENCIES} will be set to {@code "none"}, {@code true} and {@code false}, + * respectively. + * + * @param id The identifier of the type which will also be used as the value for the {@link ArtifactProperties#TYPE} + * property, must not be {@code null} or empty. + */ + public DefaultArtifactType( String id ) + { + this( id, id, "", "none", false, false ); + } + + /** + * Creates a new artifact type with the specified properties. Additionally, the properties + * {@link ArtifactProperties#CONSTITUTES_BUILD_PATH} and {@link ArtifactProperties#INCLUDES_DEPENDENCIES} will be + * set to {@code true} and {@code false}, respectively. + * + * @param id The identifier of the type which will also be used as the value for the {@link ArtifactProperties#TYPE} + * property, must not be {@code null} or empty. + * @param extension The usual file extension for artifacts of this type, may be {@code null}. + * @param classifier The usual classifier for artifacts of this type, may be {@code null}. + * @param language The value for the {@link ArtifactProperties#LANGUAGE} property, may be {@code null}. + */ + public DefaultArtifactType( String id, String extension, String classifier, String language ) + { + this( id, extension, classifier, language, true, false ); + } + + /** + * Creates a new artifact type with the specified properties. + * + * @param id The identifier of the type which will also be used as the value for the {@link ArtifactProperties#TYPE} + * property, must not be {@code null} or empty. + * @param extension The usual file extension for artifacts of this type, may be {@code null}. + * @param classifier The usual classifier for artifacts of this type, may be {@code null}. + * @param language The value for the {@link ArtifactProperties#LANGUAGE} property, may be {@code null}. + * @param constitutesBuildPath The value for the {@link ArtifactProperties#CONSTITUTES_BUILD_PATH} property. + * @param includesDependencies The value for the {@link ArtifactProperties#INCLUDES_DEPENDENCIES} property. + */ + public DefaultArtifactType( String id, String extension, String classifier, String language, + boolean constitutesBuildPath, boolean includesDependencies ) + { + if ( id == null || id.length() < 0 ) + { + throw new IllegalArgumentException( "no type id specified" ); + } + this.id = id; + this.extension = emptify( extension ); + this.classifier = emptify( classifier ); + Map props = new HashMap(); + props.put( ArtifactProperties.TYPE, id ); + props.put( ArtifactProperties.LANGUAGE, ( language != null && language.length() > 0 ) ? language : "none" ); + props.put( ArtifactProperties.INCLUDES_DEPENDENCIES, Boolean.toString( includesDependencies ) ); + props.put( ArtifactProperties.CONSTITUTES_BUILD_PATH, Boolean.toString( constitutesBuildPath ) ); + properties = Collections.unmodifiableMap( props ); + } + + /** + * Creates a new artifact type with the specified properties. + * + * @param id The identifier of the type, must not be {@code null} or empty. + * @param extension The usual file extension for artifacts of this type, may be {@code null}. + * @param classifier The usual classifier for artifacts of this type, may be {@code null}. + * @param properties The properties for artifacts of this type, may be {@code null}. + */ + public DefaultArtifactType( String id, String extension, String classifier, Map properties ) + { + if ( id == null || id.length() < 0 ) + { + throw new IllegalArgumentException( "no type id specified" ); + } + this.id = id; + this.extension = emptify( extension ); + this.classifier = emptify( classifier ); + this.properties = AbstractArtifact.copyProperties( properties ); + } + + private static String emptify( String str ) + { + return ( str == null ) ? "" : str; + } + + public String getId() + { + return id; + } + + public String getExtension() + { + return extension; + } + + public String getClassifier() + { + return classifier; + } + + public Map getProperties() + { + return properties; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/package-info.java new file mode 100644 index 000000000..6d676d127 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/package-info.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * The definition of an artifact, that is the primary entity managed by the repository system. + */ +package org.eclipse.aether.artifact; + diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectRequest.java new file mode 100644 index 000000000..856838513 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectRequest.java @@ -0,0 +1,347 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.collection; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * A request to collect the transitive dependencies and to build a dependency graph from them. There are three ways to + * create a dependency graph. First, only the root dependency can be given. Second, a root dependency and direct + * dependencies can be specified in which case the specified direct dependencies are merged with the direct dependencies + * retrieved from the artifact descriptor of the root dependency. And last, only direct dependencies can be specified in + * which case the root node of the resulting graph has no associated dependency. + * + * @see RepositorySystem#collectDependencies(RepositorySystemSession, CollectRequest) + */ +public final class CollectRequest +{ + + private Artifact rootArtifact; + + private Dependency root; + + private List dependencies = Collections.emptyList(); + + private List managedDependencies = Collections.emptyList(); + + private List repositories = Collections.emptyList(); + + private String context = ""; + + private RequestTrace trace; + + /** + * Creates an uninitialized request. + */ + public CollectRequest() + { + // enables default constructor + } + + /** + * Creates a request with the specified properties. + * + * @param root The root dependency whose transitive dependencies should be collected, may be {@code null}. + * @param repositories The repositories to use for the collection, may be {@code null}. + */ + public CollectRequest( Dependency root, List repositories ) + { + setRoot( root ); + setRepositories( repositories ); + } + + /** + * Creates a new request with the specified properties. + * + * @param root The root dependency whose transitive dependencies should be collected, may be {@code null}. + * @param dependencies The direct dependencies to merge with the direct dependencies from the root dependency's + * artifact descriptor. + * @param repositories The repositories to use for the collection, may be {@code null}. + */ + public CollectRequest( Dependency root, List dependencies, List repositories ) + { + setRoot( root ); + setDependencies( dependencies ); + setRepositories( repositories ); + } + + /** + * Creates a new request with the specified properties. + * + * @param dependencies The direct dependencies of some imaginary root, may be {@code null}. + * @param managedDependencies The dependency management information to apply to the transitive dependencies, may be + * {@code null}. + * @param repositories The repositories to use for the collection, may be {@code null}. + */ + public CollectRequest( List dependencies, List managedDependencies, + List repositories ) + { + setDependencies( dependencies ); + setManagedDependencies( managedDependencies ); + setRepositories( repositories ); + } + + /** + * Gets the root artifact for the dependency graph. + * + * @return The root artifact for the dependency graph or {@code null} if none. + */ + public Artifact getRootArtifact() + { + return rootArtifact; + } + + /** + * Sets the root artifact for the dependency graph. This must not be confused with {@link #setRoot(Dependency)}: The + * root dependency, like any other specified dependency, will be subject to dependency + * collection/resolution, i.e. should have an artifact descriptor and a corresponding artifact file. The root + * artifact on the other hand is only used as a label for the root node of the graph in case no root + * dependency was specified. As such, the configured root artifact is ignored if {@link #getRoot()} does not return + * {@code null}. + * + * @param rootArtifact The root artifact for the dependency graph, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public CollectRequest setRootArtifact( Artifact rootArtifact ) + { + this.rootArtifact = rootArtifact; + return this; + } + + /** + * Gets the root dependency of the graph. + * + * @return The root dependency of the graph or {@code null} if none. + */ + public Dependency getRoot() + { + return root; + } + + /** + * Sets the root dependency of the graph. + * + * @param root The root dependency of the graph, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public CollectRequest setRoot( Dependency root ) + { + this.root = root; + return this; + } + + /** + * Gets the direct dependencies. + * + * @return The direct dependencies, never {@code null}. + */ + public List getDependencies() + { + return dependencies; + } + + /** + * Sets the direct dependencies. If both a root dependency and direct dependencies are given in the request, the + * direct dependencies from the request will be merged with the direct dependencies from the root dependency's + * artifact descriptor, giving higher priority to the dependencies from the request. + * + * @param dependencies The direct dependencies, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public CollectRequest setDependencies( List dependencies ) + { + if ( dependencies == null ) + { + this.dependencies = Collections.emptyList(); + } + else + { + this.dependencies = dependencies; + } + return this; + } + + /** + * Adds the specified direct dependency. + * + * @param dependency The dependency to add, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public CollectRequest addDependency( Dependency dependency ) + { + if ( dependency != null ) + { + if ( this.dependencies.isEmpty() ) + { + this.dependencies = new ArrayList(); + } + this.dependencies.add( dependency ); + } + return this; + } + + /** + * Gets the dependency management to apply to transitive dependencies. + * + * @return The dependency management to apply to transitive dependencies, never {@code null}. + */ + public List getManagedDependencies() + { + return managedDependencies; + } + + /** + * Sets the dependency management to apply to transitive dependencies. To clarify, this management does not apply to + * the direct dependencies of the root node. + * + * @param managedDependencies The dependency management, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public CollectRequest setManagedDependencies( List managedDependencies ) + { + if ( managedDependencies == null ) + { + this.managedDependencies = Collections.emptyList(); + } + else + { + this.managedDependencies = managedDependencies; + } + return this; + } + + /** + * Adds the specified managed dependency. + * + * @param managedDependency The managed dependency to add, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public CollectRequest addManagedDependency( Dependency managedDependency ) + { + if ( managedDependency != null ) + { + if ( this.managedDependencies.isEmpty() ) + { + this.managedDependencies = new ArrayList(); + } + this.managedDependencies.add( managedDependency ); + } + return this; + } + + /** + * Gets the repositories to use for the collection. + * + * @return The repositories to use for the collection, never {@code null}. + */ + public List getRepositories() + { + return repositories; + } + + /** + * Sets the repositories to use for the collection. + * + * @param repositories The repositories to use for the collection, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public CollectRequest setRepositories( List repositories ) + { + if ( repositories == null ) + { + this.repositories = Collections.emptyList(); + } + else + { + this.repositories = repositories; + } + return this; + } + + /** + * Adds the specified repository for collection. + * + * @param repository The repository to collect dependency information from, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public CollectRequest addRepository( RemoteRepository repository ) + { + if ( repository != null ) + { + if ( this.repositories.isEmpty() ) + { + this.repositories = new ArrayList(); + } + this.repositories.add( repository ); + } + return this; + } + + /** + * Gets the context in which this request is made. + * + * @return The context, never {@code null}. + */ + public String getRequestContext() + { + return context; + } + + /** + * Sets the context in which this request is made. + * + * @param context The context, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public CollectRequest setRequestContext( String context ) + { + this.context = ( context != null ) ? context : ""; + return this; + } + + /** + * Gets the trace information that describes the higher level request/operation in which this request is issued. + * + * @return The trace information about the higher level operation or {@code null} if none. + */ + public RequestTrace getTrace() + { + return trace; + } + + /** + * Sets the trace information that describes the higher level request/operation in which this request is issued. + * + * @param trace The trace information about the higher level operation, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public CollectRequest setTrace( RequestTrace trace ) + { + this.trace = trace; + return this; + } + + @Override + public String toString() + { + return getRoot() + " -> " + getDependencies() + " < " + getRepositories(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectResult.java new file mode 100644 index 000000000..4975190b8 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectResult.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.collection; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.graph.DependencyCycle; +import org.eclipse.aether.graph.DependencyNode; + +/** + * The result of a dependency collection request. + * + * @see RepositorySystem#collectDependencies(RepositorySystemSession, CollectRequest) + */ +public final class CollectResult +{ + + private final CollectRequest request; + + private List exceptions; + + private List cycles; + + private DependencyNode root; + + /** + * Creates a new result for the specified request. + * + * @param request The resolution request, must not be {@code null}. + */ + public CollectResult( CollectRequest request ) + { + if ( request == null ) + { + throw new IllegalArgumentException( "dependency collection request has not been specified" ); + } + this.request = request; + exceptions = Collections.emptyList(); + cycles = Collections.emptyList(); + } + + /** + * Gets the collection request that was made. + * + * @return The collection request, never {@code null}. + */ + public CollectRequest getRequest() + { + return request; + } + + /** + * Gets the exceptions that occurred while building the dependency graph. + * + * @return The exceptions that occurred, never {@code null}. + */ + public List getExceptions() + { + return exceptions; + } + + /** + * Records the specified exception while building the dependency graph. + * + * @param exception The exception to record, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public CollectResult addException( Exception exception ) + { + if ( exception != null ) + { + if ( exceptions.isEmpty() ) + { + exceptions = new ArrayList(); + } + exceptions.add( exception ); + } + return this; + } + + /** + * Gets the dependency cycles that were encountered while building the dependency graph. + * + * @return The dependency cycles in the (raw) graph, never {@code null}. + */ + public List getCycles() + { + return cycles; + } + + /** + * Records the specified dependency cycle. + * + * @param cycle The dependency cycle to record, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public CollectResult addCycle( DependencyCycle cycle ) + { + if ( cycle != null ) + { + if ( cycles.isEmpty() ) + { + cycles = new ArrayList(); + } + cycles.add( cycle ); + } + return this; + } + + /** + * Gets the root node of the dependency graph. + * + * @return The root node of the dependency graph or {@code null} if none. + */ + public DependencyNode getRoot() + { + return root; + } + + /** + * Sets the root node of the dependency graph. + * + * @param root The root node of the dependency graph, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public CollectResult setRoot( DependencyNode root ) + { + this.root = root; + return this; + } + + @Override + public String toString() + { + return String.valueOf( getRoot() ); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionContext.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionContext.java new file mode 100644 index 000000000..3b8fbc204 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionContext.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.collection; + +import java.util.List; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.graph.Dependency; + +/** + * A context used during dependency collection to update the dependency manager, selector and traverser. + * + * @see DependencyManager#deriveChildManager(DependencyCollectionContext) + * @see DependencyTraverser#deriveChildTraverser(DependencyCollectionContext) + * @see DependencySelector#deriveChildSelector(DependencyCollectionContext) + * @see VersionFilter#deriveChildFilter(DependencyCollectionContext) + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface DependencyCollectionContext +{ + + /** + * Gets the repository system session during which the dependency collection happens. + * + * @return The repository system session, never {@code null}. + */ + RepositorySystemSession getSession(); + + /** + * Gets the artifact whose children are to be processed next during dependency collection. For all nodes but the + * root, this is simply shorthand for {@code getDependency().getArtifact()}. In case of the root node however, + * {@link #getDependency()} might be {@code null} while the node still has an artifact which serves as its label and + * is not to be resolved. + * + * @return The artifact whose children are going to be processed or {@code null} in case of the root node without + * dependency and label. + */ + Artifact getArtifact(); + + /** + * Gets the dependency whose children are to be processed next during dependency collection. + * + * @return The dependency whose children are going to be processed or {@code null} in case of the root node without + * dependency. + */ + Dependency getDependency(); + + /** + * Gets the dependency management information that was contributed by the artifact descriptor of the current + * dependency. + * + * @return The dependency management information, never {@code null}. + */ + List getManagedDependencies(); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionException.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionException.java new file mode 100644 index 000000000..0d26674af --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionException.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.collection; + +import org.eclipse.aether.RepositoryException; + +/** + * Thrown in case of bad artifact descriptors, version ranges or other issues encountered during calculation of the + * dependency graph. + */ +public class DependencyCollectionException + extends RepositoryException +{ + + private final transient CollectResult result; + + /** + * Creates a new exception with the specified result. + * + * @param result The collection result at the point the exception occurred, may be {@code null}. + */ + public DependencyCollectionException( CollectResult result ) + { + super( "Failed to collect dependencies for " + getSource( result ), getCause( result ) ); + this.result = result; + } + + /** + * Creates a new exception with the specified result and detail message. + * + * @param result The collection result at the point the exception occurred, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public DependencyCollectionException( CollectResult result, String message ) + { + super( message, getCause( result ) ); + this.result = result; + } + + /** + * Creates a new exception with the specified result, detail message and cause. + * + * @param result The collection result at the point the exception occurred, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public DependencyCollectionException( CollectResult result, String message, Throwable cause ) + { + super( message, cause ); + this.result = result; + } + + /** + * Gets the collection result at the point the exception occurred. Despite being incomplete, callers might want to + * use this result to fail gracefully and continue their operation with whatever interim data has been gathered. + * + * @return The collection result or {@code null} if unknown. + */ + public CollectResult getResult() + { + return result; + } + + private static String getSource( CollectResult result ) + { + if ( result == null ) + { + return ""; + } + + CollectRequest request = result.getRequest(); + if ( request.getRoot() != null ) + { + return request.getRoot().toString(); + } + if ( request.getRootArtifact() != null ) + { + return request.getRootArtifact().toString(); + } + + return request.getDependencies().toString(); + } + + private static Throwable getCause( CollectResult result ) + { + Throwable cause = null; + if ( result != null && !result.getExceptions().isEmpty() ) + { + cause = result.getExceptions().get( 0 ); + } + return cause; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformationContext.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformationContext.java new file mode 100644 index 000000000..d3980da74 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformationContext.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.collection; + +import org.eclipse.aether.RepositorySystemSession; + +/** + * A context used during dependency collection to exchange information within a chain of dependency graph transformers. + * + * @see DependencyGraphTransformer + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface DependencyGraphTransformationContext +{ + + /** + * Gets the repository system session during which the graph transformation happens. + * + * @return The repository system session, never {@code null}. + */ + RepositorySystemSession getSession(); + + /** + * Gets a keyed value from the context. + * + * @param key The key used to query the value, must not be {@code null}. + * @return The queried value or {@code null} if none. + */ + Object get( Object key ); + + /** + * Puts a keyed value into the context. + * + * @param key The key used to store the value, must not be {@code null}. + * @param value The value to store, may be {@code null} to remove the mapping. + * @return The previous value associated with the key or {@code null} if none. + */ + Object put( Object key, Object value ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformer.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformer.java new file mode 100644 index 000000000..b3deebef7 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformer.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.collection; + +import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.graph.DependencyNode; + +/** + * Transforms a given dependency graph. + *

+ * Note: Implementations must be stateless. + *

+ * Warning: Dependency graphs may generally contain cycles. As such a graph transformer that cannot assume for + * sure that cycles have already been eliminated must gracefully handle cyclic graphs, e.g. guard against infinite + * recursion. + * + * @see org.eclipse.aether.RepositorySystemSession#getDependencyGraphTransformer() + */ +public interface DependencyGraphTransformer +{ + + /** + * Transforms the dependency graph denoted by the specified root node. The transformer may directly change the + * provided input graph or create a new graph, the former is recommended for performance reasons. + * + * @param node The root node of the (possibly cyclic!) graph to transform, must not be {@code null}. + * @param context The graph transformation context, must not be {@code null}. + * @return The result graph of the transformation, never {@code null}. + * @throws RepositoryException If the transformation failed. + */ + DependencyNode transformGraph( DependencyNode node, DependencyGraphTransformationContext context ) + throws RepositoryException; + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManagement.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManagement.java new file mode 100644 index 000000000..f0aac7345 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManagement.java @@ -0,0 +1,168 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.collection; + +import java.util.Collection; +import java.util.Map; + +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.graph.Exclusion; + +/** + * The management updates to apply to a dependency. + * + * @see DependencyManager#manageDependency(Dependency) + */ +public final class DependencyManagement +{ + + private String version; + + private String scope; + + private Boolean optional; + + private Collection exclusions; + + private Map properties; + + /** + * Creates an empty management update. + */ + public DependencyManagement() + { + // enables default constructor + } + + /** + * Gets the new version to apply to the dependency. + * + * @return The new version or {@code null} if the version is not managed and the existing dependency version should + * remain unchanged. + */ + public String getVersion() + { + return version; + } + + /** + * Sets the new version to apply to the dependency. + * + * @param version The new version, may be {@code null} if the version is not managed. + * @return This management update for chaining, never {@code null}. + */ + public DependencyManagement setVersion( String version ) + { + this.version = version; + return this; + } + + /** + * Gets the new scope to apply to the dependency. + * + * @return The new scope or {@code null} if the scope is not managed and the existing dependency scope should remain + * unchanged. + */ + public String getScope() + { + return scope; + } + + /** + * Sets the new scope to apply to the dependency. + * + * @param scope The new scope, may be {@code null} if the scope is not managed. + * @return This management update for chaining, never {@code null}. + */ + public DependencyManagement setScope( String scope ) + { + this.scope = scope; + return this; + } + + /** + * Gets the new optional flag to apply to the dependency. + * + * @return The new optional flag or {@code null} if the flag is not managed and the existing optional flag of the + * dependency should remain unchanged. + */ + public Boolean getOptional() + { + return optional; + } + + /** + * Sets the new optional flag to apply to the dependency. + * + * @param optional The optional flag, may be {@code null} if the flag is not managed. + * @return This management update for chaining, never {@code null}. + */ + public DependencyManagement setOptional( Boolean optional ) + { + this.optional = optional; + return this; + } + + /** + * Gets the new exclusions to apply to the dependency. Note that this collection denotes the complete set of + * exclusions for the dependency, i.e. the dependency manager controls whether any existing exclusions get merged + * with information from dependency management or overridden by it. + * + * @return The new exclusions or {@code null} if the exclusions are not managed and the existing dependency + * exclusions should remain unchanged. + */ + public Collection getExclusions() + { + return exclusions; + } + + /** + * Sets the new exclusions to apply to the dependency. Note that this collection denotes the complete set of + * exclusions for the dependency, i.e. the dependency manager controls whether any existing exclusions get merged + * with information from dependency management or overridden by it. + * + * @param exclusions The new exclusions, may be {@code null} if the exclusions are not managed. + * @return This management update for chaining, never {@code null}. + */ + public DependencyManagement setExclusions( Collection exclusions ) + { + this.exclusions = exclusions; + return this; + } + + /** + * Gets the new properties to apply to the dependency. Note that this map denotes the complete set of properties, + * i.e. the dependency manager controls whether any existing properties get merged with the information from + * dependency management or overridden by it. + * + * @return The new artifact properties or {@code null} if the properties are not managed and the existing properties + * should remain unchanged. + */ + public Map getProperties() + { + return properties; + } + + /** + * Sets the new properties to apply to the dependency. Note that this map denotes the complete set of properties, + * i.e. the dependency manager controls whether any existing properties get merged with the information from + * dependency management or overridden by it. + * + * @param properties The new artifact properties, may be {@code null} if the properties are not managed. + * @return This management update for chaining, never {@code null}. + */ + public DependencyManagement setProperties( Map properties ) + { + this.properties = properties; + return this; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManager.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManager.java new file mode 100644 index 000000000..e214f6610 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManager.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.collection; + +import org.eclipse.aether.graph.Dependency; + +/** + * Applies dependency management to the dependencies of a dependency node. + *

+ * Note: Implementations must be stateless. + *

+ * Warning: This hook is called from a hot spot and therefore implementations should pay attention to + * performance. Among others, implementations should provide a semantic {@link Object#equals(Object) equals()} method. + * + * @see org.eclipse.aether.RepositorySystemSession#getDependencyManager() + * @see org.eclipse.aether.RepositorySystem#collectDependencies(org.eclipse.aether.RepositorySystemSession, + * CollectRequest) + */ +public interface DependencyManager +{ + + /** + * Applies dependency management to the specified dependency. + * + * @param dependency The dependency to manage, must not be {@code null}. + * @return The management update to apply to the dependency or {@code null} if the dependency is not managed at all. + */ + DependencyManagement manageDependency( Dependency dependency ); + + /** + * Derives a dependency manager for the specified collection context. When calculating the child manager, + * implementors are strongly advised to simply return the current instance if nothing changed to help save memory. + * + * @param context The dependency collection context, must not be {@code null}. + * @return The dependency manager for the dependencies of the target node or {@code null} if dependency management + * should no longer be applied. + */ + DependencyManager deriveChildManager( DependencyCollectionContext context ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencySelector.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencySelector.java new file mode 100644 index 000000000..de503bedb --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencySelector.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.collection; + +import org.eclipse.aether.graph.Dependency; + +/** + * Decides what dependencies to include in the dependency graph. + *

+ * Note: Implementations must be stateless. + *

+ * Warning: This hook is called from a hot spot and therefore implementations should pay attention to + * performance. Among others, implementations should provide a semantic {@link Object#equals(Object) equals()} method. + * + * @see org.eclipse.aether.RepositorySystemSession#getDependencySelector() + * @see org.eclipse.aether.RepositorySystem#collectDependencies(org.eclipse.aether.RepositorySystemSession, + * CollectRequest) + */ +public interface DependencySelector +{ + + /** + * Decides whether the specified dependency should be included in the dependency graph. + * + * @param dependency The dependency to check, must not be {@code null}. + * @return {@code false} if the dependency should be excluded from the children of the current node, {@code true} + * otherwise. + */ + boolean selectDependency( Dependency dependency ); + + /** + * Derives a dependency selector for the specified collection context. When calculating the child selector, + * implementors are strongly advised to simply return the current instance if nothing changed to help save memory. + * + * @param context The dependency collection context, must not be {@code null}. + * @return The dependency selector for the target node or {@code null} if dependencies should be unconditionally + * included in the sub graph. + */ + DependencySelector deriveChildSelector( DependencyCollectionContext context ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyTraverser.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyTraverser.java new file mode 100644 index 000000000..8140395df --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyTraverser.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.collection; + +import org.eclipse.aether.graph.Dependency; + +/** + * Decides whether the dependencies of a dependency node should be traversed as well. + *

+ * Note: Implementations must be stateless. + *

+ * Warning: This hook is called from a hot spot and therefore implementations should pay attention to + * performance. Among others, implementations should provide a semantic {@link Object#equals(Object) equals()} method. + * + * @see org.eclipse.aether.RepositorySystemSession#getDependencyTraverser() + * @see org.eclipse.aether.RepositorySystem#collectDependencies(org.eclipse.aether.RepositorySystemSession, + * CollectRequest) + */ +public interface DependencyTraverser +{ + + /** + * Decides whether the dependencies of the specified dependency should be traversed. + * + * @param dependency The dependency to check, must not be {@code null}. + * @return {@code true} if the dependency graph builder should recurse into the specified dependency and process its + * dependencies, {@code false} otherwise. + */ + boolean traverseDependency( Dependency dependency ); + + /** + * Derives a dependency traverser that will be used to decide whether the transitive dependencies of the dependency + * given in the collection context shall be traversed. When calculating the child traverser, implementors are + * strongly advised to simply return the current instance if nothing changed to help save memory. + * + * @param context The dependency collection context, must not be {@code null}. + * @return The dependency traverser for the target node or {@code null} if dependencies should be unconditionally + * traversed in the sub graph. + */ + DependencyTraverser deriveChildTraverser( DependencyCollectionContext context ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/UnsolvableVersionConflictException.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/UnsolvableVersionConflictException.java new file mode 100644 index 000000000..8db55902b --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/collection/UnsolvableVersionConflictException.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.collection; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; + +import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.version.VersionConstraint; + +/** + * Thrown in case of an unsolvable conflict between different version constraints for a dependency. + */ +public class UnsolvableVersionConflictException + extends RepositoryException +{ + + private final transient Collection versions; + + private final transient Collection> paths; + + /** + * Creates a new exception with the specified paths to conflicting nodes in the dependency graph. + * + * @param paths The paths to the dependency nodes that participate in the version conflict, may be {@code null}. + */ + public UnsolvableVersionConflictException( Collection> paths ) + { + super( "Could not resolve version conflict among " + toPaths( paths ) ); + if ( paths == null ) + { + this.paths = Collections.emptyList(); + this.versions = Collections.emptyList(); + } + else + { + this.paths = paths; + this.versions = new LinkedHashSet(); + for ( List path : paths ) + { + VersionConstraint constraint = path.get( path.size() - 1 ).getVersionConstraint(); + if ( constraint != null && constraint.getRange() != null ) + { + versions.add( constraint.toString() ); + } + } + } + } + + private static String toPaths( Collection> paths ) + { + String result = ""; + + if ( paths != null ) + { + Collection strings = new LinkedHashSet(); + + for ( List path : paths ) + { + strings.add( toPath( path ) ); + } + + result = strings.toString(); + } + + return result; + } + + private static String toPath( List path ) + { + StringBuilder buffer = new StringBuilder( 256 ); + + for ( Iterator it = path.iterator(); it.hasNext(); ) + { + DependencyNode node = it.next(); + if ( node.getDependency() == null ) + { + continue; + } + + Artifact artifact = node.getDependency().getArtifact(); + buffer.append( artifact.getGroupId() ); + buffer.append( ':' ).append( artifact.getArtifactId() ); + buffer.append( ':' ).append( artifact.getExtension() ); + if ( artifact.getClassifier().length() > 0 ) + { + buffer.append( ':' ).append( artifact.getClassifier() ); + } + buffer.append( ':' ).append( node.getVersionConstraint() ); + + if ( it.hasNext() ) + { + buffer.append( " -> " ); + } + } + + return buffer.toString(); + } + + /** + * Gets the paths leading to the conflicting dependencies. + * + * @return The (read-only) paths leading to the conflicting dependencies, never {@code null}. + */ + public Collection> getPaths() + { + return paths; + } + + /** + * Gets the conflicting version constraints of the dependency. + * + * @return The (read-only) conflicting version constraints, never {@code null}. + */ + public Collection getVersions() + { + return versions; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/VersionFilter.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/VersionFilter.java new file mode 100644 index 000000000..02e7ab301 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/collection/VersionFilter.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.collection; + +import java.util.Iterator; +import java.util.List; + +import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.repository.ArtifactRepository; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.version.Version; +import org.eclipse.aether.version.VersionConstraint; + +/** + * Decides which versions matching a version range should actually be considered for the dependency graph. The version + * filter is not invoked for dependencies that do not declare a version range but a single version. + *

+ * Note: Implementations must be stateless. + *

+ * Warning: This hook is called from a hot spot and therefore implementations should pay attention to + * performance. Among others, implementations should provide a semantic {@link Object#equals(Object) equals()} method. + * + * @see org.eclipse.aether.RepositorySystemSession#getVersionFilter() + * @see org.eclipse.aether.RepositorySystem#collectDependencies(org.eclipse.aether.RepositorySystemSession, + * CollectRequest) + */ +public interface VersionFilter +{ + + /** + * A context used during version filtering to hold relevant data. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ + interface VersionFilterContext + extends Iterable + { + + /** + * Gets the repository system session during which the version filtering happens. + * + * @return The repository system session, never {@code null}. + */ + RepositorySystemSession getSession(); + + /** + * Gets the dependency whose version range is being filtered. + * + * @return The dependency, never {@code null}. + */ + Dependency getDependency(); + + /** + * Gets the total number of available versions. This count reflects any removals made during version filtering. + * + * @return The total number of available versions. + */ + int getCount(); + + /** + * Gets an iterator over the available versions of the dependency. The iterator returns versions in ascending + * order. Use {@link Iterator#remove()} to exclude a version from further consideration in the dependency graph. + * + * @return The iterator of available versions, never {@code null}. + */ + Iterator iterator(); + + /** + * Gets the version constraint that was parsed from the dependency's version string. + * + * @return The parsed version constraint, never {@code null}. + */ + VersionConstraint getVersionConstraint(); + + /** + * Gets the repository from which the specified version was resolved. + * + * @param version The version whose source repository should be retrieved, must not be {@code null}. + * @return The repository from which the version was resolved or {@code null} if unknown. + */ + ArtifactRepository getRepository( Version version ); + + /** + * Gets the remote repositories from which the versions were resolved. + * + * @return The (read-only) list of repositories, never {@code null}. + */ + List getRepositories(); + + } + + /** + * Filters the available versions for a given dependency. Implementations will usually call + * {@link VersionFilterContext#iterator() context.iterator()} to inspect the available versions and use + * {@link java.util.Iterator#remove()} to delete unacceptable versions. If no versions remain after all filtering + * has been performed, the dependency collection process will automatically fail, i.e. implementations need not + * handle this situation on their own. + * + * @param context The version filter context, must not be {@code null}. + * @throws RepositoryException If the filtering could not be performed. + */ + void filterVersions( VersionFilterContext context ) + throws RepositoryException; + + /** + * Derives a version filter for the specified collection context. The derived filter will be used to handle version + * ranges encountered in child dependencies of the current node. When calculating the child filter, implementors are + * strongly advised to simply return the current instance if nothing changed to help save memory. + * + * @param context The dependency collection context, must not be {@code null}. + * @return The version filter for the target node or {@code null} if versions should not be filtered any more. + */ + VersionFilter deriveChildFilter( DependencyCollectionContext context ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/package-info.java new file mode 100644 index 000000000..dd7df2ed4 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/collection/package-info.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * The types and extension points for collecting the transitive dependencies of an artifact and building a dependency + * graph. + */ +package org.eclipse.aether.collection; + diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployRequest.java new file mode 100644 index 000000000..a5372ddba --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployRequest.java @@ -0,0 +1,193 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.deployment; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * A request to deploy artifacts and their accompanying metadata into the a remote repository. + * + * @see RepositorySystem#deploy(RepositorySystemSession, DeployRequest) + */ +public final class DeployRequest +{ + + private Collection artifacts = Collections.emptyList(); + + private Collection metadata = Collections.emptyList(); + + private RemoteRepository repository; + + private RequestTrace trace; + + /** + * Creates an uninitialized request. + */ + public DeployRequest() + { + } + + /** + * Gets the artifact to deploy. + * + * @return The artifacts to deploy, never {@code null}. + */ + public Collection getArtifacts() + { + return artifacts; + } + + /** + * Sets the artifacts to deploy. + * + * @param artifacts The artifacts to deploy, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public DeployRequest setArtifacts( Collection artifacts ) + { + if ( artifacts == null ) + { + this.artifacts = Collections.emptyList(); + } + else + { + this.artifacts = artifacts; + } + return this; + } + + /** + * Adds the specified artifacts for deployment. + * + * @param artifact The artifact to add, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public DeployRequest addArtifact( Artifact artifact ) + { + if ( artifact != null ) + { + if ( artifacts.isEmpty() ) + { + artifacts = new ArrayList(); + } + artifacts.add( artifact ); + } + return this; + } + + /** + * Gets the metadata to deploy. + * + * @return The metadata to deploy, never {@code null}. + */ + public Collection getMetadata() + { + return metadata; + } + + /** + * Sets the metadata to deploy. + * + * @param metadata The metadata to deploy, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public DeployRequest setMetadata( Collection metadata ) + { + if ( metadata == null ) + { + this.metadata = Collections.emptyList(); + } + else + { + this.metadata = metadata; + } + return this; + } + + /** + * Adds the specified metadata for deployment. + * + * @param metadata The metadata to add, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public DeployRequest addMetadata( Metadata metadata ) + { + if ( metadata != null ) + { + if ( this.metadata.isEmpty() ) + { + this.metadata = new ArrayList(); + } + this.metadata.add( metadata ); + } + return this; + } + + /** + * Gets the repository to deploy to. + * + * @return The repository to deploy to or {@code null} if not set. + */ + public RemoteRepository getRepository() + { + return repository; + } + + /** + * Sets the repository to deploy to. + * + * @param repository The repository to deploy to, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public DeployRequest setRepository( RemoteRepository repository ) + { + this.repository = repository; + return this; + } + + /** + * Gets the trace information that describes the higher level request/operation in which this request is issued. + * + * @return The trace information about the higher level operation or {@code null} if none. + */ + public RequestTrace getTrace() + { + return trace; + } + + /** + * Sets the trace information that describes the higher level request/operation in which this request is issued. + * + * @param trace The trace information about the higher level operation, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public DeployRequest setTrace( RequestTrace trace ) + { + this.trace = trace; + return this; + } + + @Override + public String toString() + { + return getArtifacts() + ", " + getMetadata() + " > " + getRepository(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployResult.java new file mode 100644 index 000000000..fcda3ca0c --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployResult.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.deployment; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.metadata.Metadata; + +/** + * The result of deploying artifacts and their accompanying metadata into the a remote repository. + * + * @see RepositorySystem#deploy(RepositorySystemSession, DeployRequest) + */ +public final class DeployResult +{ + + private final DeployRequest request; + + private Collection artifacts; + + private Collection metadata; + + /** + * Creates a new result for the specified request. + * + * @param request The deployment request, must not be {@code null}. + */ + public DeployResult( DeployRequest request ) + { + if ( request == null ) + { + throw new IllegalArgumentException( "deploy request has not been specified" ); + } + this.request = request; + artifacts = Collections.emptyList(); + metadata = Collections.emptyList(); + } + + /** + * Gets the deploy request that was made. + * + * @return The deploy request, never {@code null}. + */ + public DeployRequest getRequest() + { + return request; + } + + /** + * Gets the artifacts that got deployed. + * + * @return The deployed artifacts, never {@code null}. + */ + public Collection getArtifacts() + { + return artifacts; + } + + /** + * Sets the artifacts that got deployed. + * + * @param artifacts The deployed artifacts, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public DeployResult setArtifacts( Collection artifacts ) + { + if ( artifacts == null ) + { + this.artifacts = Collections.emptyList(); + } + else + { + this.artifacts = artifacts; + } + return this; + } + + /** + * Adds the specified artifacts to the result. + * + * @param artifact The deployed artifact to add, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public DeployResult addArtifact( Artifact artifact ) + { + if ( artifact != null ) + { + if ( artifacts.isEmpty() ) + { + artifacts = new ArrayList(); + } + artifacts.add( artifact ); + } + return this; + } + + /** + * Gets the metadata that got deployed. Note that due to automatically generated metadata, there might have been + * more metadata deployed than originally specified in the deploy request. + * + * @return The deployed metadata, never {@code null}. + */ + public Collection getMetadata() + { + return metadata; + } + + /** + * Sets the metadata that got deployed. + * + * @param metadata The deployed metadata, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public DeployResult setMetadata( Collection metadata ) + { + if ( metadata == null ) + { + this.metadata = Collections.emptyList(); + } + else + { + this.metadata = metadata; + } + return this; + } + + /** + * Adds the specified metadata to this result. + * + * @param metadata The deployed metadata to add, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public DeployResult addMetadata( Metadata metadata ) + { + if ( metadata != null ) + { + if ( this.metadata.isEmpty() ) + { + this.metadata = new ArrayList(); + } + this.metadata.add( metadata ); + } + return this; + } + + @Override + public String toString() + { + return getArtifacts() + ", " + getMetadata(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeploymentException.java b/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeploymentException.java new file mode 100644 index 000000000..f631530f2 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeploymentException.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.deployment; + +import org.eclipse.aether.RepositoryException; + +/** + * Thrown in case of a deployment error like authentication failure. + */ +public class DeploymentException + extends RepositoryException +{ + + /** + * Creates a new exception with the specified detail message. + * + * @param message The detail message, may be {@code null}. + */ + public DeploymentException( String message ) + { + super( message ); + } + + /** + * Creates a new exception with the specified detail message and cause. + * + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public DeploymentException( String message, Throwable cause ) + { + super( message, cause ); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/deployment/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/deployment/package-info.java new file mode 100644 index 000000000..dd5a35d34 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/deployment/package-info.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * The types supporting the publishing of artifacts to a remote repository. + */ +package org.eclipse.aether.deployment; + diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/DefaultDependencyNode.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DefaultDependencyNode.java new file mode 100644 index 000000000..c702d2398 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DefaultDependencyNode.java @@ -0,0 +1,359 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.graph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.version.Version; +import org.eclipse.aether.version.VersionConstraint; + +/** + * A node within a dependency graph. + */ +public final class DefaultDependencyNode + implements DependencyNode +{ + + private List children; + + private Dependency dependency; + + private Artifact artifact; + + private List relocations; + + private Collection aliases; + + private VersionConstraint versionConstraint; + + private Version version; + + private byte managedBits; + + private List repositories; + + private String context; + + private Map data; + + /** + * Creates a new node with the specified dependency. + * + * @param dependency The dependency associated with this node, may be {@code null} for a root node. + */ + public DefaultDependencyNode( Dependency dependency ) + { + this.dependency = dependency; + artifact = ( dependency != null ) ? dependency.getArtifact() : null; + children = new ArrayList( 0 ); + aliases = relocations = Collections.emptyList(); + repositories = Collections.emptyList(); + context = ""; + data = Collections.emptyMap(); + } + + /** + * Creates a new root node with the specified artifact as its label. Note that the new node has no dependency, i.e. + * {@link #getDependency()} will return {@code null}. Put differently, the specified artifact will not be subject to + * dependency collection/resolution. + * + * @param artifact The artifact to use as label for this node, may be {@code null}. + */ + public DefaultDependencyNode( Artifact artifact ) + { + this.artifact = artifact; + children = new ArrayList( 0 ); + aliases = relocations = Collections.emptyList(); + repositories = Collections.emptyList(); + context = ""; + data = Collections.emptyMap(); + } + + /** + * Creates a mostly shallow clone of the specified node. The new node has its own copy of any custom data and + * initially no children. + * + * @param node The node to copy, must not be {@code null}. + */ + public DefaultDependencyNode( DependencyNode node ) + { + dependency = node.getDependency(); + artifact = node.getArtifact(); + children = new ArrayList( 0 ); + setAliases( node.getAliases() ); + setRequestContext( node.getRequestContext() ); + setManagedBits( node.getManagedBits() ); + setRelocations( node.getRelocations() ); + setRepositories( node.getRepositories() ); + setVersion( node.getVersion() ); + setVersionConstraint( node.getVersionConstraint() ); + Map data = node.getData(); + setData( data.isEmpty() ? null : new HashMap( data ) ); + } + + public List getChildren() + { + return children; + } + + public void setChildren( List children ) + { + if ( children == null ) + { + this.children = new ArrayList( 0 ); + } + else + { + this.children = children; + } + } + + public Dependency getDependency() + { + return dependency; + } + + public Artifact getArtifact() + { + return artifact; + } + + public void setArtifact( Artifact artifact ) + { + if ( dependency == null ) + { + throw new UnsupportedOperationException( "node does not have a dependency" ); + } + dependency = dependency.setArtifact( artifact ); + this.artifact = dependency.getArtifact(); + } + + public List getRelocations() + { + return relocations; + } + + /** + * Sets the sequence of relocations that was followed to resolve this dependency's artifact. + * + * @param relocations The sequence of relocations, may be {@code null}. + */ + public void setRelocations( List relocations ) + { + if ( relocations == null || relocations.isEmpty() ) + { + this.relocations = Collections.emptyList(); + } + else + { + this.relocations = relocations; + } + } + + public Collection getAliases() + { + return aliases; + } + + /** + * Sets the known aliases for this dependency's artifact. + * + * @param aliases The known aliases, may be {@code null}. + */ + public void setAliases( Collection aliases ) + { + if ( aliases == null || aliases.isEmpty() ) + { + this.aliases = Collections.emptyList(); + } + else + { + this.aliases = aliases; + } + } + + public VersionConstraint getVersionConstraint() + { + return versionConstraint; + } + + /** + * Sets the version constraint that was parsed from the dependency's version declaration. + * + * @param versionConstraint The version constraint for this node, may be {@code null}. + */ + public void setVersionConstraint( VersionConstraint versionConstraint ) + { + this.versionConstraint = versionConstraint; + } + + public Version getVersion() + { + return version; + } + + /** + * Sets the version that was selected for the dependency's target artifact. + * + * @param version The parsed version, may be {@code null}. + */ + public void setVersion( Version version ) + { + this.version = version; + } + + public void setScope( String scope ) + { + if ( dependency == null ) + { + throw new UnsupportedOperationException( "node does not have a dependency" ); + } + dependency = dependency.setScope( scope ); + } + + public void setOptional( Boolean optional ) + { + if ( dependency == null ) + { + throw new UnsupportedOperationException( "node does not have a dependency" ); + } + dependency = dependency.setOptional( optional ); + } + + public int getManagedBits() + { + return managedBits; + } + + /** + * Sets a bit field indicating which attributes of this node were subject to dependency management. + * + * @param managedBits The bit field indicating the managed attributes or {@code 0} if dependency management wasn't + * applied. + */ + public void setManagedBits( int managedBits ) + { + this.managedBits = (byte) ( managedBits & 0x1F ); + } + + public List getRepositories() + { + return repositories; + } + + /** + * Sets the remote repositories from which this node's artifact shall be resolved. + * + * @param repositories The remote repositories to use for artifact resolution, may be {@code null}. + */ + public void setRepositories( List repositories ) + { + if ( repositories == null || repositories.isEmpty() ) + { + this.repositories = Collections.emptyList(); + } + else + { + this.repositories = repositories; + } + } + + public String getRequestContext() + { + return context; + } + + public void setRequestContext( String context ) + { + this.context = ( context != null ) ? context : ""; + } + + public Map getData() + { + return data; + } + + public void setData( Map data ) + { + if ( data == null ) + { + this.data = Collections.emptyMap(); + } + else + { + this.data = data; + } + } + + public void setData( Object key, Object value ) + { + if ( key == null ) + { + throw new IllegalArgumentException( "key must not be null" ); + } + + if ( value == null ) + { + if ( !data.isEmpty() ) + { + data.remove( key ); + + if ( data.isEmpty() ) + { + data = Collections.emptyMap(); + } + } + } + else + { + if ( data.isEmpty() ) + { + data = new HashMap( 1, 2 ); // nodes can be numerous so let's be space conservative + } + data.put( key, value ); + } + } + + public boolean accept( DependencyVisitor visitor ) + { + if ( visitor.visitEnter( this ) ) + { + for ( DependencyNode child : children ) + { + if ( !child.accept( visitor ) ) + { + break; + } + } + } + + return visitor.visitLeave( this ); + } + + @Override + public String toString() + { + Dependency dep = getDependency(); + if ( dep == null ) + { + return String.valueOf( getArtifact() ); + } + return dep.toString(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/Dependency.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/Dependency.java new file mode 100644 index 000000000..72ea0f6d8 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/graph/Dependency.java @@ -0,0 +1,321 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.graph; + +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.NoSuchElementException; +import java.util.Set; + +import org.eclipse.aether.artifact.Artifact; + +/** + * A dependency to some artifact. Note: Instances of this class are immutable and the exposed mutators return + * new objects rather than changing the current instance. + */ +public final class Dependency +{ + + private final Artifact artifact; + + private final String scope; + + private final Boolean optional; + + private final Set exclusions; + + /** + * Creates a mandatory dependency on the specified artifact with the given scope. + * + * @param artifact The artifact being depended on, must not be {@code null}. + * @param scope The scope of the dependency, may be {@code null}. + */ + public Dependency( Artifact artifact, String scope ) + { + this( artifact, scope, false ); + } + + /** + * Creates a dependency on the specified artifact with the given scope. + * + * @param artifact The artifact being depended on, must not be {@code null}. + * @param scope The scope of the dependency, may be {@code null}. + * @param optional A flag whether the dependency is optional or mandatory, may be {@code null}. + */ + public Dependency( Artifact artifact, String scope, Boolean optional ) + { + this( artifact, scope, optional, null ); + } + + /** + * Creates a dependency on the specified artifact with the given scope and exclusions. + * + * @param artifact The artifact being depended on, must not be {@code null}. + * @param scope The scope of the dependency, may be {@code null}. + * @param optional A flag whether the dependency is optional or mandatory, may be {@code null}. + * @param exclusions The exclusions that apply to transitive dependencies, may be {@code null} if none. + */ + public Dependency( Artifact artifact, String scope, Boolean optional, Collection exclusions ) + { + this( artifact, scope, Exclusions.copy( exclusions ), optional ); + } + + private Dependency( Artifact artifact, String scope, Set exclusions, Boolean optional ) + { + // NOTE: This constructor assumes immutability of the provided exclusion collection, for internal use only + if ( artifact == null ) + { + throw new IllegalArgumentException( "no artifact specified for dependency" ); + } + this.artifact = artifact; + this.scope = ( scope != null ) ? scope : ""; + this.optional = optional; + this.exclusions = exclusions; + } + + /** + * Gets the artifact being depended on. + * + * @return The artifact, never {@code null}. + */ + public Artifact getArtifact() + { + return artifact; + } + + /** + * Sets the artifact being depended on. + * + * @param artifact The artifact, must not be {@code null}. + * @return The new dependency, never {@code null}. + */ + public Dependency setArtifact( Artifact artifact ) + { + if ( this.artifact.equals( artifact ) ) + { + return this; + } + return new Dependency( artifact, scope, exclusions, optional ); + } + + /** + * Gets the scope of the dependency. The scope defines in which context this dependency is relevant. + * + * @return The scope or an empty string if not set, never {@code null}. + */ + public String getScope() + { + return scope; + } + + /** + * Sets the scope of the dependency, e.g. "compile". + * + * @param scope The scope of the dependency, may be {@code null}. + * @return The new dependency, never {@code null}. + */ + public Dependency setScope( String scope ) + { + if ( this.scope.equals( scope ) || ( scope == null && this.scope.length() <= 0 ) ) + { + return this; + } + return new Dependency( artifact, scope, exclusions, optional ); + } + + /** + * Indicates whether this dependency is optional or not. Optional dependencies can be ignored in some contexts. + * + * @return {@code true} if the dependency is (definitively) optional, {@code false} otherwise. + */ + public boolean isOptional() + { + return Boolean.TRUE.equals( optional ); + } + + /** + * Gets the optional flag for the dependency. Note: Most clients will usually call {@link #isOptional()} to + * determine the optional flag, this method is for advanced use cases where three-valued logic is required. + * + * @return The optional flag or {@code null} if unspecified. + */ + public Boolean getOptional() + { + return optional; + } + + /** + * Sets the optional flag for the dependency. + * + * @param optional {@code true} if the dependency is optional, {@code false} if the dependency is mandatory, may be + * {@code null} if unspecified. + * @return The new dependency, never {@code null}. + */ + public Dependency setOptional( Boolean optional ) + { + if ( eq( this.optional, optional ) ) + { + return this; + } + return new Dependency( artifact, scope, exclusions, optional ); + } + + /** + * Gets the exclusions for this dependency. Exclusions can be used to remove transitive dependencies during + * resolution. + * + * @return The (read-only) exclusions, never {@code null}. + */ + public Collection getExclusions() + { + return exclusions; + } + + /** + * Sets the exclusions for the dependency. + * + * @param exclusions The exclusions, may be {@code null}. + * @return The new dependency, never {@code null}. + */ + public Dependency setExclusions( Collection exclusions ) + { + if ( hasEquivalentExclusions( exclusions ) ) + { + return this; + } + return new Dependency( artifact, scope, optional, exclusions ); + } + + private boolean hasEquivalentExclusions( Collection exclusions ) + { + if ( exclusions == null || exclusions.isEmpty() ) + { + return this.exclusions.isEmpty(); + } + if ( exclusions instanceof Set ) + { + return this.exclusions.equals( exclusions ); + } + return exclusions.size() >= this.exclusions.size() && this.exclusions.containsAll( exclusions ) + && exclusions.containsAll( this.exclusions ); + } + + @Override + public String toString() + { + return String.valueOf( getArtifact() ) + " (" + getScope() + ( isOptional() ? "?" : "" ) + ")"; + } + + @Override + public boolean equals( Object obj ) + { + if ( obj == this ) + { + return true; + } + else if ( obj == null || !getClass().equals( obj.getClass() ) ) + { + return false; + } + + Dependency that = (Dependency) obj; + + return artifact.equals( that.artifact ) && scope.equals( that.scope ) && eq( optional, that.optional ) + && exclusions.equals( that.exclusions ); + } + + private static boolean eq( T o1, T o2 ) + { + return ( o1 != null ) ? o1.equals( o2 ) : o2 == null; + } + + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + artifact.hashCode(); + hash = hash * 31 + scope.hashCode(); + hash = hash * 31 + ( optional != null ? optional.hashCode() : 0 ); + hash = hash * 31 + exclusions.size(); + return hash; + } + + private static class Exclusions + extends AbstractSet + { + + private final Exclusion[] exclusions; + + public static Set copy( Collection exclusions ) + { + if ( exclusions == null || exclusions.isEmpty() ) + { + return Collections.emptySet(); + } + return new Exclusions( exclusions ); + } + + private Exclusions( Collection exclusions ) + { + if ( exclusions.size() > 1 && !( exclusions instanceof Set ) ) + { + exclusions = new LinkedHashSet( exclusions ); + } + this.exclusions = exclusions.toArray( new Exclusion[exclusions.size()] ); + } + + @Override + public Iterator iterator() + { + return new Iterator() + { + + private int cursor = 0; + + public boolean hasNext() + { + return cursor < exclusions.length; + } + + public Exclusion next() + { + try + { + Exclusion exclusion = exclusions[cursor]; + cursor++; + return exclusion; + } + catch ( IndexOutOfBoundsException e ) + { + throw new NoSuchElementException(); + } + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + + }; + } + + @Override + public int size() + { + return exclusions.length; + } + + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyCycle.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyCycle.java new file mode 100644 index 000000000..68f9a3230 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyCycle.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.graph; + +import java.util.List; + +/** + * A cycle within a dependency graph, that is a sequence of dependencies d_1, d_2, ..., d_n where d_1 and d_n have the + * same versionless coordinates. In more practical terms, a cycle occurs when a project directly or indirectly depends + * on its own output artifact. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface DependencyCycle +{ + + /** + * Gets the dependencies that lead to the first dependency on the cycle, starting from the root of the dependency + * graph. + * + * @return The (read-only) sequence of dependencies that precedes the cycle in the graph, potentially empty but + * never {@code null}. + */ + List getPrecedingDependencies(); + + /** + * Gets the dependencies that actually form the cycle. For example, a -> b -> c -> a, i.e. the last + * dependency in this sequence duplicates the first element and closes the cycle. Hence the length of the cycle is + * the size of the returned sequence minus 1. + * + * @return The (read-only) sequence of dependencies that forms the cycle, never {@code null}. + */ + List getCyclicDependencies(); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyFilter.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyFilter.java new file mode 100644 index 000000000..c776ddc19 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyFilter.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.graph; + +import java.util.List; + +/** + * A filter to include/exclude dependency nodes during other operations. + */ +public interface DependencyFilter +{ + + /** + * Indicates whether the specified dependency node shall be included or excluded. + * + * @param node The dependency node to filter, must not be {@code null}. + * @param parents The (read-only) chain of parent nodes that leads to the node to be filtered, must not be + * {@code null}. Iterating this (possibly empty) list walks up the dependency graph towards the root + * node, i.e. the immediate parent node (if any) is the first node in the list. The size of the list also + * denotes the zero-based depth of the filtered node. + * @return {@code true} to include the dependency node, {@code false} to exclude it. + */ + boolean accept( DependencyNode node, List parents ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyNode.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyNode.java new file mode 100644 index 000000000..4e345979f --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyNode.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.graph; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.version.Version; +import org.eclipse.aether.version.VersionConstraint; + +/** + * A node within a dependency graph. To conserve memory, dependency graphs may reuse a given node instance multiple + * times to represent reoccurring dependencies. As such clients traversing a dependency graph should be prepared to + * discover multiple paths leading to the same node instance unless the input graph is known to be a duplicate-free + * tree. Note: Unless otherwise noted, implementation classes are not thread-safe and dependency nodes should + * not be mutated by concurrent threads. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface DependencyNode +{ + + /** + * A bit flag indicating the dependency version was subject to dependency management + * + * @see #getManagedBits() + */ + int MANAGED_VERSION = 0x01; + + /** + * A bit flag indicating the dependency scope was subject to dependency management + * + * @see #getManagedBits() + */ + int MANAGED_SCOPE = 0x02; + + /** + * A bit flag indicating the optional flag was subject to dependency management + * + * @see #getManagedBits() + */ + int MANAGED_OPTIONAL = 0x04; + + /** + * A bit flag indicating the artifact properties were subject to dependency management + * + * @see #getManagedBits() + */ + int MANAGED_PROPERTIES = 0x08; + + /** + * A bit flag indicating the exclusions were subject to dependency management + * + * @see #getManagedBits() + */ + int MANAGED_EXCLUSIONS = 0x10; + + /** + * Gets the child nodes of this node. To conserve memory, dependency nodes with equal dependencies may share the + * same child list instance. Hence clients mutating the child list need to be aware that these changes might affect + * more than this node. Where this is not desired, the child list should be copied before mutation if the client + * cannot be sure whether it might be shared with other nodes in the graph. + * + * @return The child nodes of this node, never {@code null}. + */ + List getChildren(); + + /** + * Sets the child nodes of this node. + * + * @param children The child nodes, may be {@code null} + */ + void setChildren( List children ); + + /** + * Gets the dependency associated with this node. Note: For dependency graphs that have been constructed + * without a root dependency, this method will yield {@code null} when invoked on the graph's root node. The root + * node of such graphs may however still have a label as returned by {@link #getArtifact()}. + * + * @return The dependency or {@code null} if none. + */ + Dependency getDependency(); + + /** + * Gets the artifact associated with this node. If this node is associated with a dependency, this is equivalent to + * {@code getDependency().getArtifact()}. Otherwise the artifact merely provides a label for this node in which case + * the artifact must not be subjected to dependency collection/resolution. + * + * @return The associated artifact or {@code null} if none. + */ + Artifact getArtifact(); + + /** + * Updates the artifact of the dependency after resolution. The new artifact must have the same coordinates as the + * original artifact. This method may only be invoked if this node actually has a dependency, i.e. if + * {@link #getDependency()} is not null. + * + * @param artifact The artifact satisfying the dependency, must not be {@code null}. + */ + void setArtifact( Artifact artifact ); + + /** + * Gets the sequence of relocations that was followed to resolve the artifact referenced by the dependency. + * + * @return The (read-only) sequence of relocations, never {@code null}. + */ + List getRelocations(); + + /** + * Gets the known aliases for this dependency's artifact. An alias can be used to mark a patched rebuild of some + * other artifact as such, thereby allowing conflict resolution to consider the patched and the original artifact as + * a conflict. + * + * @return The (read-only) set of known aliases, never {@code null}. + */ + Collection getAliases(); + + /** + * Gets the version constraint that was parsed from the dependency's version declaration. + * + * @return The version constraint for this node or {@code null}. + */ + VersionConstraint getVersionConstraint(); + + /** + * Gets the version that was selected for the dependency's target artifact. + * + * @return The parsed version or {@code null}. + */ + Version getVersion(); + + /** + * Sets the scope of the dependency. This method may only be invoked if this node actually has a dependency, i.e. if + * {@link #getDependency()} is not null. + * + * @param scope The scope, may be {@code null}. + */ + void setScope( String scope ); + + /** + * Sets the optional flag of the dependency. This method may only be invoked if this node actually has a dependency, + * i.e. if {@link #getDependency()} is not null. + * + * @param optional The optional flag, may be {@code null}. + */ + void setOptional( Boolean optional ); + + /** + * Gets a bit field indicating which attributes of this node were subject to dependency management. + * + * @return A bit field containing any of the bits {@link #MANAGED_VERSION}, {@link #MANAGED_SCOPE}, + * {@link #MANAGED_OPTIONAL}, {@link #MANAGED_PROPERTIES} and {@link #MANAGED_EXCLUSIONS} if the + * corresponding attribute was set via dependency management. + */ + int getManagedBits(); + + /** + * Gets the remote repositories from which this node's artifact shall be resolved. + * + * @return The (read-only) list of remote repositories to use for artifact resolution, never {@code null}. + */ + List getRepositories(); + + /** + * Gets the request context in which this dependency node was created. + * + * @return The request context, never {@code null}. + */ + String getRequestContext(); + + /** + * Sets the request context in which this dependency node was created. + * + * @param context The context, may be {@code null}. + */ + void setRequestContext( String context ); + + /** + * Gets the custom data associated with this dependency node. Clients of the repository system can use this data to + * annotate dependency nodes with domain-specific information. Note that the returned map is read-only and + * {@link #setData(Object, Object)} needs to be used to update the custom data. + * + * @return The (read-only) key-value mappings, never {@code null}. + */ + Map getData(); + + /** + * Sets the custom data associated with this dependency node. + * + * @param data The new custom data, may be {@code null}. + */ + void setData( Map data ); + + /** + * Associates the specified dependency node data with the given key. Note: This method must not be called + * while {@link #getData()} is being iterated. + * + * @param key The key under which to store the data, must not be {@code null}. + * @param value The data to associate with the key, may be {@code null} to remove the mapping. + */ + void setData( Object key, Object value ); + + /** + * Traverses this node and potentially its children using the specified visitor. + * + * @param visitor The visitor to call back, must not be {@code null}. + * @return {@code true} to visit siblings nodes of this node as well, {@code false} to skip siblings. + */ + boolean accept( DependencyVisitor visitor ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyVisitor.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyVisitor.java new file mode 100644 index 000000000..d4ba2135b --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyVisitor.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.graph; + +/** + * A visitor for nodes of the dependency graph. + * + * @see DependencyNode#accept(DependencyVisitor) + */ +public interface DependencyVisitor +{ + + /** + * Notifies the visitor of a node visit before its children have been processed. + * + * @param node The dependency node being visited, must not be {@code null}. + * @return {@code true} to visit child nodes of the specified node as well, {@code false} to skip children. + */ + boolean visitEnter( DependencyNode node ); + + /** + * Notifies the visitor of a node visit after its children have been processed. Note that this method is always + * invoked regardless whether any children have actually been visited. + * + * @param node The dependency node being visited, must not be {@code null}. + * @return {@code true} to visit siblings nodes of the specified node as well, {@code false} to skip siblings. + */ + boolean visitLeave( DependencyNode node ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/Exclusion.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/Exclusion.java new file mode 100644 index 000000000..4d6b7baea --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/graph/Exclusion.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.graph; + +/** + * An exclusion of one or more transitive dependencies. Note: Instances of this class are immutable and the + * exposed mutators return new objects rather than changing the current instance. + * + * @see Dependency#getExclusions() + */ +public final class Exclusion +{ + + private final String groupId; + + private final String artifactId; + + private final String classifier; + + private final String extension; + + /** + * Creates an exclusion for artifacts with the specified coordinates. + * + * @param groupId The group identifier, may be {@code null}. + * @param artifactId The artifact identifier, may be {@code null}. + * @param classifier The classifier, may be {@code null}. + * @param extension The file extension, may be {@code null}. + */ + public Exclusion( String groupId, String artifactId, String classifier, String extension ) + { + this.groupId = ( groupId != null ) ? groupId : ""; + this.artifactId = ( artifactId != null ) ? artifactId : ""; + this.classifier = ( classifier != null ) ? classifier : ""; + this.extension = ( extension != null ) ? extension : ""; + } + + /** + * Gets the group identifier for artifacts to exclude. + * + * @return The group identifier, never {@code null}. + */ + public String getGroupId() + { + return groupId; + } + + /** + * Gets the artifact identifier for artifacts to exclude. + * + * @return The artifact identifier, never {@code null}. + */ + public String getArtifactId() + { + return artifactId; + } + + /** + * Gets the classifier for artifacts to exclude. + * + * @return The classifier, never {@code null}. + */ + public String getClassifier() + { + return classifier; + } + + /** + * Gets the file extension for artifacts to exclude. + * + * @return The file extension of artifacts to exclude, never {@code null}. + */ + public String getExtension() + { + return extension; + } + + @Override + public String toString() + { + return getGroupId() + ':' + getArtifactId() + ':' + getExtension() + + ( getClassifier().length() > 0 ? ':' + getClassifier() : "" ); + } + + @Override + public boolean equals( Object obj ) + { + if ( obj == this ) + { + return true; + } + else if ( obj == null || !getClass().equals( obj.getClass() ) ) + { + return false; + } + + Exclusion that = (Exclusion) obj; + + return artifactId.equals( that.artifactId ) && groupId.equals( that.groupId ) + && extension.equals( that.extension ) && classifier.equals( that.classifier ); + } + + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + artifactId.hashCode(); + hash = hash * 31 + groupId.hashCode(); + hash = hash * 31 + classifier.hashCode(); + hash = hash * 31 + extension.hashCode(); + return hash; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/package-info.java new file mode 100644 index 000000000..70879a3eb --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/graph/package-info.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * The representation of a dependency graph by means of connected dependency nodes. + */ +package org.eclipse.aether.graph; + diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallRequest.java new file mode 100644 index 000000000..330f85a5b --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallRequest.java @@ -0,0 +1,168 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.installation; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.metadata.Metadata; + +/** + * A request to install artifacts and their accompanying metadata into the local repository. + * + * @see RepositorySystem#install(RepositorySystemSession, InstallRequest) + */ +public final class InstallRequest +{ + + private Collection artifacts = Collections.emptyList(); + + private Collection metadata = Collections.emptyList(); + + private RequestTrace trace; + + /** + * Creates an uninitialized request. + */ + public InstallRequest() + { + } + + /** + * Gets the artifact to install. + * + * @return The artifacts to install, never {@code null}. + */ + public Collection getArtifacts() + { + return artifacts; + } + + /** + * Sets the artifacts to install. + * + * @param artifacts The artifacts to install, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public InstallRequest setArtifacts( Collection artifacts ) + { + if ( artifacts == null ) + { + this.artifacts = Collections.emptyList(); + } + else + { + this.artifacts = artifacts; + } + return this; + } + + /** + * Adds the specified artifacts for installation. + * + * @param artifact The artifact to add, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public InstallRequest addArtifact( Artifact artifact ) + { + if ( artifact != null ) + { + if ( artifacts.isEmpty() ) + { + artifacts = new ArrayList(); + } + artifacts.add( artifact ); + } + return this; + } + + /** + * Gets the metadata to install. + * + * @return The metadata to install, never {@code null}. + */ + public Collection getMetadata() + { + return metadata; + } + + /** + * Sets the metadata to install. + * + * @param metadata The metadata to install. + * @return This request for chaining, never {@code null}. + */ + public InstallRequest setMetadata( Collection metadata ) + { + if ( metadata == null ) + { + this.metadata = Collections.emptyList(); + } + else + { + this.metadata = metadata; + } + return this; + } + + /** + * Adds the specified metadata for installation. + * + * @param metadata The metadata to add, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public InstallRequest addMetadata( Metadata metadata ) + { + if ( metadata != null ) + { + if ( this.metadata.isEmpty() ) + { + this.metadata = new ArrayList(); + } + this.metadata.add( metadata ); + } + return this; + } + + /** + * Gets the trace information that describes the higher level request/operation in which this request is issued. + * + * @return The trace information about the higher level operation or {@code null} if none. + */ + public RequestTrace getTrace() + { + return trace; + } + + /** + * Sets the trace information that describes the higher level request/operation in which this request is issued. + * + * @param trace The trace information about the higher level operation, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public InstallRequest setTrace( RequestTrace trace ) + { + this.trace = trace; + return this; + } + + @Override + public String toString() + { + return getArtifacts() + ", " + getMetadata(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallResult.java new file mode 100644 index 000000000..fe3ade138 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallResult.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.installation; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.metadata.Metadata; + +/** + * The result of installing artifacts and their accompanying metadata into the a remote repository. + * + * @see RepositorySystem#install(RepositorySystemSession, InstallRequest) + */ +public final class InstallResult +{ + + private final InstallRequest request; + + private Collection artifacts; + + private Collection metadata; + + /** + * Creates a new result for the specified request. + * + * @param request The installation request, must not be {@code null}. + */ + public InstallResult( InstallRequest request ) + { + if ( request == null ) + { + throw new IllegalArgumentException( "install request has not been specified" ); + } + this.request = request; + artifacts = Collections.emptyList(); + metadata = Collections.emptyList(); + } + + /** + * Gets the install request that was made. + * + * @return The install request, never {@code null}. + */ + public InstallRequest getRequest() + { + return request; + } + + /** + * Gets the artifacts that got installed. + * + * @return The installed artifacts, never {@code null}. + */ + public Collection getArtifacts() + { + return artifacts; + } + + /** + * Sets the artifacts that got installed. + * + * @param artifacts The installed artifacts, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public InstallResult setArtifacts( Collection artifacts ) + { + if ( artifacts == null ) + { + this.artifacts = Collections.emptyList(); + } + else + { + this.artifacts = artifacts; + } + return this; + } + + /** + * Adds the specified artifacts to the result. + * + * @param artifact The installed artifact to add, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public InstallResult addArtifact( Artifact artifact ) + { + if ( artifact != null ) + { + if ( artifacts.isEmpty() ) + { + artifacts = new ArrayList(); + } + artifacts.add( artifact ); + } + return this; + } + + /** + * Gets the metadata that got installed. Note that due to automatically generated metadata, there might have been + * more metadata installed than originally specified in the install request. + * + * @return The installed metadata, never {@code null}. + */ + public Collection getMetadata() + { + return metadata; + } + + /** + * Sets the metadata that got installed. + * + * @param metadata The installed metadata, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public InstallResult setMetadata( Collection metadata ) + { + if ( metadata == null ) + { + this.metadata = Collections.emptyList(); + } + else + { + this.metadata = metadata; + } + return this; + } + + /** + * Adds the specified metadata to this result. + * + * @param metadata The installed metadata to add, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public InstallResult addMetadata( Metadata metadata ) + { + if ( metadata != null ) + { + if ( this.metadata.isEmpty() ) + { + this.metadata = new ArrayList(); + } + this.metadata.add( metadata ); + } + return this; + } + + @Override + public String toString() + { + return getArtifacts() + ", " + getMetadata(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallationException.java b/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallationException.java new file mode 100644 index 000000000..e97666546 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallationException.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.installation; + +import org.eclipse.aether.RepositoryException; + +/** + * Thrown in case of an installation error like an IO error. + */ +public class InstallationException + extends RepositoryException +{ + + /** + * Creates a new exception with the specified detail message. + * + * @param message The detail message, may be {@code null}. + */ + public InstallationException( String message ) + { + super( message ); + } + + /** + * Creates a new exception with the specified detail message and cause. + * + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public InstallationException( String message, Throwable cause ) + { + super( message, cause ); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/installation/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/installation/package-info.java new file mode 100644 index 000000000..35b910b83 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/installation/package-info.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * The types supporting the publishing of artifacts to a local repository. + */ +package org.eclipse.aether.installation; + diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/metadata/AbstractMetadata.java b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/AbstractMetadata.java new file mode 100644 index 000000000..d95eb54a6 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/AbstractMetadata.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright (c) 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.metadata; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * A skeleton class for metadata. + */ +public abstract class AbstractMetadata + implements Metadata +{ + + private Metadata newInstance( Map properties, File file ) + { + return new DefaultMetadata( getGroupId(), getArtifactId(), getVersion(), getType(), getNature(), file, + properties ); + } + + public Metadata setFile( File file ) + { + File current = getFile(); + if ( ( current == null ) ? file == null : current.equals( file ) ) + { + return this; + } + return newInstance( getProperties(), file ); + } + + public Metadata setProperties( Map properties ) + { + Map current = getProperties(); + if ( current.equals( properties ) || ( properties == null && current.isEmpty() ) ) + { + return this; + } + return newInstance( copyProperties( properties ), getFile() ); + } + + public String getProperty( String key, String defaultValue ) + { + String value = getProperties().get( key ); + return ( value != null ) ? value : defaultValue; + } + + /** + * Copies the specified metadata properties. This utility method should be used when creating new metadata instances + * with caller-supplied properties. + * + * @param properties The properties to copy, may be {@code null}. + * @return The copied and read-only properties, never {@code null}. + */ + protected static Map copyProperties( Map properties ) + { + if ( properties != null && !properties.isEmpty() ) + { + return Collections.unmodifiableMap( new HashMap( properties ) ); + } + else + { + return Collections.emptyMap(); + } + } + + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder( 128 ); + if ( getGroupId().length() > 0 ) + { + buffer.append( getGroupId() ); + } + if ( getArtifactId().length() > 0 ) + { + buffer.append( ':' ).append( getArtifactId() ); + } + if ( getVersion().length() > 0 ) + { + buffer.append( ':' ).append( getVersion() ); + } + buffer.append( '/' ).append( getType() ); + return buffer.toString(); + } + + /** + * Compares this metadata with the specified object. + * + * @param obj The object to compare this metadata against, may be {@code null}. + * @return {@code true} if and only if the specified object is another {@link Metadata} with equal coordinates, + * type, nature, properties and file, {@code false} otherwise. + */ + @Override + public boolean equals( Object obj ) + { + if ( obj == this ) + { + return true; + } + else if ( !( obj instanceof Metadata ) ) + { + return false; + } + + Metadata that = (Metadata) obj; + + return getArtifactId().equals( that.getArtifactId() ) && getGroupId().equals( that.getGroupId() ) + && getVersion().equals( that.getVersion() ) && getType().equals( that.getType() ) + && getNature().equals( that.getNature() ) && eq( getFile(), that.getFile() ) + && eq( getProperties(), that.getProperties() ); + } + + private static boolean eq( T s1, T s2 ) + { + return s1 != null ? s1.equals( s2 ) : s2 == null; + } + + /** + * Returns a hash code for this metadata. + * + * @return A hash code for the metadata. + */ + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + getGroupId().hashCode(); + hash = hash * 31 + getArtifactId().hashCode(); + hash = hash * 31 + getType().hashCode(); + hash = hash * 31 + getNature().hashCode(); + hash = hash * 31 + getVersion().hashCode(); + hash = hash * 31 + hash( getFile() ); + return hash; + } + + private static int hash( Object obj ) + { + return ( obj != null ) ? obj.hashCode() : 0; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/metadata/DefaultMetadata.java b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/DefaultMetadata.java new file mode 100644 index 000000000..aa9c83055 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/DefaultMetadata.java @@ -0,0 +1,183 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.metadata; + +import java.io.File; +import java.util.Map; + +/** + * A basic metadata instance. Note: Instances of this class are immutable and the exposed mutators return new + * objects rather than changing the current instance. + */ +public final class DefaultMetadata + extends AbstractMetadata +{ + + private final String groupId; + + private final String artifactId; + + private final String version; + + private final String type; + + private final Nature nature; + + private final File file; + + private final Map properties; + + /** + * Creates a new metadata for the repository root with the specific type and nature. + * + * @param type The type of the metadata, e.g. "maven-metadata.xml", may be {@code null}. + * @param nature The nature of the metadata, must not be {@code null}. + */ + public DefaultMetadata( String type, Nature nature ) + { + this( "", "", "", type, nature, null, (File) null ); + } + + /** + * Creates a new metadata for the groupId level with the specific type and nature. + * + * @param groupId The group identifier to which this metadata applies, may be {@code null}. + * @param type The type of the metadata, e.g. "maven-metadata.xml", may be {@code null}. + * @param nature The nature of the metadata, must not be {@code null}. + */ + public DefaultMetadata( String groupId, String type, Nature nature ) + { + this( groupId, "", "", type, nature, null, (File) null ); + } + + /** + * Creates a new metadata for the groupId:artifactId level with the specific type and nature. + * + * @param groupId The group identifier to which this metadata applies, may be {@code null}. + * @param artifactId The artifact identifier to which this metadata applies, may be {@code null}. + * @param type The type of the metadata, e.g. "maven-metadata.xml", may be {@code null}. + * @param nature The nature of the metadata, must not be {@code null}. + */ + public DefaultMetadata( String groupId, String artifactId, String type, Nature nature ) + { + this( groupId, artifactId, "", type, nature, null, (File) null ); + } + + /** + * Creates a new metadata for the groupId:artifactId:version level with the specific type and nature. + * + * @param groupId The group identifier to which this metadata applies, may be {@code null}. + * @param artifactId The artifact identifier to which this metadata applies, may be {@code null}. + * @param version The version to which this metadata applies, may be {@code null}. + * @param type The type of the metadata, e.g. "maven-metadata.xml", may be {@code null}. + * @param nature The nature of the metadata, must not be {@code null}. + */ + public DefaultMetadata( String groupId, String artifactId, String version, String type, Nature nature ) + { + this( groupId, artifactId, version, type, nature, null, (File) null ); + } + + /** + * Creates a new metadata for the groupId:artifactId:version level with the specific type and nature. + * + * @param groupId The group identifier to which this metadata applies, may be {@code null}. + * @param artifactId The artifact identifier to which this metadata applies, may be {@code null}. + * @param version The version to which this metadata applies, may be {@code null}. + * @param type The type of the metadata, e.g. "maven-metadata.xml", may be {@code null}. + * @param nature The nature of the metadata, must not be {@code null}. + * @param file The resolved file of the metadata, may be {@code null}. + */ + public DefaultMetadata( String groupId, String artifactId, String version, String type, Nature nature, File file ) + { + this( groupId, artifactId, version, type, nature, null, file ); + } + + /** + * Creates a new metadata for the groupId:artifactId:version level with the specific type and nature. + * + * @param groupId The group identifier to which this metadata applies, may be {@code null}. + * @param artifactId The artifact identifier to which this metadata applies, may be {@code null}. + * @param version The version to which this metadata applies, may be {@code null}. + * @param type The type of the metadata, e.g. "maven-metadata.xml", may be {@code null}. + * @param nature The nature of the metadata, must not be {@code null}. + * @param properties The properties of the metadata, may be {@code null} if none. + * @param file The resolved file of the metadata, may be {@code null}. + */ + public DefaultMetadata( String groupId, String artifactId, String version, String type, Nature nature, + Map properties, File file ) + { + this.groupId = emptify( groupId ); + this.artifactId = emptify( artifactId ); + this.version = emptify( version ); + this.type = emptify( type ); + if ( nature == null ) + { + throw new IllegalArgumentException( "metadata nature was not specified" ); + } + this.nature = nature; + this.file = file; + this.properties = copyProperties( properties ); + } + + DefaultMetadata( String groupId, String artifactId, String version, String type, Nature nature, File file, + Map properties ) + { + // NOTE: This constructor assumes immutability of the provided properties, for internal use only + this.groupId = emptify( groupId ); + this.artifactId = emptify( artifactId ); + this.version = emptify( version ); + this.type = emptify( type ); + this.nature = nature; + this.file = file; + this.properties = properties; + } + + private static String emptify( String str ) + { + return ( str == null ) ? "" : str; + } + + public String getGroupId() + { + return groupId; + } + + public String getArtifactId() + { + return artifactId; + } + + public String getVersion() + { + return version; + } + + public String getType() + { + return type; + } + + public Nature getNature() + { + return nature; + } + + public File getFile() + { + return file; + } + + public Map getProperties() + { + return properties; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/metadata/MergeableMetadata.java b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/MergeableMetadata.java new file mode 100644 index 000000000..25f15dfbd --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/MergeableMetadata.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.metadata; + +import java.io.File; + +import org.eclipse.aether.RepositoryException; + +/** + * A piece of metadata that needs to be merged with any current metadata before installation/deployment. + */ +public interface MergeableMetadata + extends Metadata +{ + + /** + * Merges this metadata into the current metadata (if any). Note that this method will be invoked regardless whether + * metadata currently exists or not. + * + * @param current The path to the current metadata file, may not exist but must not be {@code null}. + * @param result The path to the result file where the merged metadata should be stored, must not be {@code null}. + * @throws RepositoryException If the metadata could not be merged. + */ + void merge( File current, File result ) + throws RepositoryException; + + /** + * Indicates whether this metadata has been merged. + * + * @return {@code true} if the metadata has been merged, {@code false} otherwise. + */ + boolean isMerged(); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/metadata/Metadata.java b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/Metadata.java new file mode 100644 index 000000000..328544a5c --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/Metadata.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.metadata; + +import java.io.File; +import java.util.Map; + +/** + * A piece of repository metadata, e.g. an index of available versions. In contrast to an artifact, which usually exists + * in only one repository, metadata usually exists in multiple repositories and each repository contains a different + * copy of the metadata. Note: Metadata instances are supposed to be immutable, e.g. any exposed mutator method + * returns a new metadata instance and leaves the original instance unchanged. Implementors are strongly advised to obey + * this contract. Note: Implementors are strongly advised to inherit from {@link AbstractMetadata} instead of + * directly implementing this interface. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface Metadata +{ + + /** + * The nature of the metadata. + */ + enum Nature + { + /** + * The metadata refers to release artifacts only. + */ + RELEASE, + + /** + * The metadata refers to snapshot artifacts only. + */ + SNAPSHOT, + + /** + * The metadata refers to either release or snapshot artifacts. + */ + RELEASE_OR_SNAPSHOT + } + + /** + * Gets the group identifier of this metadata. + * + * @return The group identifier or an empty string if the metadata applies to the entire repository, never + * {@code null}. + */ + String getGroupId(); + + /** + * Gets the artifact identifier of this metadata. + * + * @return The artifact identifier or an empty string if the metadata applies to the groupId level only, never + * {@code null}. + */ + String getArtifactId(); + + /** + * Gets the version of this metadata. + * + * @return The version or an empty string if the metadata applies to the groupId:artifactId level only, never + * {@code null}. + */ + String getVersion(); + + /** + * Gets the type of the metadata, e.g. "maven-metadata.xml". + * + * @return The type of the metadata, never {@code null}. + */ + String getType(); + + /** + * Gets the nature of this metadata. The nature indicates to what artifact versions the metadata refers. + * + * @return The nature, never {@code null}. + */ + Nature getNature(); + + /** + * Gets the file of this metadata. Note that only resolved metadata has a file associated with it. + * + * @return The file or {@code null} if none. + */ + File getFile(); + + /** + * Sets the file of the metadata. + * + * @param file The file of the metadata, may be {@code null} + * @return The new metadata, never {@code null}. + */ + Metadata setFile( File file ); + + /** + * Gets the specified property. + * + * @param key The name of the property, must not be {@code null}. + * @param defaultValue The default value to return in case the property is not set, may be {@code null}. + * @return The requested property value or {@code null} if the property is not set and no default value was + * provided. + */ + String getProperty( String key, String defaultValue ); + + /** + * Gets the properties of this metadata. + * + * @return The (read-only) properties, never {@code null}. + */ + Map getProperties(); + + /** + * Sets the properties for the metadata. + * + * @param properties The properties for the metadata, may be {@code null}. + * @return The new metadata, never {@code null}. + */ + Metadata setProperties( Map properties ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/metadata/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/package-info.java new file mode 100644 index 000000000..141a8377f --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/package-info.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * The definition of metadata, that is an auxiliary entity managed by the repository system to locate artifacts. + */ +package org.eclipse.aether.metadata; + diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/package-info.java new file mode 100644 index 000000000..7268b46f3 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/package-info.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * The primary API of the {@link org.eclipse.aether.RepositorySystem} and its functionality. + */ +package org.eclipse.aether; + diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/ArtifactRepository.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/ArtifactRepository.java new file mode 100644 index 000000000..2000f8b07 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/ArtifactRepository.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +/** + * A repository hosting artifacts. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface ArtifactRepository +{ + + /** + * Gets the type of the repository, for example "default". + * + * @return The (case-sensitive) type of the repository, never {@code null}. + */ + String getContentType(); + + /** + * Gets the identifier of this repository. + * + * @return The (case-sensitive) identifier, never {@code null}. + */ + String getId(); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/Authentication.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/Authentication.java new file mode 100644 index 000000000..c1eaac027 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/Authentication.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import java.util.Map; + +/** + * The authentication to use for accessing a protected resource. This acts basically as an extensible callback mechanism + * from which network operations can request authentication data like username and password when needed. + */ +public interface Authentication +{ + + /** + * Fills the given authentication context with the data from this authentication callback. To do so, implementors + * have to call {@link AuthenticationContext#put(String, Object)}.
+ *
+ * The {@code key} parameter supplied to this method acts merely as a hint for interactive callbacks that want to + * prompt the user for only that authentication data which is required. Implementations are free to ignore this + * parameter and put all the data they have into the authentication context at once. + * + * @param context The authentication context to populate, must not be {@code null}. + * @param key The key denoting a specific piece of authentication data that is being requested for a network + * operation, may be {@code null}. + * @param data Any (read-only) extra data in form of key value pairs that might be useful when getting the + * authentication data, may be {@code null}. + */ + void fill( AuthenticationContext context, String key, Map data ); + + /** + * Updates the given digest with data from this authentication callback. To do so, implementors have to call the + * {@code update()} methods in {@link AuthenticationDigest}. + * + * @param digest The digest to update, must not be {@code null}. + */ + void digest( AuthenticationDigest digest ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationContext.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationContext.java new file mode 100644 index 000000000..5b1ba2c0a --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationContext.java @@ -0,0 +1,380 @@ +/******************************************************************************* + * Copyright (c) 2012, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import java.io.Closeable; +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.aether.RepositorySystemSession; + +/** + * A glorified map of key value pairs holding (cleartext) authentication data. Authentication contexts are used + * internally when network operations need to access secured repositories or proxies. Each authentication context + * manages the credentials required to access a single host. Unlike {@link Authentication} callbacks which exist for a + * potentially long time like the duration of a repository system session, an authentication context has a supposedly + * short lifetime and should be {@link #close() closed} as soon as the corresponding network operation has finished: + * + *

+ * AuthenticationContext context = AuthenticationContext.forRepository( session, repository );
+ * try {
+ *     // get credentials
+ *     char[] password = context.get( AuthenticationContext.PASSWORD, char[].class );
+ *     // perform network operation using retrieved credentials
+ *     ...
+ * } finally {
+ *     // erase confidential authentication data from heap memory
+ *     AuthenticationContext.close( context );
+ * }
+ * 
+ * + * The same authentication data can often be presented using different data types, e.g. a password can be presented + * using a character array or (less securely) using a string. For ease of use, an authentication context treats the + * following groups of data types as equivalent and converts values automatically during retrieval: + *
    + *
  • {@code String}, {@code char[]}
  • + *
  • {@code String}, {@code File}
  • + *
+ * An authentication context is thread-safe. + */ +public final class AuthenticationContext + implements Closeable +{ + + /** + * The key used to store the username. The corresponding authentication data should be of type {@link String}. + */ + public static final String USERNAME = "username"; + + /** + * The key used to store the password. The corresponding authentication data should be of type {@code char[]} or + * {@link String}. + */ + public static final String PASSWORD = "password"; + + /** + * The key used to store the NTLM domain. The corresponding authentication data should be of type {@link String}. + */ + public static final String NTLM_DOMAIN = "ntlm.domain"; + + /** + * The key used to store the NTML workstation. The corresponding authentication data should be of type + * {@link String}. + */ + public static final String NTLM_WORKSTATION = "ntlm.workstation"; + + /** + * The key used to store the pathname to a private key file. The corresponding authentication data should be of type + * {@link String} or {@link File}. + */ + public static final String PRIVATE_KEY_PATH = "privateKey.path"; + + /** + * The key used to store the passphrase protecting the private key. The corresponding authentication data should be + * of type {@code char[]} or {@link String}. + */ + public static final String PRIVATE_KEY_PASSPHRASE = "privateKey.passphrase"; + + /** + * The key used to store the acceptance policy for unknown host keys. The corresponding authentication data should + * be of type {@link Boolean}. When querying this authentication data, the extra data should provide + * {@link #HOST_KEY_REMOTE} and {@link #HOST_KEY_LOCAL}, e.g. to enable a well-founded decision of the user during + * an interactive prompt. + */ + public static final String HOST_KEY_ACCEPTANCE = "hostKey.acceptance"; + + /** + * The key used to store the fingerprint of the public key advertised by remote host. Note that this key is used to + * query the extra data passed to {@link #get(String, Map, Class)} when getting {@link #HOST_KEY_ACCEPTANCE}, not + * the authentication data in a context. + */ + public static final String HOST_KEY_REMOTE = "hostKey.remote"; + + /** + * The key used to store the fingerprint of the public key expected from remote host as recorded in a known hosts + * database. Note that this key is used to query the extra data passed to {@link #get(String, Map, Class)} when + * getting {@link #HOST_KEY_ACCEPTANCE}, not the authentication data in a context. + */ + public static final String HOST_KEY_LOCAL = "hostKey.local"; + + /** + * The key used to store the SSL context. The corresponding authentication data should be of type + * {@link javax.net.ssl.SSLContext}. + */ + public static final String SSL_CONTEXT = "ssl.context"; + + /** + * The key used to store the SSL hostname verifier. The corresponding authentication data should be of type + * {@link javax.net.ssl.HostnameVerifier}. + */ + public static final String SSL_HOSTNAME_VERIFIER = "ssl.hostnameVerifier"; + + private final RepositorySystemSession session; + + private final RemoteRepository repository; + + private final Proxy proxy; + + private final Authentication auth; + + private final Map authData; + + private boolean fillingAuthData; + + /** + * Gets an authentication context for the specified repository. + * + * @param session The repository system session during which the repository is accessed, must not be {@code null}. + * @param repository The repository for which to create an authentication context, must not be {@code null}. + * @return An authentication context for the repository or {@code null} if no authentication is configured for it. + */ + public static AuthenticationContext forRepository( RepositorySystemSession session, RemoteRepository repository ) + { + return newInstance( session, repository, null, repository.getAuthentication() ); + } + + /** + * Gets an authentication context for the proxy of the specified repository. + * + * @param session The repository system session during which the repository is accessed, must not be {@code null}. + * @param repository The repository for whose proxy to create an authentication context, must not be {@code null}. + * @return An authentication context for the proxy or {@code null} if no proxy is set or no authentication is + * configured for it. + */ + public static AuthenticationContext forProxy( RepositorySystemSession session, RemoteRepository repository ) + { + Proxy proxy = repository.getProxy(); + return newInstance( session, repository, proxy, ( proxy != null ) ? proxy.getAuthentication() : null ); + } + + private static AuthenticationContext newInstance( RepositorySystemSession session, RemoteRepository repository, + Proxy proxy, Authentication auth ) + { + if ( auth == null ) + { + return null; + } + return new AuthenticationContext( session, repository, proxy, auth ); + } + + private AuthenticationContext( RepositorySystemSession session, RemoteRepository repository, Proxy proxy, + Authentication auth ) + { + if ( session == null ) + { + throw new IllegalArgumentException( "repository system session missing" ); + } + this.session = session; + this.repository = repository; + this.proxy = proxy; + this.auth = auth; + authData = new HashMap(); + } + + /** + * Gets the repository system session during which the authentication happens. + * + * @return The repository system session, never {@code null}. + */ + public RepositorySystemSession getSession() + { + return session; + } + + /** + * Gets the repository requiring authentication. If {@link #getProxy()} is not {@code null}, the data gathered by + * this authentication context does not apply to the repository's host but rather the proxy. + * + * @return The repository to be contacted, never {@code null}. + */ + public RemoteRepository getRepository() + { + return repository; + } + + /** + * Gets the proxy (if any) to be authenticated with. + * + * @return The proxy or {@code null} if authenticating directly with the repository's host. + */ + public Proxy getProxy() + { + return proxy; + } + + /** + * Gets the authentication data for the specified key. + * + * @param key The key whose authentication data should be retrieved, must not be {@code null}. + * @return The requested authentication data or {@code null} if none. + */ + public String get( String key ) + { + return get( key, null, String.class ); + } + + /** + * Gets the authentication data for the specified key. + * + * @param The data type of the authentication data. + * @param key The key whose authentication data should be retrieved, must not be {@code null}. + * @param type The expected type of the authentication data, must not be {@code null}. + * @return The requested authentication data or {@code null} if none or if the data doesn't match the expected type. + */ + public T get( String key, Class type ) + { + return get( key, null, type ); + } + + /** + * Gets the authentication data for the specified key. + * + * @param The data type of the authentication data. + * @param key The key whose authentication data should be retrieved, must not be {@code null}. + * @param data Any (read-only) extra data in form of key value pairs that might be useful when getting the + * authentication data, may be {@code null}. + * @param type The expected type of the authentication data, must not be {@code null}. + * @return The requested authentication data or {@code null} if none or if the data doesn't match the expected type. + */ + public T get( String key, Map data, Class type ) + { + if ( key == null ) + { + throw new IllegalArgumentException( "authentication data key missing" ); + } + Object value; + synchronized ( authData ) + { + value = authData.get( key ); + if ( value == null && !authData.containsKey( key ) && !fillingAuthData ) + { + if ( auth != null ) + { + try + { + fillingAuthData = true; + auth.fill( this, key, data ); + } + finally + { + fillingAuthData = false; + } + value = authData.get( key ); + } + if ( value == null ) + { + authData.put( key, value ); + } + } + } + + return convert( value, type ); + } + + private T convert( Object value, Class type ) + { + if ( !type.isInstance( value ) ) + { + if ( String.class.equals( type ) ) + { + if ( value instanceof File ) + { + value = ( (File) value ).getPath(); + } + else if ( value instanceof char[] ) + { + value = new String( (char[]) value ); + } + } + else if ( File.class.equals( type ) ) + { + if ( value instanceof String ) + { + value = new File( (String) value ); + } + } + else if ( char[].class.equals( type ) ) + { + if ( value instanceof String ) + { + value = ( (String) value ).toCharArray(); + } + } + } + + if ( type.isInstance( value ) ) + { + return type.cast( value ); + } + + return null; + } + + /** + * Puts the specified authentication data into this context. This method should only be called from implementors of + * {@link Authentication#fill(AuthenticationContext, String, Map)}. Passed in character arrays are not cloned and + * become owned by this context, i.e. get erased when the context gets closed. + * + * @param key The key to associate the authentication data with, must not be {@code null}. + * @param value The (cleartext) authentication data to store, may be {@code null}. + */ + public void put( String key, Object value ) + { + if ( key == null ) + { + throw new IllegalArgumentException( "authentication data key missing" ); + } + synchronized ( authData ) + { + Object oldValue = authData.put( key, value ); + if ( oldValue instanceof char[] ) + { + Arrays.fill( (char[]) oldValue, '\0' ); + } + } + } + + /** + * Closes this authentication context and erases sensitive authentication data from heap memory. Closing an already + * closed context has no effect. + */ + public void close() + { + synchronized ( authData ) + { + for ( Object value : authData.values() ) + { + if ( value instanceof char[] ) + { + Arrays.fill( (char[]) value, '\0' ); + } + } + authData.clear(); + } + } + + /** + * Closes the specified authentication context. This is a convenience method doing a {@code null} check before + * calling {@link #close()} on the given context. + * + * @param context The authentication context to close, may be {@code null}. + */ + public static void close( AuthenticationContext context ) + { + if ( context != null ) + { + context.close(); + } + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationDigest.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationDigest.java new file mode 100644 index 000000000..f702b4aa7 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationDigest.java @@ -0,0 +1,210 @@ +/******************************************************************************* + * Copyright (c) 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.eclipse.aether.RepositorySystemSession; + +/** + * A helper to calculate a fingerprint/digest for the authentication data of a repository/proxy. Such a fingerprint can + * be used to detect changes in the authentication data across JVM restarts without exposing sensitive information. + */ +public final class AuthenticationDigest +{ + + private final MessageDigest digest; + + private final RepositorySystemSession session; + + private final RemoteRepository repository; + + private final Proxy proxy; + + /** + * Gets the fingerprint for the authentication of the specified repository. + * + * @param session The repository system session during which the fingerprint is requested, must not be {@code null}. + * @param repository The repository whose authentication is to be fingerprinted, must not be {@code null}. + * @return The fingerprint of the repository authentication or an empty string if no authentication is configured, + * never {@code null}. + */ + public static String forRepository( RepositorySystemSession session, RemoteRepository repository ) + { + String digest = ""; + Authentication auth = repository.getAuthentication(); + if ( auth != null ) + { + AuthenticationDigest authDigest = new AuthenticationDigest( session, repository, null ); + auth.digest( authDigest ); + digest = authDigest.digest(); + } + return digest; + } + + /** + * Gets the fingerprint for the authentication of the specified repository's proxy. + * + * @param session The repository system session during which the fingerprint is requested, must not be {@code null}. + * @param repository The repository whose proxy authentication is to be fingerprinted, must not be {@code null}. + * @return The fingerprint of the proxy authentication or an empty string if no proxy is present or if no proxy + * authentication is configured, never {@code null}. + */ + public static String forProxy( RepositorySystemSession session, RemoteRepository repository ) + { + String digest = ""; + Proxy proxy = repository.getProxy(); + if ( proxy != null ) + { + Authentication auth = proxy.getAuthentication(); + if ( auth != null ) + { + AuthenticationDigest authDigest = new AuthenticationDigest( session, repository, proxy ); + auth.digest( authDigest ); + digest = authDigest.digest(); + } + } + return digest; + } + + private AuthenticationDigest( RepositorySystemSession session, RemoteRepository repository, Proxy proxy ) + { + this.session = session; + this.repository = repository; + this.proxy = proxy; + digest = newDigest(); + } + + private static MessageDigest newDigest() + { + try + { + return MessageDigest.getInstance( "SHA-1" ); + } + catch ( NoSuchAlgorithmException e ) + { + try + { + return MessageDigest.getInstance( "MD5" ); + } + catch ( NoSuchAlgorithmException ne ) + { + throw new IllegalStateException( ne ); + } + } + } + + /** + * Gets the repository system session during which the authentication fingerprint is calculated. + * + * @return The repository system session, never {@code null}. + */ + public RepositorySystemSession getSession() + { + return session; + } + + /** + * Gets the repository requiring authentication. If {@link #getProxy()} is not {@code null}, the data gathered by + * this authentication digest does not apply to the repository's host but rather the proxy. + * + * @return The repository to be contacted, never {@code null}. + */ + public RemoteRepository getRepository() + { + return repository; + } + + /** + * Gets the proxy (if any) to be authenticated with. + * + * @return The proxy or {@code null} if authenticating directly with the repository's host. + */ + public Proxy getProxy() + { + return proxy; + } + + /** + * Updates the digest with the specified strings. + * + * @param strings The strings to update the digest with, may be {@code null} or contain {@code null} elements. + */ + public void update( String... strings ) + { + if ( strings != null ) + { + for ( String string : strings ) + { + if ( string != null ) + { + try + { + digest.update( string.getBytes( "UTF-8" ) ); + } + catch ( UnsupportedEncodingException e ) + { + throw new IllegalStateException( e ); + } + } + } + } + } + + /** + * Updates the digest with the specified characters. + * + * @param chars The characters to update the digest with, may be {@code null}. + */ + public void update( char... chars ) + { + if ( chars != null ) + { + for ( char c : chars ) + { + digest.update( (byte) ( c >> 8 ) ); + digest.update( (byte) ( c & 0xFF ) ); + } + } + } + + /** + * Updates the digest with the specified bytes. + * + * @param bytes The bytes to update the digest with, may be {@code null}. + */ + public void update( byte... bytes ) + { + if ( bytes != null ) + { + digest.update( bytes ); + } + } + + private String digest() + { + byte[] bytes = digest.digest(); + StringBuilder buffer = new StringBuilder( bytes.length * 2 ); + for ( byte aByte : bytes ) + { + int b = aByte & 0xFF; + if ( b < 0x10 ) + { + buffer.append( '0' ); + } + buffer.append( Integer.toHexString( b ) ); + } + return buffer.toString(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationSelector.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationSelector.java new file mode 100644 index 000000000..46c9bab8d --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationSelector.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +/** + * Selects authentication for a given remote repository. + * + * @see org.eclipse.aether.RepositorySystemSession#getAuthenticationSelector() + */ +public interface AuthenticationSelector +{ + + /** + * Selects authentication for the specified remote repository. + * + * @param repository The repository for which to select authentication, must not be {@code null}. + * @return The selected authentication or {@code null} if none. + */ + Authentication getAuthentication( RemoteRepository repository ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRegistration.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRegistration.java new file mode 100644 index 000000000..af6ea4e0f --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRegistration.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import java.util.Collection; +import java.util.Collections; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; + +/** + * A request to register an artifact within the local repository. Certain local repository implementations can refuse to + * serve physically present artifacts if those haven't been previously registered to them. + * + * @see LocalRepositoryManager#add(RepositorySystemSession, LocalArtifactRegistration) + */ +public final class LocalArtifactRegistration +{ + + private Artifact artifact; + + private RemoteRepository repository; + + private Collection contexts = Collections.emptyList(); + + /** + * Creates an uninitialized registration. + */ + public LocalArtifactRegistration() + { + // enables default constructor + } + + /** + * Creates a registration request for the specified (locally installed) artifact. + * + * @param artifact The artifact to register, may be {@code null}. + */ + public LocalArtifactRegistration( Artifact artifact ) + { + setArtifact( artifact ); + } + + /** + * Creates a registration request for the specified artifact. + * + * @param artifact The artifact to register, may be {@code null}. + * @param repository The remote repository from which the artifact was resolved or {@code null} if the artifact was + * locally installed. + * @param contexts The resolution contexts, may be {@code null}. + */ + public LocalArtifactRegistration( Artifact artifact, RemoteRepository repository, Collection contexts ) + { + setArtifact( artifact ); + setRepository( repository ); + setContexts( contexts ); + } + + /** + * Gets the artifact to register. + * + * @return The artifact or {@code null} if not set. + */ + public Artifact getArtifact() + { + return artifact; + } + + /** + * Sets the artifact to register. + * + * @param artifact The artifact, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public LocalArtifactRegistration setArtifact( Artifact artifact ) + { + this.artifact = artifact; + return this; + } + + /** + * Gets the remote repository from which the artifact was resolved. + * + * @return The remote repository or {@code null} if the artifact was locally installed. + */ + public RemoteRepository getRepository() + { + return repository; + } + + /** + * Sets the remote repository from which the artifact was resolved. + * + * @param repository The remote repository or {@code null} if the artifact was locally installed. + * @return This request for chaining, never {@code null}. + */ + public LocalArtifactRegistration setRepository( RemoteRepository repository ) + { + this.repository = repository; + return this; + } + + /** + * Gets the resolution contexts in which the artifact is available. + * + * @return The resolution contexts in which the artifact is available, never {@code null}. + */ + public Collection getContexts() + { + return contexts; + } + + /** + * Sets the resolution contexts in which the artifact is available. + * + * @param contexts The resolution contexts, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public LocalArtifactRegistration setContexts( Collection contexts ) + { + if ( contexts != null ) + { + this.contexts = contexts; + } + else + { + this.contexts = Collections.emptyList(); + } + return this; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRequest.java new file mode 100644 index 000000000..3cc67f858 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRequest.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; + +/** + * A query to the local repository for the existence of an artifact. + * + * @see LocalRepositoryManager#find(RepositorySystemSession, LocalArtifactRequest) + */ +public final class LocalArtifactRequest +{ + + private Artifact artifact; + + private String context = ""; + + private List repositories = Collections.emptyList(); + + /** + * Creates an uninitialized query. + */ + public LocalArtifactRequest() + { + // enables default constructor + } + + /** + * Creates a query with the specified properties. + * + * @param artifact The artifact to query for, may be {@code null}. + * @param repositories The remote repositories that should be considered as potential sources for the artifact, may + * be {@code null} or empty to only consider locally installed artifacts. + * @param context The resolution context for the artifact, may be {@code null}. + */ + public LocalArtifactRequest( Artifact artifact, List repositories, String context ) + { + setArtifact( artifact ); + setRepositories( repositories ); + setContext( context ); + } + + /** + * Gets the artifact to query for. + * + * @return The artifact or {@code null} if not set. + */ + public Artifact getArtifact() + { + return artifact; + } + + /** + * Sets the artifact to query for. + * + * @param artifact The artifact, may be {@code null}. + * @return This query for chaining, never {@code null}. + */ + public LocalArtifactRequest setArtifact( Artifact artifact ) + { + this.artifact = artifact; + return this; + } + + /** + * Gets the resolution context. + * + * @return The resolution context, never {@code null}. + */ + public String getContext() + { + return context; + } + + /** + * Sets the resolution context. + * + * @param context The resolution context, may be {@code null}. + * @return This query for chaining, never {@code null}. + */ + public LocalArtifactRequest setContext( String context ) + { + this.context = ( context != null ) ? context : ""; + return this; + } + + /** + * Gets the remote repositories to consider as sources of the artifact. + * + * @return The remote repositories, never {@code null}. + */ + public List getRepositories() + { + return repositories; + } + + /** + * Sets the remote repositories to consider as sources of the artifact. + * + * @param repositories The remote repositories, may be {@code null} or empty to only consider locally installed + * artifacts. + * @return This query for chaining, never {@code null}. + */ + public LocalArtifactRequest setRepositories( List repositories ) + { + if ( repositories != null ) + { + this.repositories = repositories; + } + else + { + this.repositories = Collections.emptyList(); + } + return this; + } + + @Override + public String toString() + { + return getArtifact() + " @ " + getRepositories(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactResult.java new file mode 100644 index 000000000..065b82358 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactResult.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import java.io.File; + +import org.eclipse.aether.RepositorySystemSession; + +/** + * A result from the local repository about the existence of an artifact. + * + * @see LocalRepositoryManager#find(RepositorySystemSession, LocalArtifactRequest) + */ +public final class LocalArtifactResult +{ + + private final LocalArtifactRequest request; + + private File file; + + private boolean available; + + private RemoteRepository repository; + + /** + * Creates a new result for the specified request. + * + * @param request The local artifact request, must not be {@code null}. + */ + public LocalArtifactResult( LocalArtifactRequest request ) + { + if ( request == null ) + { + throw new IllegalArgumentException( "local artifact request has not been specified" ); + } + this.request = request; + } + + /** + * Gets the request corresponding to this result. + * + * @return The corresponding request, never {@code null}. + */ + public LocalArtifactRequest getRequest() + { + return request; + } + + /** + * Gets the file to the requested artifact. Note that this file must not be used unless {@link #isAvailable()} + * returns {@code true}. An artifact file can be found but considered unavailable if the artifact was cached from a + * remote repository that is not part of the list of remote repositories used for the query. + * + * @return The file to the requested artifact or {@code null} if the artifact does not exist locally. + */ + public File getFile() + { + return file; + } + + /** + * Sets the file to requested artifact. + * + * @param file The artifact file, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public LocalArtifactResult setFile( File file ) + { + this.file = file; + return this; + } + + /** + * Indicates whether the requested artifact is available for use. As a minimum, the file needs to be physically + * existent in the local repository to be available. Additionally, a local repository manager can consider the list + * of supplied remote repositories to determine whether the artifact is logically available and mark an artifact + * unavailable (despite its physical existence) if it is not known to be hosted by any of the provided repositories. + * + * @return {@code true} if the artifact is available, {@code false} otherwise. + * @see LocalArtifactRequest#getRepositories() + */ + public boolean isAvailable() + { + return available; + } + + /** + * Sets whether the artifact is available. + * + * @param available {@code true} if the artifact is available, {@code false} otherwise. + * @return This result for chaining, never {@code null}. + */ + public LocalArtifactResult setAvailable( boolean available ) + { + this.available = available; + return this; + } + + /** + * Gets the (first) remote repository from which the artifact was cached (if any). + * + * @return The remote repository from which the artifact was originally retrieved or {@code null} if unknown or if + * the artifact has been locally installed. + * @see LocalArtifactRequest#getRepositories() + */ + public RemoteRepository getRepository() + { + return repository; + } + + /** + * Sets the (first) remote repository from which the artifact was cached. + * + * @param repository The remote repository from which the artifact was originally retrieved, may be {@code null} if + * unknown or if the artifact has been locally installed. + * @return This result for chaining, never {@code null}. + */ + public LocalArtifactResult setRepository( RemoteRepository repository ) + { + this.repository = repository; + return this; + } + + @Override + public String toString() + { + return getFile() + " (" + ( isAvailable() ? "available" : "unavailable" ) + ")"; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRegistration.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRegistration.java new file mode 100644 index 000000000..a01ba3e4c --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRegistration.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import java.util.Collection; +import java.util.Collections; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.metadata.Metadata; + +/** + * A request to register metadata within the local repository. + * + * @see LocalRepositoryManager#add(RepositorySystemSession, LocalMetadataRegistration) + */ +public final class LocalMetadataRegistration +{ + + private Metadata metadata; + + private RemoteRepository repository; + + private Collection contexts = Collections.emptyList(); + + /** + * Creates an uninitialized registration. + */ + public LocalMetadataRegistration() + { + // enables default constructor + } + + /** + * Creates a registration request for the specified metadata accompanying a locally installed artifact. + * + * @param metadata The metadata to register, may be {@code null}. + */ + public LocalMetadataRegistration( Metadata metadata ) + { + setMetadata( metadata ); + } + + /** + * Creates a registration request for the specified metadata. + * + * @param metadata The metadata to register, may be {@code null}. + * @param repository The remote repository from which the metadata was resolved or {@code null} if the metadata + * accompanies a locally installed artifact. + * @param contexts The resolution contexts, may be {@code null}. + */ + public LocalMetadataRegistration( Metadata metadata, RemoteRepository repository, Collection contexts ) + { + setMetadata( metadata ); + setRepository( repository ); + setContexts( contexts ); + } + + /** + * Gets the metadata to register. + * + * @return The metadata or {@code null} if not set. + */ + public Metadata getMetadata() + { + return metadata; + } + + /** + * Sets the metadata to register. + * + * @param metadata The metadata, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public LocalMetadataRegistration setMetadata( Metadata metadata ) + { + this.metadata = metadata; + return this; + } + + /** + * Gets the remote repository from which the metadata was resolved. + * + * @return The remote repository or {@code null} if the metadata was locally installed. + */ + public RemoteRepository getRepository() + { + return repository; + } + + /** + * Sets the remote repository from which the metadata was resolved. + * + * @param repository The remote repository or {@code null} if the metadata accompanies a locally installed artifact. + * @return This request for chaining, never {@code null}. + */ + public LocalMetadataRegistration setRepository( RemoteRepository repository ) + { + this.repository = repository; + return this; + } + + /** + * Gets the resolution contexts in which the metadata is available. + * + * @return The resolution contexts in which the metadata is available, never {@code null}. + */ + public Collection getContexts() + { + return contexts; + } + + /** + * Sets the resolution contexts in which the metadata is available. + * + * @param contexts The resolution contexts, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public LocalMetadataRegistration setContexts( Collection contexts ) + { + if ( contexts != null ) + { + this.contexts = contexts; + } + else + { + this.contexts = Collections.emptyList(); + } + return this; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRequest.java new file mode 100644 index 000000000..0ee4dc5e7 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRequest.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.metadata.Metadata; + +/** + * A query to the local repository for the existence of metadata. + * + * @see LocalRepositoryManager#find(RepositorySystemSession, LocalMetadataRequest) + */ +public final class LocalMetadataRequest +{ + + private Metadata metadata; + + private String context = ""; + + private RemoteRepository repository = null; + + /** + * Creates an uninitialized query. + */ + public LocalMetadataRequest() + { + // enables default constructor + } + + /** + * Creates a query with the specified properties. + * + * @param metadata The metadata to query for, may be {@code null}. + * @param repository The source remote repository for the metadata, may be {@code null} for local metadata. + * @param context The resolution context for the metadata, may be {@code null}. + */ + public LocalMetadataRequest( Metadata metadata, RemoteRepository repository, String context ) + { + setMetadata( metadata ); + setRepository( repository ); + setContext( context ); + } + + /** + * Gets the metadata to query for. + * + * @return The metadata or {@code null} if not set. + */ + public Metadata getMetadata() + { + return metadata; + } + + /** + * Sets the metadata to query for. + * + * @param metadata The metadata, may be {@code null}. + * @return This query for chaining, never {@code null}. + */ + public LocalMetadataRequest setMetadata( Metadata metadata ) + { + this.metadata = metadata; + return this; + } + + /** + * Gets the resolution context. + * + * @return The resolution context, never {@code null}. + */ + public String getContext() + { + return context; + } + + /** + * Sets the resolution context. + * + * @param context The resolution context, may be {@code null}. + * @return This query for chaining, never {@code null}. + */ + public LocalMetadataRequest setContext( String context ) + { + this.context = ( context != null ) ? context : ""; + return this; + } + + /** + * Gets the remote repository to use as source of the metadata. + * + * @return The remote repositories, may be {@code null} for local metadata. + */ + public RemoteRepository getRepository() + { + return repository; + } + + /** + * Sets the remote repository to use as sources of the metadata. + * + * @param repository The remote repository, may be {@code null}. + * @return This query for chaining, may be {@code null} for local metadata. + */ + public LocalMetadataRequest setRepository( RemoteRepository repository ) + { + this.repository = repository; + return this; + } + + @Override + public String toString() + { + return getMetadata() + " @ " + getRepository(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataResult.java new file mode 100644 index 000000000..6f3687a5e --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataResult.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import java.io.File; + +import org.eclipse.aether.RepositorySystemSession; + +/** + * A result from the local repository about the existence of metadata. + * + * @see LocalRepositoryManager#find(RepositorySystemSession, LocalMetadataRequest) + */ +public final class LocalMetadataResult +{ + + private final LocalMetadataRequest request; + + private File file; + + private boolean stale; + + /** + * Creates a new result for the specified request. + * + * @param request The local metadata request, must not be {@code null}. + */ + public LocalMetadataResult( LocalMetadataRequest request ) + { + if ( request == null ) + { + throw new IllegalArgumentException( "local metadata request has not been specified" ); + } + this.request = request; + } + + /** + * Gets the request corresponding to this result. + * + * @return The corresponding request, never {@code null}. + */ + public LocalMetadataRequest getRequest() + { + return request; + } + + /** + * Gets the file to the requested metadata if the metadata is available in the local repository. + * + * @return The file to the requested metadata or {@code null}. + */ + public File getFile() + { + return file; + } + + /** + * Sets the file to requested metadata. + * + * @param file The metadata file, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public LocalMetadataResult setFile( File file ) + { + this.file = file; + return this; + } + + /** + * This value indicates whether the metadata is stale and should be updated. + * + * @return {@code true} if the metadata is stale and should be updated, {@code false} otherwise. + */ + public boolean isStale() + { + return stale; + } + + /** + * Sets whether the metadata is stale. + * + * @param stale {@code true} if the metadata is stale and should be updated, {@code false} otherwise. + * @return This result for chaining, never {@code null}. + */ + public LocalMetadataResult setStale( boolean stale ) + { + this.stale = stale; + return this; + } + + @Override + public String toString() + { + return request.toString() + "(" + getFile() + ")"; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepository.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepository.java new file mode 100644 index 000000000..91b09d8b1 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepository.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import java.io.File; + +/** + * A repository on the local file system used to cache contents of remote repositories and to store locally installed + * artifacts. Note that this class merely describes such a repository, actual access to the contained artifacts is + * handled by a {@link LocalRepositoryManager} which is usually determined from the {@link #getContentType() type} of + * the repository. + */ +public final class LocalRepository + implements ArtifactRepository +{ + + private final File basedir; + + private final String type; + + /** + * Creates a new local repository with the specified base directory and unknown type. + * + * @param basedir The base directory of the repository, may be {@code null}. + */ + public LocalRepository( String basedir ) + { + this( ( basedir != null ) ? new File( basedir ) : null, "" ); + } + + /** + * Creates a new local repository with the specified base directory and unknown type. + * + * @param basedir The base directory of the repository, may be {@code null}. + */ + public LocalRepository( File basedir ) + { + this( basedir, "" ); + } + + /** + * Creates a new local repository with the specified properties. + * + * @param basedir The base directory of the repository, may be {@code null}. + * @param type The type of the repository, may be {@code null}. + */ + public LocalRepository( File basedir, String type ) + { + this.basedir = basedir; + this.type = ( type != null ) ? type : ""; + } + + public String getContentType() + { + return type; + } + + public String getId() + { + return "local"; + } + + /** + * Gets the base directory of the repository. + * + * @return The base directory or {@code null} if none. + */ + public File getBasedir() + { + return basedir; + } + + @Override + public String toString() + { + return getBasedir() + " (" + getContentType() + ")"; + } + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + { + return true; + } + if ( obj == null || !getClass().equals( obj.getClass() ) ) + { + return false; + } + + LocalRepository that = (LocalRepository) obj; + + return eq( basedir, that.basedir ) && eq( type, that.type ); + } + + private static boolean eq( T s1, T s2 ) + { + return s1 != null ? s1.equals( s2 ) : s2 == null; + } + + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + hash( basedir ); + hash = hash * 31 + hash( type ); + return hash; + } + + private static int hash( Object obj ) + { + return obj != null ? obj.hashCode() : 0; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepositoryManager.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepositoryManager.java new file mode 100644 index 000000000..d9d8777e6 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepositoryManager.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.metadata.Metadata; + +/** + * Manages access to a local repository. + * + * @see RepositorySystemSession#getLocalRepositoryManager() + * @see org.eclipse.aether.RepositorySystem#newLocalRepositoryManager(RepositorySystemSession, LocalRepository) + */ +public interface LocalRepositoryManager +{ + + /** + * Gets the description of the local repository being managed. + * + * @return The description of the local repository, never {@code null}. + */ + LocalRepository getRepository(); + + /** + * Gets the relative path for a locally installed artifact. Note that the artifact need not actually exist yet at + * the returned location, the path merely indicates where the artifact would eventually be stored. The path uses the + * forward slash as directory separator regardless of the underlying file system. + * + * @param artifact The artifact for which to determine the path, must not be {@code null}. + * @return The path, relative to the local repository's base directory. + */ + String getPathForLocalArtifact( Artifact artifact ); + + /** + * Gets the relative path for an artifact cached from a remote repository. Note that the artifact need not actually + * exist yet at the returned location, the path merely indicates where the artifact would eventually be stored. The + * path uses the forward slash as directory separator regardless of the underlying file system. + * + * @param artifact The artifact for which to determine the path, must not be {@code null}. + * @param repository The source repository of the artifact, must not be {@code null}. + * @param context The resolution context in which the artifact is being requested, may be {@code null}. + * @return The path, relative to the local repository's base directory. + */ + String getPathForRemoteArtifact( Artifact artifact, RemoteRepository repository, String context ); + + /** + * Gets the relative path for locally installed metadata. Note that the metadata need not actually exist yet at the + * returned location, the path merely indicates where the metadata would eventually be stored. The path uses the + * forward slash as directory separator regardless of the underlying file system. + * + * @param metadata The metadata for which to determine the path, must not be {@code null}. + * @return The path, relative to the local repository's base directory. + */ + String getPathForLocalMetadata( Metadata metadata ); + + /** + * Gets the relative path for metadata cached from a remote repository. Note that the metadata need not actually + * exist yet at the returned location, the path merely indicates where the metadata would eventually be stored. The + * path uses the forward slash as directory separator regardless of the underlying file system. + * + * @param metadata The metadata for which to determine the path, must not be {@code null}. + * @param repository The source repository of the metadata, must not be {@code null}. + * @param context The resolution context in which the metadata is being requested, may be {@code null}. + * @return The path, relative to the local repository's base directory. + */ + String getPathForRemoteMetadata( Metadata metadata, RemoteRepository repository, String context ); + + /** + * Queries for the existence of an artifact in the local repository. The request could be satisfied by a locally + * installed artifact or a previously downloaded artifact. + * + * @param session The repository system session during which the request is made, must not be {@code null}. + * @param request The artifact request, must not be {@code null}. + * @return The result of the request, never {@code null}. + */ + LocalArtifactResult find( RepositorySystemSession session, LocalArtifactRequest request ); + + /** + * Registers an installed or resolved artifact with the local repository. Note that artifact registration is merely + * concerned about updating the local repository's internal state, not about actually installing the artifact or its + * accompanying metadata. + * + * @param session The repository system session during which the registration is made, must not be {@code null}. + * @param request The registration request, must not be {@code null}. + */ + void add( RepositorySystemSession session, LocalArtifactRegistration request ); + + /** + * Queries for the existence of metadata in the local repository. The request could be satisfied by locally + * installed or previously downloaded metadata. + * + * @param session The repository system session during which the request is made, must not be {@code null}. + * @param request The metadata request, must not be {@code null}. + * @return The result of the request, never {@code null}. + */ + LocalMetadataResult find( RepositorySystemSession session, LocalMetadataRequest request ); + + /** + * Registers installed or resolved metadata with the local repository. Note that metadata registration is merely + * concerned about updating the local repository's internal state, not about actually installing the metadata. + * However, this method MUST be called after the actual install to give the repository manager the opportunity to + * inspect the added metadata. + * + * @param session The repository system session during which the registration is made, must not be {@code null}. + * @param request The registration request, must not be {@code null}. + */ + void add( RepositorySystemSession session, LocalMetadataRegistration request ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/MirrorSelector.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/MirrorSelector.java new file mode 100644 index 000000000..1614acc72 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/MirrorSelector.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +/** + * Selects a mirror for a given remote repository. + * + * @see org.eclipse.aether.RepositorySystemSession#getMirrorSelector() + */ +public interface MirrorSelector +{ + + /** + * Selects a mirror for the specified repository. + * + * @param repository The repository to select a mirror for, must not be {@code null}. + * @return The selected mirror or {@code null} if none. + * @see RemoteRepository#getMirroredRepositories() + */ + RemoteRepository getMirror( RemoteRepository repository ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/NoLocalRepositoryManagerException.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/NoLocalRepositoryManagerException.java new file mode 100644 index 000000000..203ccfb00 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/NoLocalRepositoryManagerException.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import org.eclipse.aether.RepositoryException; + +/** + * Thrown in case of an unsupported local repository type. + */ +public class NoLocalRepositoryManagerException + extends RepositoryException +{ + + private final transient LocalRepository repository; + + /** + * Creates a new exception with the specified repository. + * + * @param repository The local repository for which no support is available, may be {@code null}. + */ + public NoLocalRepositoryManagerException( LocalRepository repository ) + { + this( repository, toMessage( repository ) ); + } + + /** + * Creates a new exception with the specified repository and detail message. + * + * @param repository The local repository for which no support is available, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public NoLocalRepositoryManagerException( LocalRepository repository, String message ) + { + super( message ); + this.repository = repository; + } + + /** + * Creates a new exception with the specified repository and cause. + * + * @param repository The local repository for which no support is available, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public NoLocalRepositoryManagerException( LocalRepository repository, Throwable cause ) + { + this( repository, toMessage( repository ), cause ); + } + + /** + * Creates a new exception with the specified repository, detail message and cause. + * + * @param repository The local repository for which no support is available, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public NoLocalRepositoryManagerException( LocalRepository repository, String message, Throwable cause ) + { + super( message, cause ); + this.repository = repository; + } + + private static String toMessage( LocalRepository repository ) + { + if ( repository != null ) + { + return "No manager available for local repository (" + repository.getBasedir().getAbsolutePath() + + ") of type " + repository.getContentType(); + } + else + { + return "No manager available for local repository"; + } + } + + /** + * Gets the local repository whose content type is not supported. + * + * @return The unsupported local repository or {@code null} if unknown. + */ + public LocalRepository getRepository() + { + return repository; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/Proxy.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/Proxy.java new file mode 100644 index 000000000..b575bbc8e --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/Proxy.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +/** + * A proxy to use for connections to a repository. + */ +public final class Proxy +{ + + /** + * Type denoting a proxy for HTTP transfers. + */ + public static final String TYPE_HTTP = "http"; + + /** + * Type denoting a proxy for HTTPS transfers. + */ + public static final String TYPE_HTTPS = "https"; + + private final String type; + + private final String host; + + private final int port; + + private final Authentication auth; + + /** + * Creates a new proxy with the specified properties and no authentication. + * + * @param type The type of the proxy, e.g. "http", may be {@code null}. + * @param host The host of the proxy, may be {@code null}. + * @param port The port of the proxy. + */ + public Proxy( String type, String host, int port ) + { + this( type, host, port, null ); + } + + /** + * Creates a new proxy with the specified properties. + * + * @param type The type of the proxy, e.g. "http", may be {@code null}. + * @param host The host of the proxy, may be {@code null}. + * @param port The port of the proxy. + * @param auth The authentication to use for the proxy connection, may be {@code null}. + */ + public Proxy( String type, String host, int port, Authentication auth ) + { + this.type = ( type != null ) ? type : ""; + this.host = ( host != null ) ? host : ""; + this.port = port; + this.auth = auth; + } + + /** + * Gets the type of this proxy. + * + * @return The type of this proxy, never {@code null}. + */ + public String getType() + { + return type; + } + + /** + * Gets the host for this proxy. + * + * @return The host for this proxy, never {@code null}. + */ + public String getHost() + { + return host; + } + + /** + * Gets the port number for this proxy. + * + * @return The port number for this proxy. + */ + public int getPort() + { + return port; + } + + /** + * Gets the authentication to use for the proxy connection. + * + * @return The authentication to use or {@code null} if none. + */ + public Authentication getAuthentication() + { + return auth; + } + + @Override + public String toString() + { + return getHost() + ':' + getPort(); + } + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + { + return true; + } + if ( obj == null || !getClass().equals( obj.getClass() ) ) + { + return false; + } + + Proxy that = (Proxy) obj; + + return eq( type, that.type ) && eq( host, that.host ) && port == that.port && eq( auth, that.auth ); + } + + private static boolean eq( T s1, T s2 ) + { + return s1 != null ? s1.equals( s2 ) : s2 == null; + } + + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + hash( host ); + hash = hash * 31 + hash( type ); + hash = hash * 31 + port; + hash = hash * 31 + hash( auth ); + return hash; + } + + private static int hash( Object obj ) + { + return obj != null ? obj.hashCode() : 0; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/ProxySelector.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/ProxySelector.java new file mode 100644 index 000000000..680474cba --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/ProxySelector.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +/** + * Selects a proxy for a given remote repository. + * + * @see org.eclipse.aether.RepositorySystemSession#getProxySelector() + */ +public interface ProxySelector +{ + + /** + * Selects a proxy for the specified remote repository. + * + * @param repository The repository for which to select a proxy, must not be {@code null}. + * @return The selected proxy or {@code null} if none. + */ + Proxy getProxy( RemoteRepository repository ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/RemoteRepository.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/RemoteRepository.java new file mode 100644 index 000000000..aaa9acc27 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/RemoteRepository.java @@ -0,0 +1,573 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A repository on a remote server. + */ +public final class RemoteRepository + implements ArtifactRepository +{ + + private static final Pattern URL_PATTERN = + Pattern.compile( "([^:/]+(:[^:/]{2,}+(?=://))?):(//([^@/]*@)?([^/:]+))?.*" ); + + private final String id; + + private final String type; + + private final String url; + + private final String host; + + private final String protocol; + + private final RepositoryPolicy releasePolicy; + + private final RepositoryPolicy snapshotPolicy; + + private final Proxy proxy; + + private final Authentication authentication; + + private final List mirroredRepositories; + + private final boolean repositoryManager; + + RemoteRepository( Builder builder ) + { + if ( builder.prototype != null ) + { + id = ( builder.delta & Builder.ID ) != 0 ? builder.id : builder.prototype.id; + type = ( builder.delta & Builder.TYPE ) != 0 ? builder.type : builder.prototype.type; + url = ( builder.delta & Builder.URL ) != 0 ? builder.url : builder.prototype.url; + releasePolicy = + ( builder.delta & Builder.RELEASES ) != 0 ? builder.releasePolicy : builder.prototype.releasePolicy; + snapshotPolicy = + ( builder.delta & Builder.SNAPSHOTS ) != 0 ? builder.snapshotPolicy : builder.prototype.snapshotPolicy; + proxy = ( builder.delta & Builder.PROXY ) != 0 ? builder.proxy : builder.prototype.proxy; + authentication = + ( builder.delta & Builder.AUTH ) != 0 ? builder.authentication : builder.prototype.authentication; + repositoryManager = + ( builder.delta & Builder.REPOMAN ) != 0 ? builder.repositoryManager + : builder.prototype.repositoryManager; + mirroredRepositories = + ( builder.delta & Builder.MIRRORED ) != 0 ? copy( builder.mirroredRepositories ) + : builder.prototype.mirroredRepositories; + } + else + { + id = builder.id; + type = builder.type; + url = builder.url; + releasePolicy = builder.releasePolicy; + snapshotPolicy = builder.snapshotPolicy; + proxy = builder.proxy; + authentication = builder.authentication; + repositoryManager = builder.repositoryManager; + mirroredRepositories = copy( builder.mirroredRepositories ); + } + + Matcher m = URL_PATTERN.matcher( url ); + if ( m.matches() ) + { + protocol = m.group( 1 ); + String host = m.group( 5 ); + this.host = ( host != null ) ? host : ""; + } + else + { + protocol = host = ""; + } + } + + private static List copy( List repos ) + { + if ( repos == null || repos.isEmpty() ) + { + return Collections.emptyList(); + } + return Collections.unmodifiableList( Arrays.asList( repos.toArray( new RemoteRepository[repos.size()] ) ) ); + } + + public String getId() + { + return id; + } + + public String getContentType() + { + return type; + } + + /** + * Gets the (base) URL of this repository. + * + * @return The (base) URL of this repository, never {@code null}. + */ + public String getUrl() + { + return url; + } + + /** + * Gets the protocol part from the repository's URL, for example {@code file} or {@code http}. As suggested by RFC + * 2396, section 3.1 "Scheme Component", the protocol name should be treated case-insensitively. + * + * @return The protocol or an empty string if none, never {@code null}. + */ + public String getProtocol() + { + return protocol; + } + + /** + * Gets the host part from the repository's URL. + * + * @return The host or an empty string if none, never {@code null}. + */ + public String getHost() + { + return host; + } + + /** + * Gets the policy to apply for snapshot/release artifacts. + * + * @param snapshot {@code true} to retrieve the snapshot policy, {@code false} to retrieve the release policy. + * @return The requested repository policy, never {@code null}. + */ + public RepositoryPolicy getPolicy( boolean snapshot ) + { + return snapshot ? snapshotPolicy : releasePolicy; + } + + /** + * Gets the proxy that has been selected for this repository. + * + * @return The selected proxy or {@code null} if none. + */ + public Proxy getProxy() + { + return proxy; + } + + /** + * Gets the authentication that has been selected for this repository. + * + * @return The selected authentication or {@code null} if none. + */ + public Authentication getAuthentication() + { + return authentication; + } + + /** + * Gets the repositories that this repository serves as a mirror for. + * + * @return The (read-only) repositories being mirrored by this repository, never {@code null}. + */ + public List getMirroredRepositories() + { + return mirroredRepositories; + } + + /** + * Indicates whether this repository refers to a repository manager or not. + * + * @return {@code true} if this repository is a repository manager, {@code false} otherwise. + */ + public boolean isRepositoryManager() + { + return repositoryManager; + } + + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder( 256 ); + buffer.append( getId() ); + buffer.append( " (" ).append( getUrl() ); + buffer.append( ", " ).append( getContentType() ); + boolean r = getPolicy( false ).isEnabled(), s = getPolicy( true ).isEnabled(); + if ( r && s ) + { + buffer.append( ", releases+snapshots" ); + } + else if ( r ) + { + buffer.append( ", releases" ); + } + else if ( s ) + { + buffer.append( ", snapshots" ); + } + else + { + buffer.append( ", disabled" ); + } + if ( isRepositoryManager() ) + { + buffer.append( ", managed" ); + } + buffer.append( ")" ); + return buffer.toString(); + } + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + { + return true; + } + if ( obj == null || !getClass().equals( obj.getClass() ) ) + { + return false; + } + + RemoteRepository that = (RemoteRepository) obj; + + return eq( url, that.url ) && eq( type, that.type ) && eq( id, that.id ) + && eq( releasePolicy, that.releasePolicy ) && eq( snapshotPolicy, that.snapshotPolicy ) + && eq( proxy, that.proxy ) && eq( authentication, that.authentication ) + && eq( mirroredRepositories, that.mirroredRepositories ) && repositoryManager == that.repositoryManager; + } + + private static boolean eq( T s1, T s2 ) + { + return s1 != null ? s1.equals( s2 ) : s2 == null; + } + + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + hash( url ); + hash = hash * 31 + hash( type ); + hash = hash * 31 + hash( id ); + hash = hash * 31 + hash( releasePolicy ); + hash = hash * 31 + hash( snapshotPolicy ); + hash = hash * 31 + hash( proxy ); + hash = hash * 31 + hash( authentication ); + hash = hash * 31 + hash( mirroredRepositories ); + hash = hash * 31 + ( repositoryManager ? 1 : 0 ); + return hash; + } + + private static int hash( Object obj ) + { + return obj != null ? obj.hashCode() : 0; + } + + /** + * A builder to create remote repositories. + */ + public static final class Builder + { + + private static final RepositoryPolicy DEFAULT_POLICY = new RepositoryPolicy(); + + static final int ID = 0x0001, TYPE = 0x0002, URL = 0x0004, RELEASES = 0x0008, SNAPSHOTS = 0x0010, + PROXY = 0x0020, AUTH = 0x0040, MIRRORED = 0x0080, REPOMAN = 0x0100; + + int delta; + + RemoteRepository prototype; + + String id; + + String type; + + String url; + + RepositoryPolicy releasePolicy = DEFAULT_POLICY; + + RepositoryPolicy snapshotPolicy = DEFAULT_POLICY; + + Proxy proxy; + + Authentication authentication; + + List mirroredRepositories; + + boolean repositoryManager; + + /** + * Creates a new repository builder. + * + * @param id The identifier of the repository, may be {@code null}. + * @param type The type of the repository, may be {@code null}. + * @param url The (base) URL of the repository, may be {@code null}. + */ + public Builder( String id, String type, String url ) + { + this.id = ( id != null ) ? id : ""; + this.type = ( type != null ) ? type : ""; + this.url = ( url != null ) ? url : ""; + } + + /** + * Creates a new repository builder which uses the specified remote repository as a prototype for the new one. + * All properties which have not been set on the builder will be copied from the prototype when building the + * repository. + * + * @param prototype The remote repository to use as prototype, must not be {@code null}. + */ + public Builder( RemoteRepository prototype ) + { + if ( prototype == null ) + { + throw new IllegalArgumentException( "repository prototype missing" ); + } + this.prototype = prototype; + } + + /** + * Builds a new remote repository from the current values of this builder. The state of the builder itself + * remains unchanged. + * + * @return The remote repository, never {@code null}. + */ + public RemoteRepository build() + { + if ( prototype != null && delta == 0 ) + { + return prototype; + } + return new RemoteRepository( this ); + } + + private void delta( int flag, T builder, T prototype ) + { + boolean equal = ( builder != null ) ? builder.equals( prototype ) : prototype == null; + if ( equal ) + { + delta &= ~flag; + } + else + { + delta |= flag; + } + } + + /** + * Sets the identifier of the repository. + * + * @param id The identifier of the repository, may be {@code null}. + * @return This builder for chaining, never {@code null}. + */ + public Builder setId( String id ) + { + this.id = ( id != null ) ? id : ""; + if ( prototype != null ) + { + delta( ID, this.id, prototype.getId() ); + } + return this; + } + + /** + * Sets the type of the repository, e.g. "default". + * + * @param type The type of the repository, may be {@code null}. + * @return This builder for chaining, never {@code null}. + */ + public Builder setContentType( String type ) + { + this.type = ( type != null ) ? type : ""; + if ( prototype != null ) + { + delta( TYPE, this.type, prototype.getContentType() ); + } + return this; + } + + /** + * Sets the (base) URL of the repository. + * + * @param url The URL of the repository, may be {@code null}. + * @return This builder for chaining, never {@code null}. + */ + public Builder setUrl( String url ) + { + this.url = ( url != null ) ? url : ""; + if ( prototype != null ) + { + delta( URL, this.url, prototype.getUrl() ); + } + return this; + } + + /** + * Sets the policy to apply for snapshot and release artifacts. + * + * @param policy The repository policy to set, may be {@code null} to use a default policy. + * @return This builder for chaining, never {@code null}. + */ + public Builder setPolicy( RepositoryPolicy policy ) + { + this.releasePolicy = this.snapshotPolicy = ( policy != null ) ? policy : DEFAULT_POLICY; + if ( prototype != null ) + { + delta( RELEASES, this.releasePolicy, prototype.getPolicy( false ) ); + delta( SNAPSHOTS, this.snapshotPolicy, prototype.getPolicy( true ) ); + } + return this; + } + + /** + * Sets the policy to apply for release artifacts. + * + * @param releasePolicy The repository policy to set, may be {@code null} to use a default policy. + * @return This builder for chaining, never {@code null}. + */ + public Builder setReleasePolicy( RepositoryPolicy releasePolicy ) + { + this.releasePolicy = ( releasePolicy != null ) ? releasePolicy : DEFAULT_POLICY; + if ( prototype != null ) + { + delta( RELEASES, this.releasePolicy, prototype.getPolicy( false ) ); + } + return this; + } + + /** + * Sets the policy to apply for snapshot artifacts. + * + * @param snapshotPolicy The repository policy to set, may be {@code null} to use a default policy. + * @return This builder for chaining, never {@code null}. + */ + public Builder setSnapshotPolicy( RepositoryPolicy snapshotPolicy ) + { + this.snapshotPolicy = ( snapshotPolicy != null ) ? snapshotPolicy : DEFAULT_POLICY; + if ( prototype != null ) + { + delta( SNAPSHOTS, this.snapshotPolicy, prototype.getPolicy( true ) ); + } + return this; + } + + /** + * Sets the proxy to use in order to access the repository. + * + * @param proxy The proxy to use, may be {@code null}. + * @return This builder for chaining, never {@code null}. + */ + public Builder setProxy( Proxy proxy ) + { + this.proxy = proxy; + if ( prototype != null ) + { + delta( PROXY, this.proxy, prototype.getProxy() ); + } + return this; + } + + /** + * Sets the authentication to use in order to access the repository. + * + * @param authentication The authentication to use, may be {@code null}. + * @return This builder for chaining, never {@code null}. + */ + public Builder setAuthentication( Authentication authentication ) + { + this.authentication = authentication; + if ( prototype != null ) + { + delta( AUTH, this.authentication, prototype.getAuthentication() ); + } + return this; + } + + /** + * Sets the repositories being mirrored by the repository. + * + * @param mirroredRepositories The repositories being mirrored by the repository, may be {@code null}. + * @return This builder for chaining, never {@code null}. + */ + public Builder setMirroredRepositories( List mirroredRepositories ) + { + if ( this.mirroredRepositories == null ) + { + this.mirroredRepositories = new ArrayList(); + } + else + { + this.mirroredRepositories.clear(); + } + if ( mirroredRepositories != null ) + { + this.mirroredRepositories.addAll( mirroredRepositories ); + } + if ( prototype != null ) + { + delta( MIRRORED, this.mirroredRepositories, prototype.getMirroredRepositories() ); + } + return this; + } + + /** + * Adds the specified repository to the list of repositories being mirrored by the repository. If this builder + * was {@link #RemoteRepository.Builder(RemoteRepository) constructed from a prototype}, the given repository + * will be added to the list of mirrored repositories from the prototype. + * + * @param mirroredRepository The repository being mirrored by the repository, may be {@code null}. + * @return This builder for chaining, never {@code null}. + */ + public Builder addMirroredRepository( RemoteRepository mirroredRepository ) + { + if ( mirroredRepository != null ) + { + if ( this.mirroredRepositories == null ) + { + this.mirroredRepositories = new ArrayList(); + if ( prototype != null ) + { + mirroredRepositories.addAll( prototype.getMirroredRepositories() ); + } + } + mirroredRepositories.add( mirroredRepository ); + if ( prototype != null ) + { + delta |= MIRRORED; + } + } + return this; + } + + /** + * Marks the repository as a repository manager or not. + * + * @param repositoryManager {@code true} if the repository points at a repository manager, {@code false} if the + * repository is just serving static contents. + * @return This builder for chaining, never {@code null}. + */ + public Builder setRepositoryManager( boolean repositoryManager ) + { + this.repositoryManager = repositoryManager; + if ( prototype != null ) + { + delta( REPOMAN, this.repositoryManager, prototype.isRepositoryManager() ); + } + return this; + } + + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/RepositoryPolicy.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/RepositoryPolicy.java new file mode 100644 index 000000000..05224a8a7 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/RepositoryPolicy.java @@ -0,0 +1,152 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +/** + * A policy controlling access to a repository. + */ +public final class RepositoryPolicy +{ + + /** + * Never update locally cached data. + */ + public static final String UPDATE_POLICY_NEVER = "never"; + + /** + * Always update locally cached data. + */ + public static final String UPDATE_POLICY_ALWAYS = "always"; + + /** + * Update locally cached data once a day. + */ + public static final String UPDATE_POLICY_DAILY = "daily"; + + /** + * Update locally cached data every X minutes as given by "interval:X". + */ + public static final String UPDATE_POLICY_INTERVAL = "interval"; + + /** + * Verify checksums and fail the resolution if they do not match. + */ + public static final String CHECKSUM_POLICY_FAIL = "fail"; + + /** + * Verify checksums and warn if they do not match. + */ + public static final String CHECKSUM_POLICY_WARN = "warn"; + + /** + * Do not verify checksums. + */ + public static final String CHECKSUM_POLICY_IGNORE = "ignore"; + + private final boolean enabled; + + private final String updatePolicy; + + private final String checksumPolicy; + + /** + * Creates a new policy with checksum warnings and daily update checks. + */ + public RepositoryPolicy() + { + this( true, UPDATE_POLICY_DAILY, CHECKSUM_POLICY_WARN ); + } + + /** + * Creates a new policy with the specified settings. + * + * @param enabled A flag whether the associated repository should be accessed or not. + * @param updatePolicy The update interval after which locally cached data from the repository is considered stale + * and should be refetched, may be {@code null}. + * @param checksumPolicy The way checksum verification should be handled, may be {@code null}. + */ + public RepositoryPolicy( boolean enabled, String updatePolicy, String checksumPolicy ) + { + this.enabled = enabled; + this.updatePolicy = ( updatePolicy != null ) ? updatePolicy : ""; + this.checksumPolicy = ( checksumPolicy != null ) ? checksumPolicy : ""; + } + + /** + * Indicates whether the associated repository should be contacted or not. + * + * @return {@code true} if the repository should be contacted, {@code false} otherwise. + */ + public boolean isEnabled() + { + return enabled; + } + + /** + * Gets the update policy for locally cached data from the repository. + * + * @return The update policy, never {@code null}. + */ + public String getUpdatePolicy() + { + return updatePolicy; + } + + /** + * Gets the policy for checksum validation. + * + * @return The checksum policy, never {@code null}. + */ + public String getChecksumPolicy() + { + return checksumPolicy; + } + + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder( 256 ); + buffer.append( "enabled=" ).append( isEnabled() ); + buffer.append( ", checksums=" ).append( getChecksumPolicy() ); + buffer.append( ", updates=" ).append( getUpdatePolicy() ); + return buffer.toString(); + } + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + { + return true; + } + + if ( obj == null || !getClass().equals( obj.getClass() ) ) + { + return false; + } + + RepositoryPolicy that = (RepositoryPolicy) obj; + + return enabled == that.enabled && updatePolicy.equals( that.updatePolicy ) + && checksumPolicy.equals( that.checksumPolicy ); + } + + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + ( enabled ? 1 : 0 ); + hash = hash * 31 + updatePolicy.hashCode(); + hash = hash * 31 + checksumPolicy.hashCode(); + return hash; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceReader.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceReader.java new file mode 100644 index 000000000..570f6b6e7 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceReader.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import java.io.File; +import java.util.List; + +import org.eclipse.aether.artifact.Artifact; + +/** + * Manages a repository backed by the IDE workspace, a build session or a similar ad-hoc collection of artifacts. + * + * @see org.eclipse.aether.RepositorySystemSession#getWorkspaceReader() + */ +public interface WorkspaceReader +{ + + /** + * Gets a description of the workspace repository. + * + * @return The repository description, never {@code null}. + */ + WorkspaceRepository getRepository(); + + /** + * Locates the specified artifact. + * + * @param artifact The artifact to locate, must not be {@code null}. + * @return The path to the artifact or {@code null} if the artifact is not available. + */ + File findArtifact( Artifact artifact ); + + /** + * Determines all available versions of the specified artifact. + * + * @param artifact The artifact whose versions should be listed, must not be {@code null}. + * @return The available versions of the artifact, must not be {@code null}. + */ + List findVersions( Artifact artifact ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceRepository.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceRepository.java new file mode 100644 index 000000000..811c58901 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceRepository.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.repository; + +import java.util.UUID; + +/** + * A repository backed by an IDE workspace, the output of a build session or similar ad-hoc collection of artifacts. As + * far as the repository system is concerned, a workspace repository is read-only, i.e. can only be used for artifact + * resolution but not installation/deployment. Note that this class merely describes such a repository, actual access to + * the contained artifacts is handled by a {@link WorkspaceReader}. + */ +public final class WorkspaceRepository + implements ArtifactRepository +{ + + private final String type; + + private final Object key; + + /** + * Creates a new workspace repository of type {@code "workspace"} and a random key. + */ + public WorkspaceRepository() + { + this( "workspace" ); + } + + /** + * Creates a new workspace repository with the specified type and a random key. + * + * @param type The type of the repository, may be {@code null}. + */ + public WorkspaceRepository( String type ) + { + this( type, null ); + } + + /** + * Creates a new workspace repository with the specified type and key. The key is used to distinguish one workspace + * from another and should be sensitive to the artifacts that are (potentially) available in the workspace. + * + * @param type The type of the repository, may be {@code null}. + * @param key The (comparison) key for the repository, may be {@code null} to generate a unique random key. + */ + public WorkspaceRepository( String type, Object key ) + { + this.type = ( type != null ) ? type : ""; + this.key = ( key != null ) ? key : UUID.randomUUID().toString().replace( "-", "" ); + } + + public String getContentType() + { + return type; + } + + public String getId() + { + return "workspace"; + } + + /** + * Gets the key of this workspace repository. The key is used to distinguish one workspace from another and should + * be sensitive to the artifacts that are (potentially) available in the workspace. + * + * @return The (comparison) key for this workspace repository, never {@code null}. + */ + public Object getKey() + { + return key; + } + + @Override + public String toString() + { + return "(" + getContentType() + ")"; + } + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + { + return true; + } + if ( obj == null || !getClass().equals( obj.getClass() ) ) + { + return false; + } + + WorkspaceRepository that = (WorkspaceRepository) obj; + + return getContentType().equals( that.getContentType() ) && getKey().equals( that.getKey() ); + } + + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + getKey().hashCode(); + hash = hash * 31 + getContentType().hashCode(); + return hash; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/package-info.java new file mode 100644 index 000000000..21ab2bc9e --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/repository/package-info.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * The definition of various kinds of repositories that host artifacts. + */ +package org.eclipse.aether.repository; + diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorException.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorException.java new file mode 100644 index 000000000..7dae7f4c5 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorException.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import org.eclipse.aether.RepositoryException; + +/** + * Thrown in case of an unreadable or unresolvable artifact descriptor. + */ +public class ArtifactDescriptorException + extends RepositoryException +{ + + private final transient ArtifactDescriptorResult result; + + /** + * Creates a new exception with the specified result. + * + * @param result The descriptor result at the point the exception occurred, may be {@code null}. + */ + public ArtifactDescriptorException( ArtifactDescriptorResult result ) + { + super( "Failed to read artifact descriptor" + + ( result != null ? " for " + result.getRequest().getArtifact() : "" ), getCause( result ) ); + this.result = result; + } + + /** + * Creates a new exception with the specified result and detail message. + * + * @param result The descriptor result at the point the exception occurred, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public ArtifactDescriptorException( ArtifactDescriptorResult result, String message ) + { + super( message, getCause( result ) ); + this.result = result; + } + + /** + * Creates a new exception with the specified result, detail message and cause. + * + * @param result The descriptor result at the point the exception occurred, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public ArtifactDescriptorException( ArtifactDescriptorResult result, String message, Throwable cause ) + { + super( message, cause ); + this.result = result; + } + + /** + * Gets the descriptor result at the point the exception occurred. Despite being incomplete, callers might want to + * use this result to fail gracefully and continue their operation with whatever interim data has been gathered. + * + * @return The descriptor result or {@code null} if unknown. + */ + public ArtifactDescriptorResult getResult() + { + return result; + } + + private static Throwable getCause( ArtifactDescriptorResult result ) + { + Throwable cause = null; + if ( result != null && !result.getExceptions().isEmpty() ) + { + cause = result.getExceptions().get( 0 ); + } + return cause; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicy.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicy.java new file mode 100644 index 000000000..ec519fee9 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicy.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2012, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import org.eclipse.aether.RepositorySystemSession; + +/** + * Controls the handling of errors related to reading an artifact descriptor. + * + * @see RepositorySystemSession#getArtifactDescriptorPolicy() + */ +public interface ArtifactDescriptorPolicy +{ + + /** + * Bit mask indicating that errors while reading the artifact descriptor should not be tolerated. + */ + int STRICT = 0x00; + + /** + * Bit flag indicating that missing artifact descriptors should be silently ignored. + */ + int IGNORE_MISSING = 0x01; + + /** + * Bit flag indicating that existent but invalid artifact descriptors should be silently ignored. + */ + int IGNORE_INVALID = 0x02; + + /** + * Bit mask indicating that all errors should be silently ignored. + */ + int IGNORE_ERRORS = IGNORE_MISSING | IGNORE_INVALID; + + /** + * Gets the error policy for an artifact's descriptor. + * + * @param session The repository session during which the policy is determined, must not be {@code null}. + * @param request The policy request holding further details, must not be {@code null}. + * @return The bit mask describing the desired error policy. + */ + int getPolicy( RepositorySystemSession session, ArtifactDescriptorPolicyRequest request ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicyRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicyRequest.java new file mode 100644 index 000000000..2edf0c538 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicyRequest.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import org.eclipse.aether.artifact.Artifact; + +/** + * A query for the error policy for a given artifact's descriptor. + * + * @see ArtifactDescriptorPolicy + */ +public final class ArtifactDescriptorPolicyRequest +{ + + private Artifact artifact; + + private String context = ""; + + /** + * Creates an uninitialized request. + */ + public ArtifactDescriptorPolicyRequest() + { + // enables default constructor + } + + /** + * Creates a request for the specified artifact. + * + * @param artifact The artifact for whose descriptor to determine the error policy, may be {@code null}. + * @param context The context in which this request is made, may be {@code null}. + */ + public ArtifactDescriptorPolicyRequest( Artifact artifact, String context ) + { + setArtifact( artifact ); + setRequestContext( context ); + } + + /** + * Gets the artifact for whose descriptor to determine the error policy. + * + * @return The artifact for whose descriptor to determine the error policy or {@code null} if not set. + */ + public Artifact getArtifact() + { + return artifact; + } + + /** + * Sets the artifact for whose descriptor to determine the error policy. + * + * @param artifact The artifact for whose descriptor to determine the error policy, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ArtifactDescriptorPolicyRequest setArtifact( Artifact artifact ) + { + this.artifact = artifact; + return this; + } + + /** + * Gets the context in which this request is made. + * + * @return The context, never {@code null}. + */ + public String getRequestContext() + { + return context; + } + + /** + * Sets the context in which this request is made. + * + * @param context The context, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ArtifactDescriptorPolicyRequest setRequestContext( String context ) + { + this.context = ( context != null ) ? context : ""; + return this; + } + + @Override + public String toString() + { + return String.valueOf( getArtifact() ); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorRequest.java new file mode 100644 index 000000000..9a1ba6521 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorRequest.java @@ -0,0 +1,181 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * A request to read an artifact descriptor. + * + * @see RepositorySystem#readArtifactDescriptor(RepositorySystemSession, ArtifactDescriptorRequest) + */ +public final class ArtifactDescriptorRequest +{ + + private Artifact artifact; + + private List repositories = Collections.emptyList(); + + private String context = ""; + + private RequestTrace trace; + + /** + * Creates an uninitialized request. + */ + public ArtifactDescriptorRequest() + { + // enables default constructor + } + + /** + * Creates a request with the specified properties. + * + * @param artifact The artifact whose descriptor should be read, may be {@code null}. + * @param repositories The repositories to resolve the descriptor from, may be {@code null}. + * @param context The context in which this request is made, may be {@code null}. + */ + public ArtifactDescriptorRequest( Artifact artifact, List repositories, String context ) + { + setArtifact( artifact ); + setRepositories( repositories ); + setRequestContext( context ); + } + + /** + * Gets the artifact whose descriptor shall be read. + * + * @return The artifact or {@code null} if not set. + */ + public Artifact getArtifact() + { + return artifact; + } + + /** + * Sets the artifact whose descriptor shall be read. Eventually, a valid request must have an artifact set. + * + * @param artifact The artifact, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ArtifactDescriptorRequest setArtifact( Artifact artifact ) + { + this.artifact = artifact; + return this; + } + + /** + * Gets the repositories to resolve the descriptor from. + * + * @return The repositories, never {@code null}. + */ + public List getRepositories() + { + return repositories; + } + + /** + * Sets the repositories to resolve the descriptor from. + * + * @param repositories The repositories, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ArtifactDescriptorRequest setRepositories( List repositories ) + { + if ( repositories == null ) + { + this.repositories = Collections.emptyList(); + } + else + { + this.repositories = repositories; + } + return this; + } + + /** + * Adds the specified repository for the resolution of the artifact descriptor. + * + * @param repository The repository to add, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ArtifactDescriptorRequest addRepository( RemoteRepository repository ) + { + if ( repository != null ) + { + if ( this.repositories.isEmpty() ) + { + this.repositories = new ArrayList(); + } + this.repositories.add( repository ); + } + return this; + } + + /** + * Gets the context in which this request is made. + * + * @return The context, never {@code null}. + */ + public String getRequestContext() + { + return context; + } + + /** + * Sets the context in which this request is made. + * + * @param context The context, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ArtifactDescriptorRequest setRequestContext( String context ) + { + this.context = ( context != null ) ? context : ""; + return this; + } + + /** + * Gets the trace information that describes the higher level request/operation in which this request is issued. + * + * @return The trace information about the higher level operation or {@code null} if none. + */ + public RequestTrace getTrace() + { + return trace; + } + + /** + * Sets the trace information that describes the higher level request/operation in which this request is issued. + * + * @param trace The trace information about the higher level operation, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ArtifactDescriptorRequest setTrace( RequestTrace trace ) + { + this.trace = trace; + return this; + } + + @Override + public String toString() + { + return getArtifact() + " < " + getRepositories(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorResult.java new file mode 100644 index 000000000..3de8d5e02 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorResult.java @@ -0,0 +1,457 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.repository.ArtifactRepository; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * The result from reading an artifact descriptor. + * + * @see RepositorySystem#readArtifactDescriptor(RepositorySystemSession, ArtifactDescriptorRequest) + */ +public final class ArtifactDescriptorResult +{ + + private final ArtifactDescriptorRequest request; + + private List exceptions; + + private List relocations; + + private Collection aliases; + + private Artifact artifact; + + private ArtifactRepository repository; + + private List dependencies; + + private List managedDependencies; + + private List repositories; + + private Map properties; + + /** + * Creates a new result for the specified request. + * + * @param request The descriptor request, must not be {@code null}. + */ + public ArtifactDescriptorResult( ArtifactDescriptorRequest request ) + { + if ( request == null ) + { + throw new IllegalArgumentException( "artifact descriptor request has not been specified" ); + } + this.request = request; + artifact = request.getArtifact(); + exceptions = Collections.emptyList(); + relocations = Collections.emptyList(); + aliases = Collections.emptyList(); + dependencies = managedDependencies = Collections.emptyList(); + repositories = Collections.emptyList(); + properties = Collections.emptyMap(); + } + + /** + * Gets the descriptor request that was made. + * + * @return The descriptor request, never {@code null}. + */ + public ArtifactDescriptorRequest getRequest() + { + return request; + } + + /** + * Gets the exceptions that occurred while reading the artifact descriptor. + * + * @return The exceptions that occurred, never {@code null}. + */ + public List getExceptions() + { + return exceptions; + } + + /** + * Sets the exceptions that occurred while reading the artifact descriptor. + * + * @param exceptions The exceptions that occurred, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult setExceptions( List exceptions ) + { + if ( exceptions == null ) + { + this.exceptions = Collections.emptyList(); + } + else + { + this.exceptions = exceptions; + } + return this; + } + + /** + * Records the specified exception while reading the artifact descriptor. + * + * @param exception The exception to record, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult addException( Exception exception ) + { + if ( exception != null ) + { + if ( exceptions.isEmpty() ) + { + exceptions = new ArrayList(); + } + exceptions.add( exception ); + } + return this; + } + + /** + * Gets the relocations that were processed to read the artifact descriptor. The returned list denotes the hops that + * lead to the final artifact coordinates as given by {@link #getArtifact()}. + * + * @return The relocations that were processed, never {@code null}. + */ + public List getRelocations() + { + return relocations; + } + + /** + * Sets the relocations that were processed to read the artifact descriptor. + * + * @param relocations The relocations that were processed, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult setRelocations( List relocations ) + { + if ( relocations == null ) + { + this.relocations = Collections.emptyList(); + } + else + { + this.relocations = relocations; + } + return this; + } + + /** + * Records the specified relocation hop while locating the artifact descriptor. + * + * @param artifact The artifact that got relocated, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult addRelocation( Artifact artifact ) + { + if ( artifact != null ) + { + if ( relocations.isEmpty() ) + { + relocations = new ArrayList(); + } + relocations.add( artifact ); + } + return this; + } + + /** + * Gets the known aliases for this artifact. An alias denotes a different artifact with (almost) the same contents + * and can be used to mark a patched rebuild of some other artifact as such, thereby allowing conflict resolution to + * consider the patched and the original artifact as a conflict. + * + * @return The aliases of the artifact, never {@code null}. + */ + public Collection getAliases() + { + return aliases; + } + + /** + * Sets the aliases of the artifact. + * + * @param aliases The aliases of the artifact, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult setAliases( Collection aliases ) + { + if ( aliases == null ) + { + this.aliases = Collections.emptyList(); + } + else + { + this.aliases = aliases; + } + return this; + } + + /** + * Records the specified alias. + * + * @param alias The alias for the artifact, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult addAlias( Artifact alias ) + { + if ( alias != null ) + { + if ( aliases.isEmpty() ) + { + aliases = new ArrayList(); + } + aliases.add( alias ); + } + return this; + } + + /** + * Gets the artifact whose descriptor was read. This can be a different artifact than originally requested in case + * relocations were encountered. + * + * @return The artifact after following any relocations, never {@code null}. + */ + public Artifact getArtifact() + { + return artifact; + } + + /** + * Sets the artifact whose descriptor was read. + * + * @param artifact The artifact whose descriptor was read, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult setArtifact( Artifact artifact ) + { + this.artifact = artifact; + return this; + } + + /** + * Gets the repository from which the descriptor was eventually resolved. + * + * @return The repository from which the descriptor was resolved or {@code null} if unknown. + */ + public ArtifactRepository getRepository() + { + return repository; + } + + /** + * Sets the repository from which the descriptor was resolved. + * + * @param repository The repository from which the descriptor was resolved, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult setRepository( ArtifactRepository repository ) + { + this.repository = repository; + return this; + } + + /** + * Gets the list of direct dependencies of the artifact. + * + * @return The list of direct dependencies, never {@code null} + */ + public List getDependencies() + { + return dependencies; + } + + /** + * Sets the list of direct dependencies of the artifact. + * + * @param dependencies The list of direct dependencies, may be {@code null} + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult setDependencies( List dependencies ) + { + if ( dependencies == null ) + { + this.dependencies = Collections.emptyList(); + } + else + { + this.dependencies = dependencies; + } + return this; + } + + /** + * Adds the specified direct dependency. + * + * @param dependency The direct dependency to add, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult addDependency( Dependency dependency ) + { + if ( dependency != null ) + { + if ( dependencies.isEmpty() ) + { + dependencies = new ArrayList(); + } + dependencies.add( dependency ); + } + return this; + } + + /** + * Gets the dependency management information. + * + * @return The dependency management information. + */ + public List getManagedDependencies() + { + return managedDependencies; + } + + /** + * Sets the dependency management information. + * + * @param dependencies The dependency management information, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult setManagedDependencies( List dependencies ) + { + if ( dependencies == null ) + { + this.managedDependencies = Collections.emptyList(); + } + else + { + this.managedDependencies = dependencies; + } + return this; + } + + /** + * Adds the specified managed dependency. + * + * @param dependency The managed dependency to add, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult addManagedDependency( Dependency dependency ) + { + if ( dependency != null ) + { + if ( managedDependencies.isEmpty() ) + { + managedDependencies = new ArrayList(); + } + managedDependencies.add( dependency ); + } + return this; + } + + /** + * Gets the remote repositories listed in the artifact descriptor. + * + * @return The remote repositories listed in the artifact descriptor, never {@code null}. + */ + public List getRepositories() + { + return repositories; + } + + /** + * Sets the remote repositories listed in the artifact descriptor. + * + * @param repositories The remote repositories listed in the artifact descriptor, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult setRepositories( List repositories ) + { + if ( repositories == null ) + { + this.repositories = Collections.emptyList(); + } + else + { + this.repositories = repositories; + } + return this; + } + + /** + * Adds the specified remote repository. + * + * @param repository The remote repository to add, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult addRepository( RemoteRepository repository ) + { + if ( repository != null ) + { + if ( repositories.isEmpty() ) + { + repositories = new ArrayList(); + } + repositories.add( repository ); + } + return this; + } + + /** + * Gets any additional information about the artifact in form of key-value pairs. Note: Regardless of their + * actual type, all property values must be treated as being read-only. + * + * @return The additional information about the artifact, never {@code null}. + */ + public Map getProperties() + { + return properties; + } + + /** + * Sets any additional information about the artifact in form of key-value pairs. + * + * @param properties The additional information about the artifact, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactDescriptorResult setProperties( Map properties ) + { + if ( properties == null ) + { + this.properties = Collections.emptyMap(); + } + else + { + this.properties = properties; + } + return this; + } + + @Override + public String toString() + { + return getArtifact() + " -> " + getDependencies(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactRequest.java new file mode 100644 index 000000000..6076ea5df --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactRequest.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * A request to resolve an artifact. + * + * @see RepositorySystem#resolveArtifacts(RepositorySystemSession, java.util.Collection) + * @see Artifact#getFile() + */ +public final class ArtifactRequest +{ + + private Artifact artifact; + + private DependencyNode node; + + private List repositories = Collections.emptyList(); + + private String context = ""; + + private RequestTrace trace; + + /** + * Creates an uninitialized request. + */ + public ArtifactRequest() + { + // enables default constructor + } + + /** + * Creates a request with the specified properties. + * + * @param artifact The artifact to resolve, may be {@code null}. + * @param repositories The repositories to resolve the artifact from, may be {@code null}. + * @param context The context in which this request is made, may be {@code null}. + */ + public ArtifactRequest( Artifact artifact, List repositories, String context ) + { + setArtifact( artifact ); + setRepositories( repositories ); + setRequestContext( context ); + } + + /** + * Creates a request from the specified dependency node. + * + * @param node The dependency node to resolve, may be {@code null}. + */ + public ArtifactRequest( DependencyNode node ) + { + setDependencyNode( node ); + setRepositories( node.getRepositories() ); + setRequestContext( node.getRequestContext() ); + } + + /** + * Gets the artifact to resolve. + * + * @return The artifact to resolve or {@code null}. + */ + public Artifact getArtifact() + { + return artifact; + } + + /** + * Sets the artifact to resolve. + * + * @param artifact The artifact to resolve, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ArtifactRequest setArtifact( Artifact artifact ) + { + this.artifact = artifact; + return this; + } + + /** + * Gets the dependency node (if any) for which to resolve the artifact. + * + * @return The dependency node to resolve or {@code null} if unknown. + */ + public DependencyNode getDependencyNode() + { + return node; + } + + /** + * Sets the dependency node to resolve. + * + * @param node The dependency node to resolve, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ArtifactRequest setDependencyNode( DependencyNode node ) + { + this.node = node; + if ( node != null ) + { + setArtifact( node.getDependency().getArtifact() ); + } + return this; + } + + /** + * Gets the repositories to resolve the artifact from. + * + * @return The repositories, never {@code null}. + */ + public List getRepositories() + { + return repositories; + } + + /** + * Sets the repositories to resolve the artifact from. + * + * @param repositories The repositories, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ArtifactRequest setRepositories( List repositories ) + { + if ( repositories == null ) + { + this.repositories = Collections.emptyList(); + } + else + { + this.repositories = repositories; + } + return this; + } + + /** + * Adds the specified repository for the resolution. + * + * @param repository The repository to add, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ArtifactRequest addRepository( RemoteRepository repository ) + { + if ( repository != null ) + { + if ( this.repositories.isEmpty() ) + { + this.repositories = new ArrayList(); + } + this.repositories.add( repository ); + } + return this; + } + + /** + * Gets the context in which this request is made. + * + * @return The context, never {@code null}. + */ + public String getRequestContext() + { + return context; + } + + /** + * Sets the context in which this request is made. + * + * @param context The context, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ArtifactRequest setRequestContext( String context ) + { + this.context = ( context != null ) ? context : ""; + return this; + } + + /** + * Gets the trace information that describes the higher level request/operation in which this request is issued. + * + * @return The trace information about the higher level operation or {@code null} if none. + */ + public RequestTrace getTrace() + { + return trace; + } + + /** + * Sets the trace information that describes the higher level request/operation in which this request is issued. + * + * @param trace The trace information about the higher level operation, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ArtifactRequest setTrace( RequestTrace trace ) + { + this.trace = trace; + return this; + } + + @Override + public String toString() + { + return getArtifact() + " < " + getRepositories(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResolutionException.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResolutionException.java new file mode 100644 index 000000000..67d051498 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResolutionException.java @@ -0,0 +1,164 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.transfer.ArtifactNotFoundException; +import org.eclipse.aether.transfer.RepositoryOfflineException; + +/** + * Thrown in case of a unresolvable artifacts. + */ +public class ArtifactResolutionException + extends RepositoryException +{ + + private final transient List results; + + /** + * Creates a new exception with the specified results. + * + * @param results The resolution results at the point the exception occurred, may be {@code null}. + */ + public ArtifactResolutionException( List results ) + { + super( getMessage( results ), getCause( results ) ); + this.results = ( results != null ) ? results : Collections. emptyList(); + } + + /** + * Creates a new exception with the specified results and detail message. + * + * @param results The resolution results at the point the exception occurred, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public ArtifactResolutionException( List results, String message ) + { + super( message, getCause( results ) ); + this.results = ( results != null ) ? results : Collections. emptyList(); + } + + /** + * Creates a new exception with the specified results, detail message and cause. + * + * @param results The resolution results at the point the exception occurred, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public ArtifactResolutionException( List results, String message, Throwable cause ) + { + super( message, cause ); + this.results = ( results != null ) ? results : Collections. emptyList(); + } + + /** + * Gets the resolution results at the point the exception occurred. Despite being incomplete, callers might want to + * use these results to fail gracefully and continue their operation with whatever interim data has been gathered. + * + * @return The resolution results or {@code null} if unknown. + */ + public List getResults() + { + return results; + } + + /** + * Gets the first result from {@link #getResults()}. This is a convenience method for cases where callers know only + * a single result/request is involved. + * + * @return The (first) resolution result or {@code null} if none. + */ + public ArtifactResult getResult() + { + return ( results != null && !results.isEmpty() ) ? results.get( 0 ) : null; + } + + private static String getMessage( List results ) + { + StringBuilder buffer = new StringBuilder( 256 ); + + buffer.append( "The following artifacts could not be resolved: " ); + + int unresolved = 0; + + String sep = ""; + for ( ArtifactResult result : results ) + { + if ( !result.isResolved() ) + { + unresolved++; + + buffer.append( sep ); + buffer.append( result.getRequest().getArtifact() ); + sep = ", "; + } + } + + Throwable cause = getCause( results ); + if ( cause != null ) + { + if ( unresolved == 1 ) + { + buffer.setLength( 0 ); + buffer.append( cause.getMessage() ); + } + else + { + buffer.append( ": " ).append( cause.getMessage() ); + } + } + + return buffer.toString(); + } + + private static Throwable getCause( List results ) + { + for ( ArtifactResult result : results ) + { + if ( !result.isResolved() ) + { + Throwable notFound = null, offline = null; + for ( Throwable t : result.getExceptions() ) + { + if ( t instanceof ArtifactNotFoundException ) + { + if ( notFound == null ) + { + notFound = t; + } + if ( offline == null && t.getCause() instanceof RepositoryOfflineException ) + { + offline = t; + } + } + else + { + return t; + } + + } + if ( offline != null ) + { + return offline; + } + if ( notFound != null ) + { + return notFound; + } + } + } + return null; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResult.java new file mode 100644 index 000000000..106ffe02b --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResult.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.ArtifactRepository; +import org.eclipse.aether.transfer.ArtifactNotFoundException; + +/** + * The result of an artifact resolution request. + * + * @see RepositorySystem#resolveArtifacts(RepositorySystemSession, java.util.Collection) + * @see Artifact#getFile() + */ +public final class ArtifactResult +{ + + private final ArtifactRequest request; + + private List exceptions; + + private Artifact artifact; + + private ArtifactRepository repository; + + /** + * Creates a new result for the specified request. + * + * @param request The resolution request, must not be {@code null}. + */ + public ArtifactResult( ArtifactRequest request ) + { + if ( request == null ) + { + throw new IllegalArgumentException( "resolution request has not been specified" ); + } + this.request = request; + exceptions = Collections.emptyList(); + } + + /** + * Gets the resolution request that was made. + * + * @return The resolution request, never {@code null}. + */ + public ArtifactRequest getRequest() + { + return request; + } + + /** + * Gets the resolved artifact (if any). Use {@link #getExceptions()} to query the errors that occurred while trying + * to resolve the artifact. + * + * @return The resolved artifact or {@code null} if the resolution failed. + */ + public Artifact getArtifact() + { + return artifact; + } + + /** + * Sets the resolved artifact. + * + * @param artifact The resolved artifact, may be {@code null} if the resolution failed. + * @return This result for chaining, never {@code null}. + */ + public ArtifactResult setArtifact( Artifact artifact ) + { + this.artifact = artifact; + return this; + } + + /** + * Gets the exceptions that occurred while resolving the artifact. Note that this list can be non-empty even if the + * artifact was successfully resolved, e.g. when one of the contacted remote repositories didn't contain the + * artifact but a later repository eventually contained it. + * + * @return The exceptions that occurred, never {@code null}. + * @see #isResolved() + */ + public List getExceptions() + { + return exceptions; + } + + /** + * Records the specified exception while resolving the artifact. + * + * @param exception The exception to record, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactResult addException( Exception exception ) + { + if ( exception != null ) + { + if ( exceptions.isEmpty() ) + { + exceptions = new ArrayList(); + } + exceptions.add( exception ); + } + return this; + } + + /** + * Gets the repository from which the artifact was eventually resolved. Note that successive resolutions of the same + * artifact might yield different results if the employed local repository does not track the origin of an artifact. + * + * @return The repository from which the artifact was resolved or {@code null} if unknown. + */ + public ArtifactRepository getRepository() + { + return repository; + } + + /** + * Sets the repository from which the artifact was resolved. + * + * @param repository The repository from which the artifact was resolved, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public ArtifactResult setRepository( ArtifactRepository repository ) + { + this.repository = repository; + return this; + } + + /** + * Indicates whether the requested artifact was resolved. Note that the artifact might have been successfully + * resolved despite {@link #getExceptions()} indicating transfer errors while trying to fetch the artifact from some + * of the specified remote repositories. + * + * @return {@code true} if the artifact was resolved, {@code false} otherwise. + * @see Artifact#getFile() + */ + public boolean isResolved() + { + return getArtifact() != null && getArtifact().getFile() != null; + } + + /** + * Indicates whether the requested artifact is not present in any of the specified repositories. + * + * @return {@code true} if the artifact is not present in any repository, {@code false} otherwise. + */ + public boolean isMissing() + { + for ( Exception e : getExceptions() ) + { + if ( !( e instanceof ArtifactNotFoundException ) ) + { + return false; + } + } + return !isResolved(); + } + + @Override + public String toString() + { + return getArtifact() + " < " + getRepository(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyRequest.java new file mode 100644 index 000000000..f55aff7bb --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyRequest.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.graph.DependencyFilter; +import org.eclipse.aether.graph.DependencyNode; + +/** + * A request to resolve transitive dependencies. This request can either be supplied with a {@link CollectRequest} to + * calculate the transitive dependencies or with an already resolved dependency graph. + * + * @see RepositorySystem#resolveDependencies(RepositorySystemSession, DependencyRequest) + * @see Artifact#getFile() + */ +public final class DependencyRequest +{ + + private DependencyNode root; + + private CollectRequest collectRequest; + + private DependencyFilter filter; + + private RequestTrace trace; + + /** + * Creates an uninitialized request. Note that either {@link #setRoot(DependencyNode)} or + * {@link #setCollectRequest(CollectRequest)} must eventually be called to create a valid request. + */ + public DependencyRequest() + { + // enables default constructor + } + + /** + * Creates a request for the specified dependency graph and with the given resolution filter. + * + * @param node The root node of the dependency graph whose artifacts should be resolved, may be {@code null}. + * @param filter The resolution filter to use, may be {@code null}. + */ + public DependencyRequest( DependencyNode node, DependencyFilter filter ) + { + setRoot( node ); + setFilter( filter ); + } + + /** + * Creates a request for the specified collect request and with the given resolution filter. + * + * @param request The collect request used to calculate the dependency graph whose artifacts should be resolved, may + * be {@code null}. + * @param filter The resolution filter to use, may be {@code null}. + */ + public DependencyRequest( CollectRequest request, DependencyFilter filter ) + { + setCollectRequest( request ); + setFilter( filter ); + } + + /** + * Gets the root node of the dependency graph whose artifacts should be resolved. + * + * @return The root node of the dependency graph or {@code null} if none. + */ + public DependencyNode getRoot() + { + return root; + } + + /** + * Sets the root node of the dependency graph whose artifacts should be resolved. When this request is processed, + * the nodes of the given dependency graph will be updated to refer to the resolved artifacts. Eventually, either + * {@link #setRoot(DependencyNode)} or {@link #setCollectRequest(CollectRequest)} must be called to create a valid + * request. + * + * @param root The root node of the dependency graph, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public DependencyRequest setRoot( DependencyNode root ) + { + this.root = root; + return this; + } + + /** + * Gets the collect request used to calculate the dependency graph whose artifacts should be resolved. + * + * @return The collect request or {@code null} if none. + */ + public CollectRequest getCollectRequest() + { + return collectRequest; + } + + /** + * Sets the collect request used to calculate the dependency graph whose artifacts should be resolved. Eventually, + * either {@link #setRoot(DependencyNode)} or {@link #setCollectRequest(CollectRequest)} must be called to create a + * valid request. If this request is supplied with a dependency node via {@link #setRoot(DependencyNode)}, the + * collect request is ignored. + * + * @param collectRequest The collect request, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public DependencyRequest setCollectRequest( CollectRequest collectRequest ) + { + this.collectRequest = collectRequest; + return this; + } + + /** + * Gets the resolution filter used to select which artifacts of the dependency graph should be resolved. + * + * @return The resolution filter or {@code null} to resolve all artifacts of the dependency graph. + */ + public DependencyFilter getFilter() + { + return filter; + } + + /** + * Sets the resolution filter used to select which artifacts of the dependency graph should be resolved. For + * example, use this filter to restrict resolution to dependencies of a certain scope. + * + * @param filter The resolution filter, may be {@code null} to resolve all artifacts of the dependency graph. + * @return This request for chaining, never {@code null}. + */ + public DependencyRequest setFilter( DependencyFilter filter ) + { + this.filter = filter; + return this; + } + + /** + * Gets the trace information that describes the higher level request/operation in which this request is issued. + * + * @return The trace information about the higher level operation or {@code null} if none. + */ + public RequestTrace getTrace() + { + return trace; + } + + /** + * Sets the trace information that describes the higher level request/operation in which this request is issued. + * + * @param trace The trace information about the higher level operation, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public DependencyRequest setTrace( RequestTrace trace ) + { + this.trace = trace; + return this; + } + + @Override + public String toString() + { + if ( root != null ) + { + return String.valueOf( root ); + } + return String.valueOf( collectRequest ); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResolutionException.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResolutionException.java new file mode 100644 index 000000000..27d9bb2a9 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResolutionException.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import org.eclipse.aether.RepositoryException; + +/** + * Thrown in case of a unresolvable dependencies. + */ +public class DependencyResolutionException + extends RepositoryException +{ + + private final transient DependencyResult result; + + /** + * Creates a new exception with the specified result and cause. + * + * @param result The dependency result at the point the exception occurred, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public DependencyResolutionException( DependencyResult result, Throwable cause ) + { + super( getMessage( cause ), cause ); + this.result = result; + } + + /** + * Creates a new exception with the specified result, detail message and cause. + * + * @param result The dependency result at the point the exception occurred, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public DependencyResolutionException( DependencyResult result, String message, Throwable cause ) + { + super( message, cause ); + this.result = result; + } + + private static String getMessage( Throwable cause ) + { + String msg = null; + if ( cause != null ) + { + msg = cause.getMessage(); + } + if ( msg == null || msg.length() <= 0 ) + { + msg = "Could not resolve transitive dependencies"; + } + return msg; + } + + /** + * Gets the dependency result at the point the exception occurred. Despite being incomplete, callers might want to + * use this result to fail gracefully and continue their operation with whatever interim data has been gathered. + * + * @return The dependency result or {@code null} if unknown. + */ + public DependencyResult getResult() + { + return result; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResult.java new file mode 100644 index 000000000..3cc8d3a94 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResult.java @@ -0,0 +1,186 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.graph.DependencyCycle; +import org.eclipse.aether.graph.DependencyNode; + +/** + * The result of a dependency resolution request. + * + * @see RepositorySystem#resolveDependencies(RepositorySystemSession, DependencyRequest) + */ +public final class DependencyResult +{ + + private final DependencyRequest request; + + private DependencyNode root; + + private List cycles; + + private List collectExceptions; + + private List artifactResults; + + /** + * Creates a new result for the specified request. + * + * @param request The resolution request, must not be {@code null}. + */ + public DependencyResult( DependencyRequest request ) + { + if ( request == null ) + { + throw new IllegalArgumentException( "dependency request has not been specified" ); + } + this.request = request; + root = request.getRoot(); + cycles = Collections.emptyList(); + collectExceptions = Collections.emptyList(); + artifactResults = Collections.emptyList(); + } + + /** + * Gets the resolution request that was made. + * + * @return The resolution request, never {@code null}. + */ + public DependencyRequest getRequest() + { + return request; + } + + /** + * Gets the root node of the resolved dependency graph. Note that this dependency graph might be + * incomplete/unfinished in case of {@link #getCollectExceptions()} indicating errors during its calculation. + * + * @return The root node of the resolved dependency graph or {@code null} if none. + */ + public DependencyNode getRoot() + { + return root; + } + + /** + * Sets the root node of the resolved dependency graph. + * + * @param root The root node of the resolved dependency graph, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public DependencyResult setRoot( DependencyNode root ) + { + this.root = root; + return this; + } + + /** + * Gets the dependency cycles that were encountered while building the dependency graph. Note that dependency cycles + * will only be reported here if the underlying request was created from a + * {@link org.eclipse.aether.collection.CollectRequest CollectRequest}. If the underlying {@link DependencyRequest} + * was created from an existing dependency graph, information about cycles will not be available in this result. + * + * @return The dependency cycles in the (raw) graph, never {@code null}. + */ + public List getCycles() + { + return cycles; + } + + /** + * Records the specified dependency cycles while building the dependency graph. + * + * @param cycles The dependency cycles to record, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public DependencyResult setCycles( List cycles ) + { + if ( cycles == null ) + { + this.cycles = Collections.emptyList(); + } + else + { + this.cycles = cycles; + } + return this; + } + + /** + * Gets the exceptions that occurred while building the dependency graph. + * + * @return The exceptions that occurred, never {@code null}. + */ + public List getCollectExceptions() + { + return collectExceptions; + } + + /** + * Records the specified exceptions while building the dependency graph. + * + * @param exceptions The exceptions to record, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public DependencyResult setCollectExceptions( List exceptions ) + { + if ( exceptions == null ) + { + this.collectExceptions = Collections.emptyList(); + } + else + { + this.collectExceptions = exceptions; + } + return this; + } + + /** + * Gets the resolution results for the dependency artifacts that matched {@link DependencyRequest#getFilter()}. + * + * @return The resolution results for the dependency artifacts, never {@code null}. + */ + public List getArtifactResults() + { + return artifactResults; + } + + /** + * Sets the resolution results for the artifacts that matched {@link DependencyRequest#getFilter()}. + * + * @param results The resolution results for the artifacts, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public DependencyResult setArtifactResults( List results ) + { + if ( results == null ) + { + this.artifactResults = Collections.emptyList(); + } + else + { + this.artifactResults = results; + } + return this; + } + + @Override + public String toString() + { + return String.valueOf( artifactResults ); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataRequest.java new file mode 100644 index 000000000..2f6c5f1d0 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataRequest.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * A request to resolve metadata from either a remote repository or the local repository. + * + * @see RepositorySystem#resolveMetadata(RepositorySystemSession, java.util.Collection) + * @see Metadata#getFile() + */ +public final class MetadataRequest +{ + + private Metadata metadata; + + private RemoteRepository repository; + + private String context = ""; + + private boolean deleteLocalCopyIfMissing; + + private boolean favorLocalRepository; + + private RequestTrace trace; + + /** + * Creates an uninitialized request. + */ + public MetadataRequest() + { + // enables default constructor + } + + /** + * Creates a request to resolve the specified metadata from the local repository. + * + * @param metadata The metadata to resolve, may be {@code null}. + */ + public MetadataRequest( Metadata metadata ) + { + setMetadata( metadata ); + } + + /** + * Creates a request with the specified properties. + * + * @param metadata The metadata to resolve, may be {@code null}. + * @param repository The repository to resolve the metadata from, may be {@code null} to resolve from the local + * repository. + * @param context The context in which this request is made, may be {@code null}. + */ + public MetadataRequest( Metadata metadata, RemoteRepository repository, String context ) + { + setMetadata( metadata ); + setRepository( repository ); + setRequestContext( context ); + } + + /** + * Gets the metadata to resolve. + * + * @return The metadata or {@code null} if not set. + */ + public Metadata getMetadata() + { + return metadata; + } + + /** + * Sets the metadata to resolve. + * + * @param metadata The metadata, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public MetadataRequest setMetadata( Metadata metadata ) + { + this.metadata = metadata; + return this; + } + + /** + * Gets the repository from which the metadata should be resolved. + * + * @return The repository or {@code null} to resolve from the local repository. + */ + public RemoteRepository getRepository() + { + return repository; + } + + /** + * Sets the repository from which the metadata should be resolved. + * + * @param repository The repository, may be {@code null} to resolve from the local repository. + * @return This request for chaining, never {@code null}. + */ + public MetadataRequest setRepository( RemoteRepository repository ) + { + this.repository = repository; + return this; + } + + /** + * Gets the context in which this request is made. + * + * @return The context, never {@code null}. + */ + public String getRequestContext() + { + return context; + } + + /** + * Sets the context in which this request is made. + * + * @param context The context, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public MetadataRequest setRequestContext( String context ) + { + this.context = ( context != null ) ? context : ""; + return this; + } + + /** + * Indicates whether the locally cached copy of the metadata should be removed if the corresponding file does not + * exist (any more) in the remote repository. + * + * @return {@code true} if locally cached metadata should be deleted if no corresponding remote file exists, + * {@code false} to keep the local copy. + */ + public boolean isDeleteLocalCopyIfMissing() + { + return deleteLocalCopyIfMissing; + } + + /** + * Controls whether the locally cached copy of the metadata should be removed if the corresponding file does not + * exist (any more) in the remote repository. + * + * @param deleteLocalCopyIfMissing {@code true} if locally cached metadata should be deleted if no corresponding + * remote file exists, {@code false} to keep the local copy. + * @return This request for chaining, never {@code null}. + */ + public MetadataRequest setDeleteLocalCopyIfMissing( boolean deleteLocalCopyIfMissing ) + { + this.deleteLocalCopyIfMissing = deleteLocalCopyIfMissing; + return this; + } + + /** + * Indicates whether the metadata resolution should be suppressed if the corresponding metadata of the local + * repository is up-to-date according to the update policy of the remote repository. In this case, the metadata + * resolution will even be suppressed if no local copy of the remote metadata exists yet. + * + * @return {@code true} to suppress resolution of remote metadata if the corresponding metadata of the local + * repository is up-to-date, {@code false} to resolve the remote metadata normally according to the update + * policy. + */ + public boolean isFavorLocalRepository() + { + return favorLocalRepository; + } + + /** + * Controls resolution of remote metadata when already corresponding metadata of the local repository exists. In + * cases where the local repository's metadata is sufficient and going to be preferred, resolution of the remote + * metadata can be suppressed to avoid unnecessary network access. + * + * @param favorLocalRepository {@code true} to suppress resolution of remote metadata if the corresponding metadata + * of the local repository is up-to-date, {@code false} to resolve the remote metadata normally according + * to the update policy. + * @return This request for chaining, never {@code null}. + */ + public MetadataRequest setFavorLocalRepository( boolean favorLocalRepository ) + { + this.favorLocalRepository = favorLocalRepository; + return this; + } + + /** + * Gets the trace information that describes the higher level request/operation in which this request is issued. + * + * @return The trace information about the higher level operation or {@code null} if none. + */ + public RequestTrace getTrace() + { + return trace; + } + + /** + * Sets the trace information that describes the higher level request/operation in which this request is issued. + * + * @param trace The trace information about the higher level operation, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public MetadataRequest setTrace( RequestTrace trace ) + { + this.trace = trace; + return this; + } + + @Override + public String toString() + { + return getMetadata() + " < " + getRepository(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataResult.java new file mode 100644 index 000000000..3e5a7b874 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataResult.java @@ -0,0 +1,157 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.transfer.MetadataNotFoundException; + +/** + * The result of a metadata resolution request. + * + * @see RepositorySystem#resolveMetadata(RepositorySystemSession, java.util.Collection) + */ +public final class MetadataResult +{ + + private final MetadataRequest request; + + private Exception exception; + + private boolean updated; + + private Metadata metadata; + + /** + * Creates a new result for the specified request. + * + * @param request The resolution request, must not be {@code null}. + */ + public MetadataResult( MetadataRequest request ) + { + if ( request == null ) + { + throw new IllegalArgumentException( "metadata request has not been specified" ); + } + this.request = request; + } + + /** + * Gets the resolution request that was made. + * + * @return The resolution request, never {@code null}. + */ + public MetadataRequest getRequest() + { + return request; + } + + /** + * Gets the resolved metadata (if any). + * + * @return The resolved metadata or {@code null} if the resolution failed. + */ + public Metadata getMetadata() + { + return metadata; + } + + /** + * Sets the resolved metadata. + * + * @param metadata The resolved metadata, may be {@code null} if the resolution failed. + * @return This result for chaining, never {@code null}. + */ + public MetadataResult setMetadata( Metadata metadata ) + { + this.metadata = metadata; + return this; + } + + /** + * Records the specified exception while resolving the metadata. + * + * @param exception The exception to record, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public MetadataResult setException( Exception exception ) + { + this.exception = exception; + return this; + } + + /** + * Gets the exception that occurred while resolving the metadata. + * + * @return The exception that occurred or {@code null} if none. + */ + public Exception getException() + { + return exception; + } + + /** + * Sets the updated flag for the metadata. + * + * @param updated {@code true} if the metadata was actually fetched from the remote repository during the + * resolution, {@code false} if the metadata was resolved from a locally cached copy. + * @return This result for chaining, never {@code null}. + */ + public MetadataResult setUpdated( boolean updated ) + { + this.updated = updated; + return this; + } + + /** + * Indicates whether the metadata was actually fetched from the remote repository or resolved from the local cache. + * If metadata has been locally cached during a previous resolution request and this local copy is still up-to-date + * according to the remote repository's update policy, no remote access is made. + * + * @return {@code true} if the metadata was actually fetched from the remote repository during the resolution, + * {@code false} if the metadata was resolved from a locally cached copy. + */ + public boolean isUpdated() + { + return updated; + } + + /** + * Indicates whether the requested metadata was resolved. Note that the metadata might have been successfully + * resolved (from the local cache) despite {@link #getException()} indicating a transfer error while trying to + * refetch the metadata from the remote repository. + * + * @return {@code true} if the metadata was resolved, {@code false} otherwise. + * @see Metadata#getFile() + */ + public boolean isResolved() + { + return getMetadata() != null && getMetadata().getFile() != null; + } + + /** + * Indicates whether the requested metadata is not present in the remote repository. + * + * @return {@code true} if the metadata is not present in the remote repository, {@code false} otherwise. + */ + public boolean isMissing() + { + return getException() instanceof MetadataNotFoundException; + } + + @Override + public String toString() + { + return getMetadata() + ( isUpdated() ? " (updated)" : " (cached)" ); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicy.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicy.java new file mode 100644 index 000000000..50d1a0174 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicy.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2012, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.metadata.Metadata; + +/** + * Controls the caching of resolution errors for artifacts/metadata from remote repositories. If caching is enabled for + * a given resource, a marker will be set (usually somewhere in the local repository) to suppress repeated resolution + * attempts for the broken resource, thereby avoiding expensive but useless network IO. The error marker is considered + * stale once the repository's update policy has expired at which point a future resolution attempt will be allowed. + * Error caching considers the current network settings such that fixes to the configuration like authentication or + * proxy automatically trigger revalidation with the remote side regardless of the time elapsed since the previous + * resolution error. + * + * @see RepositorySystemSession#getResolutionErrorPolicy() + */ +public interface ResolutionErrorPolicy +{ + + /** + * Bit mask indicating that resolution errors should not be cached in the local repository. This forces the system + * to always query the remote repository for locally missing artifacts/metadata. + */ + int CACHE_DISABLED = 0x00; + + /** + * Bit flag indicating whether missing artifacts/metadata should be cached in the local repository. If caching is + * enabled, resolution will not be reattempted until the update policy for the affected resource has expired. + */ + int CACHE_NOT_FOUND = 0x01; + + /** + * Bit flag indicating whether connectivity/transfer errors (e.g. unreachable host, bad authentication) should be + * cached in the local repository. If caching is enabled, resolution will not be reattempted until the update policy + * for the affected resource has expired. + */ + int CACHE_TRANSFER_ERROR = 0x02; + + /** + * Bit mask indicating that all resolution errors should be cached in the local repository. + */ + int CACHE_ALL = CACHE_NOT_FOUND | CACHE_TRANSFER_ERROR; + + /** + * Gets the error policy for an artifact. + * + * @param session The repository session during which the policy is determined, must not be {@code null}. + * @param request The policy request holding further details, must not be {@code null}. + * @return The bit mask describing the desired error policy. + */ + int getArtifactPolicy( RepositorySystemSession session, ResolutionErrorPolicyRequest request ); + + /** + * Gets the error policy for some metadata. + * + * @param session The repository session during which the policy is determined, must not be {@code null}. + * @param request The policy request holding further details, must not be {@code null}. + * @return The bit mask describing the desired error policy. + */ + int getMetadataPolicy( RepositorySystemSession session, ResolutionErrorPolicyRequest request ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicyRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicyRequest.java new file mode 100644 index 000000000..6d05cf33e --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicyRequest.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import org.eclipse.aether.repository.RemoteRepository; + +/** + * A query for the resolution error policy for a given artifact/metadata. + * + * @param The type of the affected repository item (artifact or metadata). + * @see ResolutionErrorPolicy + */ +public final class ResolutionErrorPolicyRequest +{ + + private T item; + + private RemoteRepository repository; + + /** + * Creates an uninitialized request. + */ + public ResolutionErrorPolicyRequest() + { + // enables default constructor + } + + /** + * Creates a request for the specified artifact/metadata and remote repository. + * + * @param item The artifact/metadata for which to determine the error policy, may be {@code null}. + * @param repository The repository from which the resolution is attempted, may be {@code null}. + */ + public ResolutionErrorPolicyRequest( T item, RemoteRepository repository ) + { + setItem( item ); + setRepository( repository ); + } + + /** + * Gets the artifact/metadata for which to determine the error policy. + * + * @return The artifact/metadata for which to determine the error policy or {@code null} if not set. + */ + public T getItem() + { + return item; + } + + /** + * Sets the artifact/metadata for which to determine the error policy. + * + * @param item The artifact/metadata for which to determine the error policy, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ResolutionErrorPolicyRequest setItem( T item ) + { + this.item = item; + return this; + } + + /** + * Gets the remote repository from which the resolution of the artifact/metadata is attempted. + * + * @return The involved remote repository or {@code null} if not set. + */ + public RemoteRepository getRepository() + { + return repository; + } + + /** + * Sets the remote repository from which the resolution of the artifact/metadata is attempted. + * + * @param repository The repository from which the resolution is attempted, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public ResolutionErrorPolicyRequest setRepository( RemoteRepository repository ) + { + this.repository = repository; + return this; + } + + @Override + public String toString() + { + return getItem() + " < " + getRepository(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeRequest.java new file mode 100644 index 000000000..b40feb658 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeRequest.java @@ -0,0 +1,181 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * A request to resolve a version range. + * + * @see RepositorySystem#resolveVersionRange(RepositorySystemSession, VersionRangeRequest) + */ +public final class VersionRangeRequest +{ + + private Artifact artifact; + + private List repositories = Collections.emptyList(); + + private String context = ""; + + private RequestTrace trace; + + /** + * Creates an uninitialized request. + */ + public VersionRangeRequest() + { + // enables default constructor + } + + /** + * Creates a request with the specified properties. + * + * @param artifact The artifact whose version range should be resolved, may be {@code null}. + * @param repositories The repositories to resolve the version from, may be {@code null}. + * @param context The context in which this request is made, may be {@code null}. + */ + public VersionRangeRequest( Artifact artifact, List repositories, String context ) + { + setArtifact( artifact ); + setRepositories( repositories ); + setRequestContext( context ); + } + + /** + * Gets the artifact whose version range shall be resolved. + * + * @return The artifact or {@code null} if not set. + */ + public Artifact getArtifact() + { + return artifact; + } + + /** + * Sets the artifact whose version range shall be resolved. + * + * @param artifact The artifact, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public VersionRangeRequest setArtifact( Artifact artifact ) + { + this.artifact = artifact; + return this; + } + + /** + * Gets the repositories to resolve the version range from. + * + * @return The repositories, never {@code null}. + */ + public List getRepositories() + { + return repositories; + } + + /** + * Sets the repositories to resolve the version range from. + * + * @param repositories The repositories, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public VersionRangeRequest setRepositories( List repositories ) + { + if ( repositories == null ) + { + this.repositories = Collections.emptyList(); + } + else + { + this.repositories = repositories; + } + return this; + } + + /** + * Adds the specified repository for the resolution. + * + * @param repository The repository to add, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public VersionRangeRequest addRepository( RemoteRepository repository ) + { + if ( repository != null ) + { + if ( this.repositories.isEmpty() ) + { + this.repositories = new ArrayList(); + } + this.repositories.add( repository ); + } + return this; + } + + /** + * Gets the context in which this request is made. + * + * @return The context, never {@code null}. + */ + public String getRequestContext() + { + return context; + } + + /** + * Sets the context in which this request is made. + * + * @param context The context, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public VersionRangeRequest setRequestContext( String context ) + { + this.context = ( context != null ) ? context : ""; + return this; + } + + /** + * Gets the trace information that describes the higher level request/operation in which this request is issued. + * + * @return The trace information about the higher level operation or {@code null} if none. + */ + public RequestTrace getTrace() + { + return trace; + } + + /** + * Sets the trace information that describes the higher level request/operation in which this request is issued. + * + * @param trace The trace information about the higher level operation, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public VersionRangeRequest setTrace( RequestTrace trace ) + { + this.trace = trace; + return this; + } + + @Override + public String toString() + { + return getArtifact() + " < " + getRepositories(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResolutionException.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResolutionException.java new file mode 100644 index 000000000..6e62e3ff9 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResolutionException.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import org.eclipse.aether.RepositoryException; + +/** + * Thrown in case of an unparseable or unresolvable version range. + */ +public class VersionRangeResolutionException + extends RepositoryException +{ + + private final transient VersionRangeResult result; + + /** + * Creates a new exception with the specified result. + * + * @param result The version range result at the point the exception occurred, may be {@code null}. + */ + public VersionRangeResolutionException( VersionRangeResult result ) + { + super( getMessage( result ), getCause( result ) ); + this.result = result; + } + + private static String getMessage( VersionRangeResult result ) + { + StringBuilder buffer = new StringBuilder( 256 ); + buffer.append( "Failed to resolve version range" ); + if ( result != null ) + { + buffer.append( " for " ).append( result.getRequest().getArtifact() ); + if ( !result.getExceptions().isEmpty() ) + { + buffer.append( ": " ).append( result.getExceptions().iterator().next().getMessage() ); + } + } + return buffer.toString(); + } + + private static Throwable getCause( VersionRangeResult result ) + { + Throwable cause = null; + if ( result != null && !result.getExceptions().isEmpty() ) + { + cause = result.getExceptions().get( 0 ); + } + return cause; + } + + /** + * Creates a new exception with the specified result and detail message. + * + * @param result The version range result at the point the exception occurred, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public VersionRangeResolutionException( VersionRangeResult result, String message ) + { + super( message ); + this.result = result; + } + + /** + * Creates a new exception with the specified result, detail message and cause. + * + * @param result The version range result at the point the exception occurred, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public VersionRangeResolutionException( VersionRangeResult result, String message, Throwable cause ) + { + super( message, cause ); + this.result = result; + } + + /** + * Gets the version range result at the point the exception occurred. Despite being incomplete, callers might want + * to use this result to fail gracefully and continue their operation with whatever interim data has been gathered. + * + * @return The version range result or {@code null} if unknown. + */ + public VersionRangeResult getResult() + { + return result; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResult.java new file mode 100644 index 000000000..fd233f1b2 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResult.java @@ -0,0 +1,231 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.ArtifactRepository; +import org.eclipse.aether.version.Version; +import org.eclipse.aether.version.VersionConstraint; + +/** + * The result of a version range resolution request. + * + * @see RepositorySystem#resolveVersionRange(RepositorySystemSession, VersionRangeRequest) + */ +public final class VersionRangeResult +{ + + private final VersionRangeRequest request; + + private List exceptions; + + private List versions; + + private Map repositories; + + private VersionConstraint versionConstraint; + + /** + * Creates a new result for the specified request. + * + * @param request The resolution request, must not be {@code null}. + */ + public VersionRangeResult( VersionRangeRequest request ) + { + if ( request == null ) + { + throw new IllegalArgumentException( "version range request has not been specified" ); + } + this.request = request; + exceptions = Collections.emptyList(); + versions = Collections.emptyList(); + repositories = Collections.emptyMap(); + } + + /** + * Gets the resolution request that was made. + * + * @return The resolution request, never {@code null}. + */ + public VersionRangeRequest getRequest() + { + return request; + } + + /** + * Gets the exceptions that occurred while resolving the version range. + * + * @return The exceptions that occurred, never {@code null}. + */ + public List getExceptions() + { + return exceptions; + } + + /** + * Records the specified exception while resolving the version range. + * + * @param exception The exception to record, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public VersionRangeResult addException( Exception exception ) + { + if ( exception != null ) + { + if ( exceptions.isEmpty() ) + { + exceptions = new ArrayList(); + } + exceptions.add( exception ); + } + return this; + } + + /** + * Gets the versions (in ascending order) that matched the requested range. + * + * @return The matching versions (if any), never {@code null}. + */ + public List getVersions() + { + return versions; + } + + /** + * Adds the specified version to the result. Note that versions must be added in ascending order. + * + * @param version The version to add, must not be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public VersionRangeResult addVersion( Version version ) + { + if ( versions.isEmpty() ) + { + versions = new ArrayList(); + } + versions.add( version ); + return this; + } + + /** + * Sets the versions (in ascending order) matching the requested range. + * + * @param versions The matching versions, may be empty or {@code null} if none. + * @return This result for chaining, never {@code null}. + */ + public VersionRangeResult setVersions( List versions ) + { + if ( versions == null ) + { + this.versions = Collections.emptyList(); + } + else + { + this.versions = versions; + } + return this; + } + + /** + * Gets the lowest version matching the requested range. + * + * @return The lowest matching version or {@code null} if no versions matched the requested range. + */ + public Version getLowestVersion() + { + if ( versions.isEmpty() ) + { + return null; + } + return versions.get( 0 ); + } + + /** + * Gets the highest version matching the requested range. + * + * @return The highest matching version or {@code null} if no versions matched the requested range. + */ + public Version getHighestVersion() + { + if ( versions.isEmpty() ) + { + return null; + } + return versions.get( versions.size() - 1 ); + } + + /** + * Gets the repository from which the specified version was resolved. + * + * @param version The version whose source repository should be retrieved, must not be {@code null}. + * @return The repository from which the version was resolved or {@code null} if unknown. + */ + public ArtifactRepository getRepository( Version version ) + { + return repositories.get( version ); + } + + /** + * Records the repository from which the specified version was resolved + * + * @param version The version whose source repository is to be recorded, must not be {@code null}. + * @param repository The repository from which the version was resolved, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public VersionRangeResult setRepository( Version version, ArtifactRepository repository ) + { + if ( repository != null ) + { + if ( repositories.isEmpty() ) + { + repositories = new HashMap(); + } + repositories.put( version, repository ); + } + return this; + } + + /** + * Gets the version constraint that was parsed from the artifact's version string. + * + * @return The parsed version constraint or {@code null}. + */ + public VersionConstraint getVersionConstraint() + { + return versionConstraint; + } + + /** + * Sets the version constraint that was parsed from the artifact's version string. + * + * @param versionConstraint The parsed version constraint, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public VersionRangeResult setVersionConstraint( VersionConstraint versionConstraint ) + { + this.versionConstraint = versionConstraint; + return this; + } + + @Override + public String toString() + { + return String.valueOf( repositories ); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRequest.java new file mode 100644 index 000000000..e18701be9 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRequest.java @@ -0,0 +1,181 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * A request to resolve a metaversion. + * + * @see RepositorySystem#resolveVersion(RepositorySystemSession, VersionRequest) + */ +public final class VersionRequest +{ + + private Artifact artifact; + + private List repositories = Collections.emptyList(); + + private String context = ""; + + private RequestTrace trace; + + /** + * Creates an uninitialized request. + */ + public VersionRequest() + { + // enables default constructor + } + + /** + * Creates a request with the specified properties. + * + * @param artifact The artifact whose (meta-)version should be resolved, may be {@code null}. + * @param repositories The repositories to resolve the version from, may be {@code null}. + * @param context The context in which this request is made, may be {@code null}. + */ + public VersionRequest( Artifact artifact, List repositories, String context ) + { + setArtifact( artifact ); + setRepositories( repositories ); + setRequestContext( context ); + } + + /** + * Gets the artifact whose (meta-)version shall be resolved. + * + * @return The artifact or {@code null} if not set. + */ + public Artifact getArtifact() + { + return artifact; + } + + /** + * Sets the artifact whose (meta-)version shall be resolved. + * + * @param artifact The artifact, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public VersionRequest setArtifact( Artifact artifact ) + { + this.artifact = artifact; + return this; + } + + /** + * Gets the repositories to resolve the version from. + * + * @return The repositories, never {@code null}. + */ + public List getRepositories() + { + return repositories; + } + + /** + * Sets the repositories to resolve the version from. + * + * @param repositories The repositories, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public VersionRequest setRepositories( List repositories ) + { + if ( repositories == null ) + { + this.repositories = Collections.emptyList(); + } + else + { + this.repositories = repositories; + } + return this; + } + + /** + * Adds the specified repository for the resolution. + * + * @param repository The repository to add, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public VersionRequest addRepository( RemoteRepository repository ) + { + if ( repository != null ) + { + if ( this.repositories.isEmpty() ) + { + this.repositories = new ArrayList(); + } + this.repositories.add( repository ); + } + return this; + } + + /** + * Gets the context in which this request is made. + * + * @return The context, never {@code null}. + */ + public String getRequestContext() + { + return context; + } + + /** + * Sets the context in which this request is made. + * + * @param context The context, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public VersionRequest setRequestContext( String context ) + { + this.context = ( context != null ) ? context : ""; + return this; + } + + /** + * Gets the trace information that describes the higher level request/operation in which this request is issued. + * + * @return The trace information about the higher level operation or {@code null} if none. + */ + public RequestTrace getTrace() + { + return trace; + } + + /** + * Sets the trace information that describes the higher level request/operation in which this request is issued. + * + * @param trace The trace information about the higher level operation, may be {@code null}. + * @return This request for chaining, never {@code null}. + */ + public VersionRequest setTrace( RequestTrace trace ) + { + this.trace = trace; + return this; + } + + @Override + public String toString() + { + return getArtifact() + " < " + getRepositories(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResolutionException.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResolutionException.java new file mode 100644 index 000000000..25f381e11 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResolutionException.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import org.eclipse.aether.RepositoryException; + +/** + * Thrown in case of an unresolvable metaversion. + */ +public class VersionResolutionException + extends RepositoryException +{ + + private final transient VersionResult result; + + /** + * Creates a new exception with the specified result. + * + * @param result The version result at the point the exception occurred, may be {@code null}. + */ + public VersionResolutionException( VersionResult result ) + { + super( getMessage( result ), getCause( result ) ); + this.result = result; + } + + private static String getMessage( VersionResult result ) + { + StringBuilder buffer = new StringBuilder( 256 ); + buffer.append( "Failed to resolve version" ); + if ( result != null ) + { + buffer.append( " for " ).append( result.getRequest().getArtifact() ); + if ( !result.getExceptions().isEmpty() ) + { + buffer.append( ": " ).append( result.getExceptions().iterator().next().getMessage() ); + } + } + return buffer.toString(); + } + + private static Throwable getCause( VersionResult result ) + { + Throwable cause = null; + if ( result != null && !result.getExceptions().isEmpty() ) + { + cause = result.getExceptions().get( 0 ); + } + return cause; + } + + /** + * Creates a new exception with the specified result and detail message. + * + * @param result The version result at the point the exception occurred, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public VersionResolutionException( VersionResult result, String message ) + { + super( message, getCause( result ) ); + this.result = result; + } + + /** + * Creates a new exception with the specified result, detail message and cause. + * + * @param result The version result at the point the exception occurred, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public VersionResolutionException( VersionResult result, String message, Throwable cause ) + { + super( message, cause ); + this.result = result; + } + + /** + * Gets the version result at the point the exception occurred. Despite being incomplete, callers might want to use + * this result to fail gracefully and continue their operation with whatever interim data has been gathered. + * + * @return The version result or {@code null} if unknown. + */ + public VersionResult getResult() + { + return result; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResult.java new file mode 100644 index 000000000..2e76b1c32 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResult.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.resolution; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.ArtifactRepository; + +/** + * The result of a version resolution request. + * + * @see RepositorySystem#resolveVersion(RepositorySystemSession, VersionRequest) + */ +public final class VersionResult +{ + + private final VersionRequest request; + + private List exceptions; + + private String version; + + private ArtifactRepository repository; + + /** + * Creates a new result for the specified request. + * + * @param request The resolution request, must not be {@code null}. + */ + public VersionResult( VersionRequest request ) + { + if ( request == null ) + { + throw new IllegalArgumentException( "version request has not been specified" ); + } + this.request = request; + exceptions = Collections.emptyList(); + } + + /** + * Gets the resolution request that was made. + * + * @return The resolution request, never {@code null}. + */ + public VersionRequest getRequest() + { + return request; + } + + /** + * Gets the exceptions that occurred while resolving the version. + * + * @return The exceptions that occurred, never {@code null}. + */ + public List getExceptions() + { + return exceptions; + } + + /** + * Records the specified exception while resolving the version. + * + * @param exception The exception to record, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public VersionResult addException( Exception exception ) + { + if ( exception != null ) + { + if ( exceptions.isEmpty() ) + { + exceptions = new ArrayList(); + } + exceptions.add( exception ); + } + return this; + } + + /** + * Gets the resolved version. + * + * @return The resolved version or {@code null} if the resolution failed. + */ + public String getVersion() + { + return version; + } + + /** + * Sets the resolved version. + * + * @param version The resolved version, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public VersionResult setVersion( String version ) + { + this.version = version; + return this; + } + + /** + * Gets the repository from which the version was eventually resolved. + * + * @return The repository from which the version was resolved or {@code null} if unknown. + */ + public ArtifactRepository getRepository() + { + return repository; + } + + /** + * Sets the repository from which the version was resolved. + * + * @param repository The repository from which the version was resolved, may be {@code null}. + * @return This result for chaining, never {@code null}. + */ + public VersionResult setRepository( ArtifactRepository repository ) + { + this.repository = repository; + return this; + } + + @Override + public String toString() + { + return getVersion() + " @ " + getRepository(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/package-info.java new file mode 100644 index 000000000..84b825b2e --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/package-info.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * The types supporting the resolution of artifacts and metadata from repositories. + */ +package org.eclipse.aether.resolution; + diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/AbstractTransferListener.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/AbstractTransferListener.java new file mode 100644 index 000000000..01aff1727 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/AbstractTransferListener.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +/** + * A skeleton implementation for custom transfer listeners. The callback methods in this class do nothing. + */ +public abstract class AbstractTransferListener + implements TransferListener +{ + + /** + * Enables subclassing. + */ + protected AbstractTransferListener() + { + } + + public void transferInitiated( TransferEvent event ) + throws TransferCancelledException + { + } + + public void transferStarted( TransferEvent event ) + throws TransferCancelledException + { + } + + public void transferProgressed( TransferEvent event ) + throws TransferCancelledException + { + } + + public void transferCorrupted( TransferEvent event ) + throws TransferCancelledException + { + } + + public void transferSucceeded( TransferEvent event ) + { + } + + public void transferFailed( TransferEvent event ) + { + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactNotFoundException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactNotFoundException.java new file mode 100644 index 000000000..381374384 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactNotFoundException.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.ArtifactProperties; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * Thrown when an artifact was not found in a particular repository. + */ +public class ArtifactNotFoundException + extends ArtifactTransferException +{ + + /** + * Creates a new exception with the specified artifact and repository. + * + * @param artifact The missing artifact, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + */ + public ArtifactNotFoundException( Artifact artifact, RemoteRepository repository ) + { + super( artifact, repository, getMessage( artifact, repository ) ); + } + + private static String getMessage( Artifact artifact, RemoteRepository repository ) + { + StringBuilder buffer = new StringBuilder( 256 ); + buffer.append( "Could not find artifact " ).append( artifact ); + buffer.append( getString( " in ", repository ) ); + if ( artifact != null ) + { + String localPath = artifact.getProperty( ArtifactProperties.LOCAL_PATH, null ); + if ( localPath != null && repository == null ) + { + buffer.append( " at specified path " ).append( localPath ); + } + String downloadUrl = artifact.getProperty( ArtifactProperties.DOWNLOAD_URL, null ); + if ( downloadUrl != null ) + { + buffer.append( ", try downloading from " ).append( downloadUrl ); + } + } + return buffer.toString(); + } + + /** + * Creates a new exception with the specified artifact, repository and detail message. + * + * @param artifact The missing artifact, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public ArtifactNotFoundException( Artifact artifact, RemoteRepository repository, String message ) + { + super( artifact, repository, message ); + } + + /** + * Creates a new exception with the specified artifact, repository and detail message. + * + * @param artifact The missing artifact, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param fromCache {@code true} if the exception was played back from the error cache, {@code false} if the + * exception actually just occurred. + */ + public ArtifactNotFoundException( Artifact artifact, RemoteRepository repository, String message, boolean fromCache ) + { + super( artifact, repository, message, fromCache ); + } + + /** + * Creates a new exception with the specified artifact, repository, detail message and cause. + * + * @param artifact The missing artifact, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public ArtifactNotFoundException( Artifact artifact, RemoteRepository repository, String message, Throwable cause ) + { + super( artifact, repository, message, cause ); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactTransferException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactTransferException.java new file mode 100644 index 000000000..5a481eeb3 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactTransferException.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * Thrown when an artifact could not be uploaded/downloaded to/from a particular remote repository. + */ +public class ArtifactTransferException + extends RepositoryException +{ + + private final transient Artifact artifact; + + private final transient RemoteRepository repository; + + private final boolean fromCache; + + static String getString( String prefix, RemoteRepository repository ) + { + if ( repository == null ) + { + return ""; + } + else + { + return prefix + repository.getId() + " (" + repository.getUrl() + ")"; + } + } + + /** + * Creates a new exception with the specified artifact, repository and detail message. + * + * @param artifact The untransferable artifact, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public ArtifactTransferException( Artifact artifact, RemoteRepository repository, String message ) + { + this( artifact, repository, message, false ); + } + + /** + * Creates a new exception with the specified artifact, repository and detail message. + * + * @param artifact The untransferable artifact, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param fromCache {@code true} if the exception was played back from the error cache, {@code false} if the + * exception actually just occurred. + */ + public ArtifactTransferException( Artifact artifact, RemoteRepository repository, String message, boolean fromCache ) + { + super( message ); + this.artifact = artifact; + this.repository = repository; + this.fromCache = fromCache; + } + + /** + * Creates a new exception with the specified artifact, repository and cause. + * + * @param artifact The untransferable artifact, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public ArtifactTransferException( Artifact artifact, RemoteRepository repository, Throwable cause ) + { + this( artifact, repository, "Could not transfer artifact " + artifact + getString( " from/to ", repository ) + + getMessage( ": ", cause ), cause ); + } + + /** + * Creates a new exception with the specified artifact, repository, detail message and cause. + * + * @param artifact The untransferable artifact, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public ArtifactTransferException( Artifact artifact, RemoteRepository repository, String message, Throwable cause ) + { + super( message, cause ); + this.artifact = artifact; + this.repository = repository; + this.fromCache = false; + } + + /** + * Gets the artifact that could not be transferred. + * + * @return The troublesome artifact or {@code null} if unknown. + */ + public Artifact getArtifact() + { + return artifact; + } + + /** + * Gets the remote repository involved in the transfer. + * + * @return The involved remote repository or {@code null} if unknown. + */ + public RemoteRepository getRepository() + { + return repository; + } + + /** + * Indicates whether this exception actually just occurred or was played back from the error cache. + * + * @return {@code true} if the exception was played back from the error cache, {@code false} if the exception + * actually occurred just now. + */ + public boolean isFromCache() + { + return fromCache; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ChecksumFailureException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ChecksumFailureException.java new file mode 100644 index 000000000..e3f248a4b --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ChecksumFailureException.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +import org.eclipse.aether.RepositoryException; + +/** + * Thrown in case of a checksum failure during an artifact/metadata download. + */ +public class ChecksumFailureException + extends RepositoryException +{ + + private final String expected; + + private final String actual; + + private final boolean retryWorthy; + + /** + * Creates a new exception with the specified expected and actual checksum. The resulting exception is + * {@link #isRetryWorthy() retry-worthy}. + * + * @param expected The expected checksum as declared by the hosting repository, may be {@code null}. + * @param actual The actual checksum as computed from the local bytes, may be {@code null}. + */ + public ChecksumFailureException( String expected, String actual ) + { + super( "Checksum validation failed, expected " + expected + " but is " + actual ); + this.expected = expected; + this.actual = actual; + retryWorthy = true; + } + + /** + * Creates a new exception with the specified detail message. The resulting exception is not + * {@link #isRetryWorthy() retry-worthy}. + * + * @param message The detail message, may be {@code null}. + */ + public ChecksumFailureException( String message ) + { + this( false, message, null ); + } + + /** + * Creates a new exception with the specified cause. The resulting exception is not {@link #isRetryWorthy() + * retry-worthy}. + * + * @param cause The exception that caused this one, may be {@code null}. + */ + public ChecksumFailureException( Throwable cause ) + { + this( "Checksum validation failed" + getMessage( ": ", cause ), cause ); + } + + /** + * Creates a new exception with the specified detail message and cause. The resulting exception is not + * {@link #isRetryWorthy() retry-worthy}. + * + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public ChecksumFailureException( String message, Throwable cause ) + { + this( false, message, cause ); + } + + /** + * Creates a new exception with the specified retry flag, detail message and cause. + * + * @param retryWorthy {@code true} if the exception is retry-worthy, {@code false} otherwise. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public ChecksumFailureException( boolean retryWorthy, String message, Throwable cause ) + { + super( message, cause ); + expected = actual = ""; + this.retryWorthy = retryWorthy; + } + + /** + * Gets the expected checksum for the downloaded artifact/metadata. + * + * @return The expected checksum as declared by the hosting repository or {@code null} if unknown. + */ + public String getExpected() + { + return expected; + } + + /** + * Gets the actual checksum for the downloaded artifact/metadata. + * + * @return The actual checksum as computed from the local bytes or {@code null} if unknown. + */ + public String getActual() + { + return actual; + } + + /** + * Indicates whether the corresponding download is retry-worthy. + * + * @return {@code true} if retrying the download might solve the checksum failure, {@code false} if the checksum + * failure is non-recoverable. + */ + public boolean isRetryWorthy() + { + return retryWorthy; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataNotFoundException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataNotFoundException.java new file mode 100644 index 000000000..af9a84001 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataNotFoundException.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * Thrown when metadata was not found in a particular repository. + */ +public class MetadataNotFoundException + extends MetadataTransferException +{ + + /** + * Creates a new exception with the specified metadata and local repository. + * + * @param metadata The missing metadata, may be {@code null}. + * @param repository The involved local repository, may be {@code null}. + */ + public MetadataNotFoundException( Metadata metadata, LocalRepository repository ) + { + super( metadata, null, "Could not find metadata " + metadata + getString( " in ", repository ) ); + } + + private static String getString( String prefix, LocalRepository repository ) + { + if ( repository == null ) + { + return ""; + } + else + { + return prefix + repository.getId() + " (" + repository.getBasedir() + ")"; + } + } + + /** + * Creates a new exception with the specified metadata and repository. + * + * @param metadata The missing metadata, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + */ + public MetadataNotFoundException( Metadata metadata, RemoteRepository repository ) + { + super( metadata, repository, "Could not find metadata " + metadata + getString( " in ", repository ) ); + } + + /** + * Creates a new exception with the specified metadata, repository and detail message. + * + * @param metadata The missing metadata, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public MetadataNotFoundException( Metadata metadata, RemoteRepository repository, String message ) + { + super( metadata, repository, message ); + } + + /** + * Creates a new exception with the specified metadata, repository and detail message. + * + * @param metadata The missing metadata, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param fromCache {@code true} if the exception was played back from the error cache, {@code false} if the + * exception actually just occurred. + */ + public MetadataNotFoundException( Metadata metadata, RemoteRepository repository, String message, boolean fromCache ) + { + super( metadata, repository, message, fromCache ); + } + + /** + * Creates a new exception with the specified metadata, repository, detail message and cause. + * + * @param metadata The missing metadata, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public MetadataNotFoundException( Metadata metadata, RemoteRepository repository, String message, Throwable cause ) + { + super( metadata, repository, message, cause ); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataTransferException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataTransferException.java new file mode 100644 index 000000000..f86b9864e --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataTransferException.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * Thrown when metadata could not be uploaded/downloaded to/from a particular remote repository. + */ +public class MetadataTransferException + extends RepositoryException +{ + + private final transient Metadata metadata; + + private final transient RemoteRepository repository; + + private final boolean fromCache; + + static String getString( String prefix, RemoteRepository repository ) + { + if ( repository == null ) + { + return ""; + } + else + { + return prefix + repository.getId() + " (" + repository.getUrl() + ")"; + } + } + + /** + * Creates a new exception with the specified metadata, repository and detail message. + * + * @param metadata The untransferable metadata, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public MetadataTransferException( Metadata metadata, RemoteRepository repository, String message ) + { + this( metadata, repository, message, false ); + } + + /** + * Creates a new exception with the specified metadata, repository and detail message. + * + * @param metadata The untransferable metadata, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param fromCache {@code true} if the exception was played back from the error cache, {@code false} if the + * exception actually just occurred. + */ + public MetadataTransferException( Metadata metadata, RemoteRepository repository, String message, boolean fromCache ) + { + super( message ); + this.metadata = metadata; + this.repository = repository; + this.fromCache = fromCache; + } + + /** + * Creates a new exception with the specified metadata, repository and cause. + * + * @param metadata The untransferable metadata, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public MetadataTransferException( Metadata metadata, RemoteRepository repository, Throwable cause ) + { + this( metadata, repository, "Could not transfer metadata " + metadata + getString( " from/to ", repository ) + + getMessage( ": ", cause ), cause ); + } + + /** + * Creates a new exception with the specified metadata, repository, detail message and cause. + * + * @param metadata The untransferable metadata, may be {@code null}. + * @param repository The involved remote repository, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public MetadataTransferException( Metadata metadata, RemoteRepository repository, String message, Throwable cause ) + { + super( message, cause ); + this.metadata = metadata; + this.repository = repository; + this.fromCache = false; + } + + /** + * Gets the metadata that could not be transferred. + * + * @return The troublesome metadata or {@code null} if unknown. + */ + public Metadata getMetadata() + { + return metadata; + } + + /** + * Gets the remote repository involved in the transfer. + * + * @return The involved remote repository or {@code null} if unknown. + */ + public RemoteRepository getRepository() + { + return repository; + } + + /** + * Indicates whether this exception actually just occurred or was played back from the error cache. + * + * @return {@code true} if the exception was played back from the error cache, {@code false} if the exception + * actually occurred just now. + */ + public boolean isFromCache() + { + return fromCache; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryConnectorException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryConnectorException.java new file mode 100644 index 000000000..c91be2b1f --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryConnectorException.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * Thrown in case of an unsupported remote repository type. + */ +public class NoRepositoryConnectorException + extends RepositoryException +{ + + private final transient RemoteRepository repository; + + /** + * Creates a new exception with the specified repository. + * + * @param repository The remote repository whose content type is not supported, may be {@code null}. + */ + public NoRepositoryConnectorException( RemoteRepository repository ) + { + this( repository, toMessage( repository ) ); + } + + /** + * Creates a new exception with the specified repository and detail message. + * + * @param repository The remote repository whose content type is not supported, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public NoRepositoryConnectorException( RemoteRepository repository, String message ) + { + super( message ); + this.repository = repository; + } + + /** + * Creates a new exception with the specified repository and cause. + * + * @param repository The remote repository whose content type is not supported, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public NoRepositoryConnectorException( RemoteRepository repository, Throwable cause ) + { + this( repository, toMessage( repository ), cause ); + } + + /** + * Creates a new exception with the specified repository, detail message and cause. + * + * @param repository The remote repository whose content type is not supported, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public NoRepositoryConnectorException( RemoteRepository repository, String message, Throwable cause ) + { + super( message, cause ); + this.repository = repository; + } + + private static String toMessage( RemoteRepository repository ) + { + if ( repository != null ) + { + return "No connector available to access repository " + repository.getId() + " (" + repository.getUrl() + + ") of type " + repository.getContentType(); + } + else + { + return "No connector available to access repository"; + } + } + + /** + * Gets the remote repository whose content type is not supported. + * + * @return The unsupported remote repository or {@code null} if unknown. + */ + public RemoteRepository getRepository() + { + return repository; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryLayoutException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryLayoutException.java new file mode 100644 index 000000000..31766018a --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryLayoutException.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * Thrown in case of an unsupported repository layout. + */ +public class NoRepositoryLayoutException + extends RepositoryException +{ + + private final transient RemoteRepository repository; + + /** + * Creates a new exception with the specified repository. + * + * @param repository The remote repository whose layout is not supported, may be {@code null}. + */ + public NoRepositoryLayoutException( RemoteRepository repository ) + { + this( repository, toMessage( repository ) ); + } + + /** + * Creates a new exception with the specified repository and detail message. + * + * @param repository The remote repository whose layout is not supported, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public NoRepositoryLayoutException( RemoteRepository repository, String message ) + { + super( message ); + this.repository = repository; + } + + /** + * Creates a new exception with the specified repository and cause. + * + * @param repository The remote repository whose layout is not supported, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public NoRepositoryLayoutException( RemoteRepository repository, Throwable cause ) + { + this( repository, toMessage( repository ), cause ); + } + + /** + * Creates a new exception with the specified repository, detail message and cause. + * + * @param repository The remote repository whose layout is not supported, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public NoRepositoryLayoutException( RemoteRepository repository, String message, Throwable cause ) + { + super( message, cause ); + this.repository = repository; + } + + private static String toMessage( RemoteRepository repository ) + { + if ( repository != null ) + { + return "Unsupported repository layout " + repository.getContentType(); + } + else + { + return "Unsupported repository layout"; + } + } + + /** + * Gets the remote repository whose layout is not supported. + * + * @return The unsupported remote repository or {@code null} if unknown. + */ + public RemoteRepository getRepository() + { + return repository; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoTransporterException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoTransporterException.java new file mode 100644 index 000000000..895b06608 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoTransporterException.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * Thrown in case of an unsupported transport protocol. + */ +public class NoTransporterException + extends RepositoryException +{ + + private final transient RemoteRepository repository; + + /** + * Creates a new exception with the specified repository. + * + * @param repository The remote repository whose transport layout is not supported, may be {@code null}. + */ + public NoTransporterException( RemoteRepository repository ) + { + this( repository, toMessage( repository ) ); + } + + /** + * Creates a new exception with the specified repository and detail message. + * + * @param repository The remote repository whose transport layout is not supported, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public NoTransporterException( RemoteRepository repository, String message ) + { + super( message ); + this.repository = repository; + } + + /** + * Creates a new exception with the specified repository and cause. + * + * @param repository The remote repository whose transport layout is not supported, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public NoTransporterException( RemoteRepository repository, Throwable cause ) + { + this( repository, toMessage( repository ), cause ); + } + + /** + * Creates a new exception with the specified repository, detail message and cause. + * + * @param repository The remote repository whose transport layout is not supported, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public NoTransporterException( RemoteRepository repository, String message, Throwable cause ) + { + super( message, cause ); + this.repository = repository; + } + + private static String toMessage( RemoteRepository repository ) + { + if ( repository != null ) + { + return "Unsupported transport protocol " + repository.getProtocol(); + } + else + { + return "Unsupported transport protocol"; + } + } + + /** + * Gets the remote repository whose transport protocol is not supported. + * + * @return The unsupported remote repository or {@code null} if unknown. + */ + public RemoteRepository getRepository() + { + return repository; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/RepositoryOfflineException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/RepositoryOfflineException.java new file mode 100644 index 000000000..1115054f4 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/RepositoryOfflineException.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2012, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * Thrown when a transfer could not be performed because a remote repository is not accessible in offline mode. + */ +public class RepositoryOfflineException + extends RepositoryException +{ + + private final transient RemoteRepository repository; + + private static String getMessage( RemoteRepository repository ) + { + if ( repository == null ) + { + return "Cannot access remote repositories in offline mode"; + } + else + { + return "Cannot access " + repository.getId() + " (" + repository.getUrl() + ") in offline mode"; + } + } + + /** + * Creates a new exception with the specified repository. + * + * @param repository The inaccessible remote repository, may be {@code null}. + */ + public RepositoryOfflineException( RemoteRepository repository ) + { + super( getMessage( repository ) ); + this.repository = repository; + } + + /** + * Creates a new exception with the specified repository and detail message. + * + * @param repository The inaccessible remote repository, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public RepositoryOfflineException( RemoteRepository repository, String message ) + { + super( message ); + this.repository = repository; + } + + /** + * Gets the remote repository that could not be accessed due to offline mode. + * + * @return The inaccessible remote repository or {@code null} if unknown. + */ + public RemoteRepository getRepository() + { + return repository; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferCancelledException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferCancelledException.java new file mode 100644 index 000000000..5f4ed5b6d --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferCancelledException.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +import org.eclipse.aether.RepositoryException; + +/** + * Thrown in case an upload/download was cancelled (e.g. due to user request). + */ +public class TransferCancelledException + extends RepositoryException +{ + + /** + * Creates a new exception with a stock detail message. + */ + public TransferCancelledException() + { + super( "The operation was cancelled." ); + } + + /** + * Creates a new exception with the specified detail message. + * + * @param message The detail message, may be {@code null}. + */ + public TransferCancelledException( String message ) + { + super( message ); + } + + /** + * Creates a new exception with the specified detail message and cause. + * + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public TransferCancelledException( String message, Throwable cause ) + { + super( message, cause ); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferEvent.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferEvent.java new file mode 100644 index 000000000..9be298fbe --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferEvent.java @@ -0,0 +1,423 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +import java.nio.ByteBuffer; + +import org.eclipse.aether.RepositorySystemSession; + +/** + * An event fired to a transfer listener during an artifact/metadata transfer. + * + * @see TransferListener + * @see TransferEvent.Builder + */ +public final class TransferEvent +{ + + /** + * The type of the event. + */ + public enum EventType + { + + /** + * @see TransferListener#transferInitiated(TransferEvent) + */ + INITIATED, + + /** + * @see TransferListener#transferStarted(TransferEvent) + */ + STARTED, + + /** + * @see TransferListener#transferProgressed(TransferEvent) + */ + PROGRESSED, + + /** + * @see TransferListener#transferCorrupted(TransferEvent) + */ + CORRUPTED, + + /** + * @see TransferListener#transferSucceeded(TransferEvent) + */ + SUCCEEDED, + + /** + * @see TransferListener#transferFailed(TransferEvent) + */ + FAILED + + } + + /** + * The type of the request/transfer being performed. + */ + public enum RequestType + { + + /** + * Download artifact/metadata. + */ + GET, + + /** + * Check artifact/metadata existence only. + */ + GET_EXISTENCE, + + /** + * Upload artifact/metadata. + */ + PUT, + + } + + private final EventType type; + + private final RequestType requestType; + + private final RepositorySystemSession session; + + private final TransferResource resource; + + private final ByteBuffer dataBuffer; + + private final long transferredBytes; + + private final Exception exception; + + TransferEvent( Builder builder ) + { + type = builder.type; + requestType = builder.requestType; + session = builder.session; + resource = builder.resource; + dataBuffer = builder.dataBuffer; + transferredBytes = builder.transferredBytes; + exception = builder.exception; + } + + /** + * Gets the type of the event. + * + * @return The type of the event, never {@code null}. + */ + public EventType getType() + { + return type; + } + + /** + * Gets the type of the request/transfer. + * + * @return The type of the request/transfer, never {@code null}. + */ + public RequestType getRequestType() + { + return requestType; + } + + /** + * Gets the repository system session during which the event occurred. + * + * @return The repository system session during which the event occurred, never {@code null}. + */ + public RepositorySystemSession getSession() + { + return session; + } + + /** + * Gets the resource that is being transferred. + * + * @return The resource being transferred, never {@code null}. + */ + public TransferResource getResource() + { + return resource; + } + + /** + * Gets the total number of bytes that have been transferred since the download/upload of the resource was started. + * If a download has been resumed, the returned count includes the bytes that were already downloaded during the + * previous attempt. In other words, the ratio of transferred bytes to the content length of the resource indicates + * the percentage of transfer completion. + * + * @return The total number of bytes that have been transferred since the transfer started, never negative. + * @see #getDataLength() + * @see TransferResource#getResumeOffset() + */ + public long getTransferredBytes() + { + return transferredBytes; + } + + /** + * Gets the byte buffer holding the transferred bytes since the last event. A listener must assume this buffer to be + * owned by the event source and must not change any byte in this buffer. Also, the buffer is only valid for the + * duration of the event callback, i.e. the next event might reuse the same buffer (with updated contents). + * Therefore, if the actual event processing is deferred, the byte buffer would have to be cloned to create an + * immutable snapshot of its contents. + * + * @return The (read-only) byte buffer or {@code null} if not applicable to the event, i.e. if the event type is not + * {@link EventType#PROGRESSED}. + */ + public ByteBuffer getDataBuffer() + { + return ( dataBuffer != null ) ? dataBuffer.asReadOnlyBuffer() : null; + } + + /** + * Gets the number of bytes that have been transferred since the last event. + * + * @return The number of bytes that have been transferred since the last event, possibly zero but never negative. + * @see #getTransferredBytes() + */ + public int getDataLength() + { + return ( dataBuffer != null ) ? dataBuffer.remaining() : 0; + } + + /** + * Gets the error that occurred during the transfer. + * + * @return The error that occurred or {@code null} if none. + */ + public Exception getException() + { + return exception; + } + + @Override + public String toString() + { + return getRequestType() + " " + getType() + " " + getResource(); + } + + /** + * A builder to create transfer events. + */ + public static final class Builder + { + + EventType type; + + RequestType requestType; + + RepositorySystemSession session; + + TransferResource resource; + + ByteBuffer dataBuffer; + + long transferredBytes; + + Exception exception; + + /** + * Creates a new transfer event builder for the specified session and the given resource. + * + * @param session The repository system session, must not be {@code null}. + * @param resource The resource being transferred, must not be {@code null}. + */ + public Builder( RepositorySystemSession session, TransferResource resource ) + { + if ( session == null ) + { + throw new IllegalArgumentException( "session not specified" ); + } + if ( resource == null ) + { + throw new IllegalArgumentException( "transfer resource not specified" ); + } + this.session = session; + this.resource = resource; + type = EventType.INITIATED; + requestType = RequestType.GET; + } + + private Builder( Builder prototype ) + { + session = prototype.session; + resource = prototype.resource; + type = prototype.type; + requestType = prototype.requestType; + dataBuffer = prototype.dataBuffer; + transferredBytes = prototype.transferredBytes; + exception = prototype.exception; + } + + /** + * Creates a new transfer event builder from the current values of this builder. The state of this builder + * remains unchanged. + * + * @return The new event builder, never {@code null}. + */ + public Builder copy() + { + return new Builder( this ); + } + + /** + * Sets the type of the event and resets event-specific fields. In more detail, the data buffer and the + * exception fields are set to {@code null}. Furthermore, the total number of transferred bytes is set to + * {@code 0} if the event type is {@link EventType#STARTED}. + * + * @param type The type of the event, must not be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder resetType( EventType type ) + { + if ( type == null ) + { + throw new IllegalArgumentException( "event type not specified" ); + } + this.type = type; + dataBuffer = null; + exception = null; + switch ( type ) + { + case INITIATED: + case STARTED: + transferredBytes = 0; + default: + } + return this; + } + + /** + * Sets the type of the event. When re-using the same builder to generate a sequence of events for one transfer, + * {@link #resetType(TransferEvent.EventType)} might be more handy. + * + * @param type The type of the event, must not be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setType( EventType type ) + { + if ( type == null ) + { + throw new IllegalArgumentException( "event type not specified" ); + } + this.type = type; + return this; + } + + /** + * Sets the type of the request/transfer. + * + * @param requestType The request/transfer type, must not be {@code null}. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setRequestType( RequestType requestType ) + { + if ( requestType == null ) + { + throw new IllegalArgumentException( "request type not specified" ); + } + this.requestType = requestType; + return this; + } + + /** + * Sets the total number of bytes that have been transferred so far during the download/upload of the resource. + * If a download is being resumed, the count must include the bytes that were already downloaded in the previous + * attempt and from which the current transfer started. In this case, the event type {@link EventType#STARTED} + * should indicate from what byte the download resumes. + * + * @param transferredBytes The total number of bytes that have been transferred so far during the + * download/upload of the resource, must not be negative. + * @return This event builder for chaining, never {@code null}. + * @see TransferResource#setResumeOffset(long) + */ + public Builder setTransferredBytes( long transferredBytes ) + { + if ( transferredBytes < 0 ) + { + throw new IllegalArgumentException( "number of transferred bytes cannot be negative" ); + } + this.transferredBytes = transferredBytes; + return this; + } + + /** + * Increments the total number of bytes that have been transferred so far during the download/upload. + * + * @param transferredBytes The number of bytes that have been transferred since the last event, must not be + * negative. + * @return This event builder for chaining, never {@code null}. + */ + public Builder addTransferredBytes( long transferredBytes ) + { + if ( transferredBytes < 0 ) + { + throw new IllegalArgumentException( "number of transferred bytes cannot be negative" ); + } + this.transferredBytes += transferredBytes; + return this; + } + + /** + * Sets the byte buffer holding the transferred bytes since the last event. + * + * @param buffer The byte buffer holding the transferred bytes since the last event, may be {@code null} if not + * applicable to the event. + * @param offset The starting point of valid bytes in the array. + * @param length The number of valid bytes, must not be negative. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setDataBuffer( byte[] buffer, int offset, int length ) + { + return setDataBuffer( ( buffer != null ) ? ByteBuffer.wrap( buffer, offset, length ) : null ); + } + + /** + * Sets the byte buffer holding the transferred bytes since the last event. + * + * @param dataBuffer The byte buffer holding the transferred bytes since the last event, may be {@code null} if + * not applicable to the event. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setDataBuffer( ByteBuffer dataBuffer ) + { + this.dataBuffer = dataBuffer; + return this; + } + + /** + * Sets the error that occurred during the transfer. + * + * @param exception The error that occurred during the transfer, may be {@code null} if none. + * @return This event builder for chaining, never {@code null}. + */ + public Builder setException( Exception exception ) + { + this.exception = exception; + return this; + } + + /** + * Builds a new transfer event from the current values of this builder. The state of the builder itself remains + * unchanged. + * + * @return The transfer event, never {@code null}. + */ + public TransferEvent build() + { + return new TransferEvent( this ); + } + + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferListener.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferListener.java new file mode 100644 index 000000000..26c016d89 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferListener.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +/** + * A listener being notified of artifact/metadata transfers from/to remote repositories. The listener may be called from + * an arbitrary thread. Reusing common regular expression syntax, the sequence of events is roughly as follows: + * + *
+ * INITIATED ( STARTED PROGRESSED* CORRUPTED? )* ( SUCCEEDED | FAILED )
+ * 
+ * + * Note: Implementors are strongly advised to inherit from {@link AbstractTransferListener} instead of directly + * implementing this interface. + * + * @see org.eclipse.aether.RepositorySystemSession#getTransferListener() + * @see org.eclipse.aether.RepositoryListener + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface TransferListener +{ + + /** + * Notifies the listener about the initiation of a transfer. This event gets fired before any actual network access + * to the remote repository and usually indicates some thread is now about to perform the transfer. For a given + * transfer request, this event is the first one being fired and it must be emitted exactly once. + * + * @param event The event details, must not be {@code null}. + * @throws TransferCancelledException If the transfer should be aborted. + */ + void transferInitiated( TransferEvent event ) + throws TransferCancelledException; + + /** + * Notifies the listener about the start of a data transfer. This event indicates a successful connection to the + * remote repository. In case of a download, the requested remote resource exists and its size is given by + * {@link TransferResource#getContentLength()} if possible. This event may be fired multiple times for given + * transfer request if said transfer needs to be repeated (e.g. in response to an authentication challenge). + * + * @param event The event details, must not be {@code null}. + * @throws TransferCancelledException If the transfer should be aborted. + */ + void transferStarted( TransferEvent event ) + throws TransferCancelledException; + + /** + * Notifies the listener about some progress in the data transfer. This event may even be fired if actually zero + * bytes have been transferred since the last event, for instance to enable cancellation. + * + * @param event The event details, must not be {@code null}. + * @throws TransferCancelledException If the transfer should be aborted. + */ + void transferProgressed( TransferEvent event ) + throws TransferCancelledException; + + /** + * Notifies the listener that a checksum validation failed. {@link TransferEvent#getException()} will be of type + * {@link ChecksumFailureException} and can be used to query further details about the expected/actual checksums. + * + * @param event The event details, must not be {@code null}. + * @throws TransferCancelledException If the transfer should be aborted. + */ + void transferCorrupted( TransferEvent event ) + throws TransferCancelledException; + + /** + * Notifies the listener about the successful completion of a transfer. This event must be fired exactly once for a + * given transfer request unless said request failed. + * + * @param event The event details, must not be {@code null}. + */ + void transferSucceeded( TransferEvent event ); + + /** + * Notifies the listener about the unsuccessful termination of a transfer. {@link TransferEvent#getException()} will + * provide further information about the failure. + * + * @param event The event details, must not be {@code null}. + */ + void transferFailed( TransferEvent event ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferResource.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferResource.java new file mode 100644 index 000000000..b9510fb90 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferResource.java @@ -0,0 +1,192 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transfer; + +import java.io.File; + +import org.eclipse.aether.RequestTrace; + +/** + * Describes a resource being uploaded or downloaded by the repository system. + */ +public final class TransferResource +{ + + private final String repositoryUrl; + + private final String resourceName; + + private final File file; + + private final long startTime; + + private final RequestTrace trace; + + private long contentLength = -1; + + private long resumeOffset; + + /** + * Creates a new transfer resource with the specified properties. + * + * @param repositoryUrl The base URL of the repository, may be {@code null} or empty if unknown. If not empty, a + * trailing slash will automatically be added if missing. + * @param resourceName The relative path to the resource within the repository, may be {@code null}. A leading slash + * (if any) will be automatically removed. + * @param file The source/target file involved in the transfer, may be {@code null}. + * @param trace The trace information, may be {@code null}. + */ + public TransferResource( String repositoryUrl, String resourceName, File file, RequestTrace trace ) + { + if ( repositoryUrl == null || repositoryUrl.length() <= 0 ) + { + this.repositoryUrl = ""; + } + else if ( repositoryUrl.endsWith( "/" ) ) + { + this.repositoryUrl = repositoryUrl; + } + else + { + this.repositoryUrl = repositoryUrl + '/'; + } + + if ( resourceName == null || resourceName.length() <= 0 ) + { + this.resourceName = ""; + } + else if ( resourceName.startsWith( "/" ) ) + { + this.resourceName = resourceName.substring( 1 ); + } + else + { + this.resourceName = resourceName; + } + + this.file = file; + + this.trace = trace; + + startTime = System.currentTimeMillis(); + } + + /** + * The base URL of the repository, e.g. "http://repo1.maven.org/maven2/". Unless the URL is unknown, it will be + * terminated by a trailing slash. + * + * @return The base URL of the repository or an empty string if unknown, never {@code null}. + */ + public String getRepositoryUrl() + { + return repositoryUrl; + } + + /** + * The path of the resource relative to the repository's base URL, e.g. "org/apache/maven/maven/3.0/maven-3.0.pom". + * + * @return The path of the resource, never {@code null}. + */ + public String getResourceName() + { + return resourceName; + } + + /** + * Gets the local file being uploaded or downloaded. When the repository system merely checks for the existence of a + * remote resource, no local file will be involved in the transfer. + * + * @return The source/target file involved in the transfer or {@code null} if none. + */ + public File getFile() + { + return file; + } + + /** + * The size of the resource in bytes. Note that the size of a resource during downloads might be unknown to the + * client which is usually the case when transfers employ compression like gzip. In general, the content length is + * not known until the transfer has {@link TransferListener#transferStarted(TransferEvent) started}. + * + * @return The size of the resource in bytes or a negative value if unknown. + */ + public long getContentLength() + { + return contentLength; + } + + /** + * Sets the size of the resource in bytes. + * + * @param contentLength The size of the resource in bytes or a negative value if unknown. + * @return This resource for chaining, never {@code null}. + */ + public TransferResource setContentLength( long contentLength ) + { + this.contentLength = contentLength; + return this; + } + + /** + * Gets the byte offset within the resource from which the download starts. A positive offset indicates a previous + * download attempt is being resumed, {@code 0} means the transfer starts at the first byte. + * + * @return The zero-based index of the first byte being transferred, never negative. + */ + public long getResumeOffset() + { + return resumeOffset; + } + + /** + * Sets the byte offset within the resource at which the download starts. + * + * @param resumeOffset The zero-based index of the first byte being transferred, must not be negative. + * @return This resource for chaining, never {@code null}. + */ + public TransferResource setResumeOffset( long resumeOffset ) + { + if ( resumeOffset < 0 ) + { + throw new IllegalArgumentException( "resume offset cannot be negative" ); + } + this.resumeOffset = resumeOffset; + return this; + } + + /** + * Gets the timestamp when the transfer of this resource was started. + * + * @return The timestamp when the transfer of this resource was started. + */ + public long getTransferStartTime() + { + return startTime; + } + + /** + * Gets the trace information that describes the higher level request/operation during which this resource is + * transferred. + * + * @return The trace information about the higher level operation or {@code null} if none. + */ + public RequestTrace getTrace() + { + return trace; + } + + @Override + public String toString() + { + return getRepositoryUrl() + getResourceName() + " <> " + getFile(); + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/package-info.java new file mode 100644 index 000000000..5ce9ff3ce --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/package-info.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * A listener and various exception types dealing with the transfer of a resource between the local system and a remote + * repository. + */ +package org.eclipse.aether.transfer; + diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/version/InvalidVersionSpecificationException.java b/org.argeo.slc.repo/src/org/eclipse/aether/version/InvalidVersionSpecificationException.java new file mode 100644 index 000000000..b3690c5a0 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/version/InvalidVersionSpecificationException.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.version; + +import org.eclipse.aether.RepositoryException; + +/** + * Thrown when a version or version range could not be parsed. + */ +public class InvalidVersionSpecificationException + extends RepositoryException +{ + + private final String version; + + /** + * Creates a new exception with the specified version and detail message. + * + * @param version The invalid version specification, may be {@code null}. + * @param message The detail message, may be {@code null}. + */ + public InvalidVersionSpecificationException( String version, String message ) + { + super( message ); + this.version = version; + } + + /** + * Creates a new exception with the specified version and cause. + * + * @param version The invalid version specification, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public InvalidVersionSpecificationException( String version, Throwable cause ) + { + super( "Could not parse version specification " + version + getMessage( ": ", cause ), cause ); + this.version = version; + } + + /** + * Creates a new exception with the specified version, detail message and cause. + * + * @param version The invalid version specification, may be {@code null}. + * @param message The detail message, may be {@code null}. + * @param cause The exception that caused this one, may be {@code null}. + */ + public InvalidVersionSpecificationException( String version, String message, Throwable cause ) + { + super( message, cause ); + this.version = version; + } + + /** + * Gets the version or version range that could not be parsed. + * + * @return The invalid version specification or {@code null} if unknown. + */ + public String getVersion() + { + return version; + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/version/Version.java b/org.argeo.slc.repo/src/org/eclipse/aether/version/Version.java new file mode 100644 index 000000000..4aceba6c0 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/version/Version.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.version; + +/** + * A parsed artifact version. + */ +public interface Version + extends Comparable +{ + + /** + * Gets the original string representation of the version. + * + * @return The string representation of the version, never {@code null}. + */ + String toString(); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionConstraint.java b/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionConstraint.java new file mode 100644 index 000000000..dcb3b68ff --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionConstraint.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.version; + +/** + * A constraint on versions for a dependency. A constraint can either consist of a version range (e.g. "[1, ]") or a + * single version (e.g. "1.1"). In the first case, the constraint expresses a hard requirement on a version matching the + * range. In the second case, the constraint expresses a soft requirement on a specific version (i.e. a recommendation). + */ +public interface VersionConstraint +{ + + /** + * Gets the version range of this constraint. + * + * @return The version range or {@code null} if none. + */ + VersionRange getRange(); + + /** + * Gets the version recommended by this constraint. + * + * @return The recommended version or {@code null} if none. + */ + Version getVersion(); + + /** + * Determines whether the specified version satisfies this constraint. In more detail, a version satisfies this + * constraint if it matches its version range or if this constraint has no version range and the specified version + * equals the version recommended by the constraint. + * + * @param version The version to test, must not be {@code null}. + * @return {@code true} if the specified version satisfies this constraint, {@code false} otherwise. + */ + boolean containsVersion( Version version ); + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionRange.java b/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionRange.java new file mode 100644 index 000000000..cbc2405b0 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionRange.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.version; + +/** + * A range of versions. + */ +public interface VersionRange +{ + + /** + * Determines whether the specified version is contained within this range. + * + * @param version The version to test, must not be {@code null}. + * @return {@code true} if this range contains the specified version, {@code false} otherwise. + */ + boolean containsVersion( Version version ); + + /** + * Gets a lower bound (if any) for this range. If existent, this range does not contain any version smaller than its + * lower bound. Note that complex version ranges might exclude some versions even within their bounds. + * + * @return A lower bound for this range or {@code null} is there is none. + */ + Bound getLowerBound(); + + /** + * Gets an upper bound (if any) for this range. If existent, this range does not contain any version greater than + * its upper bound. Note that complex version ranges might exclude some versions even within their bounds. + * + * @return An upper bound for this range or {@code null} is there is none. + */ + Bound getUpperBound(); + + /** + * A bound of a version range. + */ + static final class Bound + { + + private final Version version; + + private final boolean inclusive; + + /** + * Creates a new bound with the specified properties. + * + * @param version The bounding version, must not be {@code null}. + * @param inclusive A flag whether the specified version is included in the range or not. + */ + public Bound( Version version, boolean inclusive ) + { + if ( version == null ) + { + throw new IllegalArgumentException( "version missing" ); + } + this.version = version; + this.inclusive = inclusive; + } + + /** + * Gets the bounding version. + * + * @return The bounding version, never {@code null}. + */ + public Version getVersion() + { + return version; + } + + /** + * Indicates whether the bounding version is included in the range or not. + * + * @return {@code true} if the bounding version is included in the range, {@code false} if not. + */ + public boolean isInclusive() + { + return inclusive; + } + + @Override + public boolean equals( Object obj ) + { + if ( obj == this ) + { + return true; + } + else if ( obj == null || !getClass().equals( obj.getClass() ) ) + { + return false; + } + + Bound that = (Bound) obj; + return inclusive == that.inclusive && version.equals( that.version ); + } + + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + version.hashCode(); + hash = hash * 31 + ( inclusive ? 1 : 0 ); + return hash; + } + + @Override + public String toString() + { + return String.valueOf( version ); + } + + } + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionScheme.java b/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionScheme.java new file mode 100644 index 000000000..c19177a22 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionScheme.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.version; + +/** + * A version scheme that handles interpretation of version strings to facilitate their comparison. + */ +public interface VersionScheme +{ + + /** + * Parses the specified version string, for example "1.0". + * + * @param version The version string to parse, must not be {@code null}. + * @return The parsed version, never {@code null}. + * @throws InvalidVersionSpecificationException If the string violates the syntax rules of this scheme. + */ + Version parseVersion( String version ) + throws InvalidVersionSpecificationException; + + /** + * Parses the specified version range specification, for example "[1.0,2.0)". + * + * @param range The range specification to parse, must not be {@code null}. + * @return The parsed version range, never {@code null}. + * @throws InvalidVersionSpecificationException If the range specification violates the syntax rules of this scheme. + */ + VersionRange parseVersionRange( String range ) + throws InvalidVersionSpecificationException; + + /** + * Parses the specified version constraint specification, for example "1.0" or "[1.0,2.0),(2.0,)". + * + * @param constraint The constraint specification to parse, must not be {@code null}. + * @return The parsed version constraint, never {@code null}. + * @throws InvalidVersionSpecificationException If the constraint specification violates the syntax rules of this + * scheme. + */ + VersionConstraint parseVersionConstraint( final String constraint ) + throws InvalidVersionSpecificationException; + +} diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/version/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/version/package-info.java new file mode 100644 index 000000000..7ef8c85d9 --- /dev/null +++ b/org.argeo.slc.repo/src/org/eclipse/aether/version/package-info.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * The definition of a version scheme for parsing and comparing versions. + */ +package org.eclipse.aether.version; + diff --git a/org.argeo.slc.server.repo/META-INF/spring/maven.xml b/org.argeo.slc.server.repo/META-INF/spring/maven.xml deleted file mode 100644 index 8836ae4ee..000000000 --- a/org.argeo.slc.server.repo/META-INF/spring/maven.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.server.repo/META-INF/spring/repo-osgi.xml b/org.argeo.slc.server.repo/META-INF/spring/repo-osgi.xml index f0fcaaa4f..830303cce 100644 --- a/org.argeo.slc.server.repo/META-INF/spring/repo-osgi.xml +++ b/org.argeo.slc.server.repo/META-INF/spring/repo-osgi.xml @@ -25,31 +25,10 @@ filter="(cn=docs)" /> - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/org.argeo.slc.server.repo/META-INF/spring/services.xml b/org.argeo.slc.server.repo/META-INF/spring/services.xml index feca34890..454009e9d 100644 --- a/org.argeo.slc.server.repo/META-INF/spring/services.xml +++ b/org.argeo.slc.server.repo/META-INF/spring/services.xml @@ -34,12 +34,14 @@ - - - - - + + + + + + - - - - - + + + + + + - - \ No newline at end of file diff --git a/org.argeo.slc.server.repo/repository-h2.xml b/org.argeo.slc.server.repo/repository-h2.xml deleted file mode 100644 index c87f1d4f4..000000000 --- a/org.argeo.slc.server.repo/repository-h2.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.server.repo/repository-localfs.xml b/org.argeo.slc.server.repo/repository-localfs.xml deleted file mode 100644 index 3ab8a2906..000000000 --- a/org.argeo.slc.server.repo/repository-localfs.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.server.repo/repository-pg-dist.xml b/org.argeo.slc.server.repo/repository-pg-dist.xml deleted file mode 100644 index 0e40bc711..000000000 --- a/org.argeo.slc.server.repo/repository-pg-dist.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.server.repo/repository-pg-docs.xml b/org.argeo.slc.server.repo/repository-pg-docs.xml deleted file mode 100644 index d67b1030f..000000000 --- a/org.argeo.slc.server.repo/repository-pg-docs.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.server.repo/repository-pg-java.xml b/org.argeo.slc.server.repo/repository-pg-java.xml deleted file mode 100644 index 38326255f..000000000 --- a/org.argeo.slc.server.repo/repository-pg-java.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.server.repo/repository-pg-rpm.xml b/org.argeo.slc.server.repo/repository-pg-rpm.xml deleted file mode 100644 index b35028dc7..000000000 --- a/org.argeo.slc.server.repo/repository-pg-rpm.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/AetherTemplate.java b/org.argeo.slc.support/src/org/argeo/slc/aether/AetherTemplate.java deleted file mode 100644 index a83caa1e0..000000000 --- a/org.argeo.slc.support/src/org/argeo/slc/aether/AetherTemplate.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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.argeo.slc.aether; - -import java.io.File; -import java.util.List; - -import org.argeo.slc.SlcException; -import org.eclipse.aether.RepositorySystem; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.collection.CollectRequest; -import org.eclipse.aether.graph.Dependency; -import org.eclipse.aether.graph.DependencyNode; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.resolution.ArtifactRequest; -import org.eclipse.aether.resolution.ArtifactResolutionException; -import org.eclipse.aether.resolution.ArtifactResult; - -/** Simplifies access to Aether. */ -public class AetherTemplate { - private RepositorySystem repositorySystem; - private RepositorySystemSession repositorySystemSession; - private List remoteRepositories; - - /** Resolves the artifact in order to give access to its file. */ - public File getResolvedFile(Artifact artifact) { - try { - ArtifactRequest artifactRequest = new ArtifactRequest(artifact, - remoteRepositories, null); - ArtifactResult result = repositorySystem.resolveArtifact( - repositorySystemSession, artifactRequest); - return result.getArtifact().getFile(); - } catch (ArtifactResolutionException e) { - throw new SlcException("Cannot resolve " + artifact, e); - } - } - - /** - * Transitively resolves the dependencies of this artifact (with scope - * 'compile') - * - * @param artifact - * the artifact to resolve - */ - public DependencyNode resolveDependencies(Artifact artifact) { - return resolveDependencies(artifact, "compile"); - } - - /** - * Transitively resolves the dependencies of this artifact. - * - * @param artifact - * the artifact to resolve - * @param scope - * the scope - */ - public DependencyNode resolveDependencies(Artifact artifact, String scope) { - try { - Dependency dependency = new Dependency(artifact, scope); - CollectRequest collectRequest = new CollectRequest(); - collectRequest.setRoot(dependency); - for (RemoteRepository remoteRepository : remoteRepositories) - collectRequest.addRepository(remoteRepository); - DependencyNode node = repositorySystem.collectDependencies( - repositorySystemSession, collectRequest).getRoot(); - - // FIXME adapt to changes in Aether - // repositorySystem.resolveDependencies(repositorySystemSession, - // node, - // null); - return node; - } catch (Exception e) { - throw new SlcException("Cannot resolve dependencies of " + artifact - + " (scope: " + scope + ")", e); - } - } - - public RepositorySystem getRepositorySystem() { - return repositorySystem; - } - - public void setRepositorySystem(RepositorySystem repositorySystem) { - this.repositorySystem = repositorySystem; - } - - public RepositorySystemSession getRepositorySystemSession() { - return repositorySystemSession; - } - - public void setRepositorySystemSession( - RepositorySystemSession repositorySystemSession) { - this.repositorySystemSession = repositorySystemSession; - } - - public List getRemoteRepositories() { - return remoteRepositories; - } - - public void setRemoteRepositories(List remoteRepositories) { - this.remoteRepositories = remoteRepositories; - } - -} diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleRepositoryListener.java b/org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleRepositoryListener.java deleted file mode 100644 index 727c5f35d..000000000 --- a/org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleRepositoryListener.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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.argeo.slc.aether; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.eclipse.aether.AbstractRepositoryListener; -import org.eclipse.aether.RepositoryEvent; - -public class ConsoleRepositoryListener extends AbstractRepositoryListener { - - private final static Log log = LogFactory - .getLog(ConsoleRepositoryListener.class); - - public void artifactDeployed(RepositoryEvent event) { - if (log.isDebugEnabled()) - log.debug("Deployed " + event.getArtifact() + " to " - + event.getRepository()); - } - - public void artifactDeploying(RepositoryEvent event) { - if (log.isTraceEnabled()) - log.trace("Deploying " + event.getArtifact() + " to " - + event.getRepository()); - } - - public void artifactDescriptorInvalid(RepositoryEvent event) { - if (log.isDebugEnabled()) - log.warn("Invalid artifact descriptor for " + event.getArtifact() - + ": " + event.getException().getMessage()); - } - - public void artifactDescriptorMissing(RepositoryEvent event) { - if (log.isTraceEnabled()) - log.warn("Missing artifact descriptor for " + event.getArtifact()); - } - - public void artifactInstalled(RepositoryEvent event) { - if (log.isDebugEnabled()) - log.debug("Installed " + event.getArtifact() + " to " - + event.getFile()); - } - - public void artifactInstalling(RepositoryEvent event) { - if (log.isTraceEnabled()) - log.trace("Installing " + event.getArtifact() + " to " - + event.getFile()); - } - - public void artifactResolved(RepositoryEvent event) { - if (log.isTraceEnabled()) - log.trace("Resolved artifact " + event.getArtifact() + " from " - + event.getRepository()); - } - - public void artifactDownloading(RepositoryEvent event) { - if (log.isTraceEnabled()) - log.trace("Downloading artifact " + event.getArtifact() + " from " - + event.getRepository()); - } - - public void artifactDownloaded(RepositoryEvent event) { - if (log.isDebugEnabled()) - log.debug("Downloaded artifact " + event.getArtifact() + " from " - + event.getRepository()); - } - - public void artifactResolving(RepositoryEvent event) { - if (log.isTraceEnabled()) - log.trace("Resolving artifact " + event.getArtifact()); - } - - public void metadataDeployed(RepositoryEvent event) { - if (log.isDebugEnabled()) - log.debug("Deployed " + event.getMetadata() + " to " - + event.getRepository()); - } - - public void metadataDeploying(RepositoryEvent event) { - if (log.isTraceEnabled()) - log.trace("Deploying " + event.getMetadata() + " to " - + event.getRepository()); - } - - public void metadataInstalled(RepositoryEvent event) { - if (log.isDebugEnabled()) - log.debug("Installed " + event.getMetadata() + " to " - + event.getFile()); - } - - public void metadataInstalling(RepositoryEvent event) { - if (log.isTraceEnabled()) - log.trace("Installing " + event.getMetadata() + " to " - + event.getFile()); - } - - public void metadataInvalid(RepositoryEvent event) { - if (log.isDebugEnabled()) - log.debug("Invalid metadata " + event.getMetadata()); - } - - public void metadataResolved(RepositoryEvent event) { - if (log.isTraceEnabled()) - log.trace("Resolved metadata " + event.getMetadata() + " from " - + event.getRepository()); - } - - public void metadataResolving(RepositoryEvent event) { - if (log.isTraceEnabled()) - log.trace("Resolving metadata " + event.getMetadata() + " from " - + event.getRepository()); - } - -} diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleTransferListener.java b/org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleTransferListener.java deleted file mode 100644 index 3543d6847..000000000 --- a/org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleTransferListener.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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.argeo.slc.aether; - -import java.io.PrintStream; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.eclipse.aether.transfer.AbstractTransferListener; -import org.eclipse.aether.transfer.TransferEvent; -import org.eclipse.aether.transfer.TransferResource; - -public class ConsoleTransferListener extends AbstractTransferListener { - private final static Log log = LogFactory - .getLog(ConsoleTransferListener.class); - - private PrintStream out; - - private Map downloads = new ConcurrentHashMap(); - - private int lastLength; - - public ConsoleTransferListener(PrintStream out) { - this.out = (out != null) ? out : System.out; - } - - @Override - public void transferInitiated(TransferEvent event) { - String message = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading" - : "Downloading"; - - if (log.isDebugEnabled()) - log.debug(message + ": " + event.getResource().getRepositoryUrl() - + event.getResource().getResourceName()); - } - - @Override - public void transferProgressed(TransferEvent event) { - TransferResource resource = event.getResource(); - downloads.put(resource, Long.valueOf(event.getTransferredBytes())); - - StringBuilder buffer = new StringBuilder(64); - - for (Map.Entry entry : downloads.entrySet()) { - long total = entry.getKey().getContentLength(); - long complete = entry.getValue().longValue(); - - buffer.append(getStatus(complete, total)).append(" "); - } - - int pad = lastLength - buffer.length(); - lastLength = buffer.length(); - pad(buffer, pad); - buffer.append('\r'); - - out.print(buffer); - } - - private String getStatus(long complete, long total) { - if (total >= 1024) { - return toKB(complete) + "/" + toKB(total) + " KB "; - } else if (total >= 0) { - return complete + "/" + total + " B "; - } else if (complete >= 1024) { - return toKB(complete) + " KB "; - } else { - return complete + " B "; - } - } - - private void pad(StringBuilder buffer, int spaces) { - String block = " "; - while (spaces > 0) { - int n = Math.min(spaces, block.length()); - buffer.append(block, 0, n); - spaces -= n; - } - } - - @Override - public void transferSucceeded(TransferEvent event) { - transferCompleted(event); - - TransferResource resource = event.getResource(); - long contentLength = event.getTransferredBytes(); - if (contentLength >= 0) { - String type = (event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" - : "Downloaded"); - String len = contentLength >= 1024 ? toKB(contentLength) + " KB" - : contentLength + " B"; - - String throughput = ""; - long duration = System.currentTimeMillis() - - resource.getTransferStartTime(); - if (duration > 0) { - DecimalFormat format = new DecimalFormat("0.0", - new DecimalFormatSymbols(Locale.ENGLISH)); - double kbPerSec = (contentLength / 1024.0) - / (duration / 1000.0); - throughput = " at " + format.format(kbPerSec) + " KB/sec"; - } - - out.println(type + ": " + resource.getRepositoryUrl() - + resource.getResourceName() + " (" + len + throughput - + ")"); - } - } - - @Override - public void transferFailed(TransferEvent event) { - transferCompleted(event); - - log.error(event.getException().getMessage() - + (event.getException().getCause() != null ? " : " - + event.getException().getCause().getMessage() : "")); - // event.getException().printStackTrace( out ); - } - - private void transferCompleted(TransferEvent event) { - downloads.remove(event.getResource()); - - StringBuilder buffer = new StringBuilder(64); - pad(buffer, lastLength); - buffer.append('\r'); - out.print(buffer); - } - - public void transferCorrupted(TransferEvent event) { - event.getException().printStackTrace(out); - } - - protected long toKB(long bytes) { - return (bytes + 1023) / 1024; - } - -} diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleArtifactDescriptorReader.java b/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleArtifactDescriptorReader.java deleted file mode 100644 index 3aca17206..000000000 --- a/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleArtifactDescriptorReader.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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.argeo.slc.aether; - -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.impl.ArtifactDescriptorReader; -import org.eclipse.aether.resolution.ArtifactDescriptorException; -import org.eclipse.aether.resolution.ArtifactDescriptorRequest; -import org.eclipse.aether.resolution.ArtifactDescriptorResult; - -public class SimpleArtifactDescriptorReader implements ArtifactDescriptorReader { - - public ArtifactDescriptorResult readArtifactDescriptor( - RepositorySystemSession session, ArtifactDescriptorRequest request) - throws ArtifactDescriptorException { - ArtifactDescriptorResult result = new ArtifactDescriptorResult(request); - return result; - } - -} diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionRangeResolver.java b/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionRangeResolver.java deleted file mode 100644 index b7e7f9522..000000000 --- a/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionRangeResolver.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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.argeo.slc.aether; - -import org.argeo.slc.aether.osgi.OsgiVersion; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.impl.VersionRangeResolver; -import org.eclipse.aether.resolution.VersionRangeRequest; -import org.eclipse.aether.resolution.VersionRangeResolutionException; -import org.eclipse.aether.resolution.VersionRangeResult; -import org.eclipse.aether.version.Version; - -public class SimpleVersionRangeResolver implements VersionRangeResolver { - - public VersionRangeResult resolveVersionRange( - RepositorySystemSession session, VersionRangeRequest request) - throws VersionRangeResolutionException { - VersionRangeResult versionRangeResult = new VersionRangeResult(request); - Version version = new OsgiVersion(request.getArtifact() - .getBaseVersion()); - versionRangeResult.addVersion(version); - return null; - } -} diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionResolver.java b/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionResolver.java deleted file mode 100644 index 51a6490c5..000000000 --- a/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionResolver.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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.argeo.slc.aether; - -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.impl.VersionResolver; -import org.eclipse.aether.resolution.VersionRequest; -import org.eclipse.aether.resolution.VersionResolutionException; -import org.eclipse.aether.resolution.VersionResult; - -public class SimpleVersionResolver implements VersionResolver { - - public VersionResult resolveVersion(RepositorySystemSession session, - VersionRequest request) throws VersionResolutionException { - VersionResult versionResult = new VersionResult(request); - versionResult.setVersion(request.getArtifact().getBaseVersion()); - return versionResult; - } - -} diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/osgi/OsgiVersion.java b/org.argeo.slc.support/src/org/argeo/slc/aether/osgi/OsgiVersion.java deleted file mode 100644 index 9f35ff99a..000000000 --- a/org.argeo.slc.support/src/org/argeo/slc/aether/osgi/OsgiVersion.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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.argeo.slc.aether.osgi; - -import org.osgi.framework.Version; - -/** - * Wraps an OSGi {@link Version} as an Aether - * {@link org.eclipse.aether.version.Version}. - */ -public class OsgiVersion implements org.eclipse.aether.version.Version { - final private Version version; - - public OsgiVersion(String str) { - version = Version.parseVersion(str); - } - - public Version getVersion() { - return version; - } - - public int compareTo(org.eclipse.aether.version.Version v) { - if (!(v instanceof OsgiVersion)) - return 0; - OsgiVersion ov = (OsgiVersion) v; - return version.compareTo(ov.version); - } -} diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/spring/RemoteRepositoryFactory.java b/org.argeo.slc.support/src/org/argeo/slc/aether/spring/RemoteRepositoryFactory.java deleted file mode 100644 index 7223c78cb..000000000 --- a/org.argeo.slc.support/src/org/argeo/slc/aether/spring/RemoteRepositoryFactory.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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.argeo.slc.aether.spring; - -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.util.repository.AuthenticationBuilder; -import org.springframework.beans.factory.BeanNameAware; -import org.springframework.beans.factory.FactoryBean; - -/** Simplifies the definition of a remote factory using Spring */ -public class RemoteRepositoryFactory implements BeanNameAware, - FactoryBean { - private String beanName; - private String id; - private String url; - private String type = "default"; - private String username; - private String password; - - public RemoteRepository getObject() throws Exception { - RemoteRepository.Builder builder = new RemoteRepository.Builder( - id != null ? id : beanName, type, url); - if (username != null) { - AuthenticationBuilder authBuilder = new AuthenticationBuilder(); - authBuilder.addUsername(username); - authBuilder.addPassword(password); - builder.setAuthentication(authBuilder.build()); - } - RemoteRepository remoteRepository = builder.build(); - return remoteRepository; - } - - public Class getObjectType() { - return RemoteRepository.class; - } - - public boolean isSingleton() { - return true; - } - - public void setBeanName(String name) { - this.beanName = name; - - } - - public void setId(String id) { - this.id = id; - } - - public void setUrl(String url) { - this.url = url; - } - - public void setType(String type) { - this.type = type; - } - - public void setUsername(String username) { - this.username = username; - } - - public void setPassword(String password) { - this.password = password; - } - -} diff --git a/pom.xml b/pom.xml index b12659b2d..cf85fe6ac 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.argeo.slc.core org.argeo.slc.unit org.argeo.slc.support - org.argeo.slc.support.maven + org.argeo.slc.repo org.argeo.slc.factory org.argeo.slc.launcher -- 2.39.2