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.List;
25  import java.util.Map;
26  
27  import org.eclipse.aether.RepositorySystemSession;
28  import org.eclipse.aether.artifact.Artifact;
29  import org.eclipse.aether.repository.ArtifactRepository;
30  import org.eclipse.aether.spi.checksums.TrustedChecksumsSource;
31  import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
32  import org.eclipse.aether.util.ConfigUtils;
33  import org.eclipse.aether.util.DirectoryUtils;
34  
35  import static java.util.Objects.requireNonNull;
36  
37  /**
38   * Support class for implementing {@link TrustedChecksumsSource} backed by local filesystem. It implements basic support
39   * like basedir calculation, "enabled" flag and "originAware" flag.
40   * <p>
41   * The configuration keys supported:
42   * <ul>
43   *     <li><pre>aether.trustedChecksumsSource.${name}</pre> (boolean) must be explicitly set to "true"
44   *     to become enabled</li>
45   *     <li><pre>aether.trustedChecksumsSource.${name}.basedir</pre> (string, path) directory from where implementation
46   *     can use files. May be relative path (then is resolved against local repository basedir) or absolute. If unset,
47   *     default value is ".checksums" and is resolved against local repository basedir.</li>
48   *     <li><pre>aether.trustedChecksumsSource.${name}.originAware</pre> (boolean) whether to make implementation
49   *     "originAware", to factor in origin repository ID as well or not.</li>
50   * </ul>
51   * <p>
52   * This implementation ensures that implementations have "name" property, used in configuration properties above.
53   *
54   * @since 1.9.0
55   */
56  abstract class FileTrustedChecksumsSourceSupport implements TrustedChecksumsSource {
57      private static final String CONFIG_PROP_PREFIX = "aether.trustedChecksumsSource.";
58  
59      private static final String CONF_NAME_BASEDIR = "basedir";
60  
61      private static final String CONF_NAME_ORIGIN_AWARE = "originAware";
62  
63      /**
64       * Visible for testing.
65       */
66      static final String LOCAL_REPO_PREFIX_DIR = ".checksums";
67  
68      private final String name;
69  
70      FileTrustedChecksumsSourceSupport(String name) {
71          this.name = requireNonNull(name);
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. Underlying implementation may still choose
97       * to return {@code null}.
98       */
99      @Override
100     public Writer getTrustedArtifactChecksumsWriter(RepositorySystemSession session) {
101         requireNonNull(session, "session is null");
102         if (isEnabled(session)) {
103             return doGetTrustedArtifactChecksumsWriter(session);
104         }
105         return null;
106     }
107 
108     /**
109      * Implementors MUST NOT return {@code null} at this point, as this source is enabled.
110      */
111     protected abstract Map<String, String> doGetTrustedArtifactChecksums(
112             RepositorySystemSession session,
113             Artifact artifact,
114             ArtifactRepository artifactRepository,
115             List<ChecksumAlgorithmFactory> checksumAlgorithmFactories);
116 
117     /**
118      * Implementors may override this method and return {@link Writer} instance.
119      */
120     protected Writer doGetTrustedArtifactChecksumsWriter(RepositorySystemSession session) {
121         return null;
122     }
123 
124     /**
125      * To be used by underlying implementations to form configuration property keys properly scoped.
126      */
127     protected String configPropKey(String name) {
128         requireNonNull(name);
129         return CONFIG_PROP_PREFIX + this.name + "." + name;
130     }
131 
132     /**
133      * Returns {@code true} if session configuration marks this instance as enabled.
134      * <p>
135      * Default value is {@code false}.
136      */
137     protected boolean isEnabled(RepositorySystemSession session) {
138         return ConfigUtils.getBoolean(session, false, CONFIG_PROP_PREFIX + this.name);
139     }
140 
141     /**
142      * Returns {@code true} if session configuration marks this instance as origin aware.
143      * <p>
144      * Default value is {@code true}.
145      */
146     protected boolean isOriginAware(RepositorySystemSession session) {
147         return ConfigUtils.getBoolean(session, true, configPropKey(CONF_NAME_ORIGIN_AWARE));
148     }
149 
150     /**
151      * Uses utility {@link DirectoryUtils#resolveDirectory(RepositorySystemSession, String, String, boolean)} to
152      * calculate (and maybe create) basedir for this implementation, never returns {@code null}. The returned
153      * {@link Path} may not exist, if invoked with {@code mayCreate} being {@code false}.
154      * <p>
155      * Default value is {@code ${LOCAL_REPOSITORY}/.checksums}.
156      *
157      * @return The {@link Path} of basedir, never {@code null}.
158      */
159     protected Path getBasedir(RepositorySystemSession session, boolean mayCreate) {
160         try {
161             return DirectoryUtils.resolveDirectory(
162                     session, LOCAL_REPO_PREFIX_DIR, configPropKey(CONF_NAME_BASEDIR), mayCreate);
163         } catch (IOException e) {
164             throw new UncheckedIOException(e);
165         }
166     }
167 }