]> source.dussan.org Git - archiva.git/blob
ea1f19c91d4fea2f1c857fdd4d23c26615f8e2e6
[archiva.git] /
1 package org.apache.archiva.repository.base.remote;
2 /*
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
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
20 import org.apache.archiva.components.registry.RegistryException;
21 import org.apache.archiva.configuration.Configuration;
22 import org.apache.archiva.configuration.IndeterminateConfigurationException;
23 import org.apache.archiva.configuration.ProxyConnectorConfiguration;
24 import org.apache.archiva.configuration.RemoteRepositoryConfiguration;
25 import org.apache.archiva.indexer.ArchivaIndexManager;
26 import org.apache.archiva.indexer.IndexCreationFailedException;
27 import org.apache.archiva.indexer.IndexManagerFactory;
28 import org.apache.archiva.repository.EditableRemoteRepository;
29 import org.apache.archiva.repository.EditableRepository;
30 import org.apache.archiva.repository.RemoteRepository;
31 import org.apache.archiva.repository.RepositoryContentFactory;
32 import org.apache.archiva.repository.RepositoryException;
33 import org.apache.archiva.repository.RepositoryHandler;
34 import org.apache.archiva.repository.RepositoryHandlerManager;
35 import org.apache.archiva.repository.RepositoryProvider;
36 import org.apache.archiva.repository.RepositoryState;
37 import org.apache.archiva.repository.RepositoryType;
38 import org.apache.archiva.repository.base.AbstractRepositoryHandler;
39 import org.apache.archiva.repository.base.ConfigurationHandler;
40 import org.apache.archiva.repository.event.LifecycleEvent;
41 import org.apache.archiva.repository.event.RepositoryEvent;
42 import org.apache.archiva.repository.features.IndexCreationFeature;
43 import org.apache.commons.lang3.StringUtils;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46 import org.springframework.stereotype.Service;
47
48 import javax.annotation.PostConstruct;
49 import javax.inject.Named;
50 import java.util.ArrayList;
51 import java.util.Collections;
52 import java.util.HashMap;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.concurrent.locks.ReentrantReadWriteLock;
56
57 /**
58  * @author Martin Stockhammer <martin_s@apache.org>
59  */
60 @Service( "remoteRepositoryHandler#default" )
61 public class RemoteRepositoryHandler extends AbstractRepositoryHandler<RemoteRepository, RemoteRepositoryConfiguration> implements RepositoryHandler<RemoteRepository, RemoteRepositoryConfiguration>
62 {
63     private static final Logger log = LoggerFactory.getLogger( RemoteRepositoryHandler.class );
64     private final RepositoryHandlerManager repositoryHandlerManager;
65     private final RepositoryContentFactory repositoryContentFactory;
66     private final IndexManagerFactory indexManagerFactory;
67
68
69     public RemoteRepositoryHandler( RepositoryHandlerManager repositoryHandlerManager, ConfigurationHandler configurationHandler,
70                                     IndexManagerFactory indexManagerFactory,
71                                     @Named( "repositoryContentFactory#default" ) RepositoryContentFactory repositoryContentFactory )
72     {
73         super( RemoteRepository.class, RemoteRepositoryConfiguration.class, configurationHandler );
74         this.repositoryHandlerManager = repositoryHandlerManager;
75         this.repositoryContentFactory = repositoryContentFactory;
76         this.indexManagerFactory = indexManagerFactory;
77     }
78
79     @Override
80     @PostConstruct
81     public void init( )
82     {
83         log.debug( "Initializing repository handler " + RemoteRepositoryHandler.class );
84         initializeStorage( );
85         // We are registering this class on the registry. This is necessary to avoid circular dependencies via injection.
86         this.repositoryHandlerManager.registerHandler( this );
87     }
88
89     private void initializeStorage( )
90     {
91
92     }
93
94     @Override
95     public void initializeFromConfig( )
96     {
97         Map<String, RemoteRepository> currentInstances = new HashMap<>( getRepositories( ) );
98         getRepositories().clear();
99         Map<String, RemoteRepository> newAndUpdated = newOrUpdateInstancesFromConfig( currentInstances );
100         getRepositories( ).putAll( newAndUpdated );
101         currentInstances.entrySet( ).stream( ).filter( entry -> !newAndUpdated.containsKey( entry.getKey( ) ) ).forEach(
102             r ->
103             deactivateRepository( r.getValue() )
104         );
105         for ( RemoteRepository remoteRepository : getRepositories( ).values( ) )
106         {
107             activateRepository( remoteRepository );
108         }
109
110
111     }
112
113     public Map<String, RemoteRepository> newOrUpdateInstancesFromConfig( Map<String, RemoteRepository> currentInstances)
114     {
115         try
116         {
117             List<RemoteRepositoryConfiguration> remoteRepoConfigs =
118                 new ArrayList<>(
119                     getConfigurationHandler( ).getBaseConfiguration( ).getRemoteRepositories( ) );
120
121             if ( remoteRepoConfigs == null )
122             {
123                 return Collections.emptyMap( );
124             }
125
126             Map<String, RemoteRepository> result = new HashMap<>( );
127             for ( RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs )
128             {
129                 String id = repoConfig.getId( );
130                 if (result.containsKey( id )) {
131                     log.error( "There are repositories with the same id in the configuration: {}", id );
132                     continue;
133                 }
134                 RemoteRepository repo;
135                 if ( currentInstances.containsKey( id ) )
136                 {
137                     repo = currentInstances.remove( id );
138                     getProvider( repo.getType( ) ).updateRemoteInstance( (EditableRemoteRepository) repo, repoConfig );
139                     updateReferences( repo, repoConfig );
140                 }
141                 else
142                 {
143                     repo = newInstance( repoConfig );
144                 }
145                 result.put( id, repo );
146             }
147             return result;
148         }
149         catch ( Throwable e )
150         {
151             log.error( "Could not initialize repositories from config: {}", e.getMessage( ), e );
152             return new HashMap<>( );
153         }
154     }
155
156
157     @Override
158     public Map<String, RemoteRepository> newInstancesFromConfig( )
159     {
160         try
161         {
162             List<RemoteRepositoryConfiguration> remoteRepoConfigs =
163                 new ArrayList<>(
164                     getConfigurationHandler( ).getBaseConfiguration( ).getRemoteRepositories( ) );
165
166             if ( remoteRepoConfigs == null )
167             {
168                 return Collections.emptyMap( );
169             }
170
171             Map<String, RemoteRepository> result = new HashMap<>( );
172             for ( RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs )
173             {
174                 RemoteRepository repo = newInstance( repoConfig );
175                 result.put( repo.getId( ), repo );
176             }
177             return result;
178         }
179         catch ( Throwable e )
180         {
181             log.error( "Could not initialize repositories from config: {}", e.getMessage( ), e );
182             return new HashMap<>( );
183         }
184     }
185
186     @Override
187     public RemoteRepository newInstance( RepositoryType type, String id ) throws RepositoryException
188     {
189         log.debug( "Creating repo {}", id );
190         RepositoryProvider provider = getProvider( type );
191         EditableRemoteRepository repo;
192         repo = provider.createRemoteInstance( id, id );
193         repo.registerEventHandler( RepositoryEvent.ANY, repositoryHandlerManager );
194         updateReferences( repo, null );
195         repo.setLastState( RepositoryState.REFERENCES_SET );
196         return repo;
197
198     }
199
200
201     @Override
202     public RemoteRepository newInstance( RemoteRepositoryConfiguration repositoryConfiguration ) throws RepositoryException
203     {
204         RepositoryType type = RepositoryType.valueOf( repositoryConfiguration.getType( ) );
205         RepositoryProvider provider = getProvider( type );
206         if ( provider == null )
207         {
208             throw new RepositoryException( "Provider not found for repository type: " + repositoryConfiguration.getType( ) );
209         }
210         final RemoteRepository repo = provider.createRemoteInstance( repositoryConfiguration );
211         repo.registerEventHandler( RepositoryEvent.ANY, repositoryHandlerManager );
212         updateReferences( repo, null );
213         if ( repo instanceof EditableRepository )
214         {
215             ( (EditableRepository) repo ).setLastState( RepositoryState.REFERENCES_SET );
216         }
217         return repo;
218     }
219
220     @Override
221     protected RemoteRepositoryConfiguration findRepositoryConfiguration( Configuration configuration, String id )
222     {
223         return configuration.findRemoteRepositoryById( id );
224     }
225
226     @Override
227     protected void removeRepositoryConfiguration( Configuration configuration, RemoteRepositoryConfiguration repoConfiguration )
228     {
229         configuration.removeRemoteRepository( repoConfiguration );
230         List<ProxyConnectorConfiguration> proxyConnectors = new ArrayList<>( configuration.getProxyConnectors( ) );
231         for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
232         {
233             if ( StringUtils.equals( proxyConnector.getTargetRepoId( ), repoConfiguration.getId( ) ) )
234             {
235                 configuration.removeProxyConnector( proxyConnector );
236             }
237         }
238     }
239
240     @Override
241     protected void addRepositoryConfiguration( Configuration configuration, RemoteRepositoryConfiguration repoConfiguration )
242     {
243         configuration.addRemoteRepository( repoConfiguration );
244
245     }
246
247
248
249     @Override
250     public RemoteRepository put( RemoteRepository repository ) throws RepositoryException
251     {
252         final String id = repository.getId( );
253         RemoteRepository originRepo = getRepositories( ).remove( id );
254         if ( originRepo == null && repositoryHandlerManager.isRegisteredId( id ) )
255         {
256             throw new RepositoryException( "There exists a repository with id " + id + ". Could not update with managed repository." );
257         }
258         try
259         {
260             if ( originRepo != null && repository != originRepo )
261             {
262                 deactivateRepository( originRepo );
263                 pushEvent( LifecycleEvent.UNREGISTERED, originRepo );
264             }
265             RepositoryProvider provider = getProvider( repository.getType( ) );
266             RemoteRepositoryConfiguration newCfg = provider.getRemoteConfiguration( repository );
267             getConfigurationHandler( ).getLock( ).writeLock( ).lock( );
268             try
269             {
270                 Configuration configuration = getConfigurationHandler( ).getBaseConfiguration( );
271                 updateReferences( repository, newCfg );
272                 RemoteRepositoryConfiguration oldCfg = configuration.findRemoteRepositoryById( id );
273                 if ( oldCfg != null )
274                 {
275                     configuration.removeRemoteRepository( oldCfg );
276                 }
277                 configuration.addRemoteRepository( newCfg );
278                 getConfigurationHandler( ).save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
279                 setLastState( repository, RepositoryState.SAVED );
280                 activateRepository( repository );
281             }
282             finally
283             {
284                 getConfigurationHandler( ).getLock( ).writeLock( ).unlock( );
285             }
286             getRepositories( ).put( id, repository );
287             setLastState( repository, RepositoryState.REGISTERED );
288             return repository;
289         }
290         catch ( Exception e )
291         {
292             // Rollback only partly, because repository is closed already
293             if ( originRepo != null )
294             {
295                 getRepositories( ).put( id, originRepo );
296             }
297             else
298             {
299                 getRepositories( ).remove( id );
300             }
301             log.error( "Exception during configuration update {}", e.getMessage( ), e );
302             throw new RepositoryException( "Could not save the configuration" + ( e.getMessage( ) == null ? "" : ": " + e.getMessage( ) ) );
303         }
304
305     }
306
307     @Override
308     public RemoteRepository put( RemoteRepositoryConfiguration repositoryConfiguration ) throws RepositoryException
309     {
310         final String id = repositoryConfiguration.getId( );
311         final RepositoryType repositoryType = RepositoryType.valueOf( repositoryConfiguration.getType( ) );
312         final RepositoryProvider provider = getProvider( repositoryType );
313         ReentrantReadWriteLock.WriteLock configLock = this.getConfigurationHandler( ).getLock( ).writeLock( );
314         configLock.lock( );
315         RemoteRepository repo = null;
316         RemoteRepository oldRepository = null;
317         Configuration configuration = null;
318         try
319         {
320             boolean updated = false;
321             configuration = getConfigurationHandler( ).getBaseConfiguration( );
322             repo = getRepositories( ).get( id );
323             oldRepository = repo == null ? null : clone( repo, id );
324             if ( repo == null )
325             {
326                 repo = put( repositoryConfiguration, configuration );
327             }
328             else
329             {
330                 setRepositoryDefaults( repositoryConfiguration );
331                 provider.updateRemoteInstance( (EditableRemoteRepository) repo, repositoryConfiguration );
332                 updated = true;
333                 pushEvent( LifecycleEvent.UPDATED, repo );
334             }
335             registerNewRepository( repositoryConfiguration, repo, configuration, updated );
336         }
337         catch ( IndeterminateConfigurationException | RegistryException e )
338         {
339             if ( oldRepository != null )
340             {
341                 RemoteRepositoryConfiguration oldCfg = provider.getRemoteConfiguration( oldRepository );
342                 provider.updateRemoteInstance( (EditableRemoteRepository) repo, oldCfg );
343                 rollback( configuration, oldRepository, e, oldCfg );
344             }
345             else
346             {
347                 getRepositories( ).remove( id );
348             }
349             log.error( "Could not save the configuration for repository {}: {}", id, e.getMessage( ), e );
350             throw new RepositoryException( "Could not save the configuration for repository " + id + ": " + e.getMessage( ) );
351         }
352         finally
353         {
354             configLock.unlock( );
355         }
356         return repo;
357
358     }
359
360     @SuppressWarnings( "unused" )
361     private void setRepositoryDefaults( RemoteRepositoryConfiguration repositoryConfiguration )
362     {
363         // We do nothing here
364     }
365
366
367     @Override
368     public RemoteRepository put( RemoteRepositoryConfiguration repositoryConfiguration, Configuration configuration ) throws RepositoryException
369     {
370         final String id = repositoryConfiguration.getId( );
371         final RepositoryType repoType = RepositoryType.valueOf( repositoryConfiguration.getType( ) );
372         RemoteRepository repo;
373         setRepositoryDefaults( repositoryConfiguration );
374         if ( getRepositories( ).containsKey( id ) )
375         {
376             repo = clone( getRepositories( ).get( id ), id );
377             if ( repo instanceof EditableRemoteRepository )
378             {
379                 getProvider( repoType ).updateRemoteInstance( (EditableRemoteRepository) repo, repositoryConfiguration );
380             }
381             else
382             {
383                 throw new RepositoryException( "The repository is not editable " + id );
384             }
385         }
386         else
387         {
388             repo = getProvider( repoType ).createRemoteInstance( repositoryConfiguration );
389             setLastState( repo, RepositoryState.CREATED );
390         }
391         if ( configuration != null )
392         {
393             replaceOrAddRepositoryConfig( repositoryConfiguration, configuration );
394         }
395         updateReferences( repo, repositoryConfiguration );
396         setLastState( repo, RepositoryState.REFERENCES_SET );
397         return repo;
398
399     }
400
401     @Override
402     public RemoteRepository clone( RemoteRepository repo, String newId ) throws RepositoryException
403     {
404         RepositoryProvider provider = getProvider( repo.getType( ) );
405         RemoteRepositoryConfiguration cfg = provider.getRemoteConfiguration( repo );
406         cfg.setId( newId );
407         RemoteRepository cloned = provider.createRemoteInstance( cfg );
408         cloned.registerEventHandler( RepositoryEvent.ANY, repositoryHandlerManager );
409         setLastState( cloned, RepositoryState.CREATED );
410         return cloned;
411
412     }
413
414     @Override
415     public void updateReferences( RemoteRepository repo, RemoteRepositoryConfiguration repositoryConfiguration ) throws RepositoryException
416     {
417         if ( repo instanceof EditableRemoteRepository && repo.getContent( ) == null )
418         {
419             EditableRemoteRepository editableRepo = (EditableRemoteRepository) repo;
420             editableRepo.setContent( repositoryContentFactory.getRemoteRepositoryContent( repo ) );
421             if ( repo.supportsFeature( IndexCreationFeature.class ) && repo.getIndexingContext( ) == null )
422             {
423                 createIndexingContext( editableRepo );
424             }
425         }
426         repo.registerEventHandler( RepositoryEvent.ANY, repositoryHandlerManager );
427
428     }
429
430     private void createIndexingContext( EditableRepository editableRepo ) throws RepositoryException
431     {
432         if ( editableRepo.supportsFeature( IndexCreationFeature.class ) )
433         {
434             ArchivaIndexManager idxManager = getIndexManager( editableRepo.getType( ) );
435             try
436             {
437                 editableRepo.setIndexingContext( idxManager.createContext( editableRepo ) );
438                 idxManager.updateLocalIndexPath( editableRepo );
439             }
440             catch ( IndexCreationFailedException e )
441             {
442                 throw new RepositoryException( "Could not create index for repository " + editableRepo.getId( ) + ": " + e.getMessage( ), e );
443             }
444         }
445     }
446
447     public ArchivaIndexManager getIndexManager( RepositoryType type )
448     {
449         return indexManagerFactory.getIndexManager( type );
450     }
451
452 }