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