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.synccontext.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.HashMap;
28  import java.util.Map;
29  
30  import org.eclipse.aether.MultiRuntimeException;
31  import org.eclipse.aether.RepositorySystemSession;
32  import org.eclipse.aether.impl.RepositorySystemLifecycle;
33  import org.eclipse.aether.named.NamedLockFactory;
34  import org.eclipse.aether.named.providers.FileLockNamedLockFactory;
35  import org.eclipse.aether.named.providers.LocalReadWriteLockNamedLockFactory;
36  import org.eclipse.aether.named.providers.LocalSemaphoreNamedLockFactory;
37  import org.eclipse.aether.named.providers.NoopNamedLockFactory;
38  import org.eclipse.aether.spi.locator.Service;
39  import org.eclipse.aether.spi.locator.ServiceLocator;
40  import org.eclipse.aether.util.ConfigUtils;
41  import org.slf4j.Logger;
42  import org.slf4j.LoggerFactory;
43  
44  import static java.util.Objects.requireNonNull;
45  
46  /**
47   * Default implementation of {@link NamedLockFactoryAdapterFactory}. This implementation creates new instances of the
48   * adapter on every call. In turn, on shutdown, it will shut down all existing named lock factories. This is merely for
49   * simplicity, to not have to track "used" named lock factories, while it exposes all available named lock factories to
50   * callers.
51   * <p>
52   * Most members and methods of this class are protected. It is meant to be extended in case of need to customize its
53   * behavior. An exception from this are private static methods, mostly meant to provide out of the box
54   * defaults and to be used when no Eclipse Sisu component container is used.
55   *
56   * @since 1.9.1
57   */
58  @Singleton
59  @Named
60  public class NamedLockFactoryAdapterFactoryImpl implements NamedLockFactoryAdapterFactory, Service {
61      private static final String DEFAULT_FACTORY_NAME = LocalReadWriteLockNamedLockFactory.NAME;
62  
63      private static final String DEFAULT_NAME_MAPPER_NAME = NameMappers.GAV_NAME;
64  
65      private static Map<String, NamedLockFactory> getManuallyCreatedFactories() {
66          HashMap<String, NamedLockFactory> factories = new HashMap<>();
67          factories.put(NoopNamedLockFactory.NAME, new NoopNamedLockFactory());
68          factories.put(LocalReadWriteLockNamedLockFactory.NAME, new LocalReadWriteLockNamedLockFactory());
69          factories.put(LocalSemaphoreNamedLockFactory.NAME, new LocalSemaphoreNamedLockFactory());
70          factories.put(FileLockNamedLockFactory.NAME, new FileLockNamedLockFactory());
71          return Collections.unmodifiableMap(factories);
72      }
73  
74      private static Map<String, NameMapper> getManuallyCreatedNameMappers() {
75          HashMap<String, NameMapper> mappers = new HashMap<>();
76          mappers.put(NameMappers.STATIC_NAME, NameMappers.staticNameMapper());
77          mappers.put(NameMappers.GAV_NAME, NameMappers.gavNameMapper());
78          mappers.put(NameMappers.DISCRIMINATING_NAME, NameMappers.discriminatingNameMapper());
79          mappers.put(NameMappers.FILE_GAV_NAME, NameMappers.fileGavNameMapper());
80          mappers.put(NameMappers.FILE_HGAV_NAME, NameMappers.fileHashingGavNameMapper());
81          return Collections.unmodifiableMap(mappers);
82      }
83  
84      protected static final String FACTORY_KEY = "aether.syncContext.named.factory";
85  
86      protected static final String NAME_MAPPER_KEY = "aether.syncContext.named.nameMapper";
87  
88      protected final Logger logger = LoggerFactory.getLogger(getClass());
89  
90      protected final Map<String, NamedLockFactory> factories;
91  
92      protected final String defaultFactoryName;
93  
94      protected final Map<String, NameMapper> nameMappers;
95  
96      protected final String defaultNameMapperName;
97  
98      /**
99       * 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 }