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