001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.impl; 020 021import java.lang.reflect.Constructor; 022import java.lang.reflect.Modifier; 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.Collections; 026import java.util.HashMap; 027import java.util.LinkedHashSet; 028import java.util.List; 029import java.util.Map; 030 031import org.eclipse.aether.RepositorySystem; 032import org.eclipse.aether.internal.impl.DefaultArtifactResolver; 033import org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider; 034import org.eclipse.aether.internal.impl.DefaultDeployer; 035import org.eclipse.aether.internal.impl.DefaultFileProcessor; 036import org.eclipse.aether.internal.impl.DefaultInstaller; 037import org.eclipse.aether.internal.impl.DefaultLocalPathComposer; 038import org.eclipse.aether.internal.impl.DefaultLocalRepositoryProvider; 039import org.eclipse.aether.internal.impl.DefaultMetadataResolver; 040import org.eclipse.aether.internal.impl.DefaultOfflineController; 041import org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager; 042import org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider; 043import org.eclipse.aether.internal.impl.DefaultRepositoryEventDispatcher; 044import org.eclipse.aether.internal.impl.DefaultRepositoryLayoutProvider; 045import org.eclipse.aether.internal.impl.DefaultRepositorySystem; 046import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle; 047import org.eclipse.aether.internal.impl.DefaultTrackingFileManager; 048import org.eclipse.aether.internal.impl.DefaultTransporterProvider; 049import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager; 050import org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer; 051import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory; 052import org.eclipse.aether.internal.impl.LocalPathComposer; 053import org.eclipse.aether.internal.impl.Maven2RepositoryLayoutFactory; 054import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory; 055import org.eclipse.aether.internal.impl.TrackingFileManager; 056import org.eclipse.aether.internal.impl.checksum.DefaultChecksumAlgorithmFactorySelector; 057import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector; 058import org.eclipse.aether.internal.impl.filter.DefaultRemoteRepositoryFilterManager; 059import org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory; 060import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory; 061import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactory; 062import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactoryImpl; 063import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector; 064import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider; 065import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory; 066import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider; 067import org.eclipse.aether.spi.connector.transport.TransporterProvider; 068import org.eclipse.aether.spi.io.FileProcessor; 069import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory; 070import org.eclipse.aether.spi.locator.Service; 071import org.eclipse.aether.spi.locator.ServiceLocator; 072import org.eclipse.aether.spi.log.LoggerFactory; 073import org.eclipse.aether.spi.synccontext.SyncContextFactory; 074 075import static java.util.Objects.requireNonNull; 076 077/** 078 * A simple service locator that is already setup with all components from this library. To acquire a complete 079 * repository system, clients need to add an artifact descriptor reader, a version resolver, a version range resolver 080 * and optionally some repository connector and transporter factories to access remote repositories. Once the locator is 081 * fully populated, the repository system can be created like this: 082 * 083 * <pre> 084 * RepositorySystem repoSystem = serviceLocator.getService( RepositorySystem.class ); 085 * </pre> 086 * 087 * <em>Note:</em> This class is not thread-safe. Clients are expected to create the service locator and the repository 088 * system on a single thread. 089 * 090 * @deprecated Use of out-of-the-box DI implementation recommended, or, as alternative new supplier from 091 * module {@code maven-resolver-supplier}. 092 */ 093@Deprecated 094public final class DefaultServiceLocator implements ServiceLocator { 095 096 private class Entry<T> { 097 098 private final Class<T> type; 099 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}