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