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