View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.internal.impl;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.List;
28  import java.util.Map;
29  
30  import org.eclipse.aether.RepositorySystemSession;
31  import org.eclipse.aether.impl.RepositoryConnectorProvider;
32  import org.eclipse.aether.repository.RemoteRepository;
33  import org.eclipse.aether.spi.connector.PipelineRepositoryConnectorFactory;
34  import org.eclipse.aether.spi.connector.RepositoryConnector;
35  import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
36  import org.eclipse.aether.transfer.NoRepositoryConnectorException;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  import static java.util.Objects.requireNonNull;
41  
42  /**
43   */
44  @Singleton
45  @Named
46  public class DefaultRepositoryConnectorProvider implements RepositoryConnectorProvider {
47  
48      private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRepositoryConnectorProvider.class);
49  
50      private final Map<String, RepositoryConnectorFactory> connectorFactories;
51  
52      private final Map<String, PipelineRepositoryConnectorFactory> pipelineConnectorFactories;
53  
54      @Inject
55      public DefaultRepositoryConnectorProvider(
56              Map<String, RepositoryConnectorFactory> connectorFactories,
57              Map<String, PipelineRepositoryConnectorFactory> pipelineConnectorFactories) {
58          this.connectorFactories = Collections.unmodifiableMap(connectorFactories);
59          this.pipelineConnectorFactories = Collections.unmodifiableMap(pipelineConnectorFactories);
60      }
61  
62      @Override
63      public RepositoryConnector newRepositoryConnector(RepositorySystemSession session, RemoteRepository repository)
64              throws NoRepositoryConnectorException {
65          requireNonNull(repository, "remote repository cannot be null");
66  
67          if (repository.isBlocked()) {
68              if (repository.getMirroredRepositories().isEmpty()) {
69                  throw new NoRepositoryConnectorException(repository, "Blocked repository: " + repository);
70              } else {
71                  throw new NoRepositoryConnectorException(
72                          repository, "Blocked mirror for repositories: " + repository.getMirroredRepositories());
73              }
74          }
75  
76          PrioritizedComponents<RepositoryConnectorFactory> factories = PrioritizedComponents.reuseOrCreate(
77                  session, RepositoryConnectorFactory.class, connectorFactories, RepositoryConnectorFactory::getPriority);
78  
79          List<NoRepositoryConnectorException> errors = new ArrayList<>();
80          for (PrioritizedComponent<RepositoryConnectorFactory> factory : factories.getEnabled()) {
81              try {
82                  RepositoryConnector connector = factory.getComponent().newInstance(session, repository);
83  
84                  if (LOGGER.isDebugEnabled()) {
85                      StringBuilder buffer = new StringBuilder(256);
86                      buffer.append("Using connector ")
87                              .append(connector.getClass().getSimpleName());
88                      Utils.appendClassLoader(buffer, connector);
89                      buffer.append(" with priority ").append(factory.getPriority());
90                      buffer.append(" for ").append(repository.getUrl());
91                      LOGGER.debug(buffer.toString());
92                  }
93  
94                  connector = pipelineConnector(session, repository, connector);
95  
96                  if (LOGGER.isDebugEnabled()) {
97                      LOGGER.debug("Final pipeline: {}", connector);
98                  }
99  
100                 return connector;
101             } catch (NoRepositoryConnectorException e) {
102                 // continue and try next factory
103                 LOGGER.debug("Could not obtain connector factory for {}", repository, e);
104                 errors.add(e);
105             }
106         }
107 
108         StringBuilder buffer = new StringBuilder(256);
109         if (factories.isEmpty()) {
110             buffer.append("No connector factories available");
111         } else {
112             buffer.append("Cannot access ").append(repository.getUrl());
113             buffer.append(" with type ").append(repository.getContentType());
114             buffer.append(" using the available connector factories: ");
115             factories.list(buffer);
116         }
117 
118         // create exception: if one error, make it cause
119         NoRepositoryConnectorException ex = new NoRepositoryConnectorException(
120                 repository, buffer.toString(), errors.size() == 1 ? errors.get(0) : null);
121         // if more errors, make them all suppressed
122         if (errors.size() > 1) {
123             errors.forEach(ex::addSuppressed);
124         }
125         throw ex;
126     }
127 
128     protected RepositoryConnector pipelineConnector(
129             RepositorySystemSession session, RemoteRepository repository, RepositoryConnector delegate) {
130         PrioritizedComponents<PipelineRepositoryConnectorFactory> factories = PrioritizedComponents.reuseOrCreate(
131                 session,
132                 PipelineRepositoryConnectorFactory.class,
133                 pipelineConnectorFactories,
134                 PipelineRepositoryConnectorFactory::getPriority);
135         for (PrioritizedComponent<PipelineRepositoryConnectorFactory> factory : factories.getEnabled()) {
136             delegate = factory.getComponent().newInstance(session, repository, delegate);
137         }
138         return delegate;
139     }
140 }