001    package org.apache.archiva.consumers.core.repository;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *  http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import org.apache.archiva.admin.model.RepositoryAdminException;
023    import org.apache.archiva.admin.model.beans.ManagedRepository;
024    import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
025    import org.apache.archiva.metadata.repository.MetadataRepository;
026    import org.apache.archiva.metadata.repository.RepositorySession;
027    import org.apache.archiva.repository.events.RepositoryListener;
028    import org.apache.archiva.common.utils.VersionComparator;
029    import org.apache.archiva.common.utils.VersionUtil;
030    import org.apache.archiva.model.ArtifactReference;
031    import org.apache.archiva.model.ProjectReference;
032    import org.apache.archiva.model.VersionedReference;
033    import org.apache.archiva.repository.ContentNotFoundException;
034    import org.apache.archiva.repository.ManagedRepositoryContent;
035    import org.apache.archiva.repository.RepositoryContentFactory;
036    import org.apache.archiva.repository.RepositoryException;
037    import org.apache.archiva.repository.RepositoryNotFoundException;
038    import org.apache.archiva.repository.layout.LayoutException;
039    import org.apache.archiva.repository.metadata.MetadataTools;
040    import org.apache.archiva.repository.metadata.RepositoryMetadataException;
041    
042    import java.io.File;
043    import java.io.IOException;
044    import java.util.ArrayList;
045    import java.util.Collections;
046    import java.util.List;
047    
048    /**
049     * <p>
050     * This will look in a single managed repository, and purge any snapshots that are present
051     * that have a corresponding released version on the same repository.
052     * </p>
053     * <p/>
054     * <p>
055     * So, if you have the following (presented in the m2/default layout form) ...
056     * <pre>
057     *   /com/foo/foo-tool/1.0-SNAPSHOT/foo-tool-1.0-SNAPSHOT.jar
058     *   /com/foo/foo-tool/1.1-SNAPSHOT/foo-tool-1.1-SNAPSHOT.jar
059     *   /com/foo/foo-tool/1.2.1-SNAPSHOT/foo-tool-1.2.1-SNAPSHOT.jar
060     *   /com/foo/foo-tool/1.2.1/foo-tool-1.2.1.jar
061     *   /com/foo/foo-tool/2.0-SNAPSHOT/foo-tool-2.0-SNAPSHOT.jar
062     *   /com/foo/foo-tool/2.0/foo-tool-2.0.jar
063     *   /com/foo/foo-tool/2.1-SNAPSHOT/foo-tool-2.1-SNAPSHOT.jar
064     * </pre>
065     * then the current highest ranked released (non-snapshot) version is 2.0, which means
066     * the snapshots from 1.0-SNAPSHOT, 1.1-SNAPSHOT, 1.2.1-SNAPSHOT, and 2.0-SNAPSHOT can
067     * be purged.  Leaving 2.1-SNAPSHOT in alone.
068     * </p>
069     *
070     *
071     */
072    public class CleanupReleasedSnapshotsRepositoryPurge
073        extends AbstractRepositoryPurge
074    {
075        private MetadataTools metadataTools;
076    
077        private ManagedRepositoryAdmin managedRepositoryAdmin;
078    
079        private RepositoryContentFactory repoContentFactory;
080    
081        public CleanupReleasedSnapshotsRepositoryPurge( ManagedRepositoryContent repository, MetadataTools metadataTools,
082                                                        ManagedRepositoryAdmin managedRepositoryAdmin,
083                                                        RepositoryContentFactory repoContentFactory,
084                                                        RepositorySession repositorySession,
085                                                        List<RepositoryListener> listeners )
086        {
087            super( repository, repositorySession, listeners );
088            this.metadataTools = metadataTools;
089            this.managedRepositoryAdmin = managedRepositoryAdmin;
090            this.repoContentFactory = repoContentFactory;
091        }
092    
093        public void process( String path )
094            throws RepositoryPurgeException
095        {
096            try
097            {
098                File artifactFile = new File( repository.getRepoRoot(), path );
099    
100                if ( !artifactFile.exists() )
101                {
102                    // Nothing to do here, file doesn't exist, skip it.
103                    return;
104                }
105    
106                ArtifactReference artifactRef = repository.toArtifactReference( path );
107    
108                if ( !VersionUtil.isSnapshot( artifactRef.getVersion() ) )
109                {
110                    // Nothing to do here, not a snapshot, skip it.
111                    return;
112                }
113    
114                ProjectReference reference = new ProjectReference();
115                reference.setGroupId( artifactRef.getGroupId() );
116                reference.setArtifactId( artifactRef.getArtifactId() );
117    
118                // Gether the released versions
119                List<String> releasedVersions = new ArrayList<String>();
120    
121                List<ManagedRepository> repos = managedRepositoryAdmin.getManagedRepositories();
122                for ( ManagedRepository repo : repos )
123                {
124                    if ( repo.isReleases() )
125                    {
126                        try
127                        {
128                            ManagedRepositoryContent repoContent =
129                                repoContentFactory.getManagedRepositoryContent( repo.getId() );
130                            for ( String version : repoContent.getVersions( reference ) )
131                            {
132                                if ( !VersionUtil.isSnapshot( version ) )
133                                {
134                                    releasedVersions.add( version );
135                                }
136                            }
137                        }
138                        catch ( RepositoryNotFoundException e )
139                        {
140                            // swallow
141                        }
142                        catch ( RepositoryException e )
143                        {
144                            // swallow
145                        }
146                    }
147                }
148    
149                Collections.sort( releasedVersions, VersionComparator.getInstance() );
150    
151                // Now clean out any version that is earlier than the highest released version.
152                boolean needsMetadataUpdate = false;
153    
154                VersionedReference versionRef = new VersionedReference();
155                versionRef.setGroupId( artifactRef.getGroupId() );
156                versionRef.setArtifactId( artifactRef.getArtifactId() );
157    
158                MetadataRepository metadataRepository = repositorySession.getRepository();
159    
160                if ( releasedVersions.contains( VersionUtil.getReleaseVersion( artifactRef.getVersion() ) ) )
161                {
162                    versionRef.setVersion( artifactRef.getVersion() );
163                    repository.deleteVersion( versionRef );
164    
165                    // FIXME: looks incomplete, might not delete related metadata?
166                    for ( RepositoryListener listener : listeners )
167                    {
168                        listener.deleteArtifact( metadataRepository, repository.getId(), artifactRef.getGroupId(),
169                                                 artifactRef.getArtifactId(), artifactRef.getVersion(),
170                                                 artifactFile.getName() );
171                    }
172    
173                    needsMetadataUpdate = true;
174                }
175    
176                if ( needsMetadataUpdate )
177                {
178                    updateMetadata( artifactRef );
179                }
180            } catch ( RepositoryAdminException e )
181            {
182                throw new RepositoryPurgeException( e.getMessage(), e );
183            }
184            catch ( LayoutException e )
185            {
186                log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
187            }
188            catch ( ContentNotFoundException e )
189            {
190                throw new RepositoryPurgeException( e.getMessage(), e );
191            }
192        }
193    
194        private void updateMetadata( ArtifactReference artifact )
195        {
196            VersionedReference versionRef = new VersionedReference();
197            versionRef.setGroupId( artifact.getGroupId() );
198            versionRef.setArtifactId( artifact.getArtifactId() );
199            versionRef.setVersion( artifact.getVersion() );
200    
201            ProjectReference projectRef = new ProjectReference();
202            projectRef.setGroupId( artifact.getGroupId() );
203            projectRef.setArtifactId( artifact.getArtifactId() );
204    
205            try
206            {
207                metadataTools.updateMetadata( repository, versionRef );
208            }
209            catch ( ContentNotFoundException e )
210            {
211                // Ignore. (Just means we have no snapshot versions left to reference).
212            }
213            catch ( RepositoryMetadataException e )
214            {
215                // Ignore. 
216            }
217            catch ( IOException e )
218            {
219                // Ignore. 
220            }
221            catch ( LayoutException e )
222            {
223                // Ignore.
224            }
225    
226            try
227            {
228                metadataTools.updateMetadata( repository, projectRef );
229            }
230            catch ( ContentNotFoundException e )
231            {
232                // Ignore. (Just means we have no snapshot versions left to reference).
233            }
234            catch ( RepositoryMetadataException e )
235            {
236                // Ignore. 
237            }
238            catch ( IOException e )
239            {
240                // Ignore. 
241            }
242            catch ( LayoutException e )
243            {
244                // Ignore.
245            }
246        }
247    }