001 package org.apache.archiva.indexer.merger; 002 /* 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 */ 020 021 import com.google.common.io.Files; 022 023 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin; 024 import org.apache.archiva.common.plexusbridge.MavenIndexerUtils; 025 import org.apache.archiva.common.plexusbridge.PlexusSisuBridge; 026 import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException; 027 import org.apache.commons.io.FileUtils; 028 import org.apache.commons.lang.time.StopWatch; 029 import org.apache.maven.index.NexusIndexer; 030 import org.apache.maven.index.context.IndexingContext; 031 import org.apache.maven.index.context.UnsupportedExistingLuceneIndexException; 032 import org.apache.maven.index.packer.IndexPacker; 033 import org.apache.maven.index.packer.IndexPackingRequest; 034 import org.slf4j.Logger; 035 import org.slf4j.LoggerFactory; 036 import org.springframework.scheduling.annotation.Async; 037 import org.springframework.stereotype.Service; 038 039 import javax.inject.Inject; 040 import java.io.File; 041 import java.io.IOException; 042 import java.util.Collection; 043 import java.util.List; 044 import java.util.concurrent.CopyOnWriteArrayList; 045 046 /** 047 * @author Olivier Lamy 048 * @since 1.4-M2 049 */ 050 @Service("indexMerger#default") 051 public class DefaultIndexMerger 052 implements IndexMerger 053 { 054 055 /** 056 * default tmp created group index ttl in minutes 057 */ 058 static final int DEFAULT_GROUP_INDEX_TTL = 30; 059 060 private Logger log = LoggerFactory.getLogger( getClass() ); 061 062 @Inject 063 private ManagedRepositoryAdmin managedRepositoryAdmin; 064 065 private MavenIndexerUtils mavenIndexerUtils; 066 067 private NexusIndexer indexer; 068 069 private IndexPacker indexPacker; 070 071 private List<TemporaryGroupIndex> temporaryGroupIndexes = new CopyOnWriteArrayList<TemporaryGroupIndex>(); 072 073 @Inject 074 public DefaultIndexMerger( PlexusSisuBridge plexusSisuBridge, MavenIndexerUtils mavenIndexerUtils ) 075 throws PlexusSisuBridgeException 076 { 077 this.indexer = plexusSisuBridge.lookup( NexusIndexer.class ); 078 this.mavenIndexerUtils = mavenIndexerUtils; 079 indexPacker = plexusSisuBridge.lookup( IndexPacker.class, "default" ); 080 } 081 082 public IndexingContext buildMergedIndex( IndexMergerRequest indexMergerRequest ) 083 throws IndexMergerException 084 { 085 StopWatch stopWatch = new StopWatch(); 086 stopWatch.reset(); 087 stopWatch.start(); 088 File tempRepoFile = Files.createTempDir(); 089 tempRepoFile.deleteOnExit(); 090 091 String tempRepoId = tempRepoFile.getName(); 092 093 try 094 { 095 File indexLocation = new File( tempRepoFile, indexMergerRequest.getMergedIndexPath() ); 096 IndexingContext indexingContext = 097 indexer.addIndexingContext( tempRepoId, tempRepoId, tempRepoFile, indexLocation, null, null, 098 mavenIndexerUtils.getAllIndexCreators() ); 099 100 for ( String repoId : indexMergerRequest.getRepositoriesIds() ) 101 { 102 IndexingContext idxToMerge = indexer.getIndexingContexts().get( repoId ); 103 if ( idxToMerge != null ) 104 { 105 indexingContext.merge( idxToMerge.getIndexDirectory() ); 106 } 107 } 108 109 indexingContext.optimize(); 110 111 if ( indexMergerRequest.isPackIndex() ) 112 { 113 IndexPackingRequest request = new IndexPackingRequest( indexingContext, indexLocation ); 114 indexPacker.packIndex( request ); 115 } 116 temporaryGroupIndexes.add( 117 new TemporaryGroupIndex( tempRepoFile, tempRepoId, indexMergerRequest.getGroupId(), indexMergerRequest.getMergedIndexTtl() ) ); 118 stopWatch.stop(); 119 log.info( "merged index for repos {} in {} s", indexMergerRequest.getRepositoriesIds(), 120 stopWatch.getTime() ); 121 return indexingContext; 122 } 123 catch ( IOException e ) 124 { 125 throw new IndexMergerException( e.getMessage(), e ); 126 } 127 catch ( UnsupportedExistingLuceneIndexException e ) 128 { 129 throw new IndexMergerException( e.getMessage(), e ); 130 } 131 } 132 133 @Async 134 public void cleanTemporaryGroupIndex( TemporaryGroupIndex temporaryGroupIndex ) 135 { 136 if ( temporaryGroupIndex == null ) 137 { 138 return; 139 } 140 141 try 142 { 143 IndexingContext indexingContext = indexer.getIndexingContexts().get( temporaryGroupIndex.getIndexId() ); 144 if ( indexingContext != null ) 145 { 146 indexer.removeIndexingContext( indexingContext, true ); 147 } 148 File directory = temporaryGroupIndex.getDirectory(); 149 if ( directory != null && directory.exists() ) 150 { 151 FileUtils.deleteDirectory( directory ); 152 } 153 temporaryGroupIndexes.remove( temporaryGroupIndex ); 154 } 155 catch ( IOException e ) 156 { 157 log.warn( "fail to delete temporary group index {}", temporaryGroupIndex.getIndexId(), e ); 158 } 159 } 160 161 public Collection<TemporaryGroupIndex> getTemporaryGroupIndexes() 162 { 163 return this.temporaryGroupIndexes; 164 } 165 }