001package org.apache.archiva.consumers.lucene; 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.beans.ManagedRepository; 024import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin; 025import org.apache.archiva.common.plexusbridge.MavenIndexerUtils; 026import org.apache.archiva.common.plexusbridge.PlexusSisuBridge; 027import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException; 028import org.apache.archiva.configuration.ArchivaConfiguration; 029import org.apache.archiva.configuration.ConfigurationNames; 030import org.apache.archiva.configuration.FileTypes; 031import org.apache.archiva.consumers.AbstractMonitoredConsumer; 032import org.apache.archiva.consumers.ConsumerException; 033import org.apache.archiva.consumers.KnownRepositoryContentConsumer; 034import org.apache.archiva.redback.components.registry.Registry; 035import org.apache.archiva.scheduler.ArchivaTaskScheduler; 036import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask; 037import org.apache.maven.index.NexusIndexer; 038import org.apache.maven.index.context.IndexCreator; 039import org.apache.maven.index.context.IndexingContext; 040import org.apache.archiva.redback.components.registry.RegistryListener; 041import org.apache.archiva.redback.components.taskqueue.TaskQueueException; 042import org.slf4j.Logger; 043import org.slf4j.LoggerFactory; 044import org.springframework.context.annotation.Scope; 045import org.springframework.stereotype.Service; 046 047import javax.annotation.PostConstruct; 048import javax.inject.Inject; 049import javax.inject.Named; 050import java.io.File; 051import java.util.ArrayList; 052import java.util.Collections; 053import java.util.Date; 054import java.util.List; 055 056/** 057 * Consumer for indexing the repository to provide search and IDE integration features. 058 */ 059@Service( "knownRepositoryContentConsumer#index-content" ) 060@Scope( "prototype" ) 061public class NexusIndexerConsumer 062 extends AbstractMonitoredConsumer 063 implements KnownRepositoryContentConsumer, RegistryListener 064{ 065 private Logger log = LoggerFactory.getLogger( getClass() ); 066 067 private ArchivaConfiguration configuration; 068 069 private FileTypes filetypes; 070 071 private File managedRepository; 072 073 private ArchivaTaskScheduler<ArtifactIndexingTask> scheduler; 074 075 private IndexingContext indexingContext; 076 077 private NexusIndexer nexusIndexer; 078 079 private List<String> includes = new ArrayList<>( 0 ); 080 081 private ManagedRepository repository; 082 083 private List<? extends IndexCreator> allIndexCreators; 084 085 private ManagedRepositoryAdmin managedRepositoryAdmin; 086 087 @Inject 088 public NexusIndexerConsumer( 089 @Named( value = "archivaTaskScheduler#indexing" ) ArchivaTaskScheduler<ArtifactIndexingTask> scheduler, 090 @Named( value = "archivaConfiguration" ) ArchivaConfiguration configuration, FileTypes filetypes, 091 PlexusSisuBridge plexusSisuBridge, MavenIndexerUtils mavenIndexerUtils, 092 ManagedRepositoryAdmin managedRepositoryAdmin ) 093 throws PlexusSisuBridgeException 094 { 095 this.configuration = configuration; 096 this.filetypes = filetypes; 097 this.scheduler = scheduler; 098 this.nexusIndexer = plexusSisuBridge.lookup( NexusIndexer.class ); 099 this.allIndexCreators = mavenIndexerUtils.getAllIndexCreators(); 100 this.managedRepositoryAdmin = managedRepositoryAdmin; 101 } 102 103 @Override 104 public String getDescription() 105 { 106 return "Indexes the repository to provide search and IDE integration features"; 107 } 108 109 @Override 110 public String getId() 111 { 112 return "index-content"; 113 } 114 115 @Override 116 public void beginScan( ManagedRepository repository, Date whenGathered ) 117 throws ConsumerException 118 { 119 this.repository = repository; 120 managedRepository = new File( repository.getLocation() ); 121 122 try 123 { 124 log.info( "Creating indexing context for repo : {}", repository.getId() ); 125 indexingContext = managedRepositoryAdmin.createIndexContext( repository ); 126 } 127 catch ( RepositoryAdminException e ) 128 { 129 throw new ConsumerException( e.getMessage(), e ); 130 } 131 } 132 133 @Override 134 public void beginScan( ManagedRepository repository, Date whenGathered, boolean executeOnEntireRepo ) 135 throws ConsumerException 136 { 137 if ( executeOnEntireRepo ) 138 { 139 beginScan( repository, whenGathered ); 140 } 141 else 142 { 143 this.repository = repository; 144 managedRepository = new File( repository.getLocation() ); 145 } 146 } 147 148 @Override 149 public void processFile( String path ) 150 throws ConsumerException 151 { 152 File artifactFile = new File( managedRepository, path ); 153 154 ArtifactIndexingTask task = 155 new ArtifactIndexingTask( repository, artifactFile, ArtifactIndexingTask.Action.ADD, getIndexingContext() ); 156 try 157 { 158 log.debug( "Queueing indexing task '{}' to add or update the artifact in the index.", task ); 159 scheduler.queueTask( task ); 160 } 161 catch ( TaskQueueException e ) 162 { 163 throw new ConsumerException( e.getMessage(), e ); 164 } 165 } 166 167 @Override 168 public void processFile( String path, boolean executeOnEntireRepo ) 169 throws Exception 170 { 171 if ( executeOnEntireRepo ) 172 { 173 processFile( path ); 174 } 175 else 176 { 177 File artifactFile = new File( managedRepository, path ); 178 179 // specify in indexing task that this is not a repo scan request! 180 ArtifactIndexingTask task = 181 new ArtifactIndexingTask( repository, artifactFile, ArtifactIndexingTask.Action.ADD, 182 getIndexingContext(), false ); 183 // only update index we don't need to scan the full repo here 184 task.setOnlyUpdate( true ); 185 try 186 { 187 log.debug( "Queueing indexing task '{}' to add or update the artifact in the index.", task ); 188 scheduler.queueTask( task ); 189 } 190 catch ( TaskQueueException e ) 191 { 192 throw new ConsumerException( e.getMessage(), e ); 193 } 194 } 195 } 196 197 @Override 198 public void completeScan() 199 { 200 IndexingContext context = this.indexingContext; 201 if ( context == null ) 202 { 203 try 204 { 205 context = getIndexingContext(); 206 } 207 catch ( ConsumerException e ) 208 { 209 log.warn( "failed to get an IndexingContext:{}", e.getMessage() ); 210 return; 211 } 212 } 213 ArtifactIndexingTask task = 214 new ArtifactIndexingTask( repository, null, ArtifactIndexingTask.Action.FINISH, context ); 215 try 216 { 217 log.debug( "Queueing indexing task '{}' to finish indexing.", task ); 218 scheduler.queueTask( task ); 219 } 220 catch ( TaskQueueException e ) 221 { 222 log.error( "Error queueing task: " + task + ": " + e.getMessage(), e ); 223 } 224 } 225 226 @Override 227 public void completeScan( boolean executeOnEntireRepo ) 228 { 229 if ( executeOnEntireRepo ) 230 { 231 completeScan(); 232 } 233 234 // else, do nothing as the context will be closed when indexing task is executed if not a repo scan request! 235 } 236 237 @Override 238 public List<String> getExcludes() 239 { 240 return Collections.emptyList(); 241 } 242 243 @Override 244 public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue ) 245 { 246 if ( ConfigurationNames.isRepositoryScanning( propertyName ) ) 247 { 248 initIncludes(); 249 } 250 } 251 252 @Override 253 public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue ) 254 { 255 /* do nothing */ 256 } 257 258 private void initIncludes() 259 { 260 List<String> indexable = filetypes.getFileTypePatterns( FileTypes.INDEXABLE_CONTENT ); 261 List<String> artifacts = filetypes.getFileTypePatterns( FileTypes.ARTIFACTS ); 262 263 includes = new ArrayList<>( indexable.size() + artifacts.size() ); 264 265 includes.addAll( indexable ); 266 267 includes.addAll( artifacts ); 268 } 269 270 @PostConstruct 271 public void initialize() 272 { 273 configuration.addChangeListener( this ); 274 275 initIncludes(); 276 } 277 278 @Override 279 public List<String> getIncludes() 280 { 281 return includes; 282 } 283 284 285 private IndexingContext getIndexingContext() 286 throws ConsumerException 287 { 288 289 if ( this.indexingContext == null ) 290 { 291 try 292 { 293 indexingContext = managedRepositoryAdmin.createIndexContext( repository ); 294 } 295 catch ( RepositoryAdminException e ) 296 { 297 throw new ConsumerException( e.getMessage(), e ); 298 } 299 } 300 return indexingContext; 301 } 302}