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.impl;
20  
21  import java.lang.reflect.Constructor;
22  import java.lang.reflect.Modifier;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.HashMap;
27  import java.util.LinkedHashSet;
28  import java.util.List;
29  import java.util.Map;
30  
31  import org.eclipse.aether.RepositorySystem;
32  import org.eclipse.aether.internal.impl.DefaultArtifactResolver;
33  import org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider;
34  import org.eclipse.aether.internal.impl.DefaultDeployer;
35  import org.eclipse.aether.internal.impl.DefaultFileProcessor;
36  import org.eclipse.aether.internal.impl.DefaultInstaller;
37  import org.eclipse.aether.internal.impl.DefaultLocalPathComposer;
38  import org.eclipse.aether.internal.impl.DefaultLocalRepositoryProvider;
39  import org.eclipse.aether.internal.impl.DefaultMetadataResolver;
40  import org.eclipse.aether.internal.impl.DefaultOfflineController;
41  import org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager;
42  import org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider;
43  import org.eclipse.aether.internal.impl.DefaultRepositoryEventDispatcher;
44  import org.eclipse.aether.internal.impl.DefaultRepositoryLayoutProvider;
45  import org.eclipse.aether.internal.impl.DefaultRepositorySystem;
46  import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle;
47  import org.eclipse.aether.internal.impl.DefaultTrackingFileManager;
48  import org.eclipse.aether.internal.impl.DefaultTransporterProvider;
49  import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager;
50  import org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer;
51  import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory;
52  import org.eclipse.aether.internal.impl.LocalPathComposer;
53  import org.eclipse.aether.internal.impl.Maven2RepositoryLayoutFactory;
54  import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
55  import org.eclipse.aether.internal.impl.TrackingFileManager;
56  import org.eclipse.aether.internal.impl.checksum.DefaultChecksumAlgorithmFactorySelector;
57  import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector;
58  import org.eclipse.aether.internal.impl.filter.DefaultRemoteRepositoryFilterManager;
59  import org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory;
60  import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory;
61  import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactory;
62  import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactoryImpl;
63  import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
64  import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
65  import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory;
66  import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider;
67  import org.eclipse.aether.spi.connector.transport.TransporterProvider;
68  import org.eclipse.aether.spi.io.FileProcessor;
69  import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory;
70  import org.eclipse.aether.spi.locator.Service;
71  import org.eclipse.aether.spi.locator.ServiceLocator;
72  import org.eclipse.aether.spi.log.LoggerFactory;
73  import org.eclipse.aether.spi.synccontext.SyncContextFactory;
74  
75  import static java.util.Objects.requireNonNull;
76  
77  /**
78   * A simple service locator that is already setup with all components from this library. To acquire a complete
79   * repository system, clients need to add an artifact descriptor reader, a version resolver, a version range resolver
80   * and optionally some repository connector and transporter factories to access remote repositories. Once the locator is
81   * fully populated, the repository system can be created like this:
82   *
83   * <pre>
84   * RepositorySystem repoSystem = serviceLocator.getService( RepositorySystem.class );
85   * </pre>
86   *
87   * <em>Note:</em> This class is not thread-safe. Clients are expected to create the service locator and the repository
88   * system on a single thread.
89   *
90   * @deprecated Use of out-of-the-box DI implementation recommended, or, as alternative new supplier from
91   * module {@code maven-resolver-supplier}.
92   */
93  @Deprecated
94  public final class DefaultServiceLocator implements ServiceLocator {
95  
96      private class Entry<T> {
97  
98          private final Class<T> type;
99  
100         private final Collection<Object> providers;
101 
102         private List<T> instances;
103 
104         Entry(Class<T> type) {
105             this.type = requireNonNull(type, "service type cannot be null");
106             providers = new LinkedHashSet<>(8);
107         }
108 
109         public synchronized void setServices(T... services) {
110             providers.clear();
111             if (services != null) {
112                 for (T service : services) {
113                     providers.add(requireNonNull(service, "service instance cannot be null"));
114                 }
115             }
116             instances = null;
117         }
118 
119         public synchronized void setService(Class<? extends T> impl) {
120             providers.clear();
121             addService(impl);
122         }
123 
124         public synchronized void addService(Class<? extends T> impl) {
125             providers.add(requireNonNull(impl, "implementation class cannot be null"));
126             instances = null;
127         }
128 
129         public T getInstance() {
130             List<T> instances = getInstances();
131             return instances.isEmpty() ? null : instances.get(0);
132         }
133 
134         public synchronized List<T> getInstances() {
135             if (instances == null) {
136                 instances = new ArrayList<>(providers.size());
137                 for (Object provider : providers) {
138                     T instance;
139                     if (provider instanceof Class) {
140                         instance = newInstance((Class<?>) provider);
141                     } else {
142                         instance = type.cast(provider);
143                     }
144                     if (instance != null) {
145                         instances.add(instance);
146                     }
147                 }
148                 instances = Collections.unmodifiableList(instances);
149             }
150             return instances;
151         }
152 
153         private T newInstance(Class<?> impl) {
154             try {
155                 Constructor<?> constr = impl.getDeclaredConstructor();
156                 if (!Modifier.isPublic(constr.getModifiers())) {
157                     constr.setAccessible(true);
158                 }
159                 Object obj = constr.newInstance();
160 
161                 T instance = type.cast(obj);
162                 if (instance instanceof Service) {
163                     ((Service) instance).initService(DefaultServiceLocator.this);
164                 }
165                 return instance;
166             } catch (Exception | LinkageError e) {
167                 serviceCreationFailed(type, impl, e);
168             }
169             return null;
170         }
171     }
172 
173     private final Map<Class<?>, Entry<?>> entries;
174 
175     private ErrorHandler errorHandler;
176 
177     /**
178      * Creates a new service locator that already knows about all service implementations included this library.
179      */
180     public DefaultServiceLocator() {
181         entries = new HashMap<>();
182 
183         addService(RepositorySystem.class, DefaultRepositorySystem.class);
184         addService(ArtifactResolver.class, DefaultArtifactResolver.class);
185         addService(DependencyCollector.class, DefaultDependencyCollector.class);
186         addService(Deployer.class, DefaultDeployer.class);
187         addService(Installer.class, DefaultInstaller.class);
188         addService(MetadataResolver.class, DefaultMetadataResolver.class);
189         addService(RepositoryLayoutProvider.class, DefaultRepositoryLayoutProvider.class);
190         addService(RepositoryLayoutFactory.class, Maven2RepositoryLayoutFactory.class);
191         addService(TransporterProvider.class, DefaultTransporterProvider.class);
192         addService(ChecksumPolicyProvider.class, DefaultChecksumPolicyProvider.class);
193         addService(RepositoryConnectorProvider.class, DefaultRepositoryConnectorProvider.class);
194         addService(RemoteRepositoryManager.class, DefaultRemoteRepositoryManager.class);
195         addService(UpdateCheckManager.class, DefaultUpdateCheckManager.class);
196         addService(UpdatePolicyAnalyzer.class, DefaultUpdatePolicyAnalyzer.class);
197         addService(FileProcessor.class, DefaultFileProcessor.class);
198         addService(
199                 org.eclipse.aether.impl.SyncContextFactory.class,
200                 org.eclipse.aether.internal.impl.synccontext.legacy.DefaultSyncContextFactory.class);
201         addService(SyncContextFactory.class, DefaultSyncContextFactory.class);
202         addService(RepositoryEventDispatcher.class, DefaultRepositoryEventDispatcher.class);
203         addService(OfflineController.class, DefaultOfflineController.class);
204         addService(LocalRepositoryProvider.class, DefaultLocalRepositoryProvider.class);
205         addService(LocalRepositoryManagerFactory.class, SimpleLocalRepositoryManagerFactory.class);
206         addService(LocalRepositoryManagerFactory.class, EnhancedLocalRepositoryManagerFactory.class);
207         addService(LoggerFactory.class, Slf4jLoggerFactory.class);
208         addService(TrackingFileManager.class, DefaultTrackingFileManager.class);
209         addService(ChecksumAlgorithmFactorySelector.class, DefaultChecksumAlgorithmFactorySelector.class);
210         addService(LocalPathComposer.class, DefaultLocalPathComposer.class);
211         addService(RemoteRepositoryFilterManager.class, DefaultRemoteRepositoryFilterManager.class);
212         addService(RepositorySystemLifecycle.class, DefaultRepositorySystemLifecycle.class);
213         addService(NamedLockFactoryAdapterFactory.class, NamedLockFactoryAdapterFactoryImpl.class);
214     }
215 
216     private <T> Entry<T> getEntry(Class<T> type, boolean create) {
217         @SuppressWarnings("unchecked")
218         Entry<T> entry = (Entry<T>) entries.get(requireNonNull(type, "service type cannot be null"));
219         if (entry == null && create) {
220             entry = new Entry<>(type);
221             entries.put(type, entry);
222         }
223         return entry;
224     }
225 
226     /**
227      * Sets the implementation class for a service. The specified class must have a no-arg constructor (of any
228      * visibility). If the service implementation itself requires other services for its operation, it should implement
229      * {@link Service} to gain access to this service locator.
230      *
231      * @param <T> The service type.
232      * @param type The interface describing the service, must not be {@code null}.
233      * @param impl The implementation class of the service, must not be {@code null}.
234      * @return This locator for chaining, never {@code null}.
235      */
236     public <T> DefaultServiceLocator setService(Class<T> type, Class<? extends T> impl) {
237         getEntry(type, true).setService(impl);
238         return this;
239     }
240 
241     /**
242      * Adds an implementation class for a service. The specified class must have a no-arg constructor (of any
243      * visibility). If the service implementation itself requires other services for its operation, it should implement
244      * {@link Service} to gain access to this service locator.
245      *
246      * @param <T> The service type.
247      * @param type The interface describing the service, must not be {@code null}.
248      * @param impl The implementation class of the service, must not be {@code null}.
249      * @return This locator for chaining, never {@code null}.
250      */
251     public <T> DefaultServiceLocator addService(Class<T> type, Class<? extends T> impl) {
252         getEntry(type, true).addService(impl);
253         return this;
254     }
255 
256     /**
257      * Sets the instances for a service.
258      *
259      * @param <T> The service type.
260      * @param type The interface describing the service, must not be {@code null}.
261      * @param services The instances of the service, may be {@code null} but must not contain {@code null} elements.
262      * @return This locator for chaining, never {@code null}.
263      */
264     public <T> DefaultServiceLocator setServices(Class<T> type, T... services) {
265         getEntry(type, true).setServices(services);
266         return this;
267     }
268 
269     public <T> T getService(Class<T> type) {
270         Entry<T> entry = getEntry(type, false);
271         return (entry != null) ? entry.getInstance() : null;
272     }
273 
274     public <T> List<T> getServices(Class<T> type) {
275         Entry<T> entry = getEntry(type, false);
276         return (entry != null) ? entry.getInstances() : null;
277     }
278 
279     private void serviceCreationFailed(Class<?> type, Class<?> impl, Throwable exception) {
280         if (errorHandler != null) {
281             errorHandler.serviceCreationFailed(type, impl, exception);
282         }
283     }
284 
285     /**
286      * Sets the error handler to use.
287      *
288      * @param errorHandler The error handler to use, may be {@code null} to ignore/swallow errors.
289      */
290     public void setErrorHandler(ErrorHandler errorHandler) {
291         this.errorHandler = errorHandler;
292     }
293 
294     /**
295      * A hook to customize the handling of errors encountered while locating a service implementation.
296      */
297     public abstract static class ErrorHandler {
298 
299         /**
300          * Handles errors during creation of a service. The default implemention does nothing.
301          *
302          * @param type The interface describing the service, must not be {@code null}.
303          * @param impl The implementation class of the service, must not be {@code null}.
304          * @param exception The error that occurred while trying to instantiate the implementation class, must not be
305          *            {@code null}.
306          */
307         public void serviceCreationFailed(Class<?> type, Class<?> impl, Throwable exception) {}
308     }
309 }