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; 024 025import org.eclipse.aether.ConfigurationProperties; 026import org.eclipse.aether.RepositorySystemSession; 027import org.eclipse.aether.internal.impl.checksum.FileTrustedChecksumsSourceSupport; 028import org.eclipse.aether.repository.RemoteRepository; 029import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilter; 030import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilterSource; 031import org.eclipse.aether.spi.remoterepo.RepositoryKeyFunctionFactory; 032import org.eclipse.aether.util.DirectoryUtils; 033 034import static java.util.Objects.requireNonNull; 035 036/** 037 * Support class for {@link RemoteRepositoryFilterSource} implementations. 038 * <p> 039 * Support class for implementing {@link RemoteRepositoryFilterSource}. It implements basic support 040 * like optional "basedir" calculation, handling of "enabled" flag. 041 * <p> 042 * The configuration keys supported: 043 * <ul> 044 * <li><pre>aether.remoteRepositoryFilter.${id}.enabled</pre> (boolean) must be explicitly set to "true" 045 * to become enabled</li> 046 * <li><pre>aether.remoteRepositoryFilter.${id}.basedir</pre> (string, path) directory from where implementation 047 * can use files. If unset, default value is ".remoteRepositoryFilters/${id}" and is resolved from local 048 * repository basedir.</li> 049 * </ul> 050 * 051 * @since 1.9.0 052 */ 053public abstract class RemoteRepositoryFilterSourceSupport implements RemoteRepositoryFilterSource { 054 protected static final String CONFIG_PROPS_PREFIX = 055 ConfigurationProperties.PREFIX_AETHER + "remoteRepositoryFilter."; 056 057 /** 058 * <b>Experimental:</b> Configuration for "repository key" function. 059 * Note: repository key functions other than "nid" produce repository keys will be <em>way different 060 * that those produced with previous versions or without this option enabled</em>. Filter uses this key function to 061 * lay down and look up files to use in filtering. 062 * 063 * @since 2.0.14 064 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 065 * @configurationType {@link java.lang.String} 066 * @configurationDefaultValue {@link #DEFAULT_REPOSITORY_KEY_FUNCTION} 067 */ 068 public static final String CONFIG_PROP_REPOSITORY_KEY_FUNCTION = CONFIG_PROPS_PREFIX + "repositoryKeyFunction"; 069 070 public static final String DEFAULT_REPOSITORY_KEY_FUNCTION = "nid"; 071 072 private final RepositoryKeyFunctionFactory repositoryKeyFunctionFactory; 073 074 protected RemoteRepositoryFilterSourceSupport(RepositoryKeyFunctionFactory repositoryKeyFunctionFactory) { 075 this.repositoryKeyFunctionFactory = requireNonNull(repositoryKeyFunctionFactory); 076 } 077 078 /** 079 * Returns {@code true} if session configuration contains this name set to {@code true}. 080 * <p> 081 * Default is {@code true}. 082 */ 083 protected abstract boolean isEnabled(RepositorySystemSession session); 084 085 /** 086 * Uses common {@link DirectoryUtils#resolveDirectory(RepositorySystemSession, String, String, boolean)} to 087 * calculate (and maybe create) basedir for this implementation, never returns {@code null}. The returned 088 * {@link Path} may not exists, if invoked with {@code mayCreate} being {@code false}. 089 * <p> 090 * Default value is {@code ${LOCAL_REPOSITORY}/.checksums}. 091 * 092 * @return The {@link Path} of basedir, never {@code null}. 093 */ 094 protected Path getBasedir( 095 RepositorySystemSession session, String defaultValue, String configPropKey, boolean mayCreate) { 096 try { 097 return DirectoryUtils.resolveDirectory(session, defaultValue, configPropKey, mayCreate); 098 } catch (IOException e) { 099 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}