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.GAV_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.DISCRIMINATING_NAME, NameMappers.discriminatingNameMapper()); 079 mappers.put(NameMappers.FILE_GAV_NAME, NameMappers.fileGavNameMapper()); 080 mappers.put(NameMappers.FILE_HGAV_NAME, NameMappers.fileHashingGavNameMapper()); 081 return Collections.unmodifiableMap(mappers); 082 } 083 084 protected static final String FACTORY_KEY = "aether.syncContext.named.factory"; 085 086 protected static final String NAME_MAPPER_KEY = "aether.syncContext.named.nameMapper"; 087 088 protected final Logger logger = LoggerFactory.getLogger(getClass()); 089 090 protected final Map<String, NamedLockFactory> factories; 091 092 protected final String defaultFactoryName; 093 094 protected final Map<String, NameMapper> nameMappers; 095 096 protected final String defaultNameMapperName; 097 098 /** 099 * Default constructor for non Eclipse Sisu uses. 100 * 101 * @deprecated for use in SL only. 102 */ 103 @Deprecated 104 public NamedLockFactoryAdapterFactoryImpl() { 105 this.factories = getManuallyCreatedFactories(); 106 this.defaultFactoryName = DEFAULT_FACTORY_NAME; 107 this.nameMappers = getManuallyCreatedNameMappers(); 108 this.defaultNameMapperName = DEFAULT_NAME_MAPPER_NAME; 109 } 110 111 @Override 112 public void initService(ServiceLocator locator) { 113 locator.getService(RepositorySystemLifecycle.class).addOnSystemEndedHandler(this::shutdown); 114 } 115 116 @Inject 117 public NamedLockFactoryAdapterFactoryImpl( 118 final Map<String, NamedLockFactory> factories, 119 final Map<String, NameMapper> nameMappers, 120 final RepositorySystemLifecycle lifecycle) { 121 this(factories, DEFAULT_FACTORY_NAME, nameMappers, DEFAULT_NAME_MAPPER_NAME, lifecycle); 122 } 123 124 public NamedLockFactoryAdapterFactoryImpl( 125 final Map<String, NamedLockFactory> factories, 126 final String defaultFactoryName, 127 final Map<String, NameMapper> nameMappers, 128 final String defaultNameMapperName, 129 final RepositorySystemLifecycle lifecycle) { 130 this.factories = requireNonNull(factories); 131 this.defaultFactoryName = requireNonNull(defaultFactoryName); 132 this.nameMappers = requireNonNull(nameMappers); 133 this.defaultNameMapperName = requireNonNull(defaultNameMapperName); 134 lifecycle.addOnSystemEndedHandler(this::shutdown); 135 136 logger.debug( 137 "Created adapter factory; available factories {}; available name mappers {}", 138 factories.keySet(), 139 nameMappers.keySet()); 140 } 141 142 /** 143 * Current implementation simply delegates to {@link #createAdapter(RepositorySystemSession)}. 144 */ 145 @Override 146 public NamedLockFactoryAdapter getAdapter(RepositorySystemSession session) { 147 return createAdapter(session); 148 } 149 150 /** 151 * Creates a new adapter instance, never returns {@code null}. 152 */ 153 protected NamedLockFactoryAdapter createAdapter(RepositorySystemSession session) { 154 final String nameMapperName = requireNonNull(getNameMapperName(session)); 155 final String factoryName = requireNonNull(getFactoryName(session)); 156 final NameMapper nameMapper = selectNameMapper(nameMapperName); 157 final NamedLockFactory factory = selectFactory(factoryName); 158 logger.debug("Creating adapter using nameMapper '{}' and factory '{}'", nameMapperName, factoryName); 159 return new NamedLockFactoryAdapter(nameMapper, factory); 160 } 161 162 /** 163 * Returns the selected (user configured or default) named lock factory name, never {@code null}. 164 */ 165 protected String getFactoryName(RepositorySystemSession session) { 166 return ConfigUtils.getString(session, getDefaultFactoryName(), FACTORY_KEY); 167 } 168 169 /** 170 * Returns the default named lock factory name, never {@code null}. 171 */ 172 protected String getDefaultFactoryName() { 173 return defaultFactoryName; 174 } 175 176 /** 177 * Returns the selected (user configured or default) name mapper name, never {@code null}. 178 */ 179 protected String getNameMapperName(RepositorySystemSession session) { 180 return ConfigUtils.getString(session, getDefaultNameMapperName(), NAME_MAPPER_KEY); 181 } 182 183 /** 184 * Returns the default name mapper name, never {@code null}. 185 */ 186 protected String getDefaultNameMapperName() { 187 return defaultNameMapperName; 188 } 189 190 /** 191 * Selects a named lock factory, never returns {@code null}. 192 */ 193 protected NamedLockFactory selectFactory(final String factoryName) { 194 NamedLockFactory factory = factories.get(factoryName); 195 if (factory == null) { 196 throw new IllegalArgumentException( 197 "Unknown NamedLockFactory name: '" + factoryName + "', known ones: " + factories.keySet()); 198 } 199 return factory; 200 } 201 202 /** 203 * Selects a name mapper, never returns {@code null}. 204 */ 205 protected NameMapper selectNameMapper(final String nameMapperName) { 206 NameMapper nameMapper = nameMappers.get(nameMapperName); 207 if (nameMapper == null) { 208 throw new IllegalArgumentException( 209 "Unknown NameMapper name: '" + nameMapperName + "', known ones: " + nameMappers.keySet()); 210 } 211 return nameMapper; 212 } 213 214 /** 215 * To be invoked on repository system shut down. This method will shut down each {@link NamedLockFactory}. 216 */ 217 protected void shutdown() { 218 logger.debug( 219 "Shutting down adapter factory; available factories {}; available name mappers {}", 220 factories.keySet(), 221 nameMappers.keySet()); 222 ArrayList<Exception> exceptions = new ArrayList<>(); 223 for (Map.Entry<String, NamedLockFactory> entry : factories.entrySet()) { 224 try { 225 logger.debug("Shutting down '{}' factory", entry.getKey()); 226 entry.getValue().shutdown(); 227 } catch (Exception e) { 228 exceptions.add(e); 229 } 230 } 231 MultiRuntimeException.mayThrow("Problem shutting down factories", exceptions); 232 } 233}