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