]> source.dussan.org Git - archiva.git/blob
13f3ce6f9f91c959806efff945e252e41b870b70
[archiva.git] /
1 package org.apache.archiva.admin.repository.group;
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  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  */
20
21 import org.apache.archiva.admin.model.AuditInformation;
22 import org.apache.archiva.admin.model.EntityExistsException;
23 import org.apache.archiva.admin.model.EntityNotFoundException;
24 import org.apache.archiva.admin.model.RepositoryAdminException;
25 import org.apache.archiva.admin.model.beans.ManagedRepository;
26 import org.apache.archiva.admin.model.beans.RepositoryGroup;
27 import org.apache.archiva.admin.model.group.RepositoryGroupAdmin;
28 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
29 import org.apache.archiva.admin.repository.AbstractRepositoryAdmin;
30 import org.apache.archiva.configuration.Configuration;
31 import org.apache.archiva.configuration.RepositoryGroupConfiguration;
32 import org.apache.archiva.event.Event;
33 import org.apache.archiva.event.EventHandler;
34 import org.apache.archiva.event.EventType;
35 import org.apache.archiva.metadata.model.facets.AuditEvent;
36 import org.apache.archiva.indexer.merger.MergedRemoteIndexesScheduler;
37 import org.apache.archiva.repository.EditableRepositoryGroup;
38 import org.apache.archiva.repository.RepositoryException;
39 import org.apache.archiva.repository.RepositoryRegistry;
40 import org.apache.archiva.repository.event.RepositoryRegistryEvent;
41 import org.apache.archiva.repository.features.IndexCreationFeature;
42 import org.apache.archiva.repository.storage.StorageAsset;
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.Inject;
50 import javax.inject.Named;
51 import java.io.IOException;
52 import java.nio.file.Files;
53 import java.nio.file.Path;
54 import java.nio.file.Paths;
55 import java.util.ArrayList;
56 import java.util.HashMap;
57 import java.util.List;
58 import java.util.Map;
59 import java.util.regex.Matcher;
60 import java.util.regex.Pattern;
61 import java.util.stream.Collectors;
62
63 /**
64  * @author Olivier Lamy
65  */
66 @Service("repositoryGroupAdmin#default")
67 public class DefaultRepositoryGroupAdmin
68     extends AbstractRepositoryAdmin
69     implements RepositoryGroupAdmin, EventHandler<Event>
70 {
71
72     private Logger log = LoggerFactory.getLogger( getClass() );
73
74     private static final Pattern REPO_GROUP_ID_PATTERN = Pattern.compile( "[A-Za-z0-9\\._\\-]+" );
75
76     @Inject
77     private ManagedRepositoryAdmin managedRepositoryAdmin;
78
79     @Inject
80     @Named("mergedRemoteIndexesScheduler#default")
81     private MergedRemoteIndexesScheduler mergedRemoteIndexesScheduler;
82
83     @Inject
84     private RepositoryRegistry repositoryRegistry;
85
86     private Path groupsDirectory;
87
88     @PostConstruct
89     public void baseInit() {
90         this.repositoryRegistry.registerEventHandler( EventType.ROOT, this );
91     }
92
93     public void initialize()
94     {
95         String appServerBase = getRegistry().getString( "appserver.base" );
96         groupsDirectory = Paths.get( appServerBase, "groups" );
97         if ( !Files.exists(groupsDirectory) )
98         {
99             Files.exists(groupsDirectory);
100         }
101
102         for ( org.apache.archiva.repository.RepositoryGroup repositoryGroup : repositoryRegistry.getRepositoryGroups() )
103         {
104             mergedRemoteIndexesScheduler.schedule( repositoryGroup,
105                                                    getMergedIndexDirectory( repositoryGroup.getId() ));
106             // create the directory for each group if not exists
107             Path groupPath = groupsDirectory.resolve(repositoryGroup.getId() );
108             if ( !Files.exists(groupPath) )
109             {
110                 try {
111                     Files.createDirectories(groupPath);
112                 } catch (IOException e) {
113                     log.error("Could not create directory {}", groupPath);
114                 }
115             }
116         }
117
118     }
119
120
121     @Override
122     public StorageAsset getMergedIndexDirectory(String repositoryGroupId )
123     {
124         org.apache.archiva.repository.RepositoryGroup group = repositoryRegistry.getRepositoryGroup(repositoryGroupId);
125         if (group!=null) {
126             return group.getFeature(IndexCreationFeature.class).get().getLocalIndexPath();
127         } else {
128             return null;
129         }
130     }
131
132     @Override
133     public List<RepositoryGroup> getRepositoriesGroups() {
134         return repositoryRegistry.getRepositoryGroups().stream().map( r -> convertRepositoryGroupObject( r ) ).collect( Collectors.toList());
135     }
136
137     @Override
138     public RepositoryGroup getRepositoryGroup( String repositoryGroupId ) throws EntityNotFoundException
139     {
140         org.apache.archiva.repository.RepositoryGroup group = repositoryRegistry.getRepositoryGroup( repositoryGroupId );
141         if (group==null) {
142             throw new EntityNotFoundException( "Repository group does not exist" );
143         } else {
144             return convertRepositoryGroupObject( group );
145         }
146     }
147
148     @Override
149     public Boolean addRepositoryGroup( RepositoryGroup repositoryGroup, AuditInformation auditInformation )
150         throws RepositoryAdminException
151     {
152         validateRepositoryGroup( repositoryGroup, false );
153         validateManagedRepositoriesExists( repositoryGroup.getRepositories() );
154
155         RepositoryGroupConfiguration repositoryGroupConfiguration = new RepositoryGroupConfiguration();
156         repositoryGroupConfiguration.setId( repositoryGroup.getId() );
157         repositoryGroupConfiguration.setRepositories( repositoryGroup.getRepositories() );
158         repositoryGroupConfiguration.setMergedIndexPath( repositoryGroup.getMergedIndexPath() );
159         repositoryGroupConfiguration.setMergedIndexTtl( repositoryGroup.getMergedIndexTtl() );
160         repositoryGroupConfiguration.setCronExpression( StringUtils.isEmpty(repositoryGroup.getCronExpression()) ? "0 0 03 ? * MON" : repositoryGroup.getCronExpression() );
161
162         try {
163             repositoryRegistry.putRepositoryGroup(repositoryGroupConfiguration);
164         } catch (RepositoryException e) {
165             log.error( "Could not add the repository group to the registry: {}", e.getMessage( ), e );
166             throw RepositoryAdminException.ofKey( "repository_group.registry.add_error", e, repositoryGroup.getId(), e.getMessage() );
167         }
168
169         triggerAuditEvent( repositoryGroup.getId(), null, AuditEvent.ADD_REPO_GROUP, auditInformation );
170         mergedRemoteIndexesScheduler.schedule( repositoryRegistry.getRepositoryGroup( repositoryGroup.getId()), getMergedIndexDirectory( repositoryGroup.getId() ) );
171         return Boolean.TRUE;
172     }
173
174     @Override
175     public Boolean deleteRepositoryGroup( String repositoryGroupId, AuditInformation auditInformation )
176         throws RepositoryAdminException
177     {
178
179         org.apache.archiva.repository.RepositoryGroup repositoryGroup = repositoryRegistry.getRepositoryGroup(repositoryGroupId);
180         try {
181             repositoryRegistry.removeRepositoryGroup(repositoryGroup);
182         } catch (RepositoryException e) {
183             log.error("Removal of repository group {} failed: {}", repositoryGroup.getId(), e.getMessage(), e);
184             throw new RepositoryAdminException("Removal of repository failed: " + e.getMessage(), e);
185         }
186         mergedRemoteIndexesScheduler.unschedule(
187             repositoryGroup );
188         triggerAuditEvent( repositoryGroupId, null, AuditEvent.DELETE_REPO_GROUP, auditInformation );
189
190         return Boolean.TRUE;
191     }
192
193     @Override
194     public Boolean updateRepositoryGroup( RepositoryGroup repositoryGroup, AuditInformation auditInformation )
195         throws RepositoryAdminException
196     {
197         return updateRepositoryGroup( repositoryGroup, auditInformation, true );
198     }
199
200     private Boolean updateRepositoryGroup( RepositoryGroup repositoryGroup, AuditInformation auditInformation,
201                                            boolean triggerAuditEvent )
202         throws RepositoryAdminException
203     {
204         validateRepositoryGroup( repositoryGroup, true );
205         validateManagedRepositoriesExists( repositoryGroup.getRepositories() );
206
207
208         Configuration configuration = getArchivaConfiguration().getConfiguration();
209
210         RepositoryGroupConfiguration repositoryGroupConfiguration =
211             configuration.getRepositoryGroupsAsMap().get( repositoryGroup.getId() );
212
213         repositoryGroupConfiguration.setRepositories( repositoryGroup.getRepositories() );
214         repositoryGroupConfiguration.setMergedIndexPath( repositoryGroup.getMergedIndexPath() );
215         repositoryGroupConfiguration.setMergedIndexTtl( repositoryGroup.getMergedIndexTtl() );
216         repositoryGroupConfiguration.setCronExpression( repositoryGroup.getCronExpression() );
217         try {
218             repositoryRegistry.putRepositoryGroup(repositoryGroupConfiguration);
219         } catch (RepositoryException e) {
220             log.error( "Could not update the repository group in the registry: {}", e.getMessage( ), e );
221             throw RepositoryAdminException.ofKey( "repository_group.registry.update_error", e, repositoryGroup.getId(), e.getMessage() );
222         }
223
224         org.apache.archiva.repository.RepositoryGroup rg = repositoryRegistry.getRepositoryGroup( repositoryGroup.getId( ) );
225         mergedRemoteIndexesScheduler.unschedule( rg );
226         mergedRemoteIndexesScheduler.schedule( rg, getMergedIndexDirectory( repositoryGroup.getId() ) );
227         triggerAuditEvent( repositoryGroup.getId(), null, AuditEvent.MODIFY_REPO_GROUP, auditInformation );
228         return Boolean.TRUE;
229     }
230
231
232     @Override
233     public Boolean addRepositoryToGroup( String repositoryGroupId, String repositoryId,
234                                          AuditInformation auditInformation )
235         throws RepositoryAdminException
236     {
237         org.apache.archiva.repository.RepositoryGroup repositoryGroup = repositoryRegistry.getRepositoryGroup( repositoryGroupId );
238         if ( repositoryGroup == null )
239         {
240             throw EntityNotFoundException.ofMessage(
241                     "Repository group with id " + repositoryGroupId + " doesn't not exists so cannot add repository to it", repositoryGroupId );
242         }
243
244         if (!(repositoryGroup instanceof EditableRepositoryGroup)) {
245             throw RepositoryAdminException.ofKey("repository_group.not_editable",repositoryGroupId);
246         }
247         EditableRepositoryGroup editableRepositoryGroup = (EditableRepositoryGroup) repositoryGroup;
248         if ( editableRepositoryGroup.getRepositories().stream().anyMatch( repo -> repositoryId.equals(repo.getId())) )
249         {
250             throw new EntityExistsException(
251                 "Repository group with id " + repositoryGroupId + " already contain repository with id" + repositoryId );
252         }
253         org.apache.archiva.repository.ManagedRepository managedRepo = repositoryRegistry.getManagedRepository(repositoryId);
254         if (managedRepo==null) {
255             throw EntityNotFoundException.ofMessage("Repository with id "+repositoryId+" does not exist", repositoryId );
256         }
257
258         editableRepositoryGroup.addRepository( managedRepo );
259         try {
260             repositoryRegistry.putRepositoryGroup(editableRepositoryGroup);
261         } catch (RepositoryException e) {
262             throw new RepositoryAdminException("Could not store the repository group "+repositoryGroupId, e);
263         }
264         triggerAuditEvent( repositoryGroup.getId(), null, AuditEvent.ADD_REPO_TO_GROUP, auditInformation );
265         return Boolean.TRUE;
266     }
267
268     @Override
269     public Boolean deleteRepositoryFromGroup( String repositoryGroupId, String repositoryId,
270                                               AuditInformation auditInformation )
271         throws RepositoryAdminException
272     {
273         org.apache.archiva.repository.RepositoryGroup repositoryGroup = repositoryRegistry.getRepositoryGroup( repositoryGroupId );
274         if ( repositoryGroup == null )
275         {
276             throw EntityNotFoundException.ofMessage( "Repository group with id " + repositoryGroupId
277                                                     + " doesn't not exists so cannot remove repository from it", repositoryGroupId );
278         }
279
280         if ( !repositoryGroup.getRepositories().stream().anyMatch( repo -> repositoryId.equals(repo.getId()) ) )
281         {
282             throw EntityNotFoundException.ofMessage(
283                 "repositoryGroup with id " + repositoryGroupId + " doesn't not contains repository with id"
284                     + repositoryId, repositoryId
285             );
286         }
287
288         if (!(repositoryGroup instanceof EditableRepositoryGroup)) {
289             throw RepositoryAdminException.ofKey("repository_group.not_editable",repositoryGroupId);
290         }
291         EditableRepositoryGroup editableRepositoryGroup = (EditableRepositoryGroup) repositoryGroup;
292
293         editableRepositoryGroup.removeRepository( repositoryId );
294         try {
295             repositoryRegistry.putRepositoryGroup(editableRepositoryGroup);
296         } catch (RepositoryException e) {
297             throw new RepositoryAdminException("Could not store repository group " + repositoryGroupId, e);
298         }
299         triggerAuditEvent( repositoryGroup.getId(), null, AuditEvent.DELETE_REPO_FROM_GROUP, auditInformation );
300         return Boolean.TRUE;
301     }
302
303     @Override
304     public Map<String, RepositoryGroup> getRepositoryGroupsAsMap()
305         throws RepositoryAdminException
306     {
307         List<RepositoryGroup> repositoriesGroups = getRepositoriesGroups();
308         Map<String, RepositoryGroup> map = new HashMap<>( repositoriesGroups.size() );
309         for ( RepositoryGroup repositoryGroup : repositoriesGroups )
310         {
311             map.put( repositoryGroup.getId(), repositoryGroup );
312         }
313         return map;
314     }
315
316     @Override
317     public Map<String, List<String>> getGroupToRepositoryMap()
318         throws RepositoryAdminException
319     {
320
321         Map<String, List<String>> map = new HashMap<>();
322
323         for ( ManagedRepository repo : getManagedRepositoryAdmin().getManagedRepositories() )
324         {
325             for ( RepositoryGroup group : getRepositoriesGroups() )
326             {
327                 if ( !group.getRepositories().contains( repo.getId() ) )
328                 {
329                     String groupId = group.getId();
330                     List<String> repos = map.get( groupId );
331                     if ( repos == null )
332                     {
333                         repos = new ArrayList<>();
334                         map.put( groupId, repos );
335                     }
336                     repos.add( repo.getId() );
337                 }
338             }
339         }
340         return map;
341     }
342
343     @Override
344     public Map<String, List<String>> getRepositoryToGroupMap()
345         throws RepositoryAdminException
346     {
347         Map<String, List<String>> map = new HashMap<>();
348
349         for ( RepositoryGroup group : getRepositoriesGroups() )
350         {
351             for ( String repositoryId : group.getRepositories() )
352             {
353                 List<String> groups = map.get( repositoryId );
354                 if ( groups == null )
355                 {
356                     groups = new ArrayList<>();
357                     map.put( repositoryId, groups );
358                 }
359                 groups.add( group.getId() );
360             }
361         }
362         return map;
363     }
364
365     public Boolean validateRepositoryGroup( RepositoryGroup repositoryGroup, boolean updateMode )
366         throws RepositoryAdminException
367     {
368         String repoGroupId = repositoryGroup.getId();
369         if ( StringUtils.isBlank( repoGroupId ) )
370         {
371             throw RepositoryAdminException.ofKey("repository_group.id.empty" );
372         }
373
374         if ( repoGroupId.length() > 100 )
375         {
376             throw RepositoryAdminException.ofKey("repository_group.id.max_length",repoGroupId, Integer.toString( 100 ));
377
378         }
379
380         Matcher matcher = REPO_GROUP_ID_PATTERN.matcher( repoGroupId );
381         if ( !matcher.matches() )
382         {
383             throw RepositoryAdminException.ofKey("repository_group.id.invalid_chars","alphanumeric, '.', '-','_'" );
384         }
385
386         if ( repositoryGroup.getMergedIndexTtl() <= 0 )
387         {
388             throw RepositoryAdminException.ofKey("repository_group.merged_index_ttl.min","0" );
389         }
390
391         Configuration configuration = getArchivaConfiguration().getConfiguration();
392
393         if ( configuration.getRepositoryGroupsAsMap().containsKey( repoGroupId ) )
394         {
395             if ( !updateMode )
396             {
397                 throw new EntityExistsException( "Unable to add new repository group with id [" + repoGroupId
398                                                         + "], that id already exists as a repository group." );
399             }
400         }
401         else if ( configuration.getManagedRepositoriesAsMap().containsKey( repoGroupId ) )
402         {
403             throw new EntityExistsException( "Unable to add new repository group with id [" + repoGroupId
404                                                     + "], that id already exists as a managed repository." );
405         }
406         else if ( configuration.getRemoteRepositoriesAsMap().containsKey( repoGroupId ) )
407         {
408             throw new EntityExistsException( "Unable to add new repository group with id [" + repoGroupId
409                                                     + "], that id already exists as a remote repository." );
410         }
411
412         return Boolean.TRUE;
413     }
414
415     private void validateManagedRepositoriesExists( List<String> managedRepositoriesIds )
416         throws RepositoryAdminException
417     {
418         for ( String id : managedRepositoriesIds )
419         {
420             if ( getManagedRepositoryAdmin().getManagedRepository( id ) == null )
421             {
422                 throw RepositoryAdminException.ofKey("repository_group.repository.not_found",id );
423             }
424         }
425     }
426
427     public ManagedRepositoryAdmin getManagedRepositoryAdmin()
428     {
429         return managedRepositoryAdmin;
430     }
431
432     public void setManagedRepositoryAdmin( ManagedRepositoryAdmin managedRepositoryAdmin )
433     {
434         this.managedRepositoryAdmin = managedRepositoryAdmin;
435     }
436
437     private RepositoryGroup convertRepositoryGroupObject( org.apache.archiva.repository.RepositoryGroup group ) {
438         RepositoryGroup rg = new RepositoryGroup( group.getId( ), group.getRepositories().stream().map(r -> r.getId()).collect( Collectors.toList()) );
439         if (group.supportsFeature( IndexCreationFeature.class ))
440         {
441             IndexCreationFeature indexCreationFeature = group.getFeature( IndexCreationFeature.class ).get();
442             rg.setMergedIndexPath( indexCreationFeature.getIndexPath().getPath() );
443         }
444         rg.setCronExpression( group.getSchedulingDefinition() );
445         rg.setMergedIndexTtl( group.getMergedIndexTTL() );
446         rg.setLocation( group.getLocation().toString() );
447         return rg;
448     }
449
450     @Override
451     public void handle( Event event )
452     {
453         if ( EventType.isInstanceOf( event.getType( ), RepositoryRegistryEvent.INITIALIZED ) )
454         {
455             log.debug( "Initializing RepositoryGroupAdmin" );
456             initialize();
457         }
458     }
459 }