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  import java.util.concurrent.TimeUnit;
28  
29  import org.eclipse.aether.Keys;
30  import org.eclipse.aether.RepositorySystemSession;
31  import org.eclipse.aether.impl.NamedLockFactorySelector;
32  import org.eclipse.aether.named.NamedLockFactory;
33  import org.eclipse.aether.spi.locking.LockingInhibitor;
34  import org.eclipse.aether.spi.locking.LockingInhibitorFactory;
35  import org.eclipse.aether.util.ConfigUtils;
36  import org.slf4j.Logger;
37  import org.slf4j.LoggerFactory;
38  
39  import static java.util.Objects.requireNonNull;
40  
41  /**
42   * Default implementation of {@link NamedLockFactoryAdapterFactory}. This implementation creates new instances of the
43   * adapter on every call. In turn, on shutdown, it will shut down all existing named lock factories. This is merely for
44   * simplicity, to not have to track "used" named lock factories, while it exposes all available named lock factories to
45   * callers.
46   * <p>
47   * Most members and methods of this class are protected. It is meant to be extended in case of need to customize its
48   * behavior. An exception from this are private static methods, mostly meant to provide out of the box
49   * defaults and to be used when no Eclipse Sisu component container is used.
50   *
51   * @since 1.9.1
52   */
53  @Singleton
54  @Named
55  public class NamedLockFactoryAdapterFactoryImpl implements NamedLockFactoryAdapterFactory {
56      public static final String DEFAULT_NAME_MAPPER_NAME = NameMappers.FILE_GAECV_NAME;
57  
58      /**
59       * Name of the lock factory to use in session. Out of the box supported ones are "file-lock", "rwlock-local",
60       * "semaphore-local", "noop". By adding extensions one can extend available lock factories (for example IPC locking).
61       * <strong>Deprecated: use {@code aether.system.named...} configuration instead.</strong>
62       *
63       * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
64       * @configurationType {@link java.lang.String}
65       * @deprecated
66       */
67      @Deprecated
68      public static final String CONFIG_PROP_FACTORY_KEY = NamedLockFactoryAdapter.CONFIG_PROPS_PREFIX + "factory";
69  
70      /**
71       * Name of the name mapper to use in session. Out of the box supported ones are "static", "gav", "gaecv", "file-gav",
72       * "file-gaecv", "file-hgav", "file-hgaecv", "file-static" and "discriminating".
73       *
74       * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
75       * @configurationType {@link java.lang.String}
76       * @configurationDefaultValue {@link #DEFAULT_NAME_MAPPER_NAME}
77       */
78      public static final String CONFIG_PROP_NAME_MAPPER_KEY = NamedLockFactoryAdapter.CONFIG_PROPS_PREFIX + "nameMapper";
79  
80      protected final Logger logger = LoggerFactory.getLogger(getClass());
81  
82      protected final NamedLockFactorySelector namedLockFactorySelector;
83  
84      protected final Map<String, NameMapper> nameMappers;
85  
86      protected final String defaultNameMapperName;
87  
88      protected final Map<String, LockingInhibitorFactory> lockingInhibitorFactories;
89  
90      @Inject
91      public NamedLockFactoryAdapterFactoryImpl(
92              final NamedLockFactorySelector namedLockFactorySelector,
93              final Map<String, NameMapper> nameMappers,
94              final Map<String, LockingInhibitorFactory> lockingInhibitorFactories) {
95          this(namedLockFactorySelector, nameMappers, DEFAULT_NAME_MAPPER_NAME, lockingInhibitorFactories);
96      }
97  
98      public NamedLockFactoryAdapterFactoryImpl(
99              final NamedLockFactorySelector namedLockFactorySelector,
100             final Map<String, NameMapper> nameMappers,
101             final String defaultNameMapperName,
102             final Map<String, LockingInhibitorFactory> lockingInhibitorFactories) {
103         this.namedLockFactorySelector = requireNonNull(namedLockFactorySelector);
104         this.nameMappers = requireNonNull(nameMappers);
105         this.defaultNameMapperName = requireNonNull(defaultNameMapperName);
106         this.lockingInhibitorFactories = requireNonNull(lockingInhibitorFactories);
107 
108         logger.debug(
109                 "Created adapter factory; available lock factories {}; available name mappers {}",
110                 namedLockFactorySelector.getAvailableLockFactories(),
111                 nameMappers.keySet());
112     }
113 
114     private static final Object ADAPTER_KEY = Keys.of(NamedLockFactoryAdapterFactoryImpl.class, "adapter");
115 
116     /**
117      * Current implementation memoize instance in session or delegates to {@link #createAdapter(RepositorySystemSession)}.
118      */
119     @Override
120     public NamedLockFactoryAdapter getAdapter(RepositorySystemSession session) {
121         requireNonNull(session, "session cannot be null");
122         return (NamedLockFactoryAdapter) session.getData().computeIfAbsent(ADAPTER_KEY, () -> createAdapter(session));
123     }
124 
125     /**
126      * Creates a new adapter instance, never returns {@code null}.
127      */
128     protected NamedLockFactoryAdapter createAdapter(RepositorySystemSession session) {
129         final NameMapper nameMapper = selectNameMapper(session, requireNonNull(getNameMapperName(session)));
130         final NamedLockFactory factory = namedLockFactorySelector.getNamedLockFactory(session.getConfigProperties());
131         final long lockWait = namedLockFactorySelector.getLockWaitTime(session.getConfigProperties());
132         final TimeUnit lockWaitUnit = namedLockFactorySelector.getLockWaitTimeUnit(session.getConfigProperties());
133         logger.debug("Creating adapter using nameMapper '{}' and factory '{}'", nameMapper, factory);
134         return new NamedLockFactoryAdapter(nameMapper, factory, lockWait, lockWaitUnit);
135     }
136 
137     /**
138      * Returns the selected (user configured or default) name mapper name, never {@code null}.
139      */
140     protected String getNameMapperName(RepositorySystemSession session) {
141         return ConfigUtils.getString(session, getDefaultNameMapperName(), CONFIG_PROP_NAME_MAPPER_KEY);
142     }
143 
144     /**
145      * Returns the default name mapper name, never {@code null}.
146      */
147     protected String getDefaultNameMapperName() {
148         return defaultNameMapperName;
149     }
150 
151     /**
152      * Selects a name mapper, never returns {@code null}. Applies inhibitors.
153      */
154     protected NameMapper selectNameMapper(final RepositorySystemSession session, final String nameMapperName) {
155         NameMapper nameMapper = nameMappers.get(nameMapperName);
156         if (nameMapper == null) {
157             throw new IllegalArgumentException(
158                     "Unknown NameMapper name: '" + nameMapperName + "', known ones: " + nameMappers.keySet());
159         }
160         if (!lockingInhibitorFactories.isEmpty()) {
161             ArrayList<LockingInhibitor> inhibitors = new ArrayList<>();
162             for (LockingInhibitorFactory factory : lockingInhibitorFactories.values()) {
163                 factory.newInstance(session).ifPresent(inhibitors::add);
164             }
165             if (!inhibitors.isEmpty()) {
166                 return new InhibitingNameMapper(nameMapper, inhibitors);
167             }
168         }
169         return nameMapper;
170     }
171 }