View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.internal.impl.named;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.HashSet;
28  import java.util.Map;
29  import java.util.Set;
30  import java.util.concurrent.ConcurrentHashMap;
31  import java.util.concurrent.ConcurrentMap;
32  import java.util.concurrent.TimeUnit;
33  
34  import org.eclipse.aether.ConfigurationProperties;
35  import org.eclipse.aether.MultiRuntimeException;
36  import org.eclipse.aether.RepositorySystemSession;
37  import org.eclipse.aether.impl.NamedLockFactorySelector;
38  import org.eclipse.aether.impl.RepositorySystemLifecycle;
39  import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapter;
40  import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactoryImpl;
41  import org.eclipse.aether.named.NamedLockFactory;
42  import org.eclipse.aether.named.providers.FileLockNamedLockFactory;
43  import org.eclipse.aether.util.ConfigUtils;
44  import org.slf4j.Logger;
45  import org.slf4j.LoggerFactory;
46  
47  import static java.util.Objects.requireNonNull;
48  
49  @Singleton
50  @Named
51  public class DefaultNamedLockFactorySelector implements NamedLockFactorySelector {
52      public static final String CONFIG_PROPS_PREFIX = ConfigurationProperties.PREFIX_SYSTEM + "named.";
53  
54      /**
55       * Name of the lock factory to use in system. Out of the box supported ones are "file-lock", "rwlock-local",
56       * "semaphore-local", "noop". By adding extensions one can extend available lock factories (for example IPC locking).
57       *
58       * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
59       * @configurationType {@link java.lang.String}
60       * @configurationDefaultValue {@link #DEFAULT_FACTORY_NAME}
61       */
62      public static final String CONFIG_PROP_FACTORY_NAME = CONFIG_PROPS_PREFIX + "factory";
63  
64      public static final String DEFAULT_FACTORY_NAME = FileLockNamedLockFactory.NAME;
65  
66      /**
67       * The maximum amount of time to be blocked, while obtaining a named lock.
68       *
69       * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
70       * @configurationType {@link java.lang.Long}
71       * @configurationDefaultValue {@link #DEFAULT_LOCK_WAIT_TIME}
72       */
73      public static final String CONFIG_PROP_LOCK_WAIT_TIME = CONFIG_PROPS_PREFIX + "time";
74  
75      public static final long DEFAULT_LOCK_WAIT_TIME = 900L;
76  
77      /**
78       * The unit of maximum amount of time. Accepts TimeUnit enum names.
79       *
80       * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
81       * @configurationType {@link java.lang.String}
82       * @configurationDefaultValue {@link #DEFAULT_LOCK_WAIT_TIME_UNIT}
83       */
84      public static final String CONFIG_PROP_LOCK_WAIT_TIME_UNIT = CONFIG_PROPS_PREFIX + "timeUnit";
85  
86      public static final String DEFAULT_LOCK_WAIT_TIME_UNIT = "SECONDS";
87  
88      protected final Logger logger = LoggerFactory.getLogger(getClass());
89  
90      protected final Map<String, NamedLockFactory> factories;
91  
92      protected final ConcurrentMap<String, NamedLockFactory> usedFactories;
93  
94      @Inject
95      public DefaultNamedLockFactorySelector(
96              Map<String, NamedLockFactory> factories, RepositorySystemLifecycle lifecycle) {
97          this.factories = requireNonNull(factories);
98          this.usedFactories = new ConcurrentHashMap<>();
99          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 }