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.audit.AuditEvent;
023    import org.apache.archiva.common.utils.VersionUtil;
024    import org.apache.archiva.metadata.model.ArtifactMetadata;
025    import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
026    import org.apache.archiva.metadata.repository.MetadataRepository;
027    import org.apache.archiva.metadata.repository.MetadataRepositoryException;
028    import org.apache.archiva.metadata.repository.MetadataResolutionException;
029    import org.apache.archiva.metadata.repository.RepositorySession;
030    import org.apache.archiva.model.ArtifactReference;
031    import org.apache.archiva.repository.ContentNotFoundException;
032    import org.apache.archiva.repository.ManagedRepositoryContent;
033    import org.apache.archiva.repository.events.RepositoryListener;
034    import org.apache.commons.lang.StringUtils;
035    import org.slf4j.Logger;
036    import org.slf4j.LoggerFactory;
037    
038    import java.io.File;
039    import java.io.FilenameFilter;
040    import java.util.Collection;
041    import java.util.List;
042    import java.util.Set;
043    
044    /**
045     * Base class for all repository purge tasks.
046     */
047    public abstract class AbstractRepositoryPurge
048        implements RepositoryPurge
049    {
050        protected Logger log = LoggerFactory.getLogger( getClass() );
051    
052        protected final ManagedRepositoryContent repository;
053    
054        protected final RepositorySession repositorySession;
055    
056        protected final List<RepositoryListener> listeners;
057    
058        private Logger logger = LoggerFactory.getLogger( "org.apache.archiva.AuditLog" );
059    
060        private static final char DELIM = ' ';
061    
062        public AbstractRepositoryPurge( ManagedRepositoryContent repository, RepositorySession repositorySession,
063                                        List<RepositoryListener> listeners )
064        {
065            this.repository = repository;
066            this.repositorySession = repositorySession;
067            this.listeners = listeners;
068        }
069    
070        /**
071         * Purge the repo. Update db and index of removed artifacts.
072         *
073         * @param references
074         */
075        protected void purge( Set<ArtifactReference> references )
076        {
077            if ( references != null && !references.isEmpty() )
078            {
079                MetadataRepository metadataRepository = repositorySession.getRepository();
080                for ( ArtifactReference reference : references )
081                {
082                    File artifactFile = repository.toFile( reference );
083    
084                    for ( RepositoryListener listener : listeners )
085                    {
086                        listener.deleteArtifact( metadataRepository, repository.getId(), reference.getGroupId(),
087                                                 reference.getArtifactId(), reference.getVersion(),
088                                                 artifactFile.getName() );
089                    }
090    
091                    // TODO: this needs to be logged
092                    artifactFile.delete();
093                    try
094                    {
095                        repository.deleteArtifact( reference );
096                    }
097                    catch ( ContentNotFoundException e )
098                    {
099                        log.warn( "skip error deleting artifact {}: {}", reference, e.getMessage() );
100                    }
101    
102                    try
103                    {
104                        metadataRepository.removeProjectVersion( repository.getId(), reference.getGroupId(),
105                                                                 reference.getArtifactId(), reference.getVersion() );
106                    }
107                    catch ( MetadataRepositoryException e )
108                    {
109                        log.warn( "skip error removeProjectVersion artifact {}: {}", reference, e.getMessage() );
110                    }
111    
112                    boolean snapshotVersion = VersionUtil.isSnapshot( reference.getVersion() );
113    
114                    try
115                    {
116                        if ( snapshotVersion )
117                        {
118                            String baseVersion = VersionUtil.getBaseVersion( reference.getVersion() );
119                            Collection<ArtifactMetadata> artifacts =
120                                metadataRepository.getArtifacts( repository.getId(), reference.getGroupId(),
121                                                                 reference.getArtifactId(), baseVersion );
122                            if ( artifacts != null )
123                            {
124                                // cleanup snapshots metadata
125                                for ( ArtifactMetadata artifactMetadata : artifacts )
126                                {
127    
128                                    // TODO: mismatch between artifact (snapshot) version and project (base) version here
129                                    if ( artifactMetadata.getVersion().equals( reference.getVersion() ) )
130                                    {
131                                        if ( StringUtils.isNotBlank( reference.getClassifier() ) )
132                                        {
133    
134                                            // cleanup facet which contains classifier information
135                                            MavenArtifactFacet mavenArtifactFacet =
136                                                (MavenArtifactFacet) artifactMetadata.getFacet(
137                                                    MavenArtifactFacet.FACET_ID );
138    
139                                            if ( StringUtils.equals( reference.getClassifier(),
140                                                                     mavenArtifactFacet.getClassifier() ) )
141                                            {
142                                                artifactMetadata.removeFacet( MavenArtifactFacet.FACET_ID );
143                                                String groupId = reference.getGroupId(), artifactId =
144                                                    reference.getArtifactId(),
145                                                    version = reference.getVersion();
146                                                MavenArtifactFacet mavenArtifactFacetToCompare = new MavenArtifactFacet();
147                                                mavenArtifactFacetToCompare.setClassifier( reference.getClassifier() );
148                                                metadataRepository.removeArtifact( repository.getId(), groupId, artifactId,
149                                                                                   version, mavenArtifactFacetToCompare );
150                                                metadataRepository.save();
151                                            }
152    
153                                        }
154                                        else
155                                        {
156                                            metadataRepository.removeArtifact( artifactMetadata, VersionUtil.getBaseVersion(
157                                                reference.getVersion() ) );
158                                        }
159    
160                                    }
161                                }
162                            }
163                        }
164                    }
165                    catch ( MetadataResolutionException e )
166                    {
167                        log.warn( "skip error deleting metadata {}: {}", reference, e.getMessage() );
168                    }
169                    catch ( MetadataRepositoryException e )
170                    {
171                        log.warn( "skip error deleting metadata {}: {}", reference, e.getMessage() );
172                    }
173    
174                    repositorySession.save();
175    
176                    triggerAuditEvent( repository.getRepository().getId(), ArtifactReference.toKey( reference ),
177                                       AuditEvent.PURGE_ARTIFACT );
178                    purgeSupportFiles( artifactFile );
179                }
180            }
181        }
182    
183        /**
184         * <p>
185         * This find support files for the artifactFile and deletes them.
186         * </p>
187         * <p>
188         * Support Files are things like ".sha1", ".md5", ".asc", etc.
189         * </p>
190         *
191         * @param artifactFile the file to base off of.
192         */
193        private void purgeSupportFiles( File artifactFile )
194        {
195            File parentDir = artifactFile.getParentFile();
196    
197            if ( !parentDir.exists() )
198            {
199                return;
200            }
201    
202            FilenameFilter filter = new ArtifactFilenameFilter( artifactFile.getName() );
203    
204            File[] files = parentDir.listFiles( filter );
205    
206            for ( File file : files )
207            {
208                if ( file.exists() && file.isFile() )
209                {
210                    String fileName = file.getName();
211                    file.delete();
212                    // TODO: log that it was deleted
213                    triggerAuditEvent( repository.getRepository().getId(), fileName, AuditEvent.PURGE_FILE );
214                }
215            }
216        }
217    
218        private void triggerAuditEvent( String repoId, String resource, String action )
219        {
220            String msg =
221                repoId + DELIM + "<system-purge>" + DELIM + "<system>" + DELIM + '\"' + resource + '\"' + DELIM + '\"' +
222                    action + '\"';
223    
224            logger.info( msg );
225        }
226    }