View Javadoc
1   package org.eclipse.aether.internal.impl.synccontext.named;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import javax.inject.Inject;
23  import javax.inject.Named;
24  import javax.inject.Singleton;
25  
26  import java.util.ArrayList;
27  import java.util.Collections;
28  import java.util.HashMap;
29  import java.util.Map;
30  
31  import org.eclipse.aether.MultiRuntimeException;
32  import org.eclipse.aether.RepositorySystemSession;
33  import org.eclipse.aether.impl.RepositorySystemLifecycle;
34  import org.eclipse.aether.named.NamedLockFactory;
35  import org.eclipse.aether.named.providers.FileLockNamedLockFactory;
36  import org.eclipse.aether.named.providers.LocalReadWriteLockNamedLockFactory;
37  import org.eclipse.aether.named.providers.LocalSemaphoreNamedLockFactory;
38  import org.eclipse.aether.named.providers.NoopNamedLockFactory;
39  import org.eclipse.aether.spi.locator.Service;
40  import org.eclipse.aether.spi.locator.ServiceLocator;
41  import org.eclipse.aether.util.ConfigUtils;
42  import org.slf4j.Logger;
43  import org.slf4j.LoggerFactory;
44  
45  import static java.util.Objects.requireNonNull;
46  
47  /**
48   * Default implementation of {@link NamedLockFactoryAdapterFactory}. This implementation creates new instances of the
49   * adapter on every call. In turn, on shutdown, it will shut down all existing named lock factories. This is merely for
50   * simplicity, to not have to track "used" named lock factories, while it exposes all available named lock factories to
51   * callers.
52   * <p>
53   * Most members and methods of this class are protected. It is meant to be extended in case of need to customize its
54   * behavior. An exception from this are private static methods, mostly meant to provide out of the box
55   * defaults and to be used when no Eclipse Sisu component container is used.
56   *
57   * @since 1.9.1
58   */
59  @Singleton
60  @Named
61  public class NamedLockFactoryAdapterFactoryImpl implements NamedLockFactoryAdapterFactory, Service
62  {
63      private static final String DEFAULT_FACTORY_NAME = LocalReadWriteLockNamedLockFactory.NAME;
64  
65      private static final String DEFAULT_NAME_MAPPER_NAME = NameMappers.GAV_NAME;
66  
67      private static Map<String, NamedLockFactory> getManuallyCreatedFactories()
68      {
69          HashMap<String, NamedLockFactory> factories = new HashMap<>();
70          factories.put( NoopNamedLockFactory.NAME, new NoopNamedLockFactory() );
71          factories.put( LocalReadWriteLockNamedLockFactory.NAME, new LocalReadWriteLockNamedLockFactory() );
72          factories.put( LocalSemaphoreNamedLockFactory.NAME, new LocalSemaphoreNamedLockFactory() );
73          factories.put( FileLockNamedLockFactory.NAME, new FileLockNamedLockFactory() );
74          return Collections.unmodifiableMap( factories );
75      }
76  
77      private static Map<String, NameMapper> getManuallyCreatedNameMappers()
78      {
79          HashMap<String, NameMapper> mappers = new HashMap<>();
80          mappers.put( NameMappers.STATIC_NAME, NameMappers.staticNameMapper() );
81          mappers.put( NameMappers.GAV_NAME, NameMappers.gavNameMapper() );
82          mappers.put( NameMappers.DISCRIMINATING_NAME, NameMappers.discriminatingNameMapper() );
83          mappers.put( NameMappers.FILE_GAV_NAME, NameMappers.fileGavNameMapper() );
84          mappers.put( NameMappers.FILE_HGAV_NAME, NameMappers.fileHashingGavNameMapper() );
85          return Collections.unmodifiableMap( mappers );
86      }
87  
88      protected static final String FACTORY_KEY = "aether.syncContext.named.factory";
89  
90      protected static final String NAME_MAPPER_KEY = "aether.syncContext.named.nameMapper";
91  
92      protected final Logger logger = LoggerFactory.getLogger( getClass() );
93  
94      protected final Map<String, NamedLockFactory> factories;
95  
96      protected final String defaultFactoryName;
97  
98      protected final Map<String, NameMapper> nameMappers;
99  
100     protected final String defaultNameMapperName;
101 
102     /**
103      * Default constructor for non Eclipse Sisu uses.
104      *
105      * @deprecated for use in SL only.
106      */
107     @Deprecated
108     public NamedLockFactoryAdapterFactoryImpl()
109     {
110         this.factories = getManuallyCreatedFactories();
111         this.defaultFactoryName = DEFAULT_FACTORY_NAME;
112         this.nameMappers = getManuallyCreatedNameMappers();
113         this.defaultNameMapperName = DEFAULT_NAME_MAPPER_NAME;
114     }
115 
116     @Override
117     public void initService( ServiceLocator locator )
118     {
119         locator.getService( RepositorySystemLifecycle.class ).addOnSystemEndedHandler( this::shutdown );
120     }
121 
122     @Inject
123     public NamedLockFactoryAdapterFactoryImpl( final Map<String, NamedLockFactory> factories,
124                                                final Map<String, NameMapper> nameMappers,
125                                                final RepositorySystemLifecycle lifecycle )
126     {
127         this( factories, DEFAULT_FACTORY_NAME, nameMappers, DEFAULT_NAME_MAPPER_NAME, lifecycle );
128     }
129 
130     public NamedLockFactoryAdapterFactoryImpl( final Map<String, NamedLockFactory> factories,
131                                                final String defaultFactoryName,
132                                                final Map<String, NameMapper> nameMappers,
133                                                final String defaultNameMapperName,
134                                                final RepositorySystemLifecycle lifecycle )
135     {
136         this.factories = requireNonNull( factories );
137         this.defaultFactoryName = requireNonNull( defaultFactoryName );
138         this.nameMappers = requireNonNull( nameMappers );
139         this.defaultNameMapperName = requireNonNull( defaultNameMapperName );
140         lifecycle.addOnSystemEndedHandler( this::shutdown );
141 
142         logger.debug( "Created adapter factory; available factories {}; available name mappers {}",
143                 factories.keySet(), nameMappers.keySet() );
144     }
145 
146     /**
147      * Current implementation simply delegates to {@link #createAdapter(RepositorySystemSession)}.
148      */
149     @Override
150     public NamedLockFactoryAdapter getAdapter( RepositorySystemSession session )
151     {
152         return createAdapter( session );
153     }
154 
155     /**
156      * Creates a new adapter instance, never returns {@code null}.
157      */
158     protected NamedLockFactoryAdapter createAdapter( RepositorySystemSession session )
159     {
160         final String nameMapperName = requireNonNull( getNameMapperName( session ) );
161         final String factoryName = requireNonNull( getFactoryName( session ) );
162         final NameMapper nameMapper = selectNameMapper( nameMapperName );
163         final NamedLockFactory factory = selectFactory( factoryName );
164         logger.debug( "Creating adapter using nameMapper '{}' and factory '{}'",
165                 nameMapperName, factoryName );
166         return new NamedLockFactoryAdapter( nameMapper, factory );
167     }
168 
169     /**
170      * Returns the selected (user configured or default) named lock factory name, never {@code null}.
171      */
172     protected String getFactoryName( RepositorySystemSession session )
173     {
174         return ConfigUtils.getString( session, getDefaultFactoryName(), FACTORY_KEY );
175     }
176 
177     /**
178      * Returns the default named lock factory name, never {@code null}.
179      */
180     protected String getDefaultFactoryName()
181     {
182         return defaultFactoryName;
183     }
184 
185     /**
186      * Returns the selected (user configured or default) name mapper name, never {@code null}.
187      */
188     protected String getNameMapperName( RepositorySystemSession session )
189     {
190         return ConfigUtils.getString( session, getDefaultNameMapperName(), NAME_MAPPER_KEY );
191     }
192 
193     /**
194      * Returns the default name mapper name, never {@code null}.
195      */
196     protected String getDefaultNameMapperName()
197     {
198         return defaultNameMapperName;
199     }
200 
201     /**
202      * Selects a named lock factory, never returns {@code null}.
203      */
204     protected NamedLockFactory selectFactory( final String factoryName )
205     {
206         NamedLockFactory factory = factories.get( factoryName );
207         if ( factory == null )
208         {
209             throw new IllegalArgumentException(
210                     "Unknown NamedLockFactory name: '" + factoryName + "', known ones: " + factories.keySet() );
211         }
212         return factory;
213     }
214 
215     /**
216      * Selects a name mapper, never returns {@code null}.
217      */
218     protected NameMapper selectNameMapper( final String nameMapperName )
219     {
220         NameMapper nameMapper = nameMappers.get( nameMapperName );
221         if ( nameMapper == null )
222         {
223             throw new IllegalArgumentException(
224                     "Unknown NameMapper name: '" + nameMapperName + "', known ones: " + nameMappers.keySet() );
225         }
226         return nameMapper;
227     }
228 
229     /**
230      * To be invoked on repository system shut down. This method will shut down each {@link NamedLockFactory}.
231      */
232     protected void shutdown()
233     {
234         logger.debug( "Shutting down adapter factory; available factories {}; available name mappers {}",
235                 factories.keySet(), nameMappers.keySet() );
236         ArrayList<Exception> exceptions = new ArrayList<>();
237         for ( Map.Entry<String, NamedLockFactory> entry : factories.entrySet() )
238         {
239             try
240             {
241                 logger.debug( "Shutting down '{}' factory", entry.getKey() );
242                 entry.getValue().shutdown();
243             }
244             catch ( Exception e )
245             {
246                 exceptions.add( e );
247             }
248         }
249         MultiRuntimeException.mayThrow( "Problem shutting down factories", exceptions );
250     }
251 }