001package org.eclipse.aether.impl; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.lang.reflect.Constructor; 023import java.lang.reflect.Modifier; 024import java.util.ArrayList; 025import java.util.Collection; 026import java.util.Collections; 027import java.util.HashMap; 028import java.util.LinkedHashSet; 029import java.util.List; 030import java.util.Map; 031import static java.util.Objects.requireNonNull; 032 033import org.eclipse.aether.RepositorySystem; 034import org.eclipse.aether.internal.impl.DefaultArtifactResolver; 035import org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider; 036import org.eclipse.aether.internal.impl.DefaultTrackingFileManager; 037import org.eclipse.aether.internal.impl.TrackingFileManager; 038import org.eclipse.aether.internal.impl.checksum.DefaultChecksumAlgorithmFactorySelector; 039import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector; 040import org.eclipse.aether.internal.impl.DefaultDeployer; 041import org.eclipse.aether.internal.impl.DefaultFileProcessor; 042import org.eclipse.aether.internal.impl.DefaultInstaller; 043import org.eclipse.aether.internal.impl.DefaultLocalRepositoryProvider; 044import org.eclipse.aether.internal.impl.DefaultMetadataResolver; 045import org.eclipse.aether.internal.impl.DefaultOfflineController; 046import org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager; 047import org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider; 048import org.eclipse.aether.internal.impl.DefaultRepositoryEventDispatcher; 049import org.eclipse.aether.internal.impl.DefaultRepositoryLayoutProvider; 050import org.eclipse.aether.internal.impl.DefaultRepositorySystem; 051import org.eclipse.aether.internal.impl.DefaultTransporterProvider; 052import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager; 053import org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer; 054import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory; 055import org.eclipse.aether.internal.impl.Maven2RepositoryLayoutFactory; 056import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory; 057import org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory; 058import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory; 059import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactorySelector; 060import org.eclipse.aether.internal.impl.synccontext.named.SimpleNamedLockFactorySelector; 061import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector; 062import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider; 063import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory; 064import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider; 065import org.eclipse.aether.spi.connector.transport.TransporterProvider; 066import org.eclipse.aether.spi.io.FileProcessor; 067import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory; 068import org.eclipse.aether.spi.locator.Service; 069import org.eclipse.aether.spi.locator.ServiceLocator; 070import org.eclipse.aether.spi.log.LoggerFactory; 071import org.eclipse.aether.spi.synccontext.SyncContextFactory; 072 073/** 074 * A simple service locator that is already setup with all components from this library. To acquire a complete 075 * repository system, clients need to add an artifact descriptor reader, a version resolver, a version range resolver 076 * and optionally some repository connector and transporter factories to access remote repositories. Once the locator is 077 * fully populated, the repository system can be created like this: 078 * 079 * <pre> 080 * RepositorySystem repoSystem = serviceLocator.getService( RepositorySystem.class ); 081 * </pre> 082 * 083 * <em>Note:</em> This class is not thread-safe. Clients are expected to create the service locator and the repository 084 * system on a single thread. 085 * 086 * @deprecated Use some out-of-the-box DI implementation instead. 087 */ 088@Deprecated 089public final class DefaultServiceLocator 090 implements ServiceLocator 091{ 092 093 private class Entry<T> 094 { 095 096 private final Class<T> type; 097 098 private final Collection<Object> providers; 099 100 private List<T> instances; 101 102 Entry( Class<T> type ) 103 { 104 this.type = requireNonNull( type, "service type cannot be null" ); 105 providers = new LinkedHashSet<>( 8 ); 106 } 107 108 public synchronized void setServices( T... services ) 109 { 110 providers.clear(); 111 if ( services != null ) 112 { 113 for ( T service : services ) 114 { 115 providers.add( requireNonNull( service, "service instance cannot be null" ) ); 116 } 117 } 118 instances = null; 119 } 120 121 public synchronized void setService( Class<? extends T> impl ) 122 { 123 providers.clear(); 124 addService( impl ); 125 } 126 127 public synchronized void addService( Class<? extends T> impl ) 128 { 129 providers.add( requireNonNull( impl, "implementation class cannot be null" ) ); 130 instances = null; 131 } 132 133 public T getInstance() 134 { 135 List<T> instances = getInstances(); 136 return instances.isEmpty() ? null : instances.get( 0 ); 137 } 138 139 public synchronized List<T> getInstances() 140 { 141 if ( instances == null ) 142 { 143 instances = new ArrayList<>( providers.size() ); 144 for ( Object provider : providers ) 145 { 146 T instance; 147 if ( provider instanceof Class ) 148 { 149 instance = newInstance( (Class<?>) provider ); 150 } 151 else 152 { 153 instance = type.cast( provider ); 154 } 155 if ( instance != null ) 156 { 157 instances.add( instance ); 158 } 159 } 160 instances = Collections.unmodifiableList( instances ); 161 } 162 return instances; 163 } 164 165 private T newInstance( Class<?> impl ) 166 { 167 try 168 { 169 Constructor<?> constr = impl.getDeclaredConstructor(); 170 if ( !Modifier.isPublic( constr.getModifiers() ) ) 171 { 172 constr.setAccessible( true ); 173 } 174 Object obj = constr.newInstance(); 175 176 T instance = type.cast( obj ); 177 if ( instance instanceof Service ) 178 { 179 ( (Service) instance ).initService( DefaultServiceLocator.this ); 180 } 181 return instance; 182 } 183 catch ( Exception | LinkageError e ) 184 { 185 serviceCreationFailed( type, impl, e ); 186 } 187 return null; 188 } 189 190 } 191 192 private final Map<Class<?>, Entry<?>> entries; 193 194 private ErrorHandler errorHandler; 195 196 /** 197 * Creates a new service locator that already knows about all service implementations included this library. 198 */ 199 public DefaultServiceLocator() 200 { 201 entries = new HashMap<>(); 202 203 addService( RepositorySystem.class, DefaultRepositorySystem.class ); 204 addService( ArtifactResolver.class, DefaultArtifactResolver.class ); 205 addService( DependencyCollector.class, DefaultDependencyCollector.class ); 206 addService( Deployer.class, DefaultDeployer.class ); 207 addService( Installer.class, DefaultInstaller.class ); 208 addService( MetadataResolver.class, DefaultMetadataResolver.class ); 209 addService( RepositoryLayoutProvider.class, DefaultRepositoryLayoutProvider.class ); 210 addService( RepositoryLayoutFactory.class, Maven2RepositoryLayoutFactory.class ); 211 addService( TransporterProvider.class, DefaultTransporterProvider.class ); 212 addService( ChecksumPolicyProvider.class, DefaultChecksumPolicyProvider.class ); 213 addService( RepositoryConnectorProvider.class, DefaultRepositoryConnectorProvider.class ); 214 addService( RemoteRepositoryManager.class, DefaultRemoteRepositoryManager.class ); 215 addService( UpdateCheckManager.class, DefaultUpdateCheckManager.class ); 216 addService( UpdatePolicyAnalyzer.class, DefaultUpdatePolicyAnalyzer.class ); 217 addService( FileProcessor.class, DefaultFileProcessor.class ); 218 addService( org.eclipse.aether.impl.SyncContextFactory.class, 219 org.eclipse.aether.internal.impl.synccontext.legacy.DefaultSyncContextFactory.class ); 220 addService( SyncContextFactory.class, DefaultSyncContextFactory.class ); 221 addService( RepositoryEventDispatcher.class, DefaultRepositoryEventDispatcher.class ); 222 addService( OfflineController.class, DefaultOfflineController.class ); 223 addService( LocalRepositoryProvider.class, DefaultLocalRepositoryProvider.class ); 224 addService( LocalRepositoryManagerFactory.class, SimpleLocalRepositoryManagerFactory.class ); 225 addService( LocalRepositoryManagerFactory.class, EnhancedLocalRepositoryManagerFactory.class ); 226 addService( LoggerFactory.class, Slf4jLoggerFactory.class ); 227 addService( TrackingFileManager.class, DefaultTrackingFileManager.class ); 228 addService( NamedLockFactorySelector.class, SimpleNamedLockFactorySelector.class ); 229 addService( ChecksumAlgorithmFactorySelector.class, DefaultChecksumAlgorithmFactorySelector.class ); 230 } 231 232 private <T> Entry<T> getEntry( Class<T> type, boolean create ) 233 { 234 @SuppressWarnings( "unchecked" ) 235 Entry<T> entry = (Entry<T>) entries.get( requireNonNull( type, "service type cannot be null" ) ); 236 if ( entry == null && create ) 237 { 238 entry = new Entry<>( type ); 239 entries.put( type, entry ); 240 } 241 return entry; 242 } 243 244 /** 245 * Sets the implementation class for a service. The specified class must have a no-arg constructor (of any 246 * visibility). If the service implementation itself requires other services for its operation, it should implement 247 * {@link Service} to gain access to this service locator. 248 * 249 * @param <T> The service type. 250 * @param type The interface describing the service, must not be {@code null}. 251 * @param impl The implementation class of the service, must not be {@code null}. 252 * @return This locator for chaining, never {@code null}. 253 */ 254 public <T> DefaultServiceLocator setService( Class<T> type, Class<? extends T> impl ) 255 { 256 getEntry( type, true ).setService( impl ); 257 return this; 258 } 259 260 /** 261 * Adds an implementation class for a service. The specified class must have a no-arg constructor (of any 262 * visibility). If the service implementation itself requires other services for its operation, it should implement 263 * {@link Service} to gain access to this service locator. 264 * 265 * @param <T> The service type. 266 * @param type The interface describing the service, must not be {@code null}. 267 * @param impl The implementation class of the service, must not be {@code null}. 268 * @return This locator for chaining, never {@code null}. 269 */ 270 public <T> DefaultServiceLocator addService( Class<T> type, Class<? extends T> impl ) 271 { 272 getEntry( type, true ).addService( impl ); 273 return this; 274 } 275 276 /** 277 * Sets the instances for a service. 278 * 279 * @param <T> The service type. 280 * @param type The interface describing the service, must not be {@code null}. 281 * @param services The instances of the service, may be {@code null} but must not contain {@code null} elements. 282 * @return This locator for chaining, never {@code null}. 283 */ 284 public <T> DefaultServiceLocator setServices( Class<T> type, T... services ) 285 { 286 getEntry( type, true ).setServices( services ); 287 return this; 288 } 289 290 public <T> T getService( Class<T> type ) 291 { 292 Entry<T> entry = getEntry( type, false ); 293 return ( entry != null ) ? entry.getInstance() : null; 294 } 295 296 public <T> List<T> getServices( Class<T> type ) 297 { 298 Entry<T> entry = getEntry( type, false ); 299 return ( entry != null ) ? entry.getInstances() : null; 300 } 301 302 private void serviceCreationFailed( Class<?> type, Class<?> impl, Throwable exception ) 303 { 304 if ( errorHandler != null ) 305 { 306 errorHandler.serviceCreationFailed( type, impl, exception ); 307 } 308 } 309 310 /** 311 * Sets the error handler to use. 312 * 313 * @param errorHandler The error handler to use, may be {@code null} to ignore/swallow errors. 314 */ 315 public void setErrorHandler( ErrorHandler errorHandler ) 316 { 317 this.errorHandler = errorHandler; 318 } 319 320 /** 321 * A hook to customize the handling of errors encountered while locating a service implementation. 322 */ 323 public abstract static class ErrorHandler 324 { 325 326 /** 327 * Handles errors during creation of a service. The default implemention does nothing. 328 * 329 * @param type The interface describing the service, must not be {@code null}. 330 * @param impl The implementation class of the service, must not be {@code null}. 331 * @param exception The error that occurred while trying to instantiate the implementation class, must not be 332 * {@code null}. 333 */ 334 public void serviceCreationFailed( Class<?> type, Class<?> impl, Throwable exception ) 335 { 336 } 337 338 } 339 340}