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