]> source.dussan.org Git - archiva.git/blob
984a2f6f6553cae5e80e736d14bbf8fa9849c142
[archiva.git] /
1 package org.apache.archiva.repository;
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 org.apache.archiva.configuration.*;
23 import org.apache.archiva.indexer.*;
24 import org.apache.archiva.metadata.model.facets.AuditEvent;
25 import org.apache.archiva.redback.components.registry.RegistryException;
26 import org.apache.archiva.repository.features.IndexCreationEvent;
27 import org.apache.archiva.repository.features.IndexCreationFeature;
28 import org.apache.archiva.repository.features.StagingRepositoryFeature;
29 import org.apache.commons.lang.StringUtils;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32 import org.springframework.stereotype.Service;
33
34 import javax.annotation.PostConstruct;
35 import javax.annotation.PreDestroy;
36 import javax.inject.Inject;
37 import javax.inject.Named;
38 import java.util.*;
39 import java.util.concurrent.locks.ReentrantReadWriteLock;
40 import java.util.stream.Collectors;
41 import java.util.stream.Stream;
42
43 /**
44  * Registry for repositories. This is the central entry point for repositories. It provides methods for
45  * retrieving, adding and removing repositories.
46  *
47  * The modification methods addXX and removeXX persist the changes immediately to the configuration. If the
48  * configuration save fails the changes are rolled back.
49  *
50  * TODO: Audit events should be sent, but we don't want dependency to the repsitory-metadata-api
51  */
52 @Service( "repositoryRegistry" )
53 public class RepositoryRegistry implements ConfigurationListener, RepositoryEventHandler, RepositoryEventListener {
54
55     private static final Logger log = LoggerFactory.getLogger( RepositoryRegistry.class );
56
57     /**
58      * We inject all repository providers
59      */
60     @Inject
61     List<RepositoryProvider> repositoryProviders;
62
63     @Inject
64     IndexManagerFactory indexManagerFactory;
65
66     @Inject
67     ArchivaConfiguration archivaConfiguration;
68
69     @Inject
70     @Named("repositoryContentFactory#default")
71     RepositoryContentFactory repositoryContentFactory;
72
73     private List<RepositoryEventListener> listeners = new ArrayList<>();
74
75
76     private Map<String, ManagedRepository> managedRepositories = new HashMap<>( );
77     private Map<String, ManagedRepository> uManagedRepository = Collections.unmodifiableMap( managedRepositories );
78
79     private Map<String, RemoteRepository> remoteRepositories = new HashMap<>( );
80     private Map<String, RemoteRepository> uRemoteRepositories = Collections.unmodifiableMap( remoteRepositories );
81
82     private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock( );
83
84     public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration) {
85         this.archivaConfiguration = archivaConfiguration;
86     }
87
88     @PostConstruct
89     private void initialize( )
90     {
91         rwLock.writeLock( ).lock( );
92         try
93         {
94             log.debug("Initializing repository registry");
95             for(ManagedRepository rep : managedRepositories.values()) {
96                 rep.close();
97             }
98             managedRepositories.clear( );
99             managedRepositories.putAll( getManagedRepositoriesFromConfig( ) );
100             for (RemoteRepository repo : remoteRepositories.values()) {
101                 repo.close();
102             }
103             remoteRepositories.clear( );
104             remoteRepositories.putAll( getRemoteRepositoriesFromConfig( ) );
105             // archivaConfiguration.addChangeListener(this);
106             archivaConfiguration.addListener(this);
107         }
108         finally
109         {
110             rwLock.writeLock( ).unlock( );
111         }
112     }
113
114     @PreDestroy
115     public void destroy() {
116         for(ManagedRepository rep : managedRepositories.values()) {
117             rep.close();
118         }
119         for (RemoteRepository repo : remoteRepositories.values()) {
120             repo.close();
121         }
122     }
123
124
125
126     private Map<RepositoryType, RepositoryProvider> createProviderMap( )
127     {
128         Map<RepositoryType, RepositoryProvider> map = new HashMap<>( );
129         if ( repositoryProviders != null )
130         {
131             for ( RepositoryProvider provider : repositoryProviders )
132             {
133                 for ( RepositoryType type : provider.provides( ) )
134                 {
135                     map.put( type, provider );
136                 }
137             }
138         }
139         return map;
140     }
141
142     private RepositoryProvider getProvider( RepositoryType type ) throws RepositoryException
143     {
144         return repositoryProviders.stream( ).filter( repositoryProvider -> repositoryProvider.provides( ).contains( type ) ).findFirst( ).orElseThrow( ( ) -> new RepositoryException( "Repository type cannot be handled: " + type ) );
145     }
146
147     private Map<String, ManagedRepository> getManagedRepositoriesFromConfig( )
148     {
149         try
150         {
151             List<ManagedRepositoryConfiguration> managedRepoConfigs =
152                 getArchivaConfiguration( ).getConfiguration( ).getManagedRepositories( );
153
154             if ( managedRepoConfigs == null )
155             {
156                 return Collections.EMPTY_MAP;
157             }
158
159             Map<String, ManagedRepository> managedRepos = new LinkedHashMap<>( managedRepoConfigs.size( ) );
160
161             Map<RepositoryType, RepositoryProvider> providerMap = createProviderMap( );
162             for ( ManagedRepositoryConfiguration repoConfig : managedRepoConfigs )
163             {
164                 RepositoryType repositoryType = RepositoryType.valueOf( repoConfig.getType( ) );
165                 if ( providerMap.containsKey( repositoryType ) )
166                 {
167                     try
168                     {
169                         ManagedRepository repo = createNewManagedRepository( providerMap.get( repositoryType ), repoConfig );
170                         managedRepos.put( repo.getId( ), repo );
171                     }
172                     catch ( Exception e )
173                     {
174                         log.error( "Could not create managed repository {}: {}", repoConfig.getId( ), e.getMessage( ), e );
175                     }
176                 }
177             }
178             return managedRepos;
179         } catch (Throwable e) {
180             log.error("Could not initialize repositories from config: {}",e.getMessage(), e );
181             //noinspection unchecked
182             return Collections.EMPTY_MAP;
183         }
184     }
185
186     private ManagedRepository createNewManagedRepository( RepositoryProvider provider, ManagedRepositoryConfiguration cfg ) throws RepositoryException
187     {
188         log.debug("Creating repo {}", cfg.getId());
189         ManagedRepository repo = provider.createManagedInstance( cfg );
190         repo.addListener(this);
191         updateRepositoryReferences( provider, repo, cfg , null);
192         return repo;
193
194     }
195
196     private void updateRepositoryReferences(RepositoryProvider provider, ManagedRepository repo, ManagedRepositoryConfiguration cfg, Configuration configuration) throws RepositoryException
197     {
198         log.debug("Updating references of repo {}",repo.getId());
199         if ( repo.supportsFeature( StagingRepositoryFeature.class ) )
200         {
201             StagingRepositoryFeature feature = repo.getFeature( StagingRepositoryFeature.class ).get( );
202             if ( feature.isStageRepoNeeded( ) && feature.getStagingRepository() == null)
203             {
204                 ManagedRepository stageRepo = getStagingRepository( provider, cfg, configuration);
205                 managedRepositories.put(stageRepo.getId(), stageRepo);
206                 feature.setStagingRepository( stageRepo );
207                 if (configuration!=null) {
208                     replaceOrAddRepositoryConfig( provider.getManagedConfiguration( stageRepo ), configuration );
209                 }
210             }
211         }
212         if ( repo instanceof EditableManagedRepository)
213         {
214             EditableManagedRepository editableRepo = (EditableManagedRepository) repo;
215             if (repo.getContent()==null) {
216                 editableRepo.setContent(repositoryContentFactory.getManagedRepositoryContent(repo));
217             }
218             log.debug("Index repo: "+repo.hasIndex());
219             if (repo.hasIndex() && repo.getIndexingContext()==null) {
220                 log.debug("Creating indexing context for {}", repo.getId());
221                 createIndexingContext(editableRepo);
222             }
223         }
224
225     }
226
227     private ArchivaIndexManager getIndexManager(RepositoryType type) {
228         return indexManagerFactory.getIndexManager(type);
229     }
230
231     private void createIndexingContext(EditableRepository editableRepo) throws RepositoryException {
232         if (editableRepo.supportsFeature(IndexCreationFeature.class)) {
233             ArchivaIndexManager idxManager = getIndexManager(editableRepo.getType());
234             try {
235                 editableRepo.setIndexingContext(idxManager.createContext(editableRepo));
236                 idxManager.updateLocalIndexPath(editableRepo);
237             } catch (IndexCreationFailedException e) {
238                 throw new RepositoryException("Could not create index for repository "+editableRepo.getId()+": "+e.getMessage(),e);
239             }
240         }
241     }
242
243     private ManagedRepository getStagingRepository(RepositoryProvider provider, ManagedRepositoryConfiguration baseRepoCfg, Configuration configuration) throws RepositoryException
244     {
245         ManagedRepository stageRepo = getManagedRepository( baseRepoCfg.getId( ) + StagingRepositoryFeature.STAGING_REPO_POSTFIX );
246         if ( stageRepo == null )
247         {
248             stageRepo = provider.createStagingInstance( baseRepoCfg );
249             if (stageRepo.supportsFeature(StagingRepositoryFeature.class)) {
250                 stageRepo.getFeature(StagingRepositoryFeature.class).get().setStageRepoNeeded(false);
251             }
252             ManagedRepositoryConfiguration stageCfg = provider.getManagedConfiguration( stageRepo );
253             updateRepositoryReferences( provider, stageRepo, stageCfg, configuration);
254         }
255         return stageRepo;
256     }
257
258
259
260
261     private Map<String, RemoteRepository> getRemoteRepositoriesFromConfig( )
262     {
263         try
264         {
265             List<RemoteRepositoryConfiguration> remoteRepoConfigs =
266                 getArchivaConfiguration( ).getConfiguration( ).getRemoteRepositories( );
267
268             if ( remoteRepoConfigs == null )
269             {
270                 //noinspection unchecked
271                 return Collections.EMPTY_MAP;
272             }
273
274             Map<String, RemoteRepository> remoteRepos = new LinkedHashMap<>( remoteRepoConfigs.size( ) );
275
276             Map<RepositoryType, RepositoryProvider> providerMap = createProviderMap( );
277             for ( RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs )
278             {
279                 RepositoryType repositoryType = RepositoryType.valueOf( repoConfig.getType( ) );
280                 if ( providerMap.containsKey( repositoryType ) )
281                 {
282                     RepositoryProvider provider = getProvider( repositoryType );
283                     try
284                     {
285
286                         RemoteRepository remoteRepository = createNewRemoteRepository( provider, repoConfig );
287                         remoteRepos.put( repoConfig.getId( ), remoteRepository);
288                     }
289                     catch ( Exception e )
290                     {
291                         log.error( "Could not create repository {} from config: {}", repoConfig.getId( ), e.getMessage( ), e );
292                     }
293                 }
294             }
295
296             return remoteRepos;
297         } catch (Throwable e) {
298             log.error("Could not initialize remote repositories from config: {}", e.getMessage(), e);
299             //noinspection unchecked
300             return Collections.EMPTY_MAP;
301         }
302     }
303
304     private RemoteRepository createNewRemoteRepository( RepositoryProvider provider, RemoteRepositoryConfiguration cfg ) throws RepositoryException
305     {
306         log.debug("Creating remote repo {}", cfg.getId());
307         RemoteRepository repo = provider.createRemoteInstance( cfg );
308         repo.addListener(this);
309         updateRepositoryReferences( provider, repo, cfg , null);
310         return repo;
311
312     }
313
314     private void updateRepositoryReferences( RepositoryProvider provider, RemoteRepository repo, RemoteRepositoryConfiguration cfg, Configuration configuration) throws RepositoryException
315     {
316         if ( repo instanceof EditableRemoteRepository && repo.getContent() == null)
317         {
318             EditableRemoteRepository editableRepo = (EditableRemoteRepository) repo;
319             if (repo.getContent()==null) {
320                 editableRepo.setContent( repositoryContentFactory.getRemoteRepositoryContent( repo ) );
321             }
322             if (repo.supportsFeature(IndexCreationFeature.class) && repo.getIndexingContext()==null ) {
323                 createIndexingContext(editableRepo);
324             }
325         }
326     }
327
328     private ArchivaConfiguration getArchivaConfiguration( )
329     {
330         return this.archivaConfiguration;
331     }
332
333     /**
334      * Returns all repositories that are registered. There is no defined order of the returned repositories.
335      *
336      * @return a list of managed and remote repositories
337      */
338     public Collection<Repository> getRepositories( )
339     {
340         rwLock.readLock( ).lock( );
341         try
342         {
343             return Stream.concat( managedRepositories.values( ).stream( ), remoteRepositories.values( ).stream( ) ).collect( Collectors.toList( ) );
344         }
345         finally
346         {
347             rwLock.readLock( ).unlock( );
348         }
349     }
350
351     /**
352      * Returns only the managed repositories. There is no defined order of the returned repositories.
353      *
354      * @return a list of managed repositories
355      */
356     public Collection<ManagedRepository> getManagedRepositories( )
357     {
358         rwLock.readLock().lock();
359         try
360         {
361             return uManagedRepository.values( );
362         } finally
363         {
364             rwLock.readLock().unlock();
365         }
366     }
367
368     /**
369      * Returns only the remote repositories. There is no defined order of the returned repositories.
370      *
371      * @return a list of remote repositories
372      */
373     public Collection<RemoteRepository> getRemoteRepositories( )
374     {
375         rwLock.readLock().lock();
376         try
377         {
378             return uRemoteRepositories.values( );
379         } finally
380         {
381             rwLock.readLock().unlock();
382         }
383     }
384
385     /**
386      * Returns the repository with the given id. The returned repository may be a managed or remote repository.
387      * It returns null, if no repository is registered with the given id.
388      *
389      * @param repoId the repository id
390      * @return the repository if found, otherwise null
391      */
392     public Repository getRepository( String repoId )
393     {
394         rwLock.readLock( ).lock( );
395         try
396         {
397             log.debug("getRepository {}", repoId);
398             if ( managedRepositories.containsKey( repoId ) )
399             {
400                 log.debug("Managed repo");
401                 return managedRepositories.get( repoId );
402             }
403             else
404             {
405                 log.debug("Remote repo");
406                 return remoteRepositories.get( repoId );
407             }
408         }
409         finally
410         {
411             rwLock.readLock( ).unlock( );
412         }
413     }
414
415     /**
416      * Convenience method, that returns the managed repository with the given id.
417      * It returns null, if no managed repository is registered with this id.
418      *
419      * @param repoId the repository id
420      * @return the managed repository if found, otherwise null
421      */
422     public ManagedRepository getManagedRepository( String repoId )
423     {
424         rwLock.readLock( ).lock( );
425         try
426         {
427             return managedRepositories.get( repoId );
428         }
429         finally
430         {
431             rwLock.readLock( ).unlock( );
432         }
433     }
434
435     /**
436      * Convenience method, that returns the remote repository with the given id.
437      * It returns null, if no remote repository is registered with this id.
438      *
439      * @param repoId the repository id
440      * @return the remote repository if found, otherwise null
441      */
442     public RemoteRepository getRemoteRepository( String repoId )
443     {
444         rwLock.readLock( ).lock( );
445         try
446         {
447             return remoteRepositories.get( repoId );
448         }
449         finally
450         {
451             rwLock.readLock( ).unlock( );
452         }
453     }
454
455     /**
456      * Adds a new repository to the current list, or replaces the repository definition with
457      * the same id, if it exists already.
458      * The change is saved to the configuration immediately.
459      *
460      * @param managedRepository the new repository.
461      * @throws RepositoryException if the new repository could not be saved to the configuration.
462      */
463     public ManagedRepository putRepository( ManagedRepository managedRepository ) throws RepositoryException
464     {
465         rwLock.writeLock( ).lock( );
466         try
467         {
468             final String id = managedRepository.getId();
469             if (remoteRepositories.containsKey( id )) {
470                 throw new RepositoryException( "There exists a remote repository with id "+id+". Could not update with managed repository." );
471             }
472
473             ManagedRepository originRepo = managedRepositories.put( id, managedRepository );
474             try
475             {
476                 if (originRepo!=null) {
477                     originRepo.close();
478                 }
479                 RepositoryProvider provider = getProvider( managedRepository.getType() );
480                 ManagedRepositoryConfiguration newCfg = provider.getManagedConfiguration( managedRepository );
481                 Configuration configuration = getArchivaConfiguration( ).getConfiguration( );
482                 updateRepositoryReferences( provider, managedRepository, newCfg, configuration );
483                 ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById( id );
484                 if (oldCfg!=null) {
485                     configuration.removeManagedRepository( oldCfg );
486                 }
487                 configuration.addManagedRepository( newCfg );
488                 getArchivaConfiguration( ).save( configuration );
489                 return managedRepository;
490             }
491             catch ( Exception e )
492             {
493                 // Rollback
494                 if ( originRepo != null )
495                 {
496                     managedRepositories.put( id, originRepo );
497                 } else {
498                     managedRepositories.remove(id);
499                 }
500                 log.error("Exception during configuration update {}", e.getMessage(), e);
501                 throw new RepositoryException( "Could not save the configuration" + (e.getMessage( )==null?"":": "+e.getMessage()) );
502             }
503         }
504         finally
505         {
506             rwLock.writeLock( ).unlock( );
507         }
508     }
509
510     /**
511      * Adds a new repository or updates the repository with the same id, if it exists already.
512      * The configuration is saved immediately.
513      *
514      * @param managedRepositoryConfiguration the repository configuration
515      * @return the updated or created repository
516      * @throws RepositoryException if an error occurs, or the configuration is not valid.
517      */
518     public ManagedRepository putRepository( ManagedRepositoryConfiguration managedRepositoryConfiguration) throws RepositoryException
519     {
520         rwLock.writeLock( ).lock( );
521         try
522         {
523             final String id = managedRepositoryConfiguration.getId();
524             final RepositoryType repositoryType = RepositoryType.valueOf( managedRepositoryConfiguration.getType() );
525             Configuration configuration = getArchivaConfiguration().getConfiguration();
526             ManagedRepository repo = managedRepositories.get(id);
527             ManagedRepositoryConfiguration oldCfg = repo!=null ? getProvider( repositoryType ).getManagedConfiguration( repo ) : null;
528             repo = putRepository( managedRepositoryConfiguration, configuration );
529             try
530             {
531                 getArchivaConfiguration().save(configuration);
532             }
533             catch ( IndeterminateConfigurationException | RegistryException e )
534             {
535                 if (oldCfg!=null) {
536                     getProvider( repositoryType ).updateManagedInstance( (EditableManagedRepository)repo, oldCfg );
537                 }
538                 log.error("Could not save the configuration for repository {}: {}", id, e.getMessage(),e );
539                 throw new RepositoryException( "Could not save the configuration for repository "+id+": "+e.getMessage() );
540             }
541             return repo;
542         }
543         finally
544         {
545             rwLock.writeLock( ).unlock( );
546         }
547
548     }
549
550     /**
551      * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
552      * the configuration is not saved.
553      *
554      * @param managedRepositoryConfiguration the new or changed repository configuration
555      * @param configuration the configuration object
556      * @return the new or updated repository
557      * @throws RepositoryException if the configuration cannot be saved or updated
558      */
559     public ManagedRepository putRepository( ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration) throws RepositoryException
560     {
561         rwLock.writeLock( ).lock( );
562         try
563         {
564             final String id = managedRepositoryConfiguration.getId();
565             final RepositoryType repoType = RepositoryType.valueOf( managedRepositoryConfiguration.getType() );
566             ManagedRepository repo;
567             if (managedRepositories.containsKey( id )) {
568                 repo = managedRepositories.get(id);
569                 if (repo instanceof EditableManagedRepository)
570                 {
571                     getProvider( repoType ).updateManagedInstance( (EditableManagedRepository) repo, managedRepositoryConfiguration );
572                 } else {
573                     throw new RepositoryException( "The repository is not editable "+id );
574                 }
575             } else
576             {
577                 repo = getProvider( repoType ).createManagedInstance( managedRepositoryConfiguration );
578                 repo.addListener(this);
579                 managedRepositories.put(id, repo);
580             }
581             updateRepositoryReferences( getProvider( repoType  ), repo, managedRepositoryConfiguration, configuration );
582             replaceOrAddRepositoryConfig( managedRepositoryConfiguration, configuration );
583             return repo;
584         }
585         finally
586         {
587             rwLock.writeLock( ).unlock( );
588         }
589     }
590
591     private void replaceOrAddRepositoryConfig(ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration) {
592         ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById( managedRepositoryConfiguration.getId() );
593         if ( oldCfg !=null) {
594             configuration.removeManagedRepository( oldCfg );
595         }
596         configuration.addManagedRepository( managedRepositoryConfiguration );
597     }
598
599     private void replaceOrAddRepositoryConfig(RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration) {
600         RemoteRepositoryConfiguration oldCfg = configuration.findRemoteRepositoryById( remoteRepositoryConfiguration.getId() );
601         if ( oldCfg !=null) {
602             configuration.removeRemoteRepository( oldCfg );
603         }
604         configuration.addRemoteRepository( remoteRepositoryConfiguration );
605     }
606
607     public RemoteRepository putRepository( RemoteRepository remoteRepository, Configuration configuration) throws RepositoryException
608     {
609         rwLock.writeLock( ).lock( );
610         try
611         {
612             final String id = remoteRepository.getId();
613             if (managedRepositories.containsKey( id )) {
614                 throw new RepositoryException( "There exists a managed repository with id "+id+". Could not update with remote repository." );
615             }
616             RemoteRepository originRepo = remoteRepositories.put( id, remoteRepository );
617             RemoteRepositoryConfiguration oldCfg=null;
618             RemoteRepositoryConfiguration newCfg=null;
619             try
620             {
621                 if (originRepo!=null) {
622                     originRepo.close();
623                 }
624                 final RepositoryProvider provider = getProvider( remoteRepository.getType() );
625                 newCfg = provider.getRemoteConfiguration( remoteRepository );
626                 updateRepositoryReferences( provider, remoteRepository, newCfg, configuration );
627                 oldCfg = configuration.findRemoteRepositoryById( id );
628                 if (oldCfg!=null) {
629                     configuration.removeRemoteRepository( oldCfg );
630                 }
631                 configuration.addRemoteRepository( newCfg );
632                 return remoteRepository;
633             }
634             catch ( Exception e )
635             {
636                 // Rollback
637                 if ( originRepo != null )
638                 {
639                     remoteRepositories.put( id, originRepo );
640                 } else {
641                     remoteRepositories.remove( id);
642                 }
643                 if (oldCfg!=null) {
644                     RemoteRepositoryConfiguration cfg = configuration.findRemoteRepositoryById( id );
645                     if (cfg!=null) {
646                         configuration.removeRemoteRepository( cfg );
647                         configuration.addRemoteRepository( oldCfg );
648                     }
649                 }
650                 log.error("Error while adding remote repository {}", e.getMessage(), e);
651                 throw new RepositoryException( "Could not save the configuration" + (e.getMessage( )==null?"":": "+e.getMessage()) );
652             }
653         }
654         finally
655         {
656             rwLock.writeLock( ).unlock( );
657         }
658     }
659
660     /**
661      * Adds a remote repository, or overwrites the repository definition with the same id, if it exists already.
662      * The modification is saved to the configuration immediately.
663      *
664      * @param remoteRepository the remote repository to add
665      * @throws RepositoryException if an error occurs during configuration save
666      */
667     public RemoteRepository putRepository( RemoteRepository remoteRepository ) throws RepositoryException
668     {
669         rwLock.writeLock( ).lock( );
670         try
671         {
672             Configuration configuration = getArchivaConfiguration().getConfiguration();
673             try
674             {
675                 RemoteRepository repo = putRepository( remoteRepository, configuration );
676                 getArchivaConfiguration().save(configuration);
677                 return repo;
678             }
679             catch ( RegistryException | IndeterminateConfigurationException e )
680             {
681                 log.error("Error while saving remote repository {}", e.getMessage(), e);
682                 throw new RepositoryException( "Could not save the configuration" + (e.getMessage( )==null?"":": "+e.getMessage()) );
683             }
684         }
685         finally
686         {
687             rwLock.writeLock( ).unlock( );
688         }
689     }
690
691     /**
692      * Adds a new repository or updates the repository with the same id, if it exists already.
693      * The configuration is saved immediately.
694      *
695      * @param remoteRepositoryConfiguration the repository configuration
696      * @return the updated or created repository
697      * @throws RepositoryException if an error occurs, or the configuration is not valid.
698      */
699     public RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration) throws RepositoryException
700     {
701         rwLock.writeLock( ).lock( );
702         try
703         {
704             final String id = remoteRepositoryConfiguration.getId();
705             final RepositoryType repositoryType = RepositoryType.valueOf( remoteRepositoryConfiguration.getType() );
706             Configuration configuration = getArchivaConfiguration().getConfiguration();
707             RemoteRepository repo = remoteRepositories.get(id);
708             RemoteRepositoryConfiguration oldCfg = repo!=null ? getProvider( repositoryType ).getRemoteConfiguration( repo ) : null;
709             repo = putRepository( remoteRepositoryConfiguration, configuration );
710             try
711             {
712                 getArchivaConfiguration().save(configuration);
713             }
714             catch ( IndeterminateConfigurationException | RegistryException e )
715             {
716                 if (oldCfg!=null) {
717                     getProvider( repositoryType ).updateRemoteInstance( (EditableRemoteRepository)repo, oldCfg );
718                 }
719                 log.error("Could not save the configuration for repository {}: {}", id, e.getMessage(),e );
720                 throw new RepositoryException( "Could not save the configuration for repository "+id+": "+e.getMessage() );
721             }
722             return repo;
723         }
724         finally
725         {
726             rwLock.writeLock( ).unlock( );
727         }
728
729     }
730
731     /**
732      * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
733      * the configuration is not saved.
734      *
735      * @param remoteRepositoryConfiguration the new or changed repository configuration
736      * @param configuration the configuration object
737      * @return the new or updated repository
738      * @throws RepositoryException if the configuration cannot be saved or updated
739      */
740     public RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration) throws RepositoryException
741     {
742         rwLock.writeLock( ).lock( );
743         try
744         {
745             final String id = remoteRepositoryConfiguration.getId();
746             final RepositoryType repoType = RepositoryType.valueOf( remoteRepositoryConfiguration.getType() );
747             RemoteRepository repo;
748             if (remoteRepositories.containsKey( id )) {
749                 repo = remoteRepositories.get(id);
750                 if (repo instanceof EditableRemoteRepository)
751                 {
752                     getProvider( repoType ).updateRemoteInstance( (EditableRemoteRepository) repo, remoteRepositoryConfiguration );
753                 } else {
754                     throw new RepositoryException( "The repository is not editable "+id );
755                 }
756             } else
757             {
758                 repo = getProvider( repoType ).createRemoteInstance( remoteRepositoryConfiguration );
759                 repo.addListener(this);
760                 remoteRepositories.put(id, repo);
761             }
762             updateRepositoryReferences( getProvider( repoType  ), repo, remoteRepositoryConfiguration, configuration );
763             replaceOrAddRepositoryConfig( remoteRepositoryConfiguration, configuration );
764             return repo;
765         }
766         finally
767         {
768             rwLock.writeLock( ).unlock( );
769         }
770
771
772     }
773
774     public void removeRepository(String repoId) throws RepositoryException {
775         Repository repo = getRepository(repoId);
776         if (repo!=null) {
777             removeRepository(repo);
778         }
779     }
780     public void removeRepository(Repository repo) throws RepositoryException
781     {
782         if (repo instanceof RemoteRepository ) {
783             removeRepository( (RemoteRepository)repo );
784         } else if (repo instanceof ManagedRepository) {
785             removeRepository( (ManagedRepository)repo);
786         } else {
787             throw new RepositoryException( "Repository type not known: "+repo.getClass() );
788         }
789     }
790
791     /**
792      * Removes a managed repository from the registry and configuration, if it exists.
793      * The change is saved to the configuration immediately.
794      *
795      * @param managedRepository the managed repository to remove
796      * @throws RepositoryException if a error occurs during configuration save
797      */
798     public void removeRepository( ManagedRepository managedRepository ) throws RepositoryException
799     {
800         final String id = managedRepository.getId();
801         ManagedRepository repo = getManagedRepository( id );
802         if (repo!=null) {
803             rwLock.writeLock().lock();
804             try {
805                 repo = managedRepositories.remove( id );
806                 if (repo!=null) {
807                     repo.close();
808                     Configuration configuration = getArchivaConfiguration().getConfiguration();
809                     ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById( id );
810                     if (cfg!=null) {
811                         configuration.removeManagedRepository( cfg );
812                     }
813                     getArchivaConfiguration().save( configuration );
814                 }
815
816             }
817             catch ( RegistryException | IndeterminateConfigurationException e )
818             {
819                 // Rollback
820                 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
821                 managedRepositories.put(repo.getId(), repo);
822                 throw new RepositoryException( "Could not save configuration after repository removal: "+e.getMessage() );
823             } finally
824             {
825                 rwLock.writeLock().unlock();
826             }
827         }
828     }
829
830     public void removeRepository(ManagedRepository managedRepository, Configuration configuration) throws RepositoryException
831     {
832         final String id = managedRepository.getId();
833         ManagedRepository repo = getManagedRepository( id );
834         if (repo!=null) {
835             rwLock.writeLock().lock();
836             try {
837                 repo = managedRepositories.remove( id );
838                 if (repo!=null) {
839                     repo.close();
840                     ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById( id );
841                     if (cfg!=null) {
842                         configuration.removeManagedRepository( cfg );
843                     }
844                 }
845             } finally
846             {
847                 rwLock.writeLock().unlock();
848             }
849         }
850
851     }
852
853
854     private void doRemoveRepo(RemoteRepository repo, Configuration configuration) {
855             repo.close();
856             RemoteRepositoryConfiguration cfg = configuration.findRemoteRepositoryById(repo.getId());
857             if (cfg != null) {
858                 configuration.removeRemoteRepository(cfg);
859             }
860             List<ProxyConnectorConfiguration> proxyConnectors = new ArrayList<>(configuration.getProxyConnectors());
861             for (ProxyConnectorConfiguration proxyConnector : proxyConnectors) {
862                 if (StringUtils.equals(proxyConnector.getTargetRepoId(), repo.getId())) {
863                     configuration.removeProxyConnector(proxyConnector);
864                 }
865             }
866     }
867
868     /**
869      * Removes the remote repository from the registry and configuration.
870      * The change is saved to the configuration immediately.
871      *
872      * @param remoteRepository the remote repository to remove
873      * @throws RepositoryException if a error occurs during configuration save
874      */
875     public void removeRepository( RemoteRepository remoteRepository ) throws RepositoryException
876     {
877
878         final String id = remoteRepository.getId();
879         RemoteRepository repo = getRemoteRepository( id );
880         if (repo!=null) {
881             rwLock.writeLock().lock();
882             try {
883                 repo = remoteRepositories.remove( id );
884                 if (repo!=null) {
885                     Configuration configuration = getArchivaConfiguration().getConfiguration();
886                     doRemoveRepo(repo, configuration);
887                     getArchivaConfiguration().save( configuration );
888                 }
889             }
890             catch ( RegistryException | IndeterminateConfigurationException e )
891             {
892                 // Rollback
893                 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
894                 remoteRepositories.put(repo.getId(), repo);
895                 throw new RepositoryException( "Could not save configuration after repository removal: "+e.getMessage() );
896             } finally
897             {
898                 rwLock.writeLock().unlock();
899             }
900         }
901     }
902
903     public void removeRepository( RemoteRepository remoteRepository, Configuration configuration) throws RepositoryException
904     {
905         final String id = remoteRepository.getId();
906         RemoteRepository repo = getRemoteRepository( id );
907         if (repo!=null) {
908             rwLock.writeLock().lock();
909             try {
910                 repo = remoteRepositories.remove( id );
911                 if (repo!=null) {
912                     doRemoveRepo(repo, configuration);
913                 }
914             } finally
915             {
916                 rwLock.writeLock().unlock();
917             }
918         }
919
920     }
921
922     /**
923      * Reloads the registry from the configuration.
924      */
925     public void reload() {
926         initialize();
927     }
928
929     /**
930      * Resets the indexing context of a given repository.
931      *
932      * @param repo
933      * @throws IndexUpdateFailedException
934      */
935     public void resetIndexingContext(Repository repo) throws IndexUpdateFailedException {
936         if (repo.hasIndex() && repo instanceof EditableRepository) {
937             EditableRepository eRepo = (EditableRepository) repo;
938             ArchivaIndexingContext newCtx = getIndexManager(repo.getType()).reset(repo.getIndexingContext());
939             eRepo.setIndexingContext(newCtx);
940         }
941     }
942
943
944     /**
945      * Creates a new repository instance with the same settings as this one. The cloned repository is not
946      * registered or saved to the configuration.
947      *
948      * @param repo The origin repository
949      * @return The cloned repository.
950      */
951     public ManagedRepository clone(ManagedRepository repo, String newId) throws RepositoryException
952     {
953         if (managedRepositories.containsKey(newId) || remoteRepositories.containsKey(newId)) {
954             throw new RepositoryException("The given id exists already "+newId);
955         }
956         RepositoryProvider provider = getProvider(repo.getType());
957         ManagedRepositoryConfiguration cfg = provider.getManagedConfiguration(repo);
958         cfg.setId(newId);
959         ManagedRepository cloned = provider.createManagedInstance(cfg);
960         cloned.addListener(this);
961         return cloned;
962     }
963
964     public <T extends Repository> Repository clone(T repo, String newId) throws RepositoryException {
965         if (repo instanceof RemoteRepository ) {
966             return this.clone((RemoteRepository)repo, newId);
967         } else if (repo instanceof ManagedRepository) {
968             return this.clone((ManagedRepository)repo, newId);
969         } else {
970             throw new RepositoryException("This repository class is not supported "+ repo.getClass().getName());
971         }
972     }
973
974     /**
975      * Creates a new repository instance with the same settings as this one. The cloned repository is not
976      * registered or saved to the configuration.
977      *
978      * @param repo The origin repository
979      * @return The cloned repository.
980      */
981     public RemoteRepository clone( RemoteRepository repo, String newId) throws RepositoryException
982     {
983         if (managedRepositories.containsKey(newId) || remoteRepositories.containsKey(newId)) {
984             throw new RepositoryException("The given id exists already "+newId);
985         }
986         RepositoryProvider provider = getProvider(repo.getType());
987         RemoteRepositoryConfiguration cfg = provider.getRemoteConfiguration(repo);
988         cfg.setId(newId);
989         RemoteRepository cloned = provider.createRemoteInstance(cfg);
990         cloned.addListener(this);
991         return cloned;
992     }
993
994
995     @Override
996     public void configurationEvent(ConfigurationEvent event) {
997
998     }
999
1000
1001     @Override
1002     public void addListener(RepositoryEventListener listener) {
1003         if (!this.listeners.contains(listener)) {
1004             this.listeners.add(listener);
1005         }
1006     }
1007
1008     @Override
1009     public void removeListener(RepositoryEventListener listener) {
1010         this.listeners.remove(listener);
1011     }
1012
1013     @Override
1014     public void clearListeners() {
1015         this.listeners.clear();
1016     }
1017
1018     @Override
1019     public <T> void raise(RepositoryEvent<T> event) {
1020         if (event.getType().equals(IndexCreationEvent.Index.URI_CHANGE)) {
1021             if (managedRepositories.containsKey(event.getRepository().getId()) ||
1022                     remoteRepositories.containsKey(event.getRepository().getId())) {
1023                 EditableRepository repo = (EditableRepository) event.getRepository();
1024                 if (repo != null && repo.getIndexingContext()!=null) {
1025                     try {
1026                         ArchivaIndexManager idxmgr = getIndexManager(repo.getType());
1027                         if (idxmgr != null) {
1028                             ArchivaIndexingContext newCtx = idxmgr.move(repo.getIndexingContext(), repo);
1029                             repo.setIndexingContext(newCtx);
1030                             idxmgr.updateLocalIndexPath(repo);
1031                         }
1032
1033                     } catch (IndexCreationFailedException e) {
1034                         log.error("Could not move index to new directory {}", e.getMessage(), e);
1035                     }
1036                 }
1037             }
1038         }
1039         for(RepositoryEventListener listener : listeners) {
1040             listener.raise(event);
1041         }
1042     }
1043 }