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.filter;
020
021import java.io.IOException;
022import java.io.UncheckedIOException;
023import java.nio.file.Path;
024import java.util.ArrayList;
025import java.util.List;
026
027import org.eclipse.aether.ConfigurationProperties;
028import org.eclipse.aether.RepositorySystemSession;
029import org.eclipse.aether.repository.RemoteRepository;
030import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilter;
031import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilterSource;
032import org.eclipse.aether.spi.remoterepo.RepositoryKeyFunctionFactory;
033import org.eclipse.aether.util.DirectoryUtils;
034import org.slf4j.Logger;
035import org.slf4j.LoggerFactory;
036
037import static java.util.Objects.requireNonNull;
038
039/**
040 * Support class for {@link RemoteRepositoryFilterSource} implementations.
041 * <p>
042 * Support class for implementing {@link RemoteRepositoryFilterSource}. It implements basic support
043 * like optional "basedir" calculation, handling of "enabled" flag.
044 * <p>
045 * The configuration keys supported:
046 * <ul>
047 *     <li><pre>aether.remoteRepositoryFilter.${id}.enabled</pre> (boolean) must be explicitly set to "true"
048 *     to become enabled</li>
049 *     <li><pre>aether.remoteRepositoryFilter.${id}.basedir</pre> (string, path) directory from where implementation
050 *     can use files. If unset, default value is ".remoteRepositoryFilters/${id}" and is resolved from local
051 *     repository basedir.</li>
052 * </ul>
053 *
054 * @since 1.9.0
055 */
056public abstract class RemoteRepositoryFilterSourceSupport implements RemoteRepositoryFilterSource {
057    protected static final String CONFIG_PROPS_PREFIX =
058            ConfigurationProperties.PREFIX_AETHER + "remoteRepositoryFilter.";
059
060    protected final Logger logger = LoggerFactory.getLogger(getClass());
061
062    private final RepositoryKeyFunctionFactory repositoryKeyFunctionFactory;
063
064    protected RemoteRepositoryFilterSourceSupport(RepositoryKeyFunctionFactory repositoryKeyFunctionFactory) {
065        this.repositoryKeyFunctionFactory = requireNonNull(repositoryKeyFunctionFactory);
066    }
067
068    /**
069     * Returns {@code true} if session configuration contains this name set to {@code true}.
070     * <p>
071     * Default is {@code true}.
072     */
073    protected abstract boolean isEnabled(RepositorySystemSession session);
074
075    /**
076     * Uses common {@link DirectoryUtils#resolveDirectory(RepositorySystemSession, String, String, boolean)} to
077     * calculate (and maybe create) basedir for this implementation, never returns {@code null}. The returned
078     * {@link Path} may not exists, if invoked with {@code mayCreate} being {@code false}.
079     * <p>
080     * Default value is {@code ${LOCAL_REPOSITORY}/.checksums}.
081     *
082     * @return The {@link Path} of basedir, never {@code null}.
083     */
084    protected Path getBasedir(
085            RepositorySystemSession session, String defaultValue, String configPropKey, boolean mayCreate) {
086        try {
087            return DirectoryUtils.resolveDirectory(session, defaultValue, configPropKey, mayCreate);
088        } catch (IOException e) {
089            throw new UncheckedIOException(e);
090        }
091    }
092
093    /**
094     * We use remote repositories as keys, so normalize them.
095     *
096     * @since 2.0.14
097     * @see RemoteRepository#toBareRemoteRepository()
098     */
099    protected RemoteRepository normalizeRemoteRepository(
100            RepositorySystemSession session, RemoteRepository remoteRepository) {
101        return remoteRepository.toBareRemoteRepository();
102    }
103
104    /**
105     * Returns repository keys to be used on file system layout for user provided files. They are ordered as
106     * "most specific" (using {@link RepositoryKeyFunctionFactory#trackingRepositoryKeyFunction(RepositorySystemSession)})
107     * to simple "id based" one. This allows user to keep using plain ID, but also to provide very narrowly targeted
108     * input files, when needed.
109     *
110     * @since 2.0.14
111     */
112    protected List<String> repositoryKeys(RepositorySystemSession session, RemoteRepository repository) {
113        ArrayList<String> keys = new ArrayList<>();
114        keys.add(repositoryKeyFunctionFactory
115                .trackingRepositoryKeyFunction(session)
116                .apply(repository, null));
117        keys.add(repositoryKeyFunctionFactory
118                .systemRepositoryKeyFunction(session)
119                .apply(repository, null));
120        return keys;
121    }
122
123    /**
124     * Simple {@link RemoteRepositoryFilter.Result} immutable implementation.
125     */
126    private static class SimpleResult implements RemoteRepositoryFilter.Result {
127        private final boolean accepted;
128
129        private final String reasoning;
130
131        private SimpleResult(boolean accepted, String reasoning) {
132            this.accepted = accepted;
133            this.reasoning = requireNonNull(reasoning);
134        }
135
136        @Override
137        public boolean isAccepted() {
138            return accepted;
139        }
140
141        @Override
142        public String reasoning() {
143            return reasoning;
144        }
145    }
146
147    /**
148     * Visible for testing.
149     */
150    static RemoteRepositoryFilter.Result result(boolean accepted, String name, String message) {
151        return new SimpleResult(accepted, name + ": " + message);
152    }
153}