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.LocalReadWriteLockNamedLockFactory; 033import org.eclipse.aether.util.ConfigUtils; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037import static java.util.Objects.requireNonNull; 038 039/** 040 * Default implementation of {@link NamedLockFactoryAdapterFactory}. This implementation creates new instances of the 041 * adapter on every call. In turn, on shutdown, it will shut down all existing named lock factories. This is merely for 042 * simplicity, to not have to track "used" named lock factories, while it exposes all available named lock factories to 043 * callers. 044 * <p> 045 * Most members and methods of this class are protected. It is meant to be extended in case of need to customize its 046 * behavior. An exception from this are private static methods, mostly meant to provide out of the box 047 * defaults and to be used when no Eclipse Sisu component container is used. 048 * 049 * @since 1.9.1 050 */ 051@Singleton 052@Named 053public class NamedLockFactoryAdapterFactoryImpl implements NamedLockFactoryAdapterFactory { 054 private static final String DEFAULT_FACTORY_NAME = LocalReadWriteLockNamedLockFactory.NAME; 055 056 private static final String DEFAULT_NAME_MAPPER_NAME = NameMappers.GAV_NAME; 057 058 protected static final String FACTORY_KEY = "aether.syncContext.named.factory"; 059 060 protected static final String NAME_MAPPER_KEY = "aether.syncContext.named.nameMapper"; 061 062 protected final Logger logger = LoggerFactory.getLogger(getClass()); 063 064 protected final Map<String, NamedLockFactory> factories; 065 066 protected final String defaultFactoryName; 067 068 protected final Map<String, NameMapper> nameMappers; 069 070 protected final String defaultNameMapperName; 071 072 @Inject 073 public NamedLockFactoryAdapterFactoryImpl( 074 final Map<String, NamedLockFactory> factories, 075 final Map<String, NameMapper> nameMappers, 076 final RepositorySystemLifecycle lifecycle) { 077 this(factories, DEFAULT_FACTORY_NAME, nameMappers, DEFAULT_NAME_MAPPER_NAME, lifecycle); 078 } 079 080 public NamedLockFactoryAdapterFactoryImpl( 081 final Map<String, NamedLockFactory> factories, 082 final String defaultFactoryName, 083 final Map<String, NameMapper> nameMappers, 084 final String defaultNameMapperName, 085 final RepositorySystemLifecycle lifecycle) { 086 this.factories = requireNonNull(factories); 087 this.defaultFactoryName = requireNonNull(defaultFactoryName); 088 this.nameMappers = requireNonNull(nameMappers); 089 this.defaultNameMapperName = requireNonNull(defaultNameMapperName); 090 lifecycle.addOnSystemEndedHandler(this::shutdown); 091 092 logger.debug( 093 "Created adapter factory; available factories {}; available name mappers {}", 094 factories.keySet(), 095 nameMappers.keySet()); 096 } 097 098 /** 099 * Current implementation simply delegates to {@link #createAdapter(RepositorySystemSession)}. 100 */ 101 @Override 102 public NamedLockFactoryAdapter getAdapter(RepositorySystemSession session) { 103 return createAdapter(session); 104 } 105 106 /** 107 * Creates a new adapter instance, never returns {@code null}. 108 */ 109 protected NamedLockFactoryAdapter createAdapter(RepositorySystemSession session) { 110 final String nameMapperName = requireNonNull(getNameMapperName(session)); 111 final String factoryName = requireNonNull(getFactoryName(session)); 112 final NameMapper nameMapper = selectNameMapper(nameMapperName); 113 final NamedLockFactory factory = selectFactory(factoryName); 114 logger.debug("Creating adapter using nameMapper '{}' and factory '{}'", nameMapperName, factoryName); 115 return new NamedLockFactoryAdapter(nameMapper, factory); 116 } 117 118 /** 119 * Returns the selected (user configured or default) named lock factory name, never {@code null}. 120 */ 121 protected String getFactoryName(RepositorySystemSession session) { 122 return ConfigUtils.getString(session, getDefaultFactoryName(), FACTORY_KEY); 123 } 124 125 /** 126 * Returns the default named lock factory name, never {@code null}. 127 */ 128 protected String getDefaultFactoryName() { 129 return defaultFactoryName; 130 } 131 132 /** 133 * Returns the selected (user configured or default) name mapper name, never {@code null}. 134 */ 135 protected String getNameMapperName(RepositorySystemSession session) { 136 return ConfigUtils.getString(session, getDefaultNameMapperName(), NAME_MAPPER_KEY); 137 } 138 139 /** 140 * Returns the default name mapper name, never {@code null}. 141 */ 142 protected String getDefaultNameMapperName() { 143 return defaultNameMapperName; 144 } 145 146 /** 147 * Selects a named lock factory, never returns {@code null}. 148 */ 149 protected NamedLockFactory selectFactory(final String factoryName) { 150 NamedLockFactory factory = factories.get(factoryName); 151 if (factory == null) { 152 throw new IllegalArgumentException( 153 "Unknown NamedLockFactory name: '" + factoryName + "', known ones: " + factories.keySet()); 154 } 155 return factory; 156 } 157 158 /** 159 * Selects a name mapper, never returns {@code null}. 160 */ 161 protected NameMapper selectNameMapper(final String nameMapperName) { 162 NameMapper nameMapper = nameMappers.get(nameMapperName); 163 if (nameMapper == null) { 164 throw new IllegalArgumentException( 165 "Unknown NameMapper name: '" + nameMapperName + "', known ones: " + nameMappers.keySet()); 166 } 167 return nameMapper; 168 } 169 170 /** 171 * To be invoked on repository system shut down. This method will shut down each {@link NamedLockFactory}. 172 */ 173 protected void shutdown() { 174 logger.debug( 175 "Shutting down adapter factory; available factories {}; available name mappers {}", 176 factories.keySet(), 177 nameMappers.keySet()); 178 ArrayList<Exception> exceptions = new ArrayList<>(); 179 for (Map.Entry<String, NamedLockFactory> entry : factories.entrySet()) { 180 try { 181 logger.debug("Shutting down '{}' factory", entry.getKey()); 182 entry.getValue().shutdown(); 183 } catch (Exception e) { 184 exceptions.add(e); 185 } 186 } 187 MultiRuntimeException.mayThrow("Problem shutting down factories", exceptions); 188 } 189}