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