001package org.eclipse.aether.internal.impl.synccontext.named; 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 javax.inject.Inject; 023import javax.inject.Named; 024import javax.inject.Singleton; 025 026import java.util.ArrayList; 027import java.util.Collections; 028import java.util.HashMap; 029import java.util.Map; 030 031import org.eclipse.aether.MultiRuntimeException; 032import org.eclipse.aether.RepositorySystemSession; 033import org.eclipse.aether.impl.RepositorySystemLifecycle; 034import org.eclipse.aether.internal.impl.synccontext.named.providers.DiscriminatingNameMapperProvider; 035import org.eclipse.aether.internal.impl.synccontext.named.providers.FileGAVNameMapperProvider; 036import org.eclipse.aether.internal.impl.synccontext.named.providers.FileHashingGAVNameMapperProvider; 037import org.eclipse.aether.internal.impl.synccontext.named.providers.GAVNameMapperProvider; 038import org.eclipse.aether.internal.impl.synccontext.named.providers.StaticNameMapperProvider; 039import org.eclipse.aether.named.NamedLockFactory; 040import org.eclipse.aether.named.providers.FileLockNamedLockFactory; 041import org.eclipse.aether.named.providers.LocalReadWriteLockNamedLockFactory; 042import org.eclipse.aether.named.providers.LocalSemaphoreNamedLockFactory; 043import org.eclipse.aether.named.providers.NoopNamedLockFactory; 044import org.eclipse.aether.spi.locator.Service; 045import org.eclipse.aether.spi.locator.ServiceLocator; 046import org.eclipse.aether.util.ConfigUtils; 047import org.slf4j.Logger; 048import org.slf4j.LoggerFactory; 049 050import static java.util.Objects.requireNonNull; 051 052/** 053 * Default implementation of {@link NamedLockFactoryAdapterFactory}. This implementation creates new instances of the 054 * adapter on every call. In turn, on shutdown, it will shut down all existing named lock factories. This is merely for 055 * simplicity, to not have to track "used" named lock factories, while it exposes all available named lock factories to 056 * callers. 057 * <p> 058 * Most members and methods of this class are protected. It is meant to be extended in case of need to customize its 059 * behavior. An exception from this are private static methods, mostly meant to provide out of the box 060 * defaults and to be used when no Eclipse Sisu component container is used. 061 * 062 * @since 1.9.1 063 */ 064@Singleton 065@Named 066public class NamedLockFactoryAdapterFactoryImpl implements NamedLockFactoryAdapterFactory, Service 067{ 068 private static final String DEFAULT_FACTORY_NAME = LocalReadWriteLockNamedLockFactory.NAME; 069 070 private static final String DEFAULT_NAME_MAPPER_NAME = GAVNameMapperProvider.NAME; 071 072 private static Map<String, NamedLockFactory> getManuallyCreatedFactories() 073 { 074 HashMap<String, NamedLockFactory> factories = new HashMap<>(); 075 factories.put( NoopNamedLockFactory.NAME, new NoopNamedLockFactory() ); 076 factories.put( LocalReadWriteLockNamedLockFactory.NAME, new LocalReadWriteLockNamedLockFactory() ); 077 factories.put( LocalSemaphoreNamedLockFactory.NAME, new LocalSemaphoreNamedLockFactory() ); 078 factories.put( FileLockNamedLockFactory.NAME, new FileLockNamedLockFactory() ); 079 return Collections.unmodifiableMap( factories ); 080 } 081 082 private static Map<String, NameMapper> getManuallyCreatedNameMappers() 083 { 084 HashMap<String, NameMapper> mappers = new HashMap<>(); 085 mappers.put( StaticNameMapperProvider.NAME, new StaticNameMapperProvider().get() ); 086 mappers.put( GAVNameMapperProvider.NAME, new GAVNameMapperProvider().get() ); 087 mappers.put( DiscriminatingNameMapperProvider.NAME, new DiscriminatingNameMapperProvider().get() ); 088 mappers.put( FileGAVNameMapperProvider.NAME, new FileGAVNameMapperProvider().get() ); 089 mappers.put( FileHashingGAVNameMapperProvider.NAME, new FileHashingGAVNameMapperProvider().get() ); 090 return Collections.unmodifiableMap( mappers ); 091 } 092 093 protected static final String FACTORY_KEY = "aether.syncContext.named.factory"; 094 095 protected static final String NAME_MAPPER_KEY = "aether.syncContext.named.nameMapper"; 096 097 protected final Logger logger = LoggerFactory.getLogger( getClass() ); 098 099 protected final Map<String, NamedLockFactory> factories; 100 101 protected final String defaultFactoryName; 102 103 protected final Map<String, NameMapper> nameMappers; 104 105 protected final String defaultNameMapperName; 106 107 /** 108 * Default constructor for non Eclipse Sisu uses. 109 * 110 * @deprecated for use in SL only. 111 */ 112 @Deprecated 113 public NamedLockFactoryAdapterFactoryImpl() 114 { 115 this.factories = getManuallyCreatedFactories(); 116 this.defaultFactoryName = DEFAULT_FACTORY_NAME; 117 this.nameMappers = getManuallyCreatedNameMappers(); 118 this.defaultNameMapperName = DEFAULT_NAME_MAPPER_NAME; 119 } 120 121 @Override 122 public void initService( ServiceLocator locator ) 123 { 124 locator.getService( RepositorySystemLifecycle.class ).addOnSystemEndedHandler( this::shutdown ); 125 } 126 127 @Inject 128 public NamedLockFactoryAdapterFactoryImpl( final Map<String, NamedLockFactory> factories, 129 final Map<String, NameMapper> nameMappers, 130 final RepositorySystemLifecycle lifecycle ) 131 { 132 this( factories, DEFAULT_FACTORY_NAME, nameMappers, DEFAULT_NAME_MAPPER_NAME, lifecycle ); 133 } 134 135 public NamedLockFactoryAdapterFactoryImpl( final Map<String, NamedLockFactory> factories, 136 final String defaultFactoryName, 137 final Map<String, NameMapper> nameMappers, 138 final String defaultNameMapperName, 139 final RepositorySystemLifecycle lifecycle ) 140 { 141 this.factories = requireNonNull( factories ); 142 this.defaultFactoryName = requireNonNull( defaultFactoryName ); 143 this.nameMappers = requireNonNull( nameMappers ); 144 this.defaultNameMapperName = requireNonNull( defaultNameMapperName ); 145 lifecycle.addOnSystemEndedHandler( this::shutdown ); 146 147 logger.debug( "Created adapter factory; available factories {}; available name mappers {}", 148 factories.keySet(), nameMappers.keySet() ); 149 } 150 151 /** 152 * Current implementation simply delegates to {@link #createAdapter(RepositorySystemSession)}. 153 */ 154 @Override 155 public NamedLockFactoryAdapter getAdapter( RepositorySystemSession session ) 156 { 157 return createAdapter( session ); 158 } 159 160 /** 161 * Creates a new adapter instance, never returns {@code null}. 162 */ 163 protected NamedLockFactoryAdapter createAdapter( RepositorySystemSession session ) 164 { 165 final String nameMapperName = requireNonNull( getNameMapperName( session ) ); 166 final String factoryName = requireNonNull( getFactoryName( session ) ); 167 final NameMapper nameMapper = selectNameMapper( nameMapperName ); 168 final NamedLockFactory factory = selectFactory( factoryName ); 169 logger.debug( "Creating adapter using nameMapper '{}' and factory '{}'", 170 nameMapperName, factoryName ); 171 return new NamedLockFactoryAdapter( nameMapper, factory ); 172 } 173 174 /** 175 * Returns the selected (user configured or default) named lock factory name, never {@code null}. 176 */ 177 protected String getFactoryName( RepositorySystemSession session ) 178 { 179 return ConfigUtils.getString( session, getDefaultFactoryName(), FACTORY_KEY ); 180 } 181 182 /** 183 * Returns the default named lock factory name, never {@code null}. 184 */ 185 protected String getDefaultFactoryName() 186 { 187 return defaultFactoryName; 188 } 189 190 /** 191 * Returns the selected (user configured or default) name mapper name, never {@code null}. 192 */ 193 protected String getNameMapperName( RepositorySystemSession session ) 194 { 195 return ConfigUtils.getString( session, getDefaultNameMapperName(), NAME_MAPPER_KEY ); 196 } 197 198 /** 199 * Returns the default name mapper name, never {@code null}. 200 */ 201 protected String getDefaultNameMapperName() 202 { 203 return defaultNameMapperName; 204 } 205 206 /** 207 * Selects a named lock factory, never returns {@code null}. 208 */ 209 protected NamedLockFactory selectFactory( final String factoryName ) 210 { 211 NamedLockFactory factory = factories.get( factoryName ); 212 if ( factory == null ) 213 { 214 throw new IllegalArgumentException( 215 "Unknown NamedLockFactory name: '" + factoryName + "', known ones: " + factories.keySet() ); 216 } 217 return factory; 218 } 219 220 /** 221 * Selects a name mapper, never returns {@code null}. 222 */ 223 protected NameMapper selectNameMapper( final String nameMapperName ) 224 { 225 NameMapper nameMapper = nameMappers.get( nameMapperName ); 226 if ( nameMapper == null ) 227 { 228 throw new IllegalArgumentException( 229 "Unknown NameMapper name: '" + nameMapperName + "', known ones: " + nameMappers.keySet() ); 230 } 231 return nameMapper; 232 } 233 234 /** 235 * To be invoked on repository system shut down. This method will shut down each {@link NamedLockFactory}. 236 */ 237 protected void shutdown() 238 { 239 logger.debug( "Shutting down adapter factory; available factories {}; available name mappers {}", 240 factories.keySet(), nameMappers.keySet() ); 241 ArrayList<Exception> exceptions = new ArrayList<>(); 242 for ( Map.Entry<String, NamedLockFactory> entry : factories.entrySet() ) 243 { 244 try 245 { 246 logger.debug( "Shutting down '{}' factory", entry.getKey() ); 247 entry.getValue().shutdown(); 248 } 249 catch ( Exception e ) 250 { 251 exceptions.add( e ); 252 } 253 } 254 MultiRuntimeException.mayThrow( "Problem shutting down factories", exceptions ); 255 } 256}