001    package org.apache.archiva.admin.repository.group;
002    /*
003     * Licensed to the Apache Software Foundation (ASF) under one
004     * or more contributor license agreements.  See the NOTICE file
005     * distributed with this work for additional information
006     * regarding copyright ownership.  The ASF licenses this file
007     * to you under the Apache License, Version 2.0 (the
008     * "License"); you may not use this file except in compliance
009     * with the License.  You may obtain a copy of the License at
010     *
011     *   http://www.apache.org/licenses/LICENSE-2.0
012     *
013     * Unless required by applicable law or agreed to in writing,
014     * software distributed under the License is distributed on an
015     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016     * KIND, either express or implied.  See the License for the
017     * specific language governing permissions and limitations
018     * under the License.
019     */
020    
021    import org.apache.archiva.admin.model.AuditInformation;
022    import org.apache.archiva.admin.model.RepositoryAdminException;
023    import org.apache.archiva.admin.model.beans.ManagedRepository;
024    import org.apache.archiva.admin.model.beans.RepositoryGroup;
025    import org.apache.archiva.admin.model.group.RepositoryGroupAdmin;
026    import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
027    import org.apache.archiva.admin.repository.AbstractRepositoryAdmin;
028    import org.apache.archiva.audit.AuditEvent;
029    import org.apache.archiva.configuration.Configuration;
030    import org.apache.archiva.configuration.RepositoryGroupConfiguration;
031    import org.apache.commons.lang.StringUtils;
032    import org.slf4j.Logger;
033    import org.slf4j.LoggerFactory;
034    import org.springframework.stereotype.Service;
035    
036    import javax.inject.Inject;
037    import java.util.ArrayList;
038    import java.util.Arrays;
039    import java.util.HashMap;
040    import java.util.List;
041    import java.util.Map;
042    import java.util.regex.Matcher;
043    import java.util.regex.Pattern;
044    
045    /**
046     * @author Olivier Lamy
047     */
048    @Service("repositoryGroupAdmin#default")
049    public class DefaultRepositoryGroupAdmin
050        extends AbstractRepositoryAdmin
051        implements RepositoryGroupAdmin
052    {
053    
054        private Logger log = LoggerFactory.getLogger( getClass() );
055    
056        private static final Pattern REPO_GROUP_ID_PATTERN = Pattern.compile( "[A-Za-z0-9\\._\\-]+" );
057    
058        @Inject
059        private ManagedRepositoryAdmin managedRepositoryAdmin;
060    
061        public List<RepositoryGroup> getRepositoriesGroups()
062            throws RepositoryAdminException
063        {
064            List<RepositoryGroup> repositoriesGroups =
065                new ArrayList<RepositoryGroup>( getArchivaConfiguration().getConfiguration().getRepositoryGroups().size() );
066    
067            for ( RepositoryGroupConfiguration repositoryGroupConfiguration : getArchivaConfiguration().getConfiguration().getRepositoryGroups() )
068            {
069                repositoriesGroups.add( new RepositoryGroup( repositoryGroupConfiguration.getId(), new ArrayList<String>(
070                    repositoryGroupConfiguration.getRepositories() ) ).mergedIndexPath(
071                    repositoryGroupConfiguration.getMergedIndexPath() ).mergedIndexTtl( repositoryGroupConfiguration.getMergedIndexTtl() ) );
072            }
073    
074            return repositoriesGroups;
075        }
076    
077        public RepositoryGroup getRepositoryGroup( String repositoryGroupId )
078            throws RepositoryAdminException
079        {
080            List<RepositoryGroup> repositoriesGroups = getRepositoriesGroups();
081            for ( RepositoryGroup repositoryGroup : repositoriesGroups )
082            {
083                if ( StringUtils.equals( repositoryGroupId, repositoryGroup.getId() ) )
084                {
085                    return repositoryGroup;
086                }
087            }
088            return null;
089        }
090    
091        public Boolean addRepositoryGroup( RepositoryGroup repositoryGroup, AuditInformation auditInformation )
092            throws RepositoryAdminException
093        {
094            validateRepositoryGroup( repositoryGroup, false );
095            validateManagedRepositoriesExists( repositoryGroup.getRepositories() );
096    
097            RepositoryGroupConfiguration repositoryGroupConfiguration = new RepositoryGroupConfiguration();
098            repositoryGroupConfiguration.setId( repositoryGroup.getId() );
099            repositoryGroupConfiguration.setRepositories( repositoryGroup.getRepositories() );
100            repositoryGroupConfiguration.setMergedIndexPath( repositoryGroup.getMergedIndexPath() );
101            repositoryGroupConfiguration.setMergedIndexTtl( repositoryGroup.getMergedIndexTtl() );
102            Configuration configuration = getArchivaConfiguration().getConfiguration();
103            configuration.addRepositoryGroup( repositoryGroupConfiguration );
104            saveConfiguration( configuration );
105            triggerAuditEvent( repositoryGroup.getId(), null, AuditEvent.ADD_REPO_GROUP, auditInformation );
106            return Boolean.TRUE;
107        }
108    
109        public Boolean deleteRepositoryGroup( String repositoryGroupId, AuditInformation auditInformation )
110            throws RepositoryAdminException
111        {
112            Configuration configuration = getArchivaConfiguration().getConfiguration();
113            RepositoryGroupConfiguration repositoryGroupConfiguration =
114                configuration.getRepositoryGroupsAsMap().get( repositoryGroupId );
115            if ( repositoryGroupConfiguration == null )
116            {
117                throw new RepositoryAdminException(
118                    "repositoryGroup with id " + repositoryGroupId + " doesn't not exists so cannot remove" );
119            }
120            configuration.removeRepositoryGroup( repositoryGroupConfiguration );
121            triggerAuditEvent( repositoryGroupId, null, AuditEvent.DELETE_REPO_GROUP, auditInformation );
122            return Boolean.TRUE;
123        }
124    
125        public Boolean updateRepositoryGroup( RepositoryGroup repositoryGroup, AuditInformation auditInformation )
126            throws RepositoryAdminException
127        {
128            return updateRepositoryGroup( repositoryGroup, auditInformation, true );
129        }
130    
131        private Boolean updateRepositoryGroup( RepositoryGroup repositoryGroup, AuditInformation auditInformation,
132                                               boolean triggerAuditEvent )
133            throws RepositoryAdminException
134        {
135            validateRepositoryGroup( repositoryGroup, true );
136            validateManagedRepositoriesExists( repositoryGroup.getRepositories() );
137            Configuration configuration = getArchivaConfiguration().getConfiguration();
138    
139            RepositoryGroupConfiguration repositoryGroupConfiguration =
140                configuration.getRepositoryGroupsAsMap().get( repositoryGroup.getId() );
141    
142            configuration.removeRepositoryGroup( repositoryGroupConfiguration );
143    
144            repositoryGroupConfiguration.setRepositories( repositoryGroup.getRepositories() );
145            repositoryGroupConfiguration.setMergedIndexPath( repositoryGroup.getMergedIndexPath() );
146            repositoryGroupConfiguration.setMergedIndexTtl( repositoryGroup.getMergedIndexTtl() );
147            configuration.addRepositoryGroup( repositoryGroupConfiguration );
148    
149            saveConfiguration( configuration );
150            if ( triggerAuditEvent )
151            {
152                triggerAuditEvent( repositoryGroup.getId(), null, AuditEvent.MODIFY_REPO_GROUP, auditInformation );
153            }
154            return Boolean.TRUE;
155        }
156    
157    
158        public Boolean addRepositoryToGroup( String repositoryGroupId, String repositoryId,
159                                             AuditInformation auditInformation )
160            throws RepositoryAdminException
161        {
162            RepositoryGroup repositoryGroup = getRepositoryGroup( repositoryGroupId );
163            if ( repositoryGroup == null )
164            {
165                throw new RepositoryAdminException(
166                    "repositoryGroup with id " + repositoryGroupId + " doesn't not exists so cannot add repository to it" );
167            }
168    
169            if ( repositoryGroup.getRepositories().contains( repositoryId ) )
170            {
171                throw new RepositoryAdminException(
172                    "repositoryGroup with id " + repositoryGroupId + " already contain repository with id" + repositoryId );
173            }
174            validateManagedRepositoriesExists( Arrays.asList( repositoryId ) );
175    
176            repositoryGroup.addRepository( repositoryId );
177            updateRepositoryGroup( repositoryGroup, auditInformation, false );
178            triggerAuditEvent( repositoryGroup.getId(), null, AuditEvent.ADD_REPO_TO_GROUP, auditInformation );
179            return Boolean.TRUE;
180        }
181    
182        public Boolean deleteRepositoryFromGroup( String repositoryGroupId, String repositoryId,
183                                                  AuditInformation auditInformation )
184            throws RepositoryAdminException
185        {
186            RepositoryGroup repositoryGroup = getRepositoryGroup( repositoryGroupId );
187            if ( repositoryGroup == null )
188            {
189                throw new RepositoryAdminException( "repositoryGroup with id " + repositoryGroupId
190                                                        + " doesn't not exists so cannot remove repository from it" );
191            }
192    
193            if ( !repositoryGroup.getRepositories().contains( repositoryId ) )
194            {
195                throw new RepositoryAdminException(
196                    "repositoryGroup with id " + repositoryGroupId + " doesn't not contains repository with id"
197                        + repositoryId );
198            }
199    
200            repositoryGroup.removeRepository( repositoryId );
201            updateRepositoryGroup( repositoryGroup, auditInformation, false );
202            triggerAuditEvent( repositoryGroup.getId(), null, AuditEvent.DELETE_REPO_FROM_GROUP, auditInformation );
203            return Boolean.TRUE;
204        }
205    
206        public Map<String, RepositoryGroup> getRepositoryGroupsAsMap()
207            throws RepositoryAdminException
208        {
209            List<RepositoryGroup> repositoriesGroups = getRepositoriesGroups();
210            Map<String, RepositoryGroup> map = new HashMap<String, RepositoryGroup>( repositoriesGroups.size() );
211            for ( RepositoryGroup repositoryGroup : repositoriesGroups )
212            {
213                map.put( repositoryGroup.getId(), repositoryGroup );
214            }
215            return map;
216        }
217    
218        public Map<String, List<String>> getGroupToRepositoryMap()
219            throws RepositoryAdminException
220        {
221    
222            java.util.Map<String, java.util.List<String>> map = new java.util.HashMap<String, java.util.List<String>>();
223    
224            for ( ManagedRepository repo : getManagedRepositoryAdmin().getManagedRepositories() )
225            {
226                for ( RepositoryGroup group : getRepositoriesGroups() )
227                {
228                    if ( !group.getRepositories().contains( repo.getId() ) )
229                    {
230                        String groupId = group.getId();
231                        java.util.List<String> repos = map.get( groupId );
232                        if ( repos == null )
233                        {
234                            repos = new ArrayList<String>();
235                            map.put( groupId, repos );
236                        }
237                        repos.add( repo.getId() );
238                    }
239                }
240            }
241            return map;
242        }
243    
244        public Map<String, List<String>> getRepositoryToGroupMap()
245            throws RepositoryAdminException
246        {
247            java.util.Map<String, java.util.List<String>> map = new java.util.HashMap<String, java.util.List<String>>();
248    
249            for ( RepositoryGroup group : getRepositoriesGroups() )
250            {
251                for ( String repositoryId : group.getRepositories() )
252                {
253                    java.util.List<String> groups = map.get( repositoryId );
254                    if ( groups == null )
255                    {
256                        groups = new ArrayList<String>();
257                        map.put( repositoryId, groups );
258                    }
259                    groups.add( group.getId() );
260                }
261            }
262            return map;
263        }
264    
265        public Boolean validateRepositoryGroup( RepositoryGroup repositoryGroup, boolean updateMode )
266            throws RepositoryAdminException
267        {
268            String repoGroupId = repositoryGroup.getId();
269            if ( StringUtils.isBlank( repoGroupId ) )
270            {
271                throw new RepositoryAdminException( "repositoryGroup id cannot be empty" );
272            }
273    
274            if ( repoGroupId.length() > 100 )
275            {
276                throw new RepositoryAdminException(
277                    "Identifier [" + repoGroupId + "] is over the maximum limit of 100 characters" );
278    
279            }
280    
281            Matcher matcher = REPO_GROUP_ID_PATTERN.matcher( repoGroupId );
282            if ( !matcher.matches() )
283            {
284                throw new RepositoryAdminException(
285                    "Invalid character(s) found in identifier. Only the following characters are allowed: alphanumeric, '.', '-' and '_'" );
286            }
287    
288            if ( repositoryGroup.getMergedIndexTtl() <= 0)
289            {
290                throw new RepositoryAdminException( "Merged Index TTL must be greater than 0." );
291            }
292    
293            Configuration configuration = getArchivaConfiguration().getConfiguration();
294    
295            if ( configuration.getRepositoryGroupsAsMap().containsKey( repoGroupId ) )
296            {
297                if ( !updateMode )
298                {
299                    throw new RepositoryAdminException( "Unable to add new repository group with id [" + repoGroupId
300                                                            + "], that id already exists as a repository group." );
301                }
302            }
303            else if ( configuration.getManagedRepositoriesAsMap().containsKey( repoGroupId ) )
304            {
305                throw new RepositoryAdminException( "Unable to add new repository group with id [" + repoGroupId
306                                                        + "], that id already exists as a managed repository." );
307            }
308            else if ( configuration.getRemoteRepositoriesAsMap().containsKey( repoGroupId ) )
309            {
310                throw new RepositoryAdminException( "Unable to add new repository group with id [" + repoGroupId
311                                                        + "], that id already exists as a remote repository." );
312            }
313    
314            return Boolean.TRUE;
315        }
316    
317        private void validateManagedRepositoriesExists( List<String> managedRepositoriesIds )
318            throws RepositoryAdminException
319        {
320            for ( String id : managedRepositoriesIds )
321            {
322                if ( getManagedRepositoryAdmin().getManagedRepository( id ) == null )
323                {
324                    throw new RepositoryAdminException(
325                        "managedRepository with id " + id + " not exists so cannot be used in a repositoryGroup" );
326                }
327            }
328        }
329    
330        public ManagedRepositoryAdmin getManagedRepositoryAdmin()
331        {
332            return managedRepositoryAdmin;
333        }
334    
335        public void setManagedRepositoryAdmin( ManagedRepositoryAdmin managedRepositoryAdmin )
336        {
337            this.managedRepositoryAdmin = managedRepositoryAdmin;
338        }
339    }