001    package org.apache.archiva.consumers.core;
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.beans.ManagedRepository;
023    import org.apache.archiva.checksum.ChecksumAlgorithm;
024    import org.apache.archiva.checksum.ChecksummedFile;
025    import org.apache.archiva.configuration.ArchivaConfiguration;
026    import org.apache.archiva.configuration.ConfigurationNames;
027    import org.apache.archiva.configuration.FileTypes;
028    import org.apache.archiva.consumers.AbstractMonitoredConsumer;
029    import org.apache.archiva.consumers.ConsumerException;
030    import org.apache.archiva.consumers.KnownRepositoryContentConsumer;
031    import org.apache.archiva.redback.components.registry.Registry;
032    import org.apache.archiva.redback.components.registry.RegistryListener;
033    import org.springframework.context.annotation.Scope;
034    import org.springframework.stereotype.Service;
035    
036    import javax.annotation.PostConstruct;
037    import javax.inject.Inject;
038    import java.io.File;
039    import java.io.IOException;
040    import java.util.ArrayList;
041    import java.util.Date;
042    import java.util.List;
043    
044    /**
045     * ArtifactMissingChecksumsConsumer - Create missing and/or fix invalid checksums for the artifact.
046     *
047     *
048     */
049    @Service( "knownRepositoryContentConsumer#create-missing-checksums" )
050    @Scope( "prototype" )
051    public class ArtifactMissingChecksumsConsumer
052        extends AbstractMonitoredConsumer
053        implements KnownRepositoryContentConsumer, RegistryListener
054    {
055        private String id = "create-missing-checksums";
056    
057        private String description = "Create Missing and/or Fix Invalid Checksums (.sha1, .md5)";
058    
059        private ArchivaConfiguration configuration;
060    
061        private FileTypes filetypes;
062    
063        private ChecksummedFile checksum;
064    
065        private static final String TYPE_CHECKSUM_NOT_FILE = "checksum-bad-not-file";
066    
067        private static final String TYPE_CHECKSUM_CANNOT_CALC = "checksum-calc-failure";
068    
069        private static final String TYPE_CHECKSUM_CANNOT_CREATE = "checksum-create-failure";
070    
071        private File repositoryDir;
072    
073        private List<String> includes = new ArrayList<String>( 0 );
074    
075        @Inject
076        public ArtifactMissingChecksumsConsumer( ArchivaConfiguration configuration, FileTypes filetypes )
077        {
078            this.configuration = configuration;
079            this.filetypes = filetypes;
080    
081            configuration.addChangeListener( this );
082    
083            initIncludes();
084        }
085    
086        public String getId()
087        {
088            return this.id;
089        }
090    
091        public String getDescription()
092        {
093            return this.description;
094        }
095    
096        public boolean isPermanent()
097        {
098            return false;
099        }
100    
101        public void beginScan( ManagedRepository repo, Date whenGathered )
102            throws ConsumerException
103        {
104            this.repositoryDir = new File( repo.getLocation() );
105        }
106    
107        public void beginScan( ManagedRepository repo, Date whenGathered, boolean executeOnEntireRepo )
108            throws ConsumerException
109        {
110            beginScan( repo, whenGathered );
111        }
112    
113        public void completeScan()
114        {
115            /* do nothing */
116        }
117    
118        public void completeScan( boolean executeOnEntireRepo )
119        {
120            completeScan();
121        }
122    
123        public List<String> getExcludes()
124        {
125            return getDefaultArtifactExclusions();
126        }
127    
128        public List<String> getIncludes()
129        {
130            return includes;
131        }
132    
133        public void processFile( String path )
134            throws ConsumerException
135        {
136            createFixChecksum( path, new ChecksumAlgorithm[]{ ChecksumAlgorithm.SHA1 } );
137            createFixChecksum( path, new ChecksumAlgorithm[]{ ChecksumAlgorithm.MD5 } );
138        }
139    
140        public void processFile( String path, boolean executeOnEntireRepo )
141            throws ConsumerException
142        {
143            processFile( path );
144        }
145    
146        private void createFixChecksum( String path, ChecksumAlgorithm checksumAlgorithm[] )
147        {
148            File artifactFile = new File( this.repositoryDir, path );
149            File checksumFile = new File( this.repositoryDir, path + checksumAlgorithm[0].getExt() );
150    
151            if ( checksumFile.exists() )
152            {
153                checksum = new ChecksummedFile( artifactFile );
154                try
155                {
156                    if ( !checksum.isValidChecksum( checksumAlgorithm[0] ) )
157                    {
158                        checksum.fixChecksums( checksumAlgorithm );
159                        triggerConsumerInfo( "Fixed checksum file " + checksumFile.getAbsolutePath() );
160                    }
161                }
162                catch ( IOException e )
163                {
164                    triggerConsumerError( TYPE_CHECKSUM_CANNOT_CALC, "Cannot calculate checksum for file " + checksumFile +
165                        ": " + e.getMessage() );
166                }
167            }
168            else if ( !checksumFile.exists() )
169            {
170                checksum = new ChecksummedFile( artifactFile );
171                try
172                {
173                    checksum.createChecksum( checksumAlgorithm[0] );
174                    triggerConsumerInfo( "Created missing checksum file " + checksumFile.getAbsolutePath() );
175                }
176                catch ( IOException e )
177                {
178                    triggerConsumerError( TYPE_CHECKSUM_CANNOT_CREATE, "Cannot create checksum for file " + checksumFile +
179                        ": " + e.getMessage() );
180                }
181            }
182            else
183            {
184                triggerConsumerWarning( TYPE_CHECKSUM_NOT_FILE,
185                                        "Checksum file " + checksumFile.getAbsolutePath() + " is not a file." );
186            }
187        }
188    
189        public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue )
190        {
191            if ( ConfigurationNames.isRepositoryScanning( propertyName ) )
192            {
193                initIncludes();
194            }
195        }
196    
197        public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
198        {
199            /* do nothing */
200        }
201    
202        private void initIncludes()
203        {
204            includes = new ArrayList<String>( filetypes.getFileTypePatterns( FileTypes.ARTIFACTS ) );
205    
206        }
207    
208        @PostConstruct
209        public void initialize()
210        {
211            configuration.addChangeListener( this );
212    
213            initIncludes();
214        }
215    }