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