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.ConfigurationProperties;
28 import org.eclipse.aether.RepositorySystemSession;
29 import org.eclipse.aether.artifact.Artifact;
30 import org.eclipse.aether.repository.ArtifactRepository;
31 import org.eclipse.aether.repository.RemoteRepository;
32 import org.eclipse.aether.spi.checksums.TrustedChecksumsSource;
33 import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
34 import org.eclipse.aether.spi.remoterepo.RepositoryKeyFunctionFactory;
35 import org.eclipse.aether.util.DirectoryUtils;
36
37 import static java.util.Objects.requireNonNull;
38
39 /**
40 * Support class for implementing {@link TrustedChecksumsSource} backed by local filesystem. It implements basic support
41 * like basedir calculation, "enabled" flag and "originAware" flag.
42 * <p>
43 * The configuration keys supported:
44 * <ul>
45 * <li><pre>aether.trustedChecksumsSource.${name}</pre> (boolean) must be explicitly set to "true"
46 * to become enabled</li>
47 * <li><pre>aether.trustedChecksumsSource.${name}.basedir</pre> (string, path) directory from where implementation
48 * can use files. May be relative path (then is resolved against local repository basedir) or absolute. If unset,
49 * default value is ".checksums" and is resolved against local repository basedir.</li>
50 * <li><pre>aether.trustedChecksumsSource.${name}.originAware</pre> (boolean) whether to make implementation
51 * "originAware", to factor in origin repository ID as well or not.</li>
52 * </ul>
53 * <p>
54 * This implementation ensures that implementations have "name" property, used in configuration properties above.
55 *
56 * @since 1.9.0
57 */
58 public abstract class FileTrustedChecksumsSourceSupport implements TrustedChecksumsSource {
59 protected static final String CONFIG_PROPS_PREFIX =
60 ConfigurationProperties.PREFIX_AETHER + "trustedChecksumsSource.";
61
62 /**
63 * <b>Experimental:</b> Configuration for "repository key" function.
64 * Note: repository key functions other than "nid" produce repository keys will be <em>way different
65 * that those produced with previous versions or without this option enabled</em>. Checksum source uses this key
66 * function to lay down and look up files to use in sources.
67 *
68 * @since 2.0.14
69 * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
70 * @configurationType {@link java.lang.String}
71 * @configurationDefaultValue {@link #DEFAULT_REPOSITORY_KEY_FUNCTION}
72 */
73 public static final String CONFIG_PROP_REPOSITORY_KEY_FUNCTION = CONFIG_PROPS_PREFIX + "repositoryKeyFunction";
74
75 public static final String DEFAULT_REPOSITORY_KEY_FUNCTION = "nid";
76
77 private final RepositoryKeyFunctionFactory repositoryKeyFunctionFactory;
78
79 protected FileTrustedChecksumsSourceSupport(RepositoryKeyFunctionFactory repositoryKeyFunctionFactory) {
80 this.repositoryKeyFunctionFactory = requireNonNull(repositoryKeyFunctionFactory);
81 }
82
83 /**
84 * This implementation will call into underlying code only if enabled, and will enforce non-{@code null} return
85 * value. In worst case, empty map should be returned, meaning "no trusted checksums available".
86 */
87 @Override
88 public Map<String, String> getTrustedArtifactChecksums(
89 RepositorySystemSession session,
90 Artifact artifact,
91 ArtifactRepository artifactRepository,
92 List<ChecksumAlgorithmFactory> checksumAlgorithmFactories) {
93 requireNonNull(session, "session is null");
94 requireNonNull(artifact, "artifact is null");
95 requireNonNull(artifactRepository, "artifactRepository is null");
96 requireNonNull(checksumAlgorithmFactories, "checksumAlgorithmFactories is null");
97 if (isEnabled(session)) {
98 return requireNonNull(
99 doGetTrustedArtifactChecksums(session, artifact, artifactRepository, checksumAlgorithmFactories));
100 }
101 return null;
102 }
103
104 /**
105 * This implementation will call into underlying code only if enabled. Underlying implementation may still choose
106 * to return {@code null}.
107 */
108 @Override
109 public Writer getTrustedArtifactChecksumsWriter(RepositorySystemSession session) {
110 requireNonNull(session, "session is null");
111 if (isEnabled(session)) {
112 return doGetTrustedArtifactChecksumsWriter(session);
113 }
114 return null;
115 }
116
117 /**
118 * Implementors MUST NOT return {@code null} at this point, as this source is enabled.
119 */
120 protected abstract Map<String, String> doGetTrustedArtifactChecksums(
121 RepositorySystemSession session,
122 Artifact artifact,
123 ArtifactRepository artifactRepository,
124 List<ChecksumAlgorithmFactory> checksumAlgorithmFactories);
125
126 /**
127 * Implementors may override this method and return {@link Writer} instance.
128 */
129 protected Writer doGetTrustedArtifactChecksumsWriter(RepositorySystemSession session) {
130 return null;
131 }
132
133 /**
134 * Returns {@code true} if session configuration marks this instance as enabled.
135 * <p>
136 * Default value is {@code false}.
137 */
138 protected abstract boolean isEnabled(RepositorySystemSession session);
139
140 /**
141 * Uses utility {@link DirectoryUtils#resolveDirectory(RepositorySystemSession, String, String, boolean)} to
142 * calculate (and maybe create) basedir for this implementation, never returns {@code null}. The returned
143 * {@link Path} may not exist, if invoked with {@code mayCreate} being {@code false}.
144 * <p>
145 * Default value is {@code ${LOCAL_REPOSITORY}/.checksums}.
146 *
147 * @return The {@link Path} of basedir, never {@code null}.
148 */
149 protected Path getBasedir(
150 RepositorySystemSession session, String defaultValue, String configPropKey, boolean mayCreate) {
151 try {
152 return DirectoryUtils.resolveDirectory(session, defaultValue, configPropKey, mayCreate);
153 } catch (IOException e) {
154 throw new UncheckedIOException(e);
155 }
156 }
157
158 /**
159 * Returns repository key to be used on file system layout.
160 *
161 * @since 2.0.14
162 */
163 protected String repositoryKey(RepositorySystemSession session, ArtifactRepository artifactRepository) {
164 if (artifactRepository instanceof RemoteRepository) {
165 return repositoryKeyFunctionFactory
166 .repositoryKeyFunction(
167 FileTrustedChecksumsSourceSupport.class,
168 session,
169 DEFAULT_REPOSITORY_KEY_FUNCTION,
170 CONFIG_PROP_REPOSITORY_KEY_FUNCTION)
171 .apply((RemoteRepository) artifactRepository, null);
172 } else {
173 return artifactRepository.getId();
174 }
175 }
176 }