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