001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.internal.impl; 020 021import javax.inject.Inject; 022import javax.inject.Named; 023import javax.inject.Singleton; 024 025import java.net.URI; 026import java.net.URISyntaxException; 027import java.util.ArrayList; 028import java.util.Collections; 029import java.util.List; 030 031import org.eclipse.aether.ConfigurationProperties; 032import org.eclipse.aether.RepositorySystemSession; 033import org.eclipse.aether.artifact.Artifact; 034import org.eclipse.aether.metadata.Metadata; 035import org.eclipse.aether.repository.RemoteRepository; 036import org.eclipse.aether.spi.artifact.ArtifactPredicate; 037import org.eclipse.aether.spi.artifact.ArtifactPredicateFactory; 038import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory; 039import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector; 040import org.eclipse.aether.spi.connector.layout.RepositoryLayout; 041import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory; 042import org.eclipse.aether.transfer.NoRepositoryLayoutException; 043import org.eclipse.aether.util.ConfigUtils; 044 045import static java.util.Objects.requireNonNull; 046 047/** 048 * Provides a Maven-2 repository layout for repositories with content type {@code "default"}. 049 */ 050@Singleton 051@Named(Maven2RepositoryLayoutFactory.NAME) 052public final class Maven2RepositoryLayoutFactory implements RepositoryLayoutFactory { 053 public static final String NAME = "maven2"; 054 055 private static final String CONFIG_PROPS_PREFIX = ConfigurationProperties.PREFIX_LAYOUT + NAME + "."; 056 057 /** 058 * Comma-separated list of checksum algorithms with which checksums are validated (downloaded) and generated 059 * (uploaded) with this layout. Resolver by default supports following algorithms: MD5, SHA-1, SHA-256 and 060 * SHA-512. New algorithms can be added by implementing ChecksumAlgorithmFactory component. 061 * 062 * @since 1.8.0 063 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 064 * @configurationType {@link java.lang.String} 065 * @configurationDefaultValue {@link #DEFAULT_CHECKSUMS_ALGORITHMS} 066 * @configurationRepoIdSuffix Yes 067 */ 068 public static final String CONFIG_PROP_CHECKSUMS_ALGORITHMS = CONFIG_PROPS_PREFIX + "checksumAlgorithms"; 069 070 public static final String DEFAULT_CHECKSUMS_ALGORITHMS = "SHA-1,MD5"; 071 072 private float priority; 073 074 private final ChecksumAlgorithmFactorySelector checksumAlgorithmFactorySelector; 075 076 private final ArtifactPredicateFactory artifactPredicateFactory; 077 078 public float getPriority() { 079 return priority; 080 } 081 082 @Inject 083 public Maven2RepositoryLayoutFactory( 084 ChecksumAlgorithmFactorySelector checksumAlgorithmFactorySelector, 085 ArtifactPredicateFactory artifactPredicateFactory) { 086 this.checksumAlgorithmFactorySelector = requireNonNull(checksumAlgorithmFactorySelector); 087 this.artifactPredicateFactory = requireNonNull(artifactPredicateFactory); 088 } 089 090 /** 091 * Sets the priority of this component. 092 * 093 * @param priority The priority. 094 * @return This component for chaining, never {@code null}. 095 */ 096 public Maven2RepositoryLayoutFactory setPriority(float priority) { 097 this.priority = priority; 098 return this; 099 } 100 101 public RepositoryLayout newInstance(RepositorySystemSession session, RemoteRepository repository) 102 throws NoRepositoryLayoutException { 103 requireNonNull(session, "session cannot be null"); 104 requireNonNull(repository, "repository cannot be null"); 105 if (!"default".equals(repository.getContentType())) { 106 throw new NoRepositoryLayoutException(repository); 107 } 108 109 List<ChecksumAlgorithmFactory> checksumsAlgorithms = checksumAlgorithmFactorySelector.selectList( 110 ConfigUtils.parseCommaSeparatedUniqueNames(ConfigUtils.getString( 111 session, 112 DEFAULT_CHECKSUMS_ALGORITHMS, 113 CONFIG_PROP_CHECKSUMS_ALGORITHMS + "." + repository.getId(), 114 CONFIG_PROP_CHECKSUMS_ALGORITHMS, 115 // MRESOLVER-701: support legacy properties for simpler transitioning 116 "aether.checksums.algorithms", 117 "aether.checksums.algorithms." + repository.getId()))); 118 119 return new Maven2RepositoryLayout(checksumsAlgorithms, artifactPredicateFactory.newInstance(session)); 120 } 121 122 private static class Maven2RepositoryLayout implements RepositoryLayout { 123 private final List<ChecksumAlgorithmFactory> configuredChecksumAlgorithms; 124 private final ArtifactPredicate artifactPredicate; 125 126 private Maven2RepositoryLayout( 127 List<ChecksumAlgorithmFactory> configuredChecksumAlgorithms, ArtifactPredicate artifactPredicate) { 128 this.configuredChecksumAlgorithms = Collections.unmodifiableList(configuredChecksumAlgorithms); 129 this.artifactPredicate = requireNonNull(artifactPredicate); 130 } 131 132 private URI toUri(String path) { 133 try { 134 return new URI(null, null, path, null); 135 } catch (URISyntaxException e) { 136 throw new IllegalStateException(e); 137 } 138 } 139 140 @Override 141 public List<ChecksumAlgorithmFactory> getChecksumAlgorithmFactories() { 142 return configuredChecksumAlgorithms; 143 } 144 145 @Override 146 public boolean hasChecksums(Artifact artifact) { 147 return !artifactPredicate.isWithoutChecksum(artifact); 148 } 149 150 @Override 151 public URI getLocation(Artifact artifact, boolean upload) { 152 StringBuilder path = new StringBuilder(128); 153 154 path.append(artifact.getGroupId().replace('.', '/')).append('/'); 155 156 path.append(artifact.getArtifactId()).append('/'); 157 158 path.append(artifact.getBaseVersion()).append('/'); 159 160 path.append(artifact.getArtifactId()).append('-').append(artifact.getVersion()); 161 162 if (!artifact.getClassifier().isEmpty()) { 163 path.append('-').append(artifact.getClassifier()); 164 } 165 166 if (!artifact.getExtension().isEmpty()) { 167 path.append('.').append(artifact.getExtension()); 168 } 169 170 return toUri(path.toString()); 171 } 172 173 @Override 174 public URI getLocation(Metadata metadata, boolean upload) { 175 StringBuilder path = new StringBuilder(128); 176 177 if (!metadata.getGroupId().isEmpty()) { 178 path.append(metadata.getGroupId().replace('.', '/')).append('/'); 179 180 if (!metadata.getArtifactId().isEmpty()) { 181 path.append(metadata.getArtifactId()).append('/'); 182 183 if (!metadata.getVersion().isEmpty()) { 184 path.append(metadata.getVersion()).append('/'); 185 } 186 } 187 } 188 189 path.append(metadata.getType()); 190 191 return toUri(path.toString()); 192 } 193 194 @Override 195 public List<ChecksumLocation> getChecksumLocations(Artifact artifact, boolean upload, URI location) { 196 if (artifactPredicate.isWithoutChecksum(artifact) || artifactPredicate.isChecksum(artifact)) { 197 return Collections.emptyList(); 198 } 199 return getChecksumLocations(location); 200 } 201 202 @Override 203 public List<ChecksumLocation> getChecksumLocations(Metadata metadata, boolean upload, URI location) { 204 return getChecksumLocations(location); 205 } 206 207 private List<ChecksumLocation> getChecksumLocations(URI location) { 208 List<ChecksumLocation> checksumLocations = new ArrayList<>(configuredChecksumAlgorithms.size()); 209 for (ChecksumAlgorithmFactory checksumAlgorithmFactory : configuredChecksumAlgorithms) { 210 checksumLocations.add(ChecksumLocation.forLocation(location, checksumAlgorithmFactory)); 211 } 212 return checksumLocations; 213 } 214 } 215}