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