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.supplier;
20  
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.LinkedHashMap;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.concurrent.atomic.AtomicBoolean;
27  import java.util.function.Supplier;
28  
29  import org.apache.maven.model.building.DefaultModelBuilderFactory;
30  import org.apache.maven.model.building.ModelBuilder;
31  import org.apache.maven.repository.internal.DefaultArtifactDescriptorReader;
32  import org.apache.maven.repository.internal.DefaultModelCacheFactory;
33  import org.apache.maven.repository.internal.DefaultVersionRangeResolver;
34  import org.apache.maven.repository.internal.DefaultVersionResolver;
35  import org.apache.maven.repository.internal.MavenArtifactRelocationSource;
36  import org.apache.maven.repository.internal.ModelCacheFactory;
37  import org.apache.maven.repository.internal.PluginsMetadataGeneratorFactory;
38  import org.apache.maven.repository.internal.SnapshotMetadataGeneratorFactory;
39  import org.apache.maven.repository.internal.VersionsMetadataGeneratorFactory;
40  import org.apache.maven.repository.internal.relocation.DistributionManagementArtifactRelocationSource;
41  import org.apache.maven.repository.internal.relocation.UserPropertiesArtifactRelocationSource;
42  import org.eclipse.aether.RepositoryListener;
43  import org.eclipse.aether.RepositorySystem;
44  import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
45  import org.eclipse.aether.impl.ArtifactDescriptorReader;
46  import org.eclipse.aether.impl.ArtifactResolver;
47  import org.eclipse.aether.impl.DependencyCollector;
48  import org.eclipse.aether.impl.Deployer;
49  import org.eclipse.aether.impl.Installer;
50  import org.eclipse.aether.impl.LocalRepositoryProvider;
51  import org.eclipse.aether.impl.MetadataGeneratorFactory;
52  import org.eclipse.aether.impl.MetadataResolver;
53  import org.eclipse.aether.impl.OfflineController;
54  import org.eclipse.aether.impl.RemoteRepositoryFilterManager;
55  import org.eclipse.aether.impl.RemoteRepositoryManager;
56  import org.eclipse.aether.impl.RepositoryConnectorProvider;
57  import org.eclipse.aether.impl.RepositoryEventDispatcher;
58  import org.eclipse.aether.impl.RepositorySystemLifecycle;
59  import org.eclipse.aether.impl.RepositorySystemValidator;
60  import org.eclipse.aether.impl.UpdateCheckManager;
61  import org.eclipse.aether.impl.UpdatePolicyAnalyzer;
62  import org.eclipse.aether.impl.VersionRangeResolver;
63  import org.eclipse.aether.impl.VersionResolver;
64  import org.eclipse.aether.internal.impl.DefaultArtifactPredicateFactory;
65  import org.eclipse.aether.internal.impl.DefaultArtifactResolver;
66  import org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider;
67  import org.eclipse.aether.internal.impl.DefaultChecksumProcessor;
68  import org.eclipse.aether.internal.impl.DefaultDeployer;
69  import org.eclipse.aether.internal.impl.DefaultInstaller;
70  import org.eclipse.aether.internal.impl.DefaultLocalPathComposer;
71  import org.eclipse.aether.internal.impl.DefaultLocalPathPrefixComposerFactory;
72  import org.eclipse.aether.internal.impl.DefaultLocalRepositoryProvider;
73  import org.eclipse.aether.internal.impl.DefaultMetadataResolver;
74  import org.eclipse.aether.internal.impl.DefaultOfflineController;
75  import org.eclipse.aether.internal.impl.DefaultPathProcessor;
76  import org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager;
77  import org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider;
78  import org.eclipse.aether.internal.impl.DefaultRepositoryEventDispatcher;
79  import org.eclipse.aether.internal.impl.DefaultRepositoryLayoutProvider;
80  import org.eclipse.aether.internal.impl.DefaultRepositorySystem;
81  import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle;
82  import org.eclipse.aether.internal.impl.DefaultRepositorySystemValidator;
83  import org.eclipse.aether.internal.impl.DefaultTrackingFileManager;
84  import org.eclipse.aether.internal.impl.DefaultTransporterProvider;
85  import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager;
86  import org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer;
87  import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory;
88  import org.eclipse.aether.internal.impl.LocalPathComposer;
89  import org.eclipse.aether.internal.impl.LocalPathPrefixComposerFactory;
90  import org.eclipse.aether.internal.impl.Maven2RepositoryLayoutFactory;
91  import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
92  import org.eclipse.aether.internal.impl.TrackingFileManager;
93  import org.eclipse.aether.internal.impl.checksum.DefaultChecksumAlgorithmFactorySelector;
94  import org.eclipse.aether.internal.impl.checksum.Md5ChecksumAlgorithmFactory;
95  import org.eclipse.aether.internal.impl.checksum.Sha1ChecksumAlgorithmFactory;
96  import org.eclipse.aether.internal.impl.checksum.Sha256ChecksumAlgorithmFactory;
97  import org.eclipse.aether.internal.impl.checksum.Sha512ChecksumAlgorithmFactory;
98  import org.eclipse.aether.internal.impl.checksum.SparseDirectoryTrustedChecksumsSource;
99  import org.eclipse.aether.internal.impl.checksum.SummaryFileTrustedChecksumsSource;
100 import org.eclipse.aether.internal.impl.checksum.TrustedToProvidedChecksumsSourceAdapter;
101 import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector;
102 import org.eclipse.aether.internal.impl.collect.DependencyCollectorDelegate;
103 import org.eclipse.aether.internal.impl.collect.bf.BfDependencyCollector;
104 import org.eclipse.aether.internal.impl.collect.df.DfDependencyCollector;
105 import org.eclipse.aether.internal.impl.filter.DefaultRemoteRepositoryFilterManager;
106 import org.eclipse.aether.internal.impl.filter.FilteringPipelineRepositoryConnectorFactory;
107 import org.eclipse.aether.internal.impl.filter.GroupIdRemoteRepositoryFilterSource;
108 import org.eclipse.aether.internal.impl.filter.PrefixesRemoteRepositoryFilterSource;
109 import org.eclipse.aether.internal.impl.offline.OfflinePipelineRepositoryConnectorFactory;
110 import org.eclipse.aether.internal.impl.resolution.TrustedChecksumsArtifactResolverPostProcessor;
111 import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory;
112 import org.eclipse.aether.internal.impl.synccontext.named.NameMapper;
113 import org.eclipse.aether.internal.impl.synccontext.named.NameMappers;
114 import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactory;
115 import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactoryImpl;
116 import org.eclipse.aether.internal.impl.transport.http.DefaultChecksumExtractor;
117 import org.eclipse.aether.internal.impl.transport.http.Nx2ChecksumExtractor;
118 import org.eclipse.aether.internal.impl.transport.http.XChecksumExtractor;
119 import org.eclipse.aether.named.NamedLockFactory;
120 import org.eclipse.aether.named.providers.FileLockNamedLockFactory;
121 import org.eclipse.aether.named.providers.LocalReadWriteLockNamedLockFactory;
122 import org.eclipse.aether.named.providers.LocalSemaphoreNamedLockFactory;
123 import org.eclipse.aether.named.providers.NoopNamedLockFactory;
124 import org.eclipse.aether.spi.artifact.ArtifactPredicateFactory;
125 import org.eclipse.aether.spi.artifact.decorator.ArtifactDecoratorFactory;
126 import org.eclipse.aether.spi.artifact.generator.ArtifactGeneratorFactory;
127 import org.eclipse.aether.spi.artifact.transformer.ArtifactTransformer;
128 import org.eclipse.aether.spi.checksums.ProvidedChecksumsSource;
129 import org.eclipse.aether.spi.checksums.TrustedChecksumsSource;
130 import org.eclipse.aether.spi.connector.PipelineRepositoryConnectorFactory;
131 import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
132 import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
133 import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
134 import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
135 import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilterSource;
136 import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory;
137 import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider;
138 import org.eclipse.aether.spi.connector.transport.TransporterFactory;
139 import org.eclipse.aether.spi.connector.transport.TransporterProvider;
140 import org.eclipse.aether.spi.connector.transport.http.ChecksumExtractor;
141 import org.eclipse.aether.spi.connector.transport.http.ChecksumExtractorStrategy;
142 import org.eclipse.aether.spi.io.ChecksumProcessor;
143 import org.eclipse.aether.spi.io.PathProcessor;
144 import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory;
145 import org.eclipse.aether.spi.resolution.ArtifactResolverPostProcessor;
146 import org.eclipse.aether.spi.synccontext.SyncContextFactory;
147 import org.eclipse.aether.spi.validator.ValidatorFactory;
148 import org.eclipse.aether.transport.apache.ApacheTransporterFactory;
149 import org.eclipse.aether.transport.file.FileTransporterFactory;
150 import org.eclipse.aether.util.version.GenericVersionScheme;
151 import org.eclipse.aether.version.VersionScheme;
152 
153 /**
154  * A simple memorizing {@link Supplier} of {@link RepositorySystem} instance, that on first call
155  * supplies lazily constructed instance, and on each subsequent call same instance. Hence, this instance should be
156  * thrown away immediately once repository system was created and there is no need for more instances. If new
157  * repository system instance needed, new instance of this class must be created. For proper shut down of returned
158  * repository system instance(s) use {@link RepositorySystem#shutdown()} method on supplied instance(s).
159  * <p>
160  * Since Resolver 2.0 this class offers access to various components via public getters, and allows even partial object
161  * graph construction.
162  * <p>
163  * Extend this class {@code createXXX()} methods and override to customize, if needed. The contract of this class makes
164  * sure that these (potentially overridden) methods are invoked only once, and instance created by those methods are
165  * memorized and kept as long as supplier instance is kept open.
166  * <p>
167  * This class is not thread safe and must be used from one thread only, while the constructed {@link RepositorySystem}
168  * is thread safe.
169  * <p>
170  * Important: Given the instance of supplier memorizes the supplier {@link RepositorySystem} instance it supplies,
171  * their lifecycle is shared as well: once supplied repository system is shut-down, this instance becomes closed as
172  * well. Any subsequent {@code getXXX} method invocation attempt will fail with {@link IllegalStateException}.
173  *
174  * @since 2.0.0
175  */
176 public class RepositorySystemSupplier implements Supplier<RepositorySystem> {
177     private final AtomicBoolean closed = new AtomicBoolean(false);
178 
179     public RepositorySystemSupplier() {}
180 
181     private void checkClosed() {
182         if (closed.get()) {
183             throw new IllegalStateException("Supplier is closed");
184         }
185     }
186 
187     private PathProcessor pathProcessor;
188 
189     public final PathProcessor getPathProcessor() {
190         checkClosed();
191         if (pathProcessor == null) {
192             pathProcessor = createPathProcessor();
193         }
194         return pathProcessor;
195     }
196 
197     protected PathProcessor createPathProcessor() {
198         return new DefaultPathProcessor();
199     }
200 
201     private ChecksumProcessor checksumProcessor;
202 
203     public final ChecksumProcessor getChecksumProcessor() {
204         checkClosed();
205         if (checksumProcessor == null) {
206             checksumProcessor = createChecksumProcessor();
207         }
208         return checksumProcessor;
209     }
210 
211     protected ChecksumProcessor createChecksumProcessor() {
212         return new DefaultChecksumProcessor(getPathProcessor());
213     }
214 
215     private TrackingFileManager trackingFileManager;
216 
217     public final TrackingFileManager getTrackingFileManager() {
218         checkClosed();
219         if (trackingFileManager == null) {
220             trackingFileManager = createTrackingFileManager();
221         }
222         return trackingFileManager;
223     }
224 
225     protected TrackingFileManager createTrackingFileManager() {
226         return new DefaultTrackingFileManager();
227     }
228 
229     private LocalPathComposer localPathComposer;
230 
231     public final LocalPathComposer getLocalPathComposer() {
232         checkClosed();
233         if (localPathComposer == null) {
234             localPathComposer = createLocalPathComposer();
235         }
236         return localPathComposer;
237     }
238 
239     protected LocalPathComposer createLocalPathComposer() {
240         return new DefaultLocalPathComposer();
241     }
242 
243     private LocalPathPrefixComposerFactory localPathPrefixComposerFactory;
244 
245     public final LocalPathPrefixComposerFactory getLocalPathPrefixComposerFactory() {
246         checkClosed();
247         if (localPathPrefixComposerFactory == null) {
248             localPathPrefixComposerFactory = createLocalPathPrefixComposerFactory();
249         }
250         return localPathPrefixComposerFactory;
251     }
252 
253     protected LocalPathPrefixComposerFactory createLocalPathPrefixComposerFactory() {
254         return new DefaultLocalPathPrefixComposerFactory();
255     }
256 
257     private RepositorySystemLifecycle repositorySystemLifecycle;
258 
259     public final RepositorySystemLifecycle getRepositorySystemLifecycle() {
260         checkClosed();
261         if (repositorySystemLifecycle == null) {
262             repositorySystemLifecycle = createRepositorySystemLifecycle();
263             repositorySystemLifecycle.addOnSystemEndedHandler(() -> closed.set(true));
264         }
265         return repositorySystemLifecycle;
266     }
267 
268     protected RepositorySystemLifecycle createRepositorySystemLifecycle() {
269         return new DefaultRepositorySystemLifecycle();
270     }
271 
272     private OfflineController offlineController;
273 
274     public final OfflineController getOfflineController() {
275         checkClosed();
276         if (offlineController == null) {
277             offlineController = createOfflineController();
278         }
279         return offlineController;
280     }
281 
282     protected OfflineController createOfflineController() {
283         return new DefaultOfflineController();
284     }
285 
286     private UpdatePolicyAnalyzer updatePolicyAnalyzer;
287 
288     public final UpdatePolicyAnalyzer getUpdatePolicyAnalyzer() {
289         checkClosed();
290         if (updatePolicyAnalyzer == null) {
291             updatePolicyAnalyzer = createUpdatePolicyAnalyzer();
292         }
293         return updatePolicyAnalyzer;
294     }
295 
296     protected UpdatePolicyAnalyzer createUpdatePolicyAnalyzer() {
297         return new DefaultUpdatePolicyAnalyzer();
298     }
299 
300     private ChecksumPolicyProvider checksumPolicyProvider;
301 
302     public final ChecksumPolicyProvider getChecksumPolicyProvider() {
303         checkClosed();
304         if (checksumPolicyProvider == null) {
305             checksumPolicyProvider = createChecksumPolicyProvider();
306         }
307         return checksumPolicyProvider;
308     }
309 
310     protected ChecksumPolicyProvider createChecksumPolicyProvider() {
311         return new DefaultChecksumPolicyProvider();
312     }
313 
314     private UpdateCheckManager updateCheckManager;
315 
316     public final UpdateCheckManager getUpdateCheckManager() {
317         checkClosed();
318         if (updateCheckManager == null) {
319             updateCheckManager = createUpdateCheckManager();
320         }
321         return updateCheckManager;
322     }
323 
324     protected UpdateCheckManager createUpdateCheckManager() {
325         return new DefaultUpdateCheckManager(getTrackingFileManager(), getUpdatePolicyAnalyzer(), getPathProcessor());
326     }
327 
328     private Map<String, NamedLockFactory> namedLockFactories;
329 
330     public final Map<String, NamedLockFactory> getNamedLockFactories() {
331         checkClosed();
332         if (namedLockFactories == null) {
333             namedLockFactories = createNamedLockFactories();
334         }
335         return namedLockFactories;
336     }
337 
338     protected Map<String, NamedLockFactory> createNamedLockFactories() {
339         HashMap<String, NamedLockFactory> result = new HashMap<>();
340         result.put(NoopNamedLockFactory.NAME, new NoopNamedLockFactory());
341         result.put(LocalReadWriteLockNamedLockFactory.NAME, new LocalReadWriteLockNamedLockFactory());
342         result.put(LocalSemaphoreNamedLockFactory.NAME, new LocalSemaphoreNamedLockFactory());
343         result.put(FileLockNamedLockFactory.NAME, new FileLockNamedLockFactory());
344         return result;
345     }
346 
347     private Map<String, NameMapper> nameMappers;
348 
349     public final Map<String, NameMapper> getNameMappers() {
350         checkClosed();
351         if (nameMappers == null) {
352             nameMappers = createNameMappers();
353         }
354         return nameMappers;
355     }
356 
357     protected Map<String, NameMapper> createNameMappers() {
358         HashMap<String, NameMapper> result = new HashMap<>();
359         result.put(NameMappers.STATIC_NAME, NameMappers.staticNameMapper());
360         result.put(NameMappers.GAV_NAME, NameMappers.gavNameMapper());
361         result.put(NameMappers.DISCRIMINATING_NAME, NameMappers.discriminatingNameMapper());
362         result.put(NameMappers.FILE_GAV_NAME, NameMappers.fileGavNameMapper());
363         result.put(NameMappers.FILE_HGAV_NAME, NameMappers.fileHashingGavNameMapper());
364         return result;
365     }
366 
367     private NamedLockFactoryAdapterFactory namedLockFactoryAdapterFactory;
368 
369     public final NamedLockFactoryAdapterFactory getNamedLockFactoryAdapterFactory() {
370         checkClosed();
371         if (namedLockFactoryAdapterFactory == null) {
372             namedLockFactoryAdapterFactory = createNamedLockFactoryAdapterFactory();
373         }
374         return namedLockFactoryAdapterFactory;
375     }
376 
377     protected NamedLockFactoryAdapterFactory createNamedLockFactoryAdapterFactory() {
378         return new NamedLockFactoryAdapterFactoryImpl(
379                 getNamedLockFactories(), getNameMappers(), getRepositorySystemLifecycle());
380     }
381 
382     private SyncContextFactory syncContextFactory;
383 
384     public final SyncContextFactory getSyncContextFactory() {
385         checkClosed();
386         if (syncContextFactory == null) {
387             syncContextFactory = createSyncContextFactory();
388         }
389         return syncContextFactory;
390     }
391 
392     protected SyncContextFactory createSyncContextFactory() {
393         return new DefaultSyncContextFactory(getNamedLockFactoryAdapterFactory());
394     }
395 
396     private Map<String, ChecksumAlgorithmFactory> checksumAlgorithmFactories;
397 
398     public final Map<String, ChecksumAlgorithmFactory> getChecksumAlgorithmFactories() {
399         checkClosed();
400         if (checksumAlgorithmFactories == null) {
401             checksumAlgorithmFactories = createChecksumAlgorithmFactories();
402         }
403         return checksumAlgorithmFactories;
404     }
405 
406     protected Map<String, ChecksumAlgorithmFactory> createChecksumAlgorithmFactories() {
407         HashMap<String, ChecksumAlgorithmFactory> result = new HashMap<>();
408         result.put(Sha512ChecksumAlgorithmFactory.NAME, new Sha512ChecksumAlgorithmFactory());
409         result.put(Sha256ChecksumAlgorithmFactory.NAME, new Sha256ChecksumAlgorithmFactory());
410         result.put(Sha1ChecksumAlgorithmFactory.NAME, new Sha1ChecksumAlgorithmFactory());
411         result.put(Md5ChecksumAlgorithmFactory.NAME, new Md5ChecksumAlgorithmFactory());
412         return result;
413     }
414 
415     private ChecksumAlgorithmFactorySelector checksumAlgorithmFactorySelector;
416 
417     public final ChecksumAlgorithmFactorySelector getChecksumAlgorithmFactorySelector() {
418         checkClosed();
419         if (checksumAlgorithmFactorySelector == null) {
420             checksumAlgorithmFactorySelector = createChecksumAlgorithmFactorySelector();
421         }
422         return checksumAlgorithmFactorySelector;
423     }
424 
425     protected ChecksumAlgorithmFactorySelector createChecksumAlgorithmFactorySelector() {
426         return new DefaultChecksumAlgorithmFactorySelector(getChecksumAlgorithmFactories());
427     }
428 
429     private ArtifactPredicateFactory artifactPredicateFactory;
430 
431     public final ArtifactPredicateFactory getArtifactPredicateFactory() {
432         checkClosed();
433         if (artifactPredicateFactory == null) {
434             artifactPredicateFactory = createArtifactPredicateFactory();
435         }
436         return artifactPredicateFactory;
437     }
438 
439     protected ArtifactPredicateFactory createArtifactPredicateFactory() {
440         return new DefaultArtifactPredicateFactory(getChecksumAlgorithmFactorySelector());
441     }
442 
443     private Map<String, RepositoryLayoutFactory> repositoryLayoutFactories;
444 
445     public final Map<String, RepositoryLayoutFactory> getRepositoryLayoutFactories() {
446         checkClosed();
447         if (repositoryLayoutFactories == null) {
448             repositoryLayoutFactories = createRepositoryLayoutFactories();
449         }
450         return repositoryLayoutFactories;
451     }
452 
453     protected Map<String, RepositoryLayoutFactory> createRepositoryLayoutFactories() {
454         HashMap<String, RepositoryLayoutFactory> result = new HashMap<>();
455         result.put(
456                 Maven2RepositoryLayoutFactory.NAME,
457                 new Maven2RepositoryLayoutFactory(
458                         getChecksumAlgorithmFactorySelector(), getArtifactPredicateFactory()));
459         return result;
460     }
461 
462     private RepositoryLayoutProvider repositoryLayoutProvider;
463 
464     public final RepositoryLayoutProvider getRepositoryLayoutProvider() {
465         checkClosed();
466         if (repositoryLayoutProvider == null) {
467             repositoryLayoutProvider = createRepositoryLayoutProvider();
468         }
469         return repositoryLayoutProvider;
470     }
471 
472     protected RepositoryLayoutProvider createRepositoryLayoutProvider() {
473         return new DefaultRepositoryLayoutProvider(getRepositoryLayoutFactories());
474     }
475 
476     private LocalRepositoryProvider localRepositoryProvider;
477 
478     public final LocalRepositoryProvider getLocalRepositoryProvider() {
479         checkClosed();
480         if (localRepositoryProvider == null) {
481             localRepositoryProvider = createLocalRepositoryProvider();
482         }
483         return localRepositoryProvider;
484     }
485 
486     protected LocalRepositoryProvider createLocalRepositoryProvider() {
487         LocalPathComposer localPathComposer = getLocalPathComposer();
488         HashMap<String, LocalRepositoryManagerFactory> localRepositoryProviders = new HashMap<>(2);
489         localRepositoryProviders.put(
490                 SimpleLocalRepositoryManagerFactory.NAME, new SimpleLocalRepositoryManagerFactory(localPathComposer));
491         localRepositoryProviders.put(
492                 EnhancedLocalRepositoryManagerFactory.NAME,
493                 new EnhancedLocalRepositoryManagerFactory(
494                         localPathComposer, getTrackingFileManager(), getLocalPathPrefixComposerFactory()));
495         return new DefaultLocalRepositoryProvider(localRepositoryProviders);
496     }
497 
498     private RemoteRepositoryManager remoteRepositoryManager;
499 
500     public final RemoteRepositoryManager getRemoteRepositoryManager() {
501         checkClosed();
502         if (remoteRepositoryManager == null) {
503             remoteRepositoryManager = createRemoteRepositoryManager();
504         }
505         return remoteRepositoryManager;
506     }
507 
508     protected RemoteRepositoryManager createRemoteRepositoryManager() {
509         return new DefaultRemoteRepositoryManager(getUpdatePolicyAnalyzer(), getChecksumPolicyProvider());
510     }
511 
512     private Map<String, RemoteRepositoryFilterSource> remoteRepositoryFilterSources;
513 
514     public final Map<String, RemoteRepositoryFilterSource> getRemoteRepositoryFilterSources() {
515         checkClosed();
516         if (remoteRepositoryFilterSources == null) {
517             remoteRepositoryFilterSources = createRemoteRepositoryFilterSources();
518         }
519         return remoteRepositoryFilterSources;
520     }
521 
522     protected Map<String, RemoteRepositoryFilterSource> createRemoteRepositoryFilterSources() {
523         HashMap<String, RemoteRepositoryFilterSource> result = new HashMap<>();
524         result.put(
525                 GroupIdRemoteRepositoryFilterSource.NAME,
526                 new GroupIdRemoteRepositoryFilterSource(getRepositorySystemLifecycle()));
527         result.put(
528                 PrefixesRemoteRepositoryFilterSource.NAME,
529                 new PrefixesRemoteRepositoryFilterSource(getRepositoryLayoutProvider()));
530         return result;
531     }
532 
533     private RemoteRepositoryFilterManager remoteRepositoryFilterManager;
534 
535     public final RemoteRepositoryFilterManager getRemoteRepositoryFilterManager() {
536         checkClosed();
537         if (remoteRepositoryFilterManager == null) {
538             remoteRepositoryFilterManager = createRemoteRepositoryFilterManager();
539         }
540         return remoteRepositoryFilterManager;
541     }
542 
543     protected RemoteRepositoryFilterManager createRemoteRepositoryFilterManager() {
544         return new DefaultRemoteRepositoryFilterManager(getRemoteRepositoryFilterSources());
545     }
546 
547     private Map<String, RepositoryListener> repositoryListeners;
548 
549     public final Map<String, RepositoryListener> getRepositoryListeners() {
550         checkClosed();
551         if (repositoryListeners == null) {
552             repositoryListeners = createRepositoryListeners();
553         }
554         return repositoryListeners;
555     }
556 
557     protected Map<String, RepositoryListener> createRepositoryListeners() {
558         return new HashMap<>();
559     }
560 
561     private RepositoryEventDispatcher repositoryEventDispatcher;
562 
563     public final RepositoryEventDispatcher getRepositoryEventDispatcher() {
564         checkClosed();
565         if (repositoryEventDispatcher == null) {
566             repositoryEventDispatcher = createRepositoryEventDispatcher();
567         }
568         return repositoryEventDispatcher;
569     }
570 
571     protected RepositoryEventDispatcher createRepositoryEventDispatcher() {
572         return new DefaultRepositoryEventDispatcher(getRepositoryListeners());
573     }
574 
575     private Map<String, TrustedChecksumsSource> trustedChecksumsSources;
576 
577     public final Map<String, TrustedChecksumsSource> getTrustedChecksumsSources() {
578         checkClosed();
579         if (trustedChecksumsSources == null) {
580             trustedChecksumsSources = createTrustedChecksumsSources();
581         }
582         return trustedChecksumsSources;
583     }
584 
585     protected Map<String, TrustedChecksumsSource> createTrustedChecksumsSources() {
586         HashMap<String, TrustedChecksumsSource> result = new HashMap<>();
587         result.put(
588                 SparseDirectoryTrustedChecksumsSource.NAME,
589                 new SparseDirectoryTrustedChecksumsSource(getChecksumProcessor(), getLocalPathComposer()));
590         result.put(
591                 SummaryFileTrustedChecksumsSource.NAME,
592                 new SummaryFileTrustedChecksumsSource(getLocalPathComposer(), getRepositorySystemLifecycle()));
593         return result;
594     }
595 
596     private Map<String, ProvidedChecksumsSource> providedChecksumsSources;
597 
598     public final Map<String, ProvidedChecksumsSource> getProvidedChecksumsSources() {
599         checkClosed();
600         if (providedChecksumsSources == null) {
601             providedChecksumsSources = createProvidedChecksumsSources();
602         }
603         return providedChecksumsSources;
604     }
605 
606     protected Map<String, ProvidedChecksumsSource> createProvidedChecksumsSources() {
607         HashMap<String, ProvidedChecksumsSource> result = new HashMap<>();
608         result.put(
609                 TrustedToProvidedChecksumsSourceAdapter.NAME,
610                 new TrustedToProvidedChecksumsSourceAdapter(getTrustedChecksumsSources()));
611         return result;
612     }
613 
614     private Map<String, ChecksumExtractorStrategy> checksumExtractorStrategies;
615 
616     public final Map<String, ChecksumExtractorStrategy> getChecksumExtractorStrategies() {
617         checkClosed();
618         if (checksumExtractorStrategies == null) {
619             checksumExtractorStrategies = createChecksumExtractorStrategies();
620         }
621         return checksumExtractorStrategies;
622     }
623 
624     protected Map<String, ChecksumExtractorStrategy> createChecksumExtractorStrategies() {
625         HashMap<String, ChecksumExtractorStrategy> result = new HashMap<>();
626         result.put(XChecksumExtractor.NAME, new XChecksumExtractor());
627         result.put(Nx2ChecksumExtractor.NAME, new Nx2ChecksumExtractor());
628         return result;
629     }
630 
631     private ChecksumExtractor checksumExtractor;
632 
633     public final ChecksumExtractor getChecksumExtractor() {
634         checkClosed();
635         if (checksumExtractor == null) {
636             checksumExtractor = createChecksumExtractor();
637         }
638         return checksumExtractor;
639     }
640 
641     protected ChecksumExtractor createChecksumExtractor() {
642         return new DefaultChecksumExtractor(getChecksumExtractorStrategies());
643     }
644 
645     private Map<String, TransporterFactory> transporterFactories;
646 
647     public final Map<String, TransporterFactory> getTransporterFactories() {
648         checkClosed();
649         if (transporterFactories == null) {
650             transporterFactories = createTransporterFactories();
651         }
652         return transporterFactories;
653     }
654 
655     protected Map<String, TransporterFactory> createTransporterFactories() {
656         HashMap<String, TransporterFactory> result = new HashMap<>();
657         result.put(FileTransporterFactory.NAME, new FileTransporterFactory());
658         result.put(
659                 ApacheTransporterFactory.NAME,
660                 new ApacheTransporterFactory(getChecksumExtractor(), getPathProcessor()));
661         return result;
662     }
663 
664     private TransporterProvider transporterProvider;
665 
666     public final TransporterProvider getTransporterProvider() {
667         checkClosed();
668         if (transporterProvider == null) {
669             transporterProvider = createTransporterProvider();
670         }
671         return transporterProvider;
672     }
673 
674     protected TransporterProvider createTransporterProvider() {
675         return new DefaultTransporterProvider(getTransporterFactories());
676     }
677 
678     private BasicRepositoryConnectorFactory basicRepositoryConnectorFactory;
679 
680     public final BasicRepositoryConnectorFactory getBasicRepositoryConnectorFactory() {
681         checkClosed();
682         if (basicRepositoryConnectorFactory == null) {
683             basicRepositoryConnectorFactory = createBasicRepositoryConnectorFactory();
684         }
685         return basicRepositoryConnectorFactory;
686     }
687 
688     protected BasicRepositoryConnectorFactory createBasicRepositoryConnectorFactory() {
689         return new BasicRepositoryConnectorFactory(
690                 getTransporterProvider(),
691                 getRepositoryLayoutProvider(),
692                 getChecksumPolicyProvider(),
693                 getChecksumProcessor(),
694                 getProvidedChecksumsSources());
695     }
696 
697     private Map<String, RepositoryConnectorFactory> repositoryConnectorFactories;
698 
699     public final Map<String, RepositoryConnectorFactory> getRepositoryConnectorFactories() {
700         checkClosed();
701         if (repositoryConnectorFactories == null) {
702             repositoryConnectorFactories = createRepositoryConnectorFactories();
703         }
704         return repositoryConnectorFactories;
705     }
706 
707     protected Map<String, RepositoryConnectorFactory> createRepositoryConnectorFactories() {
708         HashMap<String, RepositoryConnectorFactory> result = new HashMap<>();
709         result.put(BasicRepositoryConnectorFactory.NAME, getBasicRepositoryConnectorFactory());
710         return result;
711     }
712 
713     private Map<String, PipelineRepositoryConnectorFactory> pipelineRepositoryConnectorFactories;
714 
715     public final Map<String, PipelineRepositoryConnectorFactory> getPipelineRepositoryConnectorFactories() {
716         checkClosed();
717         if (pipelineRepositoryConnectorFactories == null) {
718             pipelineRepositoryConnectorFactories = createPipelineRepositoryConnectorFactories();
719         }
720         return pipelineRepositoryConnectorFactories;
721     }
722 
723     protected Map<String, PipelineRepositoryConnectorFactory> createPipelineRepositoryConnectorFactories() {
724         HashMap<String, PipelineRepositoryConnectorFactory> result = new HashMap<>();
725         result.put(
726                 FilteringPipelineRepositoryConnectorFactory.NAME,
727                 new FilteringPipelineRepositoryConnectorFactory(getRemoteRepositoryFilterManager()));
728         result.put(
729                 OfflinePipelineRepositoryConnectorFactory.NAME,
730                 new OfflinePipelineRepositoryConnectorFactory(getOfflineController()));
731         return result;
732     }
733 
734     private RepositoryConnectorProvider repositoryConnectorProvider;
735 
736     public final RepositoryConnectorProvider getRepositoryConnectorProvider() {
737         checkClosed();
738         if (repositoryConnectorProvider == null) {
739             repositoryConnectorProvider = createRepositoryConnectorProvider();
740         }
741         return repositoryConnectorProvider;
742     }
743 
744     protected RepositoryConnectorProvider createRepositoryConnectorProvider() {
745         return new DefaultRepositoryConnectorProvider(
746                 getRepositoryConnectorFactories(), getPipelineRepositoryConnectorFactories());
747     }
748 
749     private Installer installer;
750 
751     public final Installer getInstaller() {
752         checkClosed();
753         if (installer == null) {
754             installer = createInstaller();
755         }
756         return installer;
757     }
758 
759     protected Installer createInstaller() {
760         return new DefaultInstaller(
761                 getPathProcessor(),
762                 getRepositoryEventDispatcher(),
763                 getArtifactGeneratorFactories(),
764                 getMetadataGeneratorFactories(),
765                 getArtifactTransformers(),
766                 getSyncContextFactory());
767     }
768 
769     private Deployer deployer;
770 
771     public final Deployer getDeployer() {
772         checkClosed();
773         if (deployer == null) {
774             deployer = createDeployer();
775         }
776         return deployer;
777     }
778 
779     protected Deployer createDeployer() {
780         return new DefaultDeployer(
781                 getPathProcessor(),
782                 getRepositoryEventDispatcher(),
783                 getRepositoryConnectorProvider(),
784                 getRemoteRepositoryManager(),
785                 getUpdateCheckManager(),
786                 getArtifactGeneratorFactories(),
787                 getMetadataGeneratorFactories(),
788                 getArtifactTransformers(),
789                 getSyncContextFactory(),
790                 getOfflineController());
791     }
792 
793     private Map<String, DependencyCollectorDelegate> dependencyCollectorDelegates;
794 
795     public final Map<String, DependencyCollectorDelegate> getDependencyCollectorDelegates() {
796         checkClosed();
797         if (dependencyCollectorDelegates == null) {
798             dependencyCollectorDelegates = createDependencyCollectorDelegates();
799         }
800         return dependencyCollectorDelegates;
801     }
802 
803     protected Map<String, DependencyCollectorDelegate> createDependencyCollectorDelegates() {
804         RemoteRepositoryManager remoteRepositoryManager = getRemoteRepositoryManager();
805         ArtifactDescriptorReader artifactDescriptorReader = getArtifactDescriptorReader();
806         VersionRangeResolver versionRangeResolver = getVersionRangeResolver();
807         HashMap<String, DependencyCollectorDelegate> result = new HashMap<>();
808         result.put(
809                 DfDependencyCollector.NAME,
810                 new DfDependencyCollector(
811                         remoteRepositoryManager,
812                         artifactDescriptorReader,
813                         versionRangeResolver,
814                         getArtifactDecoratorFactories()));
815         result.put(
816                 BfDependencyCollector.NAME,
817                 new BfDependencyCollector(
818                         remoteRepositoryManager,
819                         artifactDescriptorReader,
820                         versionRangeResolver,
821                         getArtifactDecoratorFactories()));
822         return result;
823     }
824 
825     private DependencyCollector dependencyCollector;
826 
827     public final DependencyCollector getDependencyCollector() {
828         checkClosed();
829         if (dependencyCollector == null) {
830             dependencyCollector = createDependencyCollector();
831         }
832         return dependencyCollector;
833     }
834 
835     protected DependencyCollector createDependencyCollector() {
836         return new DefaultDependencyCollector(getDependencyCollectorDelegates());
837     }
838 
839     private Map<String, ArtifactResolverPostProcessor> artifactResolverPostProcessors;
840 
841     public final Map<String, ArtifactResolverPostProcessor> getArtifactResolverPostProcessors() {
842         checkClosed();
843         if (artifactResolverPostProcessors == null) {
844             artifactResolverPostProcessors = createArtifactResolverPostProcessors();
845         }
846         return artifactResolverPostProcessors;
847     }
848 
849     protected Map<String, ArtifactResolverPostProcessor> createArtifactResolverPostProcessors() {
850         HashMap<String, ArtifactResolverPostProcessor> result = new HashMap<>();
851         result.put(
852                 TrustedChecksumsArtifactResolverPostProcessor.NAME,
853                 new TrustedChecksumsArtifactResolverPostProcessor(
854                         getChecksumAlgorithmFactorySelector(), getTrustedChecksumsSources()));
855         return result;
856     }
857 
858     private ArtifactResolver artifactResolver;
859 
860     public final ArtifactResolver getArtifactResolver() {
861         checkClosed();
862         if (artifactResolver == null) {
863             artifactResolver = createArtifactResolver();
864         }
865         return artifactResolver;
866     }
867 
868     protected ArtifactResolver createArtifactResolver() {
869         return new DefaultArtifactResolver(
870                 getPathProcessor(),
871                 getRepositoryEventDispatcher(),
872                 getVersionResolver(),
873                 getUpdateCheckManager(),
874                 getRepositoryConnectorProvider(),
875                 getRemoteRepositoryManager(),
876                 getSyncContextFactory(),
877                 getOfflineController(),
878                 getArtifactResolverPostProcessors(),
879                 getRemoteRepositoryFilterManager());
880     }
881 
882     private MetadataResolver metadataResolver;
883 
884     public final MetadataResolver getMetadataResolver() {
885         checkClosed();
886         if (metadataResolver == null) {
887             metadataResolver = createMetadataResolver();
888         }
889         return metadataResolver;
890     }
891 
892     protected MetadataResolver createMetadataResolver() {
893         return new DefaultMetadataResolver(
894                 getRepositoryEventDispatcher(),
895                 getUpdateCheckManager(),
896                 getRepositoryConnectorProvider(),
897                 getRemoteRepositoryManager(),
898                 getSyncContextFactory(),
899                 getOfflineController(),
900                 getRemoteRepositoryFilterManager(),
901                 getPathProcessor());
902     }
903 
904     private VersionScheme versionScheme;
905 
906     public final VersionScheme getVersionScheme() {
907         checkClosed();
908         if (versionScheme == null) {
909             versionScheme = createVersionScheme();
910         }
911         return versionScheme;
912     }
913 
914     protected VersionScheme createVersionScheme() {
915         return new GenericVersionScheme();
916     }
917 
918     private Map<String, ArtifactGeneratorFactory> artifactGeneratorFactories;
919 
920     public final Map<String, ArtifactGeneratorFactory> getArtifactGeneratorFactories() {
921         checkClosed();
922         if (artifactGeneratorFactories == null) {
923             artifactGeneratorFactories = createArtifactGeneratorFactories();
924         }
925         return artifactGeneratorFactories;
926     }
927 
928     protected Map<String, ArtifactGeneratorFactory> createArtifactGeneratorFactories() {
929         // by default none, this is extension point
930         return new HashMap<>();
931     }
932 
933     private Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories;
934 
935     public final Map<String, ArtifactDecoratorFactory> getArtifactDecoratorFactories() {
936         checkClosed();
937         if (artifactDecoratorFactories == null) {
938             artifactDecoratorFactories = createArtifactDecoratorFactories();
939         }
940         return artifactDecoratorFactories;
941     }
942 
943     protected Map<String, ArtifactDecoratorFactory> createArtifactDecoratorFactories() {
944         // by default none, this is extension point
945         return new HashMap<>();
946     }
947 
948     // Maven provided
949 
950     private Map<String, ArtifactTransformer> artifactTransformers;
951 
952     public final Map<String, ArtifactTransformer> getArtifactTransformers() {
953         checkClosed();
954         if (artifactTransformers == null) {
955             artifactTransformers = createArtifactTransformers();
956         }
957         return artifactTransformers;
958     }
959 
960     protected Map<String, ArtifactTransformer> createArtifactTransformers() {
961         return new HashMap<>();
962     }
963 
964     private Map<String, MetadataGeneratorFactory> metadataGeneratorFactories;
965 
966     public final Map<String, MetadataGeneratorFactory> getMetadataGeneratorFactories() {
967         checkClosed();
968         if (metadataGeneratorFactories == null) {
969             metadataGeneratorFactories = createMetadataGeneratorFactories();
970         }
971         return metadataGeneratorFactories;
972     }
973 
974     protected Map<String, MetadataGeneratorFactory> createMetadataGeneratorFactories() {
975         // from maven-resolver-provider
976         HashMap<String, MetadataGeneratorFactory> result = new HashMap<>();
977         result.put(PluginsMetadataGeneratorFactory.NAME, new PluginsMetadataGeneratorFactory());
978         result.put(VersionsMetadataGeneratorFactory.NAME, new VersionsMetadataGeneratorFactory());
979         result.put(SnapshotMetadataGeneratorFactory.NAME, new SnapshotMetadataGeneratorFactory());
980         return result;
981     }
982 
983     private LinkedHashMap<String, MavenArtifactRelocationSource> artifactRelocationSources;
984 
985     public final LinkedHashMap<String, MavenArtifactRelocationSource> getMavenArtifactRelocationSources() {
986         checkClosed();
987         if (artifactRelocationSources == null) {
988             artifactRelocationSources = createMavenArtifactRelocationSources();
989         }
990         return artifactRelocationSources;
991     }
992 
993     protected LinkedHashMap<String, MavenArtifactRelocationSource> createMavenArtifactRelocationSources() {
994         // from maven-resolver-provider
995         LinkedHashMap<String, MavenArtifactRelocationSource> result = new LinkedHashMap<>();
996         result.put(UserPropertiesArtifactRelocationSource.NAME, new UserPropertiesArtifactRelocationSource());
997         result.put(
998                 DistributionManagementArtifactRelocationSource.NAME,
999                 new DistributionManagementArtifactRelocationSource());
1000         return result;
1001     }
1002 
1003     private ArtifactDescriptorReader artifactDescriptorReader;
1004 
1005     public final ArtifactDescriptorReader getArtifactDescriptorReader() {
1006         checkClosed();
1007         if (artifactDescriptorReader == null) {
1008             artifactDescriptorReader = createArtifactDescriptorReader();
1009         }
1010         return artifactDescriptorReader;
1011     }
1012 
1013     protected ArtifactDescriptorReader createArtifactDescriptorReader() {
1014         // from maven-resolver-provider
1015         return new DefaultArtifactDescriptorReader(
1016                 getRemoteRepositoryManager(),
1017                 getVersionResolver(),
1018                 getVersionRangeResolver(),
1019                 getArtifactResolver(),
1020                 getModelBuilder(),
1021                 getRepositoryEventDispatcher(),
1022                 getModelCacheFactory(),
1023                 getMavenArtifactRelocationSources());
1024     }
1025 
1026     private VersionResolver versionResolver;
1027 
1028     public final VersionResolver getVersionResolver() {
1029         checkClosed();
1030         if (versionResolver == null) {
1031             versionResolver = createVersionResolver();
1032         }
1033         return versionResolver;
1034     }
1035 
1036     protected VersionResolver createVersionResolver() {
1037         // from maven-resolver-provider
1038         return new DefaultVersionResolver(
1039                 getMetadataResolver(), getSyncContextFactory(), getRepositoryEventDispatcher());
1040     }
1041 
1042     private VersionRangeResolver versionRangeResolver;
1043 
1044     public final VersionRangeResolver getVersionRangeResolver() {
1045         checkClosed();
1046         if (versionRangeResolver == null) {
1047             versionRangeResolver = createVersionRangeResolver();
1048         }
1049         return versionRangeResolver;
1050     }
1051 
1052     protected VersionRangeResolver createVersionRangeResolver() {
1053         // from maven-resolver-provider
1054         return new DefaultVersionRangeResolver(
1055                 getMetadataResolver(), getSyncContextFactory(), getRepositoryEventDispatcher(), getVersionScheme());
1056     }
1057 
1058     private ModelBuilder modelBuilder;
1059 
1060     public final ModelBuilder getModelBuilder() {
1061         checkClosed();
1062         if (modelBuilder == null) {
1063             modelBuilder = createModelBuilder();
1064         }
1065         return modelBuilder;
1066     }
1067 
1068     protected ModelBuilder createModelBuilder() {
1069         // from maven-model-builder
1070         return new DefaultModelBuilderFactory().newInstance();
1071     }
1072 
1073     private ModelCacheFactory modelCacheFactory;
1074 
1075     public final ModelCacheFactory getModelCacheFactory() {
1076         checkClosed();
1077         if (modelCacheFactory == null) {
1078             modelCacheFactory = createModelCacheFactory();
1079         }
1080         return modelCacheFactory;
1081     }
1082 
1083     protected ModelCacheFactory createModelCacheFactory() {
1084         // from maven-resolver-provider
1085         return new DefaultModelCacheFactory();
1086     }
1087 
1088     private List<ValidatorFactory> validatorFactories;
1089 
1090     public final List<ValidatorFactory> getValidatorFactories() {
1091         checkClosed();
1092         if (validatorFactories == null) {
1093             validatorFactories = createValidatorFactories();
1094         }
1095         return validatorFactories;
1096     }
1097 
1098     protected List<ValidatorFactory> createValidatorFactories() {
1099         return new ArrayList<>();
1100     }
1101 
1102     private RepositorySystemValidator repositorySystemValidator;
1103 
1104     public final RepositorySystemValidator getRepositorySystemValidator() {
1105         checkClosed();
1106         if (repositorySystemValidator == null) {
1107             repositorySystemValidator = createRepositorySystemValidator();
1108         }
1109         return repositorySystemValidator;
1110     }
1111 
1112     protected RepositorySystemValidator createRepositorySystemValidator() {
1113         return new DefaultRepositorySystemValidator(getValidatorFactories());
1114     }
1115 
1116     private RepositorySystem repositorySystem;
1117 
1118     public final RepositorySystem getRepositorySystem() {
1119         checkClosed();
1120         if (repositorySystem == null) {
1121             repositorySystem = createRepositorySystem();
1122         }
1123         return repositorySystem;
1124     }
1125 
1126     protected RepositorySystem createRepositorySystem() {
1127         return new DefaultRepositorySystem(
1128                 getVersionResolver(),
1129                 getVersionRangeResolver(),
1130                 getArtifactResolver(),
1131                 getMetadataResolver(),
1132                 getArtifactDescriptorReader(),
1133                 getDependencyCollector(),
1134                 getInstaller(),
1135                 getDeployer(),
1136                 getLocalRepositoryProvider(),
1137                 getSyncContextFactory(),
1138                 getRemoteRepositoryManager(),
1139                 getRepositorySystemLifecycle(),
1140                 getArtifactDecoratorFactories(),
1141                 getRepositorySystemValidator());
1142     }
1143 
1144     @Override
1145     public RepositorySystem get() {
1146         return getRepositorySystem();
1147     }
1148 }