This project has retired. For details please refer to its Attic page.
RepositoryScannerInstance xref
View Javadoc
1   package org.apache.archiva.repository.scanner;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.archiva.common.utils.BaseFile;
23  import org.apache.archiva.common.utils.PathUtil;
24  import org.apache.archiva.consumers.InvalidRepositoryContentConsumer;
25  import org.apache.archiva.consumers.KnownRepositoryContentConsumer;
26  import org.apache.archiva.consumers.RepositoryContentConsumer;
27  import org.apache.archiva.consumers.functors.ConsumerWantsFilePredicate;
28  import org.apache.archiva.repository.ManagedRepository;
29  import org.apache.archiva.repository.scanner.functors.ConsumerProcessFileClosure;
30  import org.apache.archiva.repository.scanner.functors.TriggerBeginScanClosure;
31  import org.apache.archiva.repository.scanner.functors.TriggerScanCompletedClosure;
32  import org.apache.commons.collections4.Closure;
33  import org.apache.commons.collections4.CollectionUtils;
34  import org.apache.commons.collections4.IterableUtils;
35  import org.apache.commons.collections4.functors.IfClosure;
36  import org.apache.commons.lang3.SystemUtils;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  import java.io.IOException;
41  import java.nio.file.FileSystem;
42  import java.nio.file.FileSystems;
43  import java.nio.file.FileVisitResult;
44  import java.nio.file.FileVisitor;
45  import java.nio.file.Files;
46  import java.nio.file.Path;
47  import java.nio.file.PathMatcher;
48  import java.nio.file.attribute.BasicFileAttributes;
49  import java.util.ArrayList;
50  import java.util.Date;
51  import java.util.HashMap;
52  import java.util.List;
53  import java.util.Map;
54  import java.util.stream.Collectors;
55  
56  /**
57   * RepositoryScannerInstance
58   */
59  public class RepositoryScannerInstance
60      implements FileVisitor<Path>
61  {
62      private Logger log = LoggerFactory.getLogger( RepositoryScannerInstance.class );
63  
64      /**
65       * Consumers that process known content.
66       */
67      private List<KnownRepositoryContentConsumer> knownConsumers;
68  
69      /**
70       * Consumers that process unknown/invalid content.
71       */
72      private List<InvalidRepositoryContentConsumer> invalidConsumers;
73  
74      private ManagedRepository repository;
75  
76      private RepositoryScanStatistics stats;
77  
78      private long changesSince = 0;
79  
80      private ConsumerProcessFileClosure consumerProcessFile;
81  
82      private ConsumerWantsFilePredicate consumerWantsFile;
83  
84      private Map<String, Long> consumerTimings;
85  
86      private Map<String, Long> consumerCounts;
87  
88  
89      private List<String> fileNameIncludePattern = new ArrayList<>();
90      private List<String> fileNameExcludePattern = new ArrayList<>();
91  
92      private List<PathMatcher> includeMatcher = new ArrayList<>();
93      private List<PathMatcher> excludeMatcher = new ArrayList<>();
94  
95      private boolean isRunning = false;
96  
97      Path basePath = null;
98  
99      public RepositoryScannerInstance( ManagedRepository repository,
100                                       List<KnownRepositoryContentConsumer> knownConsumerList,
101                                       List<InvalidRepositoryContentConsumer> invalidConsumerList )
102     {
103         this.repository = repository;
104         this.knownConsumers = knownConsumerList;
105         this.invalidConsumers = invalidConsumerList;
106 
107         addFileNameIncludePattern("**/*");
108 
109         consumerTimings = new HashMap<>();
110         consumerCounts = new HashMap<>();
111 
112         this.consumerProcessFile = new ConsumerProcessFileClosure();
113         consumerProcessFile.setExecuteOnEntireRepo( true );
114         consumerProcessFile.setConsumerTimings( consumerTimings );
115         consumerProcessFile.setConsumerCounts( consumerCounts );
116 
117         this.consumerWantsFile = new ConsumerWantsFilePredicate( repository );
118 
119         stats = new RepositoryScanStatistics();
120         stats.setRepositoryId( repository.getId() );
121 
122         Closure<RepositoryContentConsumer> triggerBeginScan =
123             new TriggerBeginScanClosure( repository, new Date( System.currentTimeMillis() ), true );
124 
125         IterableUtils.forEach( knownConsumerList, triggerBeginScan );
126         IterableUtils.forEach( invalidConsumerList, triggerBeginScan );
127 
128         if ( SystemUtils.IS_OS_WINDOWS )
129         {
130             consumerWantsFile.setCaseSensitive( false );
131         }
132     }
133 
134     public RepositoryScannerInstance( ManagedRepository repository,
135                                       List<KnownRepositoryContentConsumer> knownContentConsumers,
136                                       List<InvalidRepositoryContentConsumer> invalidContentConsumers,
137                                       long changesSince )
138     {
139         this( repository, knownContentConsumers, invalidContentConsumers );
140 
141         consumerWantsFile.setChangesSince( changesSince );
142 
143         this.changesSince = changesSince;
144     }
145 
146     public RepositoryScanStatistics getStatistics()
147     {
148         return stats;
149     }
150 
151     public Map<String, Long> getConsumerTimings()
152     {
153         return consumerTimings;
154     }
155 
156     public Map<String, Long> getConsumerCounts()
157     {
158         return consumerCounts;
159     }
160 
161     public ManagedRepository getRepository()
162     {
163         return repository;
164     }
165 
166     public RepositoryScanStatistics getStats()
167     {
168         return stats;
169     }
170 
171     public long getChangesSince()
172     {
173         return changesSince;
174     }
175 
176     public List<String> getFileNameIncludePattern() {
177         return fileNameIncludePattern;
178     }
179 
180     public void setFileNameIncludePattern(List<String> fileNamePattern) {
181         this.fileNameIncludePattern = fileNamePattern;
182         FileSystem sys = FileSystems.getDefault();
183         this.includeMatcher = fileNamePattern.stream().map(ts ->sys
184                 .getPathMatcher("glob:" + ts)).collect(Collectors.toList());
185     }
186 
187     public void addFileNameIncludePattern(String fileNamePattern) {
188         if (! this.fileNameIncludePattern.contains(fileNamePattern)) {
189             this.fileNameIncludePattern.add(fileNamePattern);
190             this.includeMatcher.add(FileSystems.getDefault().getPathMatcher("glob:" + fileNamePattern));
191         }
192     }
193 
194     public List<String> getFileNameExcludePattern() {
195         return fileNameExcludePattern;
196     }
197 
198     public void setFileNameExcludePattern(List<String> fileNamePattern) {
199         this.fileNameExcludePattern = fileNamePattern;
200         FileSystem sys = FileSystems.getDefault();
201         this.excludeMatcher = fileNamePattern.stream().map(ts ->sys
202                 .getPathMatcher("glob:" + ts)).collect(Collectors.toList());
203     }
204 
205     public void addFileNameExcludePattern(String fileNamePattern) {
206         if (! this.fileNameExcludePattern.contains(fileNamePattern)) {
207             this.fileNameExcludePattern.add(fileNamePattern);
208             this.excludeMatcher.add(FileSystems.getDefault().getPathMatcher("glob:" + fileNamePattern));
209         }
210     }
211 
212 
213     @Override
214     public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
215         if (!isRunning) {
216             isRunning = true;
217             this.basePath = dir;
218             log.info( "Walk Started: [{}] {}", this.repository.getId(), this.repository.getLocation() );
219             stats.triggerStart();
220         }
221         return FileVisitResult.CONTINUE;
222     }
223 
224     @Override
225     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
226         final Path relativeFile = basePath.relativize( file );
227         if (excludeMatcher.stream().noneMatch(m -> m.matches(relativeFile)) && includeMatcher.stream().allMatch(m -> m.matches(relativeFile))) {
228             log.debug( "Walk Step: {}, {}", file );
229 
230             stats.increaseFileCount();
231 
232             // consume files regardless - the predicate will check the timestamp
233             Path repoPath = PathUtil.getPathFromUri( repository.getLocation() );
234             BaseFilels/BaseFile.html#BaseFile">BaseFile basefile = new BaseFile( repoPath.toString(), file.toFile() );
235 
236             // Timestamp finished points to the last successful scan, not this current one.
237             if ( Files.getLastModifiedTime(file).toMillis() >= changesSince )
238             {
239                 stats.increaseNewFileCount();
240             }
241 
242             consumerProcessFile.setBasefile( basefile );
243             consumerWantsFile.setBasefile( basefile );
244 
245             Closure<RepositoryContentConsumer> processIfWanted = IfClosure.ifClosure( consumerWantsFile, consumerProcessFile );
246             IterableUtils.forEach( this.knownConsumers, processIfWanted );
247 
248             if ( consumerWantsFile.getWantedFileCount() <= 0 )
249             {
250                 // Nothing known processed this file.  It is invalid!
251                 IterableUtils.forEach( this.invalidConsumers, consumerProcessFile );
252             }
253 
254         }
255         return FileVisitResult.CONTINUE;
256     }
257 
258     @Override
259     public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
260         log.error("Error occured at {}: {}", file, exc.getMessage(), exc);
261         try
262         {
263             if ( basePath != null && Files.isSameFile( file, basePath ) )
264             {
265                 log.debug( "Finishing walk from visitFileFailed" );
266                 finishWalk( );
267             }
268         } catch (Throwable e) {
269             log.error( "Error during visitFileFailed handling: {}", e.getMessage( ), e );
270         }
271         return FileVisitResult.CONTINUE;
272     }
273 
274     @Override
275     public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
276         if (Files.isSameFile(dir, basePath)) {
277             finishWalk();
278         }
279         return FileVisitResult.CONTINUE;
280     }
281 
282     private void finishWalk() {
283         this.isRunning = false;
284         TriggerScanCompletedClosurempletedClosure.html#TriggerScanCompletedClosure">TriggerScanCompletedClosure scanCompletedClosure = new TriggerScanCompletedClosure( repository, true );
285         IterableUtils.forEach( knownConsumers, scanCompletedClosure );
286         IterableUtils.forEach( invalidConsumers, scanCompletedClosure );
287 
288         stats.setConsumerTimings( consumerTimings );
289         stats.setConsumerCounts( consumerCounts );
290 
291         log.info( "Walk Finished: [{}] {}", this.repository.getId(), this.repository.getLocation() );
292         stats.triggerFinished();
293         this.basePath = null;
294     }
295 }