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.internal.impl.synccontext.named.providers.DiscriminatingNameMapperProvider;
35  import org.eclipse.aether.internal.impl.synccontext.named.providers.FileGAVNameMapperProvider;
36  import org.eclipse.aether.internal.impl.synccontext.named.providers.FileHashingGAVNameMapperProvider;
37  import org.eclipse.aether.internal.impl.synccontext.named.providers.GAVNameMapperProvider;
38  import org.eclipse.aether.internal.impl.synccontext.named.providers.StaticNameMapperProvider;
39  import org.eclipse.aether.named.NamedLockFactory;
40  import org.eclipse.aether.named.providers.FileLockNamedLockFactory;
41  import org.eclipse.aether.named.providers.LocalReadWriteLockNamedLockFactory;
42  import org.eclipse.aether.named.providers.LocalSemaphoreNamedLockFactory;
43  import org.eclipse.aether.named.providers.NoopNamedLockFactory;
44  import org.eclipse.aether.spi.locator.Service;
45  import org.eclipse.aether.spi.locator.ServiceLocator;
46  import org.eclipse.aether.util.ConfigUtils;
47  import org.slf4j.Logger;
48  import org.slf4j.LoggerFactory;
49  
50  import static java.util.Objects.requireNonNull;
51  
52  /**
53   * Default implementation of {@link NamedLockFactoryAdapterFactory}. This implementation creates new instances of the
54   * adapter on every call. In turn, on shutdown, it will shut down all existing named lock factories. This is merely for
55   * simplicity, to not have to track "used" named lock factories, while it exposes all available named lock factories to
56   * callers.
57   * <p>
58   * Most members and methods of this class are protected. It is meant to be extended in case of need to customize its
59   * behavior. An exception from this are private static methods, mostly meant to provide out of the box
60   * defaults and to be used when no Eclipse Sisu component container is used.
61   *
62   * @since 1.9.1
63   */
64  @Singleton
65  @Named
66  public class NamedLockFactoryAdapterFactoryImpl implements NamedLockFactoryAdapterFactory, Service
67  {
68      private static final String DEFAULT_FACTORY_NAME = LocalReadWriteLockNamedLockFactory.NAME;
69  
70      private static final String DEFAULT_NAME_MAPPER_NAME = GAVNameMapperProvider.NAME;
71  
72      private static Map<String, NamedLockFactory> getManuallyCreatedFactories()
73      {
74          HashMap<String, NamedLockFactory> factories = new HashMap<>();
75          factories.put( NoopNamedLockFactory.NAME, new NoopNamedLockFactory() );
76          factories.put( LocalReadWriteLockNamedLockFactory.NAME, new LocalReadWriteLockNamedLockFactory() );
77          factories.put( LocalSemaphoreNamedLockFactory.NAME, new LocalSemaphoreNamedLockFactory() );
78          factories.put( FileLockNamedLockFactory.NAME, new FileLockNamedLockFactory() );
79          return Collections.unmodifiableMap( factories );
80      }
81  
82      private static Map<String, NameMapper> getManuallyCreatedNameMappers()
83      {
84          HashMap<String, NameMapper> mappers = new HashMap<>();
85          mappers.put( StaticNameMapperProvider.NAME, new StaticNameMapperProvider().get() );
86          mappers.put( GAVNameMapperProvider.NAME, new GAVNameMapperProvider().get() );
87          mappers.put( DiscriminatingNameMapperProvider.NAME, new DiscriminatingNameMapperProvider().get() );
88          mappers.put( FileGAVNameMapperProvider.NAME, new FileGAVNameMapperProvider().get() );
89          mappers.put( FileHashingGAVNameMapperProvider.NAME, new FileHashingGAVNameMapperProvider().get() );
90          return Collections.unmodifiableMap( mappers );
91      }
92  
93      protected static final String FACTORY_KEY = "aether.syncContext.named.factory";
94  
95      protected static final String NAME_MAPPER_KEY = "aether.syncContext.named.nameMapper";
96  
97      protected final Logger logger = LoggerFactory.getLogger( getClass() );
98  
99      protected final Map<String, NamedLockFactory> factories;
100 
101     protected final String defaultFactoryName;
102 
103     protected final Map<String, NameMapper> nameMappers;
104 
105     protected final String defaultNameMapperName;
106 
107     /**
108      * Default constructor for non Eclipse Sisu uses.
109      *
110      * @deprecated for use in SL only.
111      */
112     @Deprecated
113     public NamedLockFactoryAdapterFactoryImpl()
114     {
115         this.factories = getManuallyCreatedFactories();
116         this.defaultFactoryName = DEFAULT_FACTORY_NAME;
117         this.nameMappers = getManuallyCreatedNameMappers();
118         this.defaultNameMapperName = DEFAULT_NAME_MAPPER_NAME;
119     }
120 
121     @Override
122     public void initService( ServiceLocator locator )
123     {
124         locator.getService( RepositorySystemLifecycle.class ).addOnSystemEndedHandler( this::shutdown );
125     }
126 
127     @Inject
128     public NamedLockFactoryAdapterFactoryImpl( final Map<String, NamedLockFactory> factories,
129                                                final Map<String, NameMapper> nameMappers,
130                                                final RepositorySystemLifecycle lifecycle )
131     {
132         this( factories, DEFAULT_FACTORY_NAME, nameMappers, DEFAULT_NAME_MAPPER_NAME, lifecycle );
133     }
134 
135     public NamedLockFactoryAdapterFactoryImpl( final Map<String, NamedLockFactory> factories,
136                                                final String defaultFactoryName,
137                                                final Map<String, NameMapper> nameMappers,
138                                                final String defaultNameMapperName,
139                                                final RepositorySystemLifecycle lifecycle )
140     {
141         this.factories = requireNonNull( factories );
142         this.defaultFactoryName = requireNonNull( defaultFactoryName );
143         this.nameMappers = requireNonNull( nameMappers );
144         this.defaultNameMapperName = requireNonNull( defaultNameMapperName );
145         lifecycle.addOnSystemEndedHandler( this::shutdown );
146 
147         logger.debug( "Created adapter factory; available factories {}; available name mappers {}",
148                 factories.keySet(), nameMappers.keySet() );
149     }
150 
151     /**
152      * Current implementation simply delegates to {@link #createAdapter(RepositorySystemSession)}.
153      */
154     @Override
155     public NamedLockFactoryAdapter getAdapter( RepositorySystemSession session )
156     {
157         return createAdapter( session );
158     }
159 
160     /**
161      * Creates a new adapter instance, never returns {@code null}.
162      */
163     protected NamedLockFactoryAdapter createAdapter( RepositorySystemSession session )
164     {
165         final String nameMapperName = requireNonNull( getNameMapperName( session ) );
166         final String factoryName = requireNonNull( getFactoryName( session ) );
167         final NameMapper nameMapper = selectNameMapper( nameMapperName );
168         final NamedLockFactory factory = selectFactory( factoryName );
169         logger.debug( "Creating adapter using nameMapper '{}' and factory '{}'",
170                 nameMapperName, factoryName );
171         return new NamedLockFactoryAdapter( nameMapper, factory );
172     }
173 
174     /**
175      * Returns the selected (user configured or default) named lock factory name, never {@code null}.
176      */
177     protected String getFactoryName( RepositorySystemSession session )
178     {
179         return ConfigUtils.getString( session, getDefaultFactoryName(), FACTORY_KEY );
180     }
181 
182     /**
183      * Returns the default named lock factory name, never {@code null}.
184      */
185     protected String getDefaultFactoryName()
186     {
187         return defaultFactoryName;
188     }
189 
190     /**
191      * Returns the selected (user configured or default) name mapper name, never {@code null}.
192      */
193     protected String getNameMapperName( RepositorySystemSession session )
194     {
195         return ConfigUtils.getString( session, getDefaultNameMapperName(), NAME_MAPPER_KEY );
196     }
197 
198     /**
199      * Returns the default name mapper name, never {@code null}.
200      */
201     protected String getDefaultNameMapperName()
202     {
203         return defaultNameMapperName;
204     }
205 
206     /**
207      * Selects a named lock factory, never returns {@code null}.
208      */
209     protected NamedLockFactory selectFactory( final String factoryName )
210     {
211         NamedLockFactory factory = factories.get( factoryName );
212         if ( factory == null )
213         {
214             throw new IllegalArgumentException(
215                     "Unknown NamedLockFactory name: '" + factoryName + "', known ones: " + factories.keySet() );
216         }
217         return factory;
218     }
219 
220     /**
221      * Selects a name mapper, never returns {@code null}.
222      */
223     protected NameMapper selectNameMapper( final String nameMapperName )
224     {
225         NameMapper nameMapper = nameMappers.get( nameMapperName );
226         if ( nameMapper == null )
227         {
228             throw new IllegalArgumentException(
229                     "Unknown NameMapper name: '" + nameMapperName + "', known ones: " + nameMappers.keySet() );
230         }
231         return nameMapper;
232     }
233 
234     /**
235      * To be invoked on repository system shut down. This method will shut down each {@link NamedLockFactory}.
236      */
237     protected void shutdown()
238     {
239         logger.debug( "Shutting down adapter factory; available factories {}; available name mappers {}",
240                 factories.keySet(), nameMappers.keySet() );
241         ArrayList<Exception> exceptions = new ArrayList<>();
242         for ( Map.Entry<String, NamedLockFactory> entry : factories.entrySet() )
243         {
244             try
245             {
246                 logger.debug( "Shutting down '{}' factory", entry.getKey() );
247                 entry.getValue().shutdown();
248             }
249             catch ( Exception e )
250             {
251                 exceptions.add( e );
252             }
253         }
254         MultiRuntimeException.mayThrow( "Problem shutting down factories", exceptions );
255     }
256 }