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.filter;
20
21 import java.io.IOException;
22 import java.io.UncheckedIOException;
23 import java.nio.file.Path;
24
25 import org.eclipse.aether.ConfigurationProperties;
26 import org.eclipse.aether.RepositorySystemSession;
27 import org.eclipse.aether.internal.impl.checksum.FileTrustedChecksumsSourceSupport;
28 import org.eclipse.aether.repository.RemoteRepository;
29 import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilter;
30 import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilterSource;
31 import org.eclipse.aether.spi.remoterepo.RepositoryKeyFunctionFactory;
32 import org.eclipse.aether.util.DirectoryUtils;
33
34 import static java.util.Objects.requireNonNull;
35
36 /**
37 * Support class for {@link RemoteRepositoryFilterSource} implementations.
38 * <p>
39 * Support class for implementing {@link RemoteRepositoryFilterSource}. It implements basic support
40 * like optional "basedir" calculation, handling of "enabled" flag.
41 * <p>
42 * The configuration keys supported:
43 * <ul>
44 * <li><pre>aether.remoteRepositoryFilter.${id}.enabled</pre> (boolean) must be explicitly set to "true"
45 * to become enabled</li>
46 * <li><pre>aether.remoteRepositoryFilter.${id}.basedir</pre> (string, path) directory from where implementation
47 * can use files. If unset, default value is ".remoteRepositoryFilters/${id}" and is resolved from local
48 * repository basedir.</li>
49 * </ul>
50 *
51 * @since 1.9.0
52 */
53 public abstract class RemoteRepositoryFilterSourceSupport implements RemoteRepositoryFilterSource {
54 protected static final String CONFIG_PROPS_PREFIX =
55 ConfigurationProperties.PREFIX_AETHER + "remoteRepositoryFilter.";
56
57 /**
58 * <b>Experimental:</b> Configuration for "repository key" function.
59 * Note: repository key functions other than "nid" produce repository keys will be <em>way different
60 * that those produced with previous versions or without this option enabled</em>. Filter uses this key function to
61 * lay down and look up files to use in filtering.
62 *
63 * @since 2.0.14
64 * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
65 * @configurationType {@link java.lang.String}
66 * @configurationDefaultValue {@link #DEFAULT_REPOSITORY_KEY_FUNCTION}
67 */
68 public static final String CONFIG_PROP_REPOSITORY_KEY_FUNCTION = CONFIG_PROPS_PREFIX + "repositoryKeyFunction";
69
70 public static final String DEFAULT_REPOSITORY_KEY_FUNCTION = "nid";
71
72 private final RepositoryKeyFunctionFactory repositoryKeyFunctionFactory;
73
74 protected RemoteRepositoryFilterSourceSupport(RepositoryKeyFunctionFactory repositoryKeyFunctionFactory) {
75 this.repositoryKeyFunctionFactory = requireNonNull(repositoryKeyFunctionFactory);
76 }
77
78 /**
79 * Returns {@code true} if session configuration contains this name set to {@code true}.
80 * <p>
81 * Default is {@code true}.
82 */
83 protected abstract boolean isEnabled(RepositorySystemSession session);
84
85 /**
86 * Uses common {@link DirectoryUtils#resolveDirectory(RepositorySystemSession, String, String, boolean)} to
87 * calculate (and maybe create) basedir for this implementation, never returns {@code null}. The returned
88 * {@link Path} may not exists, if invoked with {@code mayCreate} being {@code false}.
89 * <p>
90 * Default value is {@code ${LOCAL_REPOSITORY}/.checksums}.
91 *
92 * @return The {@link Path} of basedir, never {@code null}.
93 */
94 protected Path getBasedir(
95 RepositorySystemSession session, String defaultValue, String configPropKey, boolean mayCreate) {
96 try {
97 return DirectoryUtils.resolveDirectory(session, defaultValue, configPropKey, mayCreate);
98 } catch (IOException e) {
99 throw new UncheckedIOException(e);
100 }
101 }
102
103 /**
104 * We use remote repositories as keys, so normalize them.
105 *
106 * @since 2.0.14
107 * @see RemoteRepository#toBareRemoteRepository()
108 */
109 protected RemoteRepository normalizeRemoteRepository(
110 RepositorySystemSession session, RemoteRepository remoteRepository) {
111 return remoteRepository.toBareRemoteRepository();
112 }
113
114 /**
115 * Returns repository key to be used on file system layout.
116 *
117 * @since 2.0.14
118 */
119 protected String repositoryKey(RepositorySystemSession session, RemoteRepository repository) {
120 return repositoryKeyFunctionFactory
121 .repositoryKeyFunction(
122 FileTrustedChecksumsSourceSupport.class,
123 session,
124 DEFAULT_REPOSITORY_KEY_FUNCTION,
125 CONFIG_PROP_REPOSITORY_KEY_FUNCTION)
126 .apply(repository, null);
127 }
128
129 /**
130 * Simple {@link RemoteRepositoryFilter.Result} immutable implementation.
131 */
132 private static class SimpleResult implements RemoteRepositoryFilter.Result {
133 private final boolean accepted;
134
135 private final String reasoning;
136
137 private SimpleResult(boolean accepted, String reasoning) {
138 this.accepted = accepted;
139 this.reasoning = requireNonNull(reasoning);
140 }
141
142 @Override
143 public boolean isAccepted() {
144 return accepted;
145 }
146
147 @Override
148 public String reasoning() {
149 return reasoning;
150 }
151 }
152
153 /**
154 * Visible for testing.
155 */
156 static RemoteRepositoryFilter.Result result(boolean accepted, String name, String message) {
157 return new SimpleResult(accepted, name + ": " + message);
158 }
159 }