View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.internal.impl.checksum;
20  
21  import java.io.IOException;
22  import java.io.UncheckedIOException;
23  import java.nio.file.Path;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.Map;
27  
28  import org.eclipse.aether.ConfigurationProperties;
29  import org.eclipse.aether.RepositorySystemSession;
30  import org.eclipse.aether.artifact.Artifact;
31  import org.eclipse.aether.metadata.Metadata;
32  import org.eclipse.aether.repository.ArtifactRepository;
33  import org.eclipse.aether.repository.RemoteRepository;
34  import org.eclipse.aether.spi.checksums.TrustedChecksumsSource;
35  import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
36  import org.eclipse.aether.spi.remoterepo.RepositoryKeyFunctionFactory;
37  import org.eclipse.aether.util.DirectoryUtils;
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  
41  import static java.util.Objects.requireNonNull;
42  
43  /**
44   * Support class for implementing {@link TrustedChecksumsSource} backed by local filesystem. It implements basic support
45   * like basedir calculation, "enabled" flag and "originAware" flag.
46   * <p>
47   * The configuration keys supported:
48   * <ul>
49   *     <li><pre>aether.trustedChecksumsSource.${name}</pre> (boolean) must be explicitly set to "true"
50   *     to become enabled</li>
51   *     <li><pre>aether.trustedChecksumsSource.${name}.basedir</pre> (string, path) directory from where implementation
52   *     can use files. May be relative path (then is resolved against local repository basedir) or absolute. If unset,
53   *     default value is ".checksums" and is resolved against local repository basedir.</li>
54   *     <li><pre>aether.trustedChecksumsSource.${name}.originAware</pre> (boolean) whether to make implementation
55   *     "originAware", to factor in origin repository ID as well or not.</li>
56   * </ul>
57   * <p>
58   * This implementation ensures that implementations have "name" property, used in configuration properties above.
59   *
60   * @since 1.9.0
61   */
62  public abstract class FileTrustedChecksumsSourceSupport implements TrustedChecksumsSource {
63      protected static final String CONFIG_PROPS_PREFIX =
64              ConfigurationProperties.PREFIX_AETHER + "trustedChecksumsSource.";
65  
66      protected final Logger logger = LoggerFactory.getLogger(getClass());
67  
68      private final RepositoryKeyFunctionFactory repositoryKeyFunctionFactory;
69  
70      protected FileTrustedChecksumsSourceSupport(RepositoryKeyFunctionFactory repositoryKeyFunctionFactory) {
71          this.repositoryKeyFunctionFactory = requireNonNull(repositoryKeyFunctionFactory);
72      }
73  
74      /**
75       * This implementation will call into underlying code only if enabled, and will enforce non-{@code null} return
76       * value. In worst case, empty map should be returned, meaning "no trusted checksums available".
77       */
78      @Override
79      public Map<String, String> getTrustedArtifactChecksums(
80              RepositorySystemSession session,
81              Artifact artifact,
82              ArtifactRepository artifactRepository,
83              List<ChecksumAlgorithmFactory> checksumAlgorithmFactories) {
84          requireNonNull(session, "session is null");
85          requireNonNull(artifact, "artifact is null");
86          requireNonNull(artifactRepository, "artifactRepository is null");
87          requireNonNull(checksumAlgorithmFactories, "checksumAlgorithmFactories is null");
88          if (isEnabled(session)) {
89              return requireNonNull(
90                      doGetTrustedArtifactChecksums(session, artifact, artifactRepository, checksumAlgorithmFactories));
91          }
92          return null;
93      }
94  
95      /**
96       * This implementation will call into underlying code only if enabled, and will enforce non-{@code null} return
97       * value. In worst case, empty map should be returned, meaning "no trusted checksums available".
98       *
99       * @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 }