001    package org.apache.archiva.repository.scanner;
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.common.utils.BaseFile;
024    import org.apache.archiva.consumers.InvalidRepositoryContentConsumer;
025    import org.apache.archiva.consumers.KnownRepositoryContentConsumer;
026    import org.apache.archiva.consumers.functors.ConsumerWantsFilePredicate;
027    import org.apache.archiva.repository.scanner.functors.ConsumerProcessFileClosure;
028    import org.apache.archiva.repository.scanner.functors.TriggerBeginScanClosure;
029    import org.apache.archiva.repository.scanner.functors.TriggerScanCompletedClosure;
030    import org.apache.commons.collections.Closure;
031    import org.apache.commons.collections.CollectionUtils;
032    import org.apache.commons.collections.functors.IfClosure;
033    import org.apache.commons.lang.SystemUtils;
034    import org.codehaus.plexus.util.DirectoryWalkListener;
035    import org.slf4j.Logger;
036    import org.slf4j.LoggerFactory;
037    
038    import java.io.File;
039    import java.util.Date;
040    import java.util.HashMap;
041    import java.util.List;
042    import java.util.Map;
043    
044    /**
045     * RepositoryScannerInstance
046     *
047     *
048     */
049    public class RepositoryScannerInstance
050        implements DirectoryWalkListener
051    {
052        private Logger log = LoggerFactory.getLogger( RepositoryScannerInstance.class );
053    
054        /**
055         * Consumers that process known content.
056         */
057        private List<KnownRepositoryContentConsumer> knownConsumers;
058    
059        /**
060         * Consumers that process unknown/invalid content.
061         */
062        private List<InvalidRepositoryContentConsumer> invalidConsumers;
063    
064        private ManagedRepository repository;
065    
066        private RepositoryScanStatistics stats;
067    
068        private long changesSince = 0;
069    
070        private ConsumerProcessFileClosure consumerProcessFile;
071    
072        private ConsumerWantsFilePredicate consumerWantsFile;
073    
074        private Map<String, Long> consumerTimings;
075    
076        private Map<String, Long> consumerCounts;
077    
078        public RepositoryScannerInstance( ManagedRepository repository,
079                                          List<KnownRepositoryContentConsumer> knownConsumerList,
080                                          List<InvalidRepositoryContentConsumer> invalidConsumerList )
081        {
082            this.repository = repository;
083            this.knownConsumers = knownConsumerList;
084            this.invalidConsumers = invalidConsumerList;
085    
086            consumerTimings = new HashMap<String, Long>();
087            consumerCounts = new HashMap<String, Long>();
088    
089            this.consumerProcessFile = new ConsumerProcessFileClosure();
090            consumerProcessFile.setExecuteOnEntireRepo( true );
091            consumerProcessFile.setConsumerTimings( consumerTimings );
092            consumerProcessFile.setConsumerCounts( consumerCounts );
093    
094            this.consumerWantsFile = new ConsumerWantsFilePredicate();
095    
096            stats = new RepositoryScanStatistics();
097            stats.setRepositoryId( repository.getId() );
098    
099            Closure triggerBeginScan =
100                new TriggerBeginScanClosure( repository, new Date( System.currentTimeMillis() ), true );
101    
102            CollectionUtils.forAllDo( knownConsumerList, triggerBeginScan );
103            CollectionUtils.forAllDo( invalidConsumerList, triggerBeginScan );
104    
105            if ( SystemUtils.IS_OS_WINDOWS )
106            {
107                consumerWantsFile.setCaseSensitive( false );
108            }
109        }
110    
111        public RepositoryScannerInstance( ManagedRepository repository,
112                                          List<KnownRepositoryContentConsumer> knownContentConsumers,
113                                          List<InvalidRepositoryContentConsumer> invalidContentConsumers,
114                                          long changesSince )
115        {
116            this( repository, knownContentConsumers, invalidContentConsumers );
117    
118            consumerWantsFile.setChangesSince( changesSince );
119    
120            this.changesSince = changesSince;
121        }
122    
123        public RepositoryScanStatistics getStatistics()
124        {
125            return stats;
126        }
127    
128        public Map<String, Long> getConsumerTimings()
129        {
130            return consumerTimings;
131        }
132    
133        public Map<String, Long> getConsumerCounts()
134        {
135            return consumerCounts;
136        }
137    
138        public void directoryWalkStarting( File basedir )
139        {
140            log.info( "Walk Started: [{}] {}", this.repository.getId(), this.repository.getLocation() );
141            stats.triggerStart();
142        }
143    
144        public void directoryWalkStep( int percentage, File file )
145        {
146            log.debug( "Walk Step: {}, {}", percentage, file );
147    
148            stats.increaseFileCount();
149    
150            // consume files regardless - the predicate will check the timestamp
151            BaseFile basefile = new BaseFile( repository.getLocation(), file );
152    
153            // Timestamp finished points to the last successful scan, not this current one.
154            if ( file.lastModified() >= changesSince )
155            {
156                stats.increaseNewFileCount();
157            }
158    
159            consumerProcessFile.setBasefile( basefile );
160            consumerWantsFile.setBasefile( basefile );
161    
162            Closure processIfWanted = IfClosure.getInstance( consumerWantsFile, consumerProcessFile );
163            CollectionUtils.forAllDo( this.knownConsumers, processIfWanted );
164    
165            if ( consumerWantsFile.getWantedFileCount() <= 0 )
166            {
167                // Nothing known processed this file.  It is invalid!
168                CollectionUtils.forAllDo( this.invalidConsumers, consumerProcessFile );
169            }
170        }
171    
172        public void directoryWalkFinished()
173        {
174            TriggerScanCompletedClosure scanCompletedClosure = new TriggerScanCompletedClosure( repository, true );
175            CollectionUtils.forAllDo( knownConsumers, scanCompletedClosure );
176            CollectionUtils.forAllDo( invalidConsumers, scanCompletedClosure );
177    
178            stats.setConsumerTimings( consumerTimings );
179            stats.setConsumerCounts( consumerCounts );
180    
181            log.info( "Walk Finished: [{}] {}", this.repository.getId(), this.repository.getLocation() );
182            stats.triggerFinished();
183        }
184    
185        /**
186         * Debug method from DirectoryWalker.
187         */
188        public void debug( String message )
189        {
190            log.debug( "Repository Scanner: {}", message );
191        }
192    
193        public ManagedRepository getRepository()
194        {
195            return repository;
196        }
197    
198        public RepositoryScanStatistics getStats()
199        {
200            return stats;
201        }
202    
203        public long getChangesSince()
204        {
205            return changesSince;
206        }
207    }