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.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.HashSet; 028import java.util.Map; 029import java.util.Set; 030import java.util.concurrent.ConcurrentHashMap; 031import java.util.concurrent.ConcurrentMap; 032import java.util.concurrent.TimeUnit; 033 034import org.eclipse.aether.ConfigurationProperties; 035import org.eclipse.aether.MultiRuntimeException; 036import org.eclipse.aether.RepositorySystemSession; 037import org.eclipse.aether.impl.NamedLockFactorySelector; 038import org.eclipse.aether.impl.RepositorySystemLifecycle; 039import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapter; 040import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactoryImpl; 041import org.eclipse.aether.named.NamedLockFactory; 042import org.eclipse.aether.named.providers.FileLockNamedLockFactory; 043import org.eclipse.aether.util.ConfigUtils; 044import org.slf4j.Logger; 045import org.slf4j.LoggerFactory; 046 047import static java.util.Objects.requireNonNull; 048 049@Singleton 050@Named 051public class DefaultNamedLockFactorySelector implements NamedLockFactorySelector { 052 public static final String CONFIG_PROPS_PREFIX = ConfigurationProperties.PREFIX_SYSTEM + "named."; 053 054 /** 055 * Name of the lock factory to use in system. Out of the box supported ones are "file-lock", "rwlock-local", 056 * "semaphore-local", "noop". By adding extensions one can extend available lock factories (for example IPC locking). 057 * 058 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 059 * @configurationType {@link java.lang.String} 060 * @configurationDefaultValue {@link #DEFAULT_FACTORY_NAME} 061 */ 062 public static final String CONFIG_PROP_FACTORY_NAME = CONFIG_PROPS_PREFIX + "factory"; 063 064 public static final String DEFAULT_FACTORY_NAME = FileLockNamedLockFactory.NAME; 065 066 /** 067 * The maximum amount of time to be blocked, while obtaining a named lock. 068 * 069 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 070 * @configurationType {@link java.lang.Long} 071 * @configurationDefaultValue {@link #DEFAULT_LOCK_WAIT_TIME} 072 */ 073 public static final String CONFIG_PROP_LOCK_WAIT_TIME = CONFIG_PROPS_PREFIX + "time"; 074 075 public static final long DEFAULT_LOCK_WAIT_TIME = 900L; 076 077 /** 078 * The unit of maximum amount of time. Accepts TimeUnit enum names. 079 * 080 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 081 * @configurationType {@link java.lang.String} 082 * @configurationDefaultValue {@link #DEFAULT_LOCK_WAIT_TIME_UNIT} 083 */ 084 public static final String CONFIG_PROP_LOCK_WAIT_TIME_UNIT = CONFIG_PROPS_PREFIX + "timeUnit"; 085 086 public static final String DEFAULT_LOCK_WAIT_TIME_UNIT = "SECONDS"; 087 088 protected final Logger logger = LoggerFactory.getLogger(getClass()); 089 090 protected final Map<String, NamedLockFactory> factories; 091 092 protected final ConcurrentMap<String, NamedLockFactory> usedFactories; 093 094 @Inject 095 public DefaultNamedLockFactorySelector( 096 Map<String, NamedLockFactory> factories, RepositorySystemLifecycle lifecycle) { 097 this.factories = requireNonNull(factories); 098 this.usedFactories = new ConcurrentHashMap<>(); 099 lifecycle.addOnSystemEndedHandler(this::shutdown); 100 101 logger.debug("Created lock factory selector; available lock factories {}", factories.keySet()); 102 } 103 104 @Override 105 public Set<String> getAvailableLockFactories() { 106 return Collections.unmodifiableSet(new HashSet<>(factories.keySet())); 107 } 108 109 @Override 110 public NamedLockFactory getNamedLockFactory(Map<String, ?> configuration) { 111 String factoryName = ConfigUtils.getString( 112 configuration, 113 DEFAULT_FACTORY_NAME, 114 CONFIG_PROP_FACTORY_NAME, 115 NamedLockFactoryAdapterFactoryImpl.CONFIG_PROP_FACTORY_KEY); 116 NamedLockFactory factory = factories.get(factoryName); 117 if (factory == null) { 118 throw new IllegalArgumentException( 119 "Unknown NamedLockFactory name: '" + factoryName + "', known ones: " + factories.keySet()); 120 } 121 usedFactories.putIfAbsent(factoryName, factory); 122 return factory; 123 } 124 125 @Override 126 public long getLockWaitTime(Map<String, ?> configuration) { 127 long result = ConfigUtils.getLong( 128 configuration, 129 DEFAULT_LOCK_WAIT_TIME, 130 CONFIG_PROP_LOCK_WAIT_TIME, 131 NamedLockFactoryAdapter.CONFIG_PROP_TIME); 132 if (result <= 0) { 133 throw new IllegalArgumentException( 134 "The " + CONFIG_PROP_LOCK_WAIT_TIME + " configuration must be greater than zero"); 135 } 136 return result; 137 } 138 139 @Override 140 public TimeUnit getLockWaitTimeUnit(Map<String, ?> configuration) { 141 return TimeUnit.valueOf(ConfigUtils.getString( 142 configuration, 143 DEFAULT_LOCK_WAIT_TIME_UNIT, 144 CONFIG_PROP_LOCK_WAIT_TIME_UNIT, 145 NamedLockFactoryAdapter.CONFIG_PROP_TIME_UNIT)); 146 } 147 148 private void shutdown() { 149 logger.debug("Shutting down used lock factories {}", usedFactories.keySet()); 150 ArrayList<Exception> exceptions = new ArrayList<>(); 151 for (Map.Entry<String, NamedLockFactory> entry : usedFactories.entrySet()) { 152 try { 153 logger.debug("Shutting down '{}' factory", entry.getKey()); 154 entry.getValue().shutdown(); 155 } catch (Exception e) { 156 exceptions.add(e); 157 } 158 } 159 MultiRuntimeException.mayThrow("Problem shutting down used lock factories", exceptions); 160 } 161}