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 javax.inject.Inject; 022import javax.inject.Named; 023import javax.inject.Singleton; 024 025import java.util.Collections; 026import java.util.HashMap; 027import java.util.Map; 028import java.util.stream.Collectors; 029 030import org.eclipse.aether.RepositorySystemSession; 031import org.eclipse.aether.artifact.Artifact; 032import org.eclipse.aether.impl.RemoteRepositoryFilterManager; 033import org.eclipse.aether.metadata.Metadata; 034import org.eclipse.aether.repository.RemoteRepository; 035import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilter; 036import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilterSource; 037 038import static java.util.Objects.requireNonNull; 039 040/** 041 * Default implementation of {@link RemoteRepositoryFilterManager}, it always returns a {@link RemoteRepositoryFilter} 042 * instance, even if no filter sources enabled/registered (then "always allow" instance). 043 * <p> 044 * The created {@link RemoteRepositoryFilter} instance is created once per session and cached. 045 * 046 * @since 1.9.0 047 */ 048@Singleton 049@Named 050public final class DefaultRemoteRepositoryFilterManager implements RemoteRepositoryFilterManager { 051 private static final String INSTANCE_KEY = DefaultRemoteRepositoryFilterManager.class.getName() + ".instance"; 052 053 private final Map<String, RemoteRepositoryFilterSource> sources; 054 055 @Inject 056 public DefaultRemoteRepositoryFilterManager(Map<String, RemoteRepositoryFilterSource> sources) { 057 this.sources = requireNonNull(sources); 058 } 059 060 @Override 061 public RemoteRepositoryFilter getRemoteRepositoryFilter(RepositorySystemSession session) { 062 return (RemoteRepositoryFilter) session.getData().computeIfAbsent(INSTANCE_KEY, () -> { 063 HashMap<String, RemoteRepositoryFilter> filters = new HashMap<>(); 064 for (Map.Entry<String, RemoteRepositoryFilterSource> entry : sources.entrySet()) { 065 RemoteRepositoryFilter filter = entry.getValue().getRemoteRepositoryFilter(session); 066 if (filter != null) { 067 filters.put(entry.getKey(), filter); 068 } 069 } 070 if (!filters.isEmpty()) { 071 return new Participants(filters); 072 } else { 073 return null; 074 } 075 }); 076 } 077 078 /** 079 * {@link RemoteRepositoryFilter} instance when there are participant filters present. It evaluates into result 080 * using {@link Consensus}. 081 */ 082 private static class Participants implements RemoteRepositoryFilter { 083 private final Map<String, RemoteRepositoryFilter> participants; 084 085 private Participants(Map<String, RemoteRepositoryFilter> participants) { 086 this.participants = Collections.unmodifiableMap(participants); 087 } 088 089 @Override 090 public RemoteRepositoryFilter.Result acceptArtifact(RemoteRepository remoteRepository, Artifact artifact) { 091 return new Consensus( 092 participants.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue() 093 .acceptArtifact(remoteRepository, artifact)))); 094 } 095 096 @Override 097 public RemoteRepositoryFilter.Result acceptMetadata(RemoteRepository remoteRepository, Metadata metadata) { 098 return new Consensus( 099 participants.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue() 100 .acceptMetadata(remoteRepository, metadata)))); 101 } 102 } 103 104 /** 105 * {@link RemoteRepositoryFilter.Result} based on "consensus". All participant have to "accept" to make this 106 * instance "accept". 107 */ 108 private static class Consensus implements RemoteRepositoryFilter.Result { 109 private final boolean accepted; 110 111 private final String reasoning; 112 113 Consensus(Map<String, RemoteRepositoryFilter.Result> results) { 114 this.accepted = results.values().stream().allMatch(RemoteRepositoryFilter.Result::isAccepted); 115 this.reasoning = results.values().stream() 116 .filter(r -> !r.isAccepted()) 117 .map(RemoteRepositoryFilter.Result::reasoning) 118 .collect(Collectors.joining("; ")); 119 } 120 121 @Override 122 public boolean isAccepted() { 123 return accepted; 124 } 125 126 @Override 127 public String reasoning() { 128 return reasoning; 129 } 130 } 131}