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 /** 056 * SL enabled ctor. 057 * 058 * @deprecated for SL and testing purposes only. 059 */ 060 @Deprecated 061 public DefaultRemoteRepositoryFilterManager() { 062 this.sources = new HashMap<>(); 063 } 064 065 @Inject 066 public DefaultRemoteRepositoryFilterManager(Map<String, RemoteRepositoryFilterSource> sources) { 067 this.sources = requireNonNull(sources); 068 } 069 070 @Override 071 public RemoteRepositoryFilter getRemoteRepositoryFilter(RepositorySystemSession session) { 072 return (RemoteRepositoryFilter) session.getData().computeIfAbsent(INSTANCE_KEY, () -> { 073 HashMap<String, RemoteRepositoryFilter> filters = new HashMap<>(); 074 for (Map.Entry<String, RemoteRepositoryFilterSource> entry : sources.entrySet()) { 075 RemoteRepositoryFilter filter = entry.getValue().getRemoteRepositoryFilter(session); 076 if (filter != null) { 077 filters.put(entry.getKey(), filter); 078 } 079 } 080 if (!filters.isEmpty()) { 081 return new Participants(filters); 082 } else { 083 return null; 084 } 085 }); 086 } 087 088 /** 089 * {@link RemoteRepositoryFilter} instance when there are participant filters present. It evaluates into result 090 * using {@link Consensus}. 091 */ 092 private static class Participants implements RemoteRepositoryFilter { 093 private final Map<String, RemoteRepositoryFilter> participants; 094 095 private Participants(Map<String, RemoteRepositoryFilter> participants) { 096 this.participants = Collections.unmodifiableMap(participants); 097 } 098 099 @Override 100 public RemoteRepositoryFilter.Result acceptArtifact(RemoteRepository remoteRepository, Artifact artifact) { 101 return new Consensus( 102 participants.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue() 103 .acceptArtifact(remoteRepository, artifact)))); 104 } 105 106 @Override 107 public RemoteRepositoryFilter.Result acceptMetadata(RemoteRepository remoteRepository, Metadata metadata) { 108 return new Consensus( 109 participants.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue() 110 .acceptMetadata(remoteRepository, metadata)))); 111 } 112 } 113 114 /** 115 * {@link RemoteRepositoryFilter.Result} based on "consensus". All participant have to "accept" to make this 116 * instance "accept". 117 */ 118 private static class Consensus implements RemoteRepositoryFilter.Result { 119 private final boolean accepted; 120 121 private final String reasoning; 122 123 Consensus(Map<String, RemoteRepositoryFilter.Result> results) { 124 this.accepted = results.values().stream().allMatch(RemoteRepositoryFilter.Result::isAccepted); 125 this.reasoning = results.values().stream() 126 .filter(r -> !r.isAccepted()) 127 .map(RemoteRepositoryFilter.Result::reasoning) 128 .collect(Collectors.joining("; ")); 129 } 130 131 @Override 132 public boolean isAccepted() { 133 return accepted; 134 } 135 136 @Override 137 public String reasoning() { 138 return reasoning; 139 } 140 } 141}