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          LOGGER.debug("Selecting RepositoryConnector for {}", repository);
80  
81          List<NoRepositoryConnectorException> errors = new ArrayList<>();
82          for (PrioritizedComponent<RepositoryConnectorFactory> factory : factories.getEnabled()) {
83              try {
84                  RepositoryConnector connector = factory.getComponent().newInstance(session, repository);
85  
86                  if (LOGGER.isDebugEnabled()) {
87                      StringBuilder buffer = new StringBuilder(256);
88                      buffer.append("Using connector ")
89                              .append(connector.getClass().getSimpleName());
90                      Utils.appendClassLoader(buffer, connector);
91                      buffer.append(" with priority ").append(factory.getPriority());
92                      buffer.append(" for ").append(repository.getUrl());
93                      LOGGER.debug(buffer.toString());
94                  }
95  
96                  connector = pipelineConnector(session, repository, connector);
97  
98                  if (LOGGER.isDebugEnabled()) {
99                      LOGGER.debug("Final pipeline: {}", connector);
100                 }
101 
102                 return connector;
103             } catch (NoRepositoryConnectorException e) {
104                 // continue and try next factory
105                 if (LOGGER.isTraceEnabled()) {
106                     LOGGER.trace(
107                             "Connector factory {} did not provide connector for {}",
108                             factory.getComponent().getClass(),
109                             repository,
110                             e);
111                 } else {
112                     LOGGER.debug(
113                             "Connector factory {} did not provide connector for {}: {}",
114                             factory.getComponent().getClass(),
115                             repository,
116                             e.getMessage());
117                 }
118                 errors.add(e);
119             }
120         }
121 
122         StringBuilder buffer = new StringBuilder(256);
123         if (factories.isEmpty()) {
124             buffer.append("No connector factories available");
125         } else {
126             buffer.append("Cannot access ").append(repository.getUrl());
127             buffer.append(" with type ").append(repository.getContentType());
128             buffer.append(" using the available connector factories: ");
129             factories.list(buffer);
130         }
131 
132         // create exception: if one error, make it cause
133         NoRepositoryConnectorException ex = new NoRepositoryConnectorException(
134                 repository, buffer.toString(), errors.size() == 1 ? errors.get(0) : null);
135         // if more errors, make them all suppressed
136         if (errors.size() > 1) {
137             errors.forEach(ex::addSuppressed);
138         }
139         throw ex;
140     }
141 
142     protected RepositoryConnector pipelineConnector(
143             RepositorySystemSession session, RemoteRepository repository, RepositoryConnector delegate) {
144         PrioritizedComponents<PipelineRepositoryConnectorFactory> factories = PrioritizedComponents.reuseOrCreate(
145                 session,
146                 PipelineRepositoryConnectorFactory.class,
147                 pipelineConnectorFactories,
148                 PipelineRepositoryConnectorFactory::getPriority);
149         for (PrioritizedComponent<PipelineRepositoryConnectorFactory> factory : factories.getEnabled()) {
150             delegate = factory.getComponent().newInstance(session, repository, delegate);
151         }
152         return delegate;
153     }
154 }