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 some out-of-the-box DI implementation instead. 091 */ 092@Deprecated 093public final class DefaultServiceLocator implements ServiceLocator { 094 095 private class Entry<T> { 096 097 private final Class<T> type; 098 099 private final Collection<Object> providers; 100 101 private List<T> instances; 102 103 Entry(Class<T> type) { 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 providers.clear(); 110 if (services != null) { 111 for (T service : services) { 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 providers.clear(); 120 addService(impl); 121 } 122 123 public synchronized void addService(Class<? extends T> impl) { 124 providers.add(requireNonNull(impl, "implementation class cannot be null")); 125 instances = null; 126 } 127 128 public T getInstance() { 129 List<T> instances = getInstances(); 130 return instances.isEmpty() ? null : instances.get(0); 131 } 132 133 public synchronized List<T> getInstances() { 134 if (instances == null) { 135 instances = new ArrayList<>(providers.size()); 136 for (Object provider : providers) { 137 T instance; 138 if (provider instanceof Class) { 139 instance = newInstance((Class<?>) provider); 140 } else { 141 instance = type.cast(provider); 142 } 143 if (instance != null) { 144 instances.add(instance); 145 } 146 } 147 instances = Collections.unmodifiableList(instances); 148 } 149 return instances; 150 } 151 152 private T newInstance(Class<?> impl) { 153 try { 154 Constructor<?> constr = impl.getDeclaredConstructor(); 155 if (!Modifier.isPublic(constr.getModifiers())) { 156 constr.setAccessible(true); 157 } 158 Object obj = constr.newInstance(); 159 160 T instance = type.cast(obj); 161 if (instance instanceof Service) { 162 ((Service) instance).initService(DefaultServiceLocator.this); 163 } 164 return instance; 165 } catch (Exception | LinkageError e) { 166 serviceCreationFailed(type, impl, e); 167 } 168 return null; 169 } 170 } 171 172 private final Map<Class<?>, Entry<?>> entries; 173 174 private ErrorHandler errorHandler; 175 176 /** 177 * Creates a new service locator that already knows about all service implementations included this library. 178 */ 179 public DefaultServiceLocator() { 180 entries = new HashMap<>(); 181 182 addService(RepositorySystem.class, DefaultRepositorySystem.class); 183 addService(ArtifactResolver.class, DefaultArtifactResolver.class); 184 addService(DependencyCollector.class, DefaultDependencyCollector.class); 185 addService(Deployer.class, DefaultDeployer.class); 186 addService(Installer.class, DefaultInstaller.class); 187 addService(MetadataResolver.class, DefaultMetadataResolver.class); 188 addService(RepositoryLayoutProvider.class, DefaultRepositoryLayoutProvider.class); 189 addService(RepositoryLayoutFactory.class, Maven2RepositoryLayoutFactory.class); 190 addService(TransporterProvider.class, DefaultTransporterProvider.class); 191 addService(ChecksumPolicyProvider.class, DefaultChecksumPolicyProvider.class); 192 addService(RepositoryConnectorProvider.class, DefaultRepositoryConnectorProvider.class); 193 addService(RemoteRepositoryManager.class, DefaultRemoteRepositoryManager.class); 194 addService(UpdateCheckManager.class, DefaultUpdateCheckManager.class); 195 addService(UpdatePolicyAnalyzer.class, DefaultUpdatePolicyAnalyzer.class); 196 addService(FileProcessor.class, DefaultFileProcessor.class); 197 addService( 198 org.eclipse.aether.impl.SyncContextFactory.class, 199 org.eclipse.aether.internal.impl.synccontext.legacy.DefaultSyncContextFactory.class); 200 addService(SyncContextFactory.class, DefaultSyncContextFactory.class); 201 addService(RepositoryEventDispatcher.class, DefaultRepositoryEventDispatcher.class); 202 addService(OfflineController.class, DefaultOfflineController.class); 203 addService(LocalRepositoryProvider.class, DefaultLocalRepositoryProvider.class); 204 addService(LocalRepositoryManagerFactory.class, SimpleLocalRepositoryManagerFactory.class); 205 addService(LocalRepositoryManagerFactory.class, EnhancedLocalRepositoryManagerFactory.class); 206 addService(LoggerFactory.class, Slf4jLoggerFactory.class); 207 addService(TrackingFileManager.class, DefaultTrackingFileManager.class); 208 addService(ChecksumAlgorithmFactorySelector.class, DefaultChecksumAlgorithmFactorySelector.class); 209 addService(LocalPathComposer.class, DefaultLocalPathComposer.class); 210 addService(RemoteRepositoryFilterManager.class, DefaultRemoteRepositoryFilterManager.class); 211 addService(RepositorySystemLifecycle.class, DefaultRepositorySystemLifecycle.class); 212 addService(NamedLockFactoryAdapterFactory.class, NamedLockFactoryAdapterFactoryImpl.class); 213 } 214 215 private <T> Entry<T> getEntry(Class<T> type, boolean create) { 216 @SuppressWarnings("unchecked") 217 Entry<T> entry = (Entry<T>) entries.get(requireNonNull(type, "service type cannot be null")); 218 if (entry == null && create) { 219 entry = new Entry<>(type); 220 entries.put(type, entry); 221 } 222 return entry; 223 } 224 225 /** 226 * Sets the implementation class for a service. The specified class must have a no-arg constructor (of any 227 * visibility). If the service implementation itself requires other services for its operation, it should implement 228 * {@link Service} to gain access to this service locator. 229 * 230 * @param <T> The service type. 231 * @param type The interface describing the service, must not be {@code null}. 232 * @param impl The implementation class of the service, must not be {@code null}. 233 * @return This locator for chaining, never {@code null}. 234 */ 235 public <T> DefaultServiceLocator setService(Class<T> type, Class<? extends T> impl) { 236 getEntry(type, true).setService(impl); 237 return this; 238 } 239 240 /** 241 * Adds an 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 addService(Class<T> type, Class<? extends T> impl) { 251 getEntry(type, true).addService(impl); 252 return this; 253 } 254 255 /** 256 * Sets the instances for a service. 257 * 258 * @param <T> The service type. 259 * @param type The interface describing the service, must not be {@code null}. 260 * @param services The instances of the service, may be {@code null} but must not contain {@code null} elements. 261 * @return This locator for chaining, never {@code null}. 262 */ 263 public <T> DefaultServiceLocator setServices(Class<T> type, T... services) { 264 getEntry(type, true).setServices(services); 265 return this; 266 } 267 268 public <T> T getService(Class<T> type) { 269 Entry<T> entry = getEntry(type, false); 270 return (entry != null) ? entry.getInstance() : null; 271 } 272 273 public <T> List<T> getServices(Class<T> type) { 274 Entry<T> entry = getEntry(type, false); 275 return (entry != null) ? entry.getInstances() : null; 276 } 277 278 private void serviceCreationFailed(Class<?> type, Class<?> impl, Throwable exception) { 279 if (errorHandler != null) { 280 errorHandler.serviceCreationFailed(type, impl, exception); 281 } 282 } 283 284 /** 285 * Sets the error handler to use. 286 * 287 * @param errorHandler The error handler to use, may be {@code null} to ignore/swallow errors. 288 */ 289 public void setErrorHandler(ErrorHandler errorHandler) { 290 this.errorHandler = errorHandler; 291 } 292 293 /** 294 * A hook to customize the handling of errors encountered while locating a service implementation. 295 */ 296 public abstract static class ErrorHandler { 297 298 /** 299 * Handles errors during creation of a service. The default implemention does nothing. 300 * 301 * @param type The interface describing the service, must not be {@code null}. 302 * @param impl The implementation class of the service, must not be {@code null}. 303 * @param exception The error that occurred while trying to instantiate the implementation class, must not be 304 * {@code null}. 305 */ 306 public void serviceCreationFailed(Class<?> type, Class<?> impl, Throwable exception) {} 307 } 308}