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      public static final String DEFAULT_FACTORY_NAME = LocalReadWriteLockNamedLockFactory.NAME;
55  
56      public static final String DEFAULT_NAME_MAPPER_NAME = NameMappers.GAV_NAME;
57  
58      /**
59       * Name of the lock factory to use in session.
60       *
61       * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
62       * @configurationType {@link java.lang.String}
63       * @configurationDefaultValue {@link #DEFAULT_FACTORY_NAME}
64       */
65      public static final String CONFIG_PROP_FACTORY_KEY = NamedLockFactoryAdapter.CONFIG_PROPS_PREFIX + "factory";
66  
67      /**
68       * Name of the name mapper to use in session. Out of the box supported ones are "static", "gav", "file-gav",
69       * "file-hgav", "file-static" and "discriminating".
70       *
71       * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
72       * @configurationType {@link java.lang.String}
73       * @configurationDefaultValue {@link #DEFAULT_NAME_MAPPER_NAME}
74       */
75      public static final String CONFIG_PROP_NAME_MAPPER_KEY = NamedLockFactoryAdapter.CONFIG_PROPS_PREFIX + "nameMapper";
76  
77      protected final Logger logger = LoggerFactory.getLogger(getClass());
78  
79      protected final Map<String, NamedLockFactory> factories;
80  
81      protected final String defaultFactoryName;
82  
83      protected final Map<String, NameMapper> nameMappers;
84  
85      protected final String defaultNameMapperName;
86  
87      @Inject
88      public NamedLockFactoryAdapterFactoryImpl(
89              final Map<String, NamedLockFactory> factories,
90              final Map<String, NameMapper> nameMappers,
91              final RepositorySystemLifecycle lifecycle) {
92          this(factories, DEFAULT_FACTORY_NAME, nameMappers, DEFAULT_NAME_MAPPER_NAME, lifecycle);
93      }
94  
95      public NamedLockFactoryAdapterFactoryImpl(
96              final Map<String, NamedLockFactory> factories,
97              final String defaultFactoryName,
98              final Map<String, NameMapper> nameMappers,
99              final String defaultNameMapperName,
100             final RepositorySystemLifecycle lifecycle) {
101         this.factories = requireNonNull(factories);
102         this.defaultFactoryName = requireNonNull(defaultFactoryName);
103         this.nameMappers = requireNonNull(nameMappers);
104         this.defaultNameMapperName = requireNonNull(defaultNameMapperName);
105         lifecycle.addOnSystemEndedHandler(this::shutdown);
106 
107         logger.debug(
108                 "Created adapter factory; available factories {}; available name mappers {}",
109                 factories.keySet(),
110                 nameMappers.keySet());
111     }
112 
113     /**
114      * Current implementation simply delegates to {@link #createAdapter(RepositorySystemSession)}.
115      */
116     @Override
117     public NamedLockFactoryAdapter getAdapter(RepositorySystemSession session) {
118         return createAdapter(session);
119     }
120 
121     /**
122      * Creates a new adapter instance, never returns {@code null}.
123      */
124     protected NamedLockFactoryAdapter createAdapter(RepositorySystemSession session) {
125         final String nameMapperName = requireNonNull(getNameMapperName(session));
126         final String factoryName = requireNonNull(getFactoryName(session));
127         final NameMapper nameMapper = selectNameMapper(nameMapperName);
128         final NamedLockFactory factory = selectFactory(factoryName);
129         logger.debug("Creating adapter using nameMapper '{}' and factory '{}'", nameMapperName, factoryName);
130         return new NamedLockFactoryAdapter(nameMapper, factory);
131     }
132 
133     /**
134      * Returns the selected (user configured or default) named lock factory name, never {@code null}.
135      */
136     protected String getFactoryName(RepositorySystemSession session) {
137         return ConfigUtils.getString(session, getDefaultFactoryName(), CONFIG_PROP_FACTORY_KEY);
138     }
139 
140     /**
141      * Returns the default named lock factory name, never {@code null}.
142      */
143     protected String getDefaultFactoryName() {
144         return defaultFactoryName;
145     }
146 
147     /**
148      * Returns the selected (user configured or default) name mapper name, never {@code null}.
149      */
150     protected String getNameMapperName(RepositorySystemSession session) {
151         return ConfigUtils.getString(session, getDefaultNameMapperName(), CONFIG_PROP_NAME_MAPPER_KEY);
152     }
153 
154     /**
155      * Returns the default name mapper name, never {@code null}.
156      */
157     protected String getDefaultNameMapperName() {
158         return defaultNameMapperName;
159     }
160 
161     /**
162      * Selects a named lock factory, never returns {@code null}.
163      */
164     protected NamedLockFactory selectFactory(final String factoryName) {
165         NamedLockFactory factory = factories.get(factoryName);
166         if (factory == null) {
167             throw new IllegalArgumentException(
168                     "Unknown NamedLockFactory name: '" + factoryName + "', known ones: " + factories.keySet());
169         }
170         return factory;
171     }
172 
173     /**
174      * Selects a name mapper, never returns {@code null}.
175      */
176     protected NameMapper selectNameMapper(final String nameMapperName) {
177         NameMapper nameMapper = nameMappers.get(nameMapperName);
178         if (nameMapper == null) {
179             throw new IllegalArgumentException(
180                     "Unknown NameMapper name: '" + nameMapperName + "', known ones: " + nameMappers.keySet());
181         }
182         return nameMapper;
183     }
184 
185     /**
186      * To be invoked on repository system shut down. This method will shut down each {@link NamedLockFactory}.
187      */
188     protected void shutdown() {
189         logger.debug(
190                 "Shutting down adapter factory; available factories {}; available name mappers {}",
191                 factories.keySet(),
192                 nameMappers.keySet());
193         ArrayList<Exception> exceptions = new ArrayList<>();
194         for (Map.Entry<String, NamedLockFactory> entry : factories.entrySet()) {
195             try {
196                 logger.debug("Shutting down '{}' factory", entry.getKey());
197                 entry.getValue().shutdown();
198             } catch (Exception e) {
199                 exceptions.add(e);
200             }
201         }
202         MultiRuntimeException.mayThrow("Problem shutting down factories", exceptions);
203     }
204 }