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