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.RepositoryAdminException; 023import org.apache.archiva.admin.model.admin.ArchivaAdministration; 024import org.apache.archiva.admin.model.beans.ManagedRepository; 025import org.apache.archiva.common.utils.BaseFile; 026import org.apache.archiva.configuration.ArchivaConfiguration; 027import org.apache.archiva.consumers.InvalidRepositoryContentConsumer; 028import org.apache.archiva.consumers.KnownRepositoryContentConsumer; 029import org.apache.archiva.consumers.functors.ConsumerWantsFilePredicate; 030import org.apache.archiva.redback.components.registry.RegistryListener; 031import org.apache.archiva.repository.scanner.functors.ConsumerProcessFileClosure; 032import org.apache.archiva.repository.scanner.functors.TriggerBeginScanClosure; 033import org.apache.archiva.repository.scanner.functors.TriggerScanCompletedClosure; 034import org.apache.commons.collections.Closure; 035import org.apache.commons.collections.CollectionUtils; 036import org.apache.commons.collections.functors.IfClosure; 037import org.springframework.beans.BeansException; 038import org.springframework.context.ApplicationContext; 039import org.springframework.context.ApplicationContextAware; 040import org.springframework.stereotype.Service; 041 042import javax.inject.Inject; 043import java.io.File; 044import java.util.ArrayList; 045import java.util.Date; 046import java.util.HashMap; 047import java.util.List; 048import java.util.Map; 049 050/** 051 * RepositoryContentConsumerUtil 052 */ 053@Service("repositoryContentConsumers") 054public class RepositoryContentConsumers 055 implements ApplicationContextAware 056{ 057 058 @Inject 059 private ApplicationContext applicationContext; 060 061 private ArchivaAdministration archivaAdministration; 062 063 private List<KnownRepositoryContentConsumer> selectedKnownConsumers; 064 065 private List<InvalidRepositoryContentConsumer> selectedInvalidConsumers; 066 067 @Inject 068 private ArchivaConfiguration archivaConfiguration; 069 070 @Inject 071 public RepositoryContentConsumers( ArchivaAdministration archivaAdministration ) 072 { 073 this.archivaAdministration = archivaAdministration; 074 } 075 076 @Override 077 public void setApplicationContext( ApplicationContext applicationContext ) 078 throws BeansException 079 { 080 this.applicationContext = applicationContext; 081 } 082 083 /** 084 * <p> 085 * Get the list of Ids associated with those {@link KnownRepositoryContentConsumer} that have 086 * been selected in the configuration to execute. 087 * </p> 088 * <p> 089 * NOTE: This list can be larger and contain entries that might not exist or be available 090 * in the classpath, or as a component. 091 * </p> 092 * 093 * @return the list of consumer ids that have been selected by the configuration. 094 */ 095 public List<String> getSelectedKnownConsumerIds() 096 throws RepositoryAdminException 097 { 098 return archivaAdministration.getKnownContentConsumers(); 099 } 100 101 /** 102 * <p> 103 * Get the list of Ids associated with those {@link InvalidRepositoryContentConsumer} that have 104 * been selected in the configuration to execute. 105 * </p> 106 * <p> 107 * NOTE: This list can be larger and contain entries that might not exist or be available 108 * in the classpath, or as a component. 109 * </p> 110 * 111 * @return the list of consumer ids that have been selected by the configuration. 112 */ 113 public List<String> getSelectedInvalidConsumerIds() 114 throws RepositoryAdminException 115 { 116 return archivaAdministration.getInvalidContentConsumers(); 117 } 118 119 /** 120 * Get the map of {@link String} ids to {@link KnownRepositoryContentConsumer} implementations, 121 * for those consumers that have been selected according to the active configuration. 122 * 123 * @return the map of String ids to {@link KnownRepositoryContentConsumer} objects. 124 */ 125 public Map<String, KnownRepositoryContentConsumer> getSelectedKnownConsumersMap() 126 throws RepositoryAdminException 127 { 128 Map<String, KnownRepositoryContentConsumer> consumerMap = new HashMap<>(); 129 130 for ( KnownRepositoryContentConsumer consumer : getSelectedKnownConsumers() ) 131 { 132 consumerMap.put( consumer.getId(), consumer ); 133 } 134 135 return consumerMap; 136 } 137 138 /** 139 * Get the map of {@link String} ids to {@link InvalidRepositoryContentConsumer} implementations, 140 * for those consumers that have been selected according to the active configuration. 141 * 142 * @return the map of String ids to {@link InvalidRepositoryContentConsumer} objects. 143 */ 144 public Map<String, InvalidRepositoryContentConsumer> getSelectedInvalidConsumersMap() 145 throws RepositoryAdminException 146 { 147 Map<String, InvalidRepositoryContentConsumer> consumerMap = new HashMap<>(); 148 149 for ( InvalidRepositoryContentConsumer consumer : getSelectedInvalidConsumers() ) 150 { 151 consumerMap.put( consumer.getId(), consumer ); 152 } 153 154 return consumerMap; 155 } 156 157 /** 158 * Get the list of {@link KnownRepositoryContentConsumer} objects that are 159 * selected according to the active configuration. 160 * 161 * @return the list of {@link KnownRepositoryContentConsumer} that have been selected 162 * by the active configuration. 163 */ 164 public List<KnownRepositoryContentConsumer> getSelectedKnownConsumers() 165 throws RepositoryAdminException 166 { 167 // FIXME only for testing 168 if ( selectedKnownConsumers != null ) 169 { 170 return selectedKnownConsumers; 171 } 172 List<KnownRepositoryContentConsumer> ret = new ArrayList<>(); 173 174 List<String> knownSelected = getSelectedKnownConsumerIds(); 175 176 for ( KnownRepositoryContentConsumer consumer : getAvailableKnownConsumers() ) 177 { 178 if ( knownSelected.contains( consumer.getId() ) ) 179 { 180 ret.add( consumer ); 181 } 182 } 183 return ret; 184 } 185 186 public void releaseSelectedKnownConsumers( List<KnownRepositoryContentConsumer> repositoryContentConsumers ) 187 { 188 if ( repositoryContentConsumers == null ) 189 { 190 return; 191 } 192 for ( KnownRepositoryContentConsumer knownRepositoryContentConsumer : repositoryContentConsumers ) 193 { 194 if ( RegistryListener.class.isAssignableFrom( knownRepositoryContentConsumer.getClass() ) ) 195 { 196 archivaConfiguration.removeChangeListener( 197 RegistryListener.class.cast( knownRepositoryContentConsumer ) ); 198 } 199 } 200 } 201 202 /** 203 * Get the list of {@link InvalidRepositoryContentConsumer} objects that are 204 * selected according to the active configuration. 205 * 206 * @return the list of {@link InvalidRepositoryContentConsumer} that have been selected 207 * by the active configuration. 208 */ 209 public synchronized List<InvalidRepositoryContentConsumer> getSelectedInvalidConsumers() 210 throws RepositoryAdminException 211 { 212 213 // FIXME only for testing 214 if ( selectedInvalidConsumers != null ) 215 { 216 return selectedInvalidConsumers; 217 } 218 219 List<InvalidRepositoryContentConsumer> ret = new ArrayList<>(); 220 221 List<String> invalidSelected = getSelectedInvalidConsumerIds(); 222 223 for ( InvalidRepositoryContentConsumer consumer : getAvailableInvalidConsumers() ) 224 { 225 if ( invalidSelected.contains( consumer.getId() ) ) 226 { 227 ret.add( consumer ); 228 } 229 } 230 return ret; 231 } 232 233 234 /** 235 * Get the list of {@link KnownRepositoryContentConsumer} objects that are 236 * available and present in the classpath and as components in the IoC. 237 * 238 * @return the list of all available {@link KnownRepositoryContentConsumer} present in the classpath 239 * and as a component in the IoC. 240 */ 241 public List<KnownRepositoryContentConsumer> getAvailableKnownConsumers() 242 { 243 return new ArrayList<>( applicationContext.getBeansOfType( KnownRepositoryContentConsumer.class ).values() ); 244 } 245 246 /** 247 * Get the list of {@link InvalidRepositoryContentConsumer} objects that are 248 * available and present in the classpath and as components in the IoC. 249 * 250 * @return the list of all available {@link InvalidRepositoryContentConsumer} present in the classpath 251 * and as a component in the IoC. 252 */ 253 public List<InvalidRepositoryContentConsumer> getAvailableInvalidConsumers() 254 { 255 return new ArrayList<>( applicationContext.getBeansOfType( InvalidRepositoryContentConsumer.class ).values() ); 256 } 257 258 /** 259 * A convienence method to execute all of the active selected consumers for a 260 * particular arbitrary file. 261 * NOTE: Make sure that there is no repository scanning task executing before invoking this so as to prevent 262 * the index writer/reader of the current index-content consumer executing from getting closed. For an example, 263 * see ArchivaDavResource#executeConsumers( File ). 264 * 265 * @param repository the repository configuration to use. 266 * @param localFile the local file to execute the consumers against. 267 * @param updateRelatedArtifacts TODO 268 */ 269 public void executeConsumers( ManagedRepository repository, File localFile, boolean updateRelatedArtifacts ) 270 throws RepositoryAdminException 271 { 272 List<KnownRepositoryContentConsumer> selectedKnownConsumers = null; 273 // Run the repository consumers 274 try 275 { 276 Closure triggerBeginScan = new TriggerBeginScanClosure( repository, getStartTime(), false ); 277 278 selectedKnownConsumers = getSelectedKnownConsumers(); 279 280 // MRM-1212/MRM-1197 281 // - do not create missing/fix invalid checksums and update metadata when deploying from webdav since these are uploaded by maven 282 if ( !updateRelatedArtifacts ) 283 { 284 List<KnownRepositoryContentConsumer> clone = new ArrayList<>(); 285 clone.addAll( selectedKnownConsumers ); 286 287 for ( KnownRepositoryContentConsumer consumer : clone ) 288 { 289 if ( consumer.getId().equals( "create-missing-checksums" ) || consumer.getId().equals( 290 "metadata-updater" ) ) 291 { 292 selectedKnownConsumers.remove( consumer ); 293 } 294 } 295 } 296 297 List<InvalidRepositoryContentConsumer> selectedInvalidConsumers = getSelectedInvalidConsumers(); 298 CollectionUtils.forAllDo( selectedKnownConsumers, triggerBeginScan ); 299 CollectionUtils.forAllDo( selectedInvalidConsumers, triggerBeginScan ); 300 301 // yuck. In case you can't read this, it says 302 // "process the file if the consumer has it in the includes list, and not in the excludes list" 303 BaseFile baseFile = new BaseFile( repository.getLocation(), localFile ); 304 ConsumerWantsFilePredicate predicate = new ConsumerWantsFilePredicate( repository ); 305 predicate.setBasefile( baseFile ); 306 predicate.setCaseSensitive( false ); 307 308 ConsumerProcessFileClosure closure = new ConsumerProcessFileClosure(); 309 closure.setBasefile( baseFile ); 310 closure.setExecuteOnEntireRepo( false ); 311 312 Closure processIfWanted = IfClosure.getInstance( predicate, closure ); 313 314 CollectionUtils.forAllDo( selectedKnownConsumers, processIfWanted ); 315 316 if ( predicate.getWantedFileCount() <= 0 ) 317 { 318 // Nothing known processed this file. It is invalid! 319 CollectionUtils.forAllDo( selectedInvalidConsumers, closure ); 320 } 321 322 TriggerScanCompletedClosure scanCompletedClosure = new TriggerScanCompletedClosure( repository, false ); 323 324 CollectionUtils.forAllDo( selectedKnownConsumers, scanCompletedClosure ); 325 } 326 finally 327 { 328 /* TODO: This is never called by the repository scanner instance, so not calling here either - but it probably should be? 329 CollectionUtils.forAllDo( availableKnownConsumers, triggerCompleteScan ); 330 CollectionUtils.forAllDo( availableInvalidConsumers, triggerCompleteScan ); 331 */ 332 releaseSelectedKnownConsumers( selectedKnownConsumers ); 333 } 334 } 335 336 public void setSelectedKnownConsumers( List<KnownRepositoryContentConsumer> selectedKnownConsumers ) 337 { 338 this.selectedKnownConsumers = selectedKnownConsumers; 339 } 340 341 public void setSelectedInvalidConsumers( List<InvalidRepositoryContentConsumer> selectedInvalidConsumers ) 342 { 343 this.selectedInvalidConsumers = selectedInvalidConsumers; 344 } 345 346 protected Date getStartTime() 347 { 348 return new Date( System.currentTimeMillis() ); 349 } 350 351 public void setArchivaAdministration( ArchivaAdministration archivaAdministration ) 352 { 353 this.archivaAdministration = archivaAdministration; 354 } 355}