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.checksum; 020 021import java.io.IOException; 022import java.io.UncheckedIOException; 023import java.nio.file.Path; 024import java.util.ArrayList; 025import java.util.List; 026import java.util.Map; 027 028import org.eclipse.aether.ConfigurationProperties; 029import org.eclipse.aether.RepositorySystemSession; 030import org.eclipse.aether.artifact.Artifact; 031import org.eclipse.aether.metadata.Metadata; 032import org.eclipse.aether.repository.ArtifactRepository; 033import org.eclipse.aether.repository.RemoteRepository; 034import org.eclipse.aether.spi.checksums.TrustedChecksumsSource; 035import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory; 036import org.eclipse.aether.spi.remoterepo.RepositoryKeyFunctionFactory; 037import org.eclipse.aether.util.DirectoryUtils; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041import static java.util.Objects.requireNonNull; 042 043/** 044 * Support class for implementing {@link TrustedChecksumsSource} backed by local filesystem. It implements basic support 045 * like basedir calculation, "enabled" flag and "originAware" flag. 046 * <p> 047 * The configuration keys supported: 048 * <ul> 049 * <li><pre>aether.trustedChecksumsSource.${name}</pre> (boolean) must be explicitly set to "true" 050 * to become enabled</li> 051 * <li><pre>aether.trustedChecksumsSource.${name}.basedir</pre> (string, path) directory from where implementation 052 * can use files. May be relative path (then is resolved against local repository basedir) or absolute. If unset, 053 * default value is ".checksums" and is resolved against local repository basedir.</li> 054 * <li><pre>aether.trustedChecksumsSource.${name}.originAware</pre> (boolean) whether to make implementation 055 * "originAware", to factor in origin repository ID as well or not.</li> 056 * </ul> 057 * <p> 058 * This implementation ensures that implementations have "name" property, used in configuration properties above. 059 * 060 * @since 1.9.0 061 */ 062public abstract class FileTrustedChecksumsSourceSupport implements TrustedChecksumsSource { 063 protected static final String CONFIG_PROPS_PREFIX = 064 ConfigurationProperties.PREFIX_AETHER + "trustedChecksumsSource."; 065 066 protected final Logger logger = LoggerFactory.getLogger(getClass()); 067 068 private final RepositoryKeyFunctionFactory repositoryKeyFunctionFactory; 069 070 protected FileTrustedChecksumsSourceSupport(RepositoryKeyFunctionFactory repositoryKeyFunctionFactory) { 071 this.repositoryKeyFunctionFactory = requireNonNull(repositoryKeyFunctionFactory); 072 } 073 074 /** 075 * This implementation will call into underlying code only if enabled, and will enforce non-{@code null} return 076 * value. In worst case, empty map should be returned, meaning "no trusted checksums available". 077 */ 078 @Override 079 public Map<String, String> getTrustedArtifactChecksums( 080 RepositorySystemSession session, 081 Artifact artifact, 082 ArtifactRepository artifactRepository, 083 List<ChecksumAlgorithmFactory> checksumAlgorithmFactories) { 084 requireNonNull(session, "session is null"); 085 requireNonNull(artifact, "artifact is null"); 086 requireNonNull(artifactRepository, "artifactRepository is null"); 087 requireNonNull(checksumAlgorithmFactories, "checksumAlgorithmFactories is null"); 088 if (isEnabled(session)) { 089 return requireNonNull( 090 doGetTrustedArtifactChecksums(session, artifact, artifactRepository, checksumAlgorithmFactories)); 091 } 092 return null; 093 } 094 095 /** 096 * This implementation will call into underlying code only if enabled, and will enforce non-{@code null} return 097 * value. In worst case, empty map should be returned, meaning "no trusted checksums available". 098 * 099 * @since 2.0.23 100 */ 101 @Override 102 public Map<String, String> getTrustedMetadataChecksums( 103 RepositorySystemSession session, 104 Metadata metadata, 105 ArtifactRepository artifactRepository, 106 List<ChecksumAlgorithmFactory> checksumAlgorithmFactories) { 107 requireNonNull(session, "session is null"); 108 requireNonNull(metadata, "metadata is null"); 109 requireNonNull(artifactRepository, "artifactRepository is null"); 110 requireNonNull(checksumAlgorithmFactories, "checksumAlgorithmFactories is null"); 111 if (isEnabled(session)) { 112 return requireNonNull( 113 doGetTrustedMetadataChecksums(session, metadata, artifactRepository, checksumAlgorithmFactories)); 114 } 115 return null; 116 } 117 118 /** 119 * This implementation will call into underlying code only if enabled. Underlying implementation may still choose 120 * to return {@code null}. 121 */ 122 @Override 123 public Writer getTrustedArtifactChecksumsWriter(RepositorySystemSession session) { 124 requireNonNull(session, "session is null"); 125 if (isEnabled(session)) { 126 return doGetTrustedArtifactChecksumsWriter(session); 127 } 128 return null; 129 } 130 131 /** 132 * Implementors MUST NOT return {@code null} at this point, as this source is enabled. 133 */ 134 protected abstract Map<String, String> doGetTrustedArtifactChecksums( 135 RepositorySystemSession session, 136 Artifact artifact, 137 ArtifactRepository artifactRepository, 138 List<ChecksumAlgorithmFactory> checksumAlgorithmFactories); 139 140 /** 141 * Implementors MUST NOT return {@code null} at this point, as this source is enabled. Metadata checksums are 142 * looked up using the same file conventions as artifact checksums, with the metadata path composed from the 143 * origin repository key (for example {@code g/a/v/maven-metadata-central.xml}). 144 * 145 * @since 2.0.23 146 */ 147 protected abstract Map<String, String> doGetTrustedMetadataChecksums( 148 RepositorySystemSession session, 149 Metadata metadata, 150 ArtifactRepository artifactRepository, 151 List<ChecksumAlgorithmFactory> checksumAlgorithmFactories); 152 153 /** 154 * Implementors may override this method and return {@link Writer} instance. 155 */ 156 protected Writer doGetTrustedArtifactChecksumsWriter(RepositorySystemSession session) { 157 return null; 158 } 159 160 /** 161 * Returns {@code true} if session configuration marks this instance as enabled. 162 * <p> 163 * Default value is {@code false}. 164 */ 165 protected abstract boolean isEnabled(RepositorySystemSession session); 166 167 /** 168 * Uses utility {@link DirectoryUtils#resolveDirectory(RepositorySystemSession, String, String, boolean)} to 169 * calculate (and maybe create) basedir for this implementation, never returns {@code null}. The returned 170 * {@link Path} may not exist, if invoked with {@code mayCreate} being {@code false}. 171 * <p> 172 * Default value is {@code ${LOCAL_REPOSITORY}/.checksums}. 173 * 174 * @return The {@link Path} of basedir, never {@code null}. 175 */ 176 protected Path getBasedir( 177 RepositorySystemSession session, String defaultValue, String configPropKey, boolean mayCreate) { 178 try { 179 return DirectoryUtils.resolveDirectory(session, defaultValue, configPropKey, mayCreate); 180 } catch (IOException e) { 181 throw new UncheckedIOException(e); 182 } 183 } 184 185 /** 186 * Returns repository keys to be used on file system layout. Always returns a list with at least one element. 187 * Elements are sorted from "most specific" to "least specific" keys. 188 * 189 * @since 2.0.14 190 */ 191 protected List<String> repositoryKey(RepositorySystemSession session, ArtifactRepository artifactRepository) { 192 ArrayList<String> keys = new ArrayList<>(); 193 if (artifactRepository instanceof RemoteRepository) { 194 RemoteRepository rr = (RemoteRepository) artifactRepository; 195 keys.add(repositoryKeyFunctionFactory 196 .trackingRepositoryKeyFunction(session) 197 .apply(rr, null)); 198 keys.add(repositoryKeyFunctionFactory 199 .systemRepositoryKeyFunction(session) 200 .apply(rr, null)); 201 } else { 202 keys.add(artifactRepository.getId()); 203 } 204 return keys; 205 } 206}