View Javadoc
1   package org.eclipse.aether.internal.impl.filter;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import javax.inject.Inject;
23  import javax.inject.Named;
24  import javax.inject.Singleton;
25  
26  import java.util.Collections;
27  import java.util.HashMap;
28  import java.util.Map;
29  import java.util.stream.Collectors;
30  
31  import org.eclipse.aether.RepositorySystemSession;
32  import org.eclipse.aether.artifact.Artifact;
33  import org.eclipse.aether.impl.RemoteRepositoryFilterManager;
34  import org.eclipse.aether.metadata.Metadata;
35  import org.eclipse.aether.repository.RemoteRepository;
36  import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilter;
37  import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilterSource;
38  
39  import static java.util.Objects.requireNonNull;
40  
41  /**
42   * Default implementation of {@link RemoteRepositoryFilterManager}, it always returns a {@link RemoteRepositoryFilter}
43   * instance, even if no filter sources enabled/registered (then "always allow" instance).
44   * <p>
45   * The created {@link RemoteRepositoryFilter} instance is created once per session and cached.
46   *
47   * @since 1.9.0
48   */
49  @Singleton
50  @Named
51  public final class DefaultRemoteRepositoryFilterManager
52          implements RemoteRepositoryFilterManager
53  {
54      private static final String INSTANCE_KEY = DefaultRemoteRepositoryFilterManager.class.getName() + ".instance";
55  
56      private final Map<String, RemoteRepositoryFilterSource> sources;
57  
58      /**
59       * SL enabled ctor.
60       *
61       * @deprecated for SL and testing purposes only.
62       */
63      @Deprecated
64      public DefaultRemoteRepositoryFilterManager()
65      {
66          this.sources = new HashMap<>();
67      }
68  
69      @Inject
70      public DefaultRemoteRepositoryFilterManager( Map<String, RemoteRepositoryFilterSource> sources )
71      {
72          this.sources = requireNonNull( sources );
73      }
74  
75      @Override
76      public RemoteRepositoryFilter getRemoteRepositoryFilter( RepositorySystemSession session )
77      {
78          return (RemoteRepositoryFilter) session.getData().computeIfAbsent( INSTANCE_KEY, () ->
79                  {
80                      HashMap<String, RemoteRepositoryFilter> filters = new HashMap<>();
81                      for ( Map.Entry<String, RemoteRepositoryFilterSource> entry : sources.entrySet() )
82                      {
83                          RemoteRepositoryFilter filter = entry.getValue().getRemoteRepositoryFilter( session );
84                          if ( filter != null )
85                          {
86                              filters.put( entry.getKey(), filter );
87                          }
88                      }
89                      if ( !filters.isEmpty() )
90                      {
91                          return new Participants( filters );
92                      }
93                      else
94                      {
95                          return null;
96                      }
97                  }
98          );
99      }
100 
101     /**
102      * {@link RemoteRepositoryFilter} instance when there are participant filters present. It evaluates into result
103      * using {@link Consensus}.
104      */
105     private static class Participants implements RemoteRepositoryFilter
106     {
107         private final Map<String, RemoteRepositoryFilter> participants;
108 
109         private Participants( Map<String, RemoteRepositoryFilter> participants )
110         {
111             this.participants = Collections.unmodifiableMap( participants );
112         }
113 
114         @Override
115         public RemoteRepositoryFilter.Result acceptArtifact( RemoteRepository remoteRepository, Artifact artifact )
116         {
117             return new Consensus( participants.entrySet().stream()
118                     .collect( Collectors.toMap(
119                             Map.Entry::getKey,
120                             e -> e.getValue().acceptArtifact( remoteRepository, artifact ) ) ) );
121         }
122 
123         @Override
124         public RemoteRepositoryFilter.Result acceptMetadata( RemoteRepository remoteRepository, Metadata metadata )
125         {
126             return new Consensus( participants.entrySet().stream()
127                     .collect( Collectors.toMap(
128                             Map.Entry::getKey,
129                             e -> e.getValue().acceptMetadata( remoteRepository, metadata ) ) ) );
130         }
131     }
132 
133     /**
134      * {@link RemoteRepositoryFilter.Result} based on "consensus". All participant have to "accept" to make this
135      * instance "accept".
136      */
137     private static class Consensus implements RemoteRepositoryFilter.Result
138     {
139         private final boolean accepted;
140 
141         private final String reasoning;
142 
143         Consensus( Map<String, RemoteRepositoryFilter.Result> results )
144         {
145             this.accepted = results.values().stream().allMatch( RemoteRepositoryFilter.Result::isAccepted );
146             this.reasoning = results.values().stream().filter( r -> !r.isAccepted() ).map(
147                     RemoteRepositoryFilter.Result::reasoning ).collect(
148                     Collectors.joining( "; " ) );
149         }
150 
151         @Override
152         public boolean isAccepted()
153         {
154             return accepted;
155         }
156 
157         @Override
158         public String reasoning()
159         {
160             return reasoning;
161         }
162     }
163 }