This project has retired. For details please refer to its Attic page.
Source code
001package org.apache.archiva.indexer.maven.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
021import org.apache.archiva.common.utils.FileUtils;
022import org.apache.archiva.indexer.UnsupportedBaseContextException;
023import org.apache.archiva.indexer.merger.IndexMerger;
024import org.apache.archiva.indexer.merger.IndexMergerException;
025import org.apache.archiva.indexer.merger.IndexMergerRequest;
026import org.apache.archiva.indexer.merger.TemporaryGroupIndex;
027import org.apache.archiva.repository.RepositoryRegistry;
028import org.apache.archiva.repository.RepositoryType;
029import org.apache.commons.lang.time.StopWatch;
030import org.apache.maven.index.Indexer;
031import org.apache.maven.index.context.ContextMemberProvider;
032import org.apache.maven.index.context.IndexCreator;
033import org.apache.maven.index.context.IndexingContext;
034import org.apache.maven.index.context.StaticContextMemberProvider;
035import org.apache.maven.index.packer.IndexPacker;
036import org.apache.maven.index.packer.IndexPackingRequest;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039import org.springframework.scheduling.annotation.Async;
040import org.springframework.stereotype.Service;
041
042import javax.inject.Inject;
043import java.io.IOException;
044import java.nio.file.Files;
045import java.nio.file.Path;
046import java.util.Collection;
047import java.util.List;
048import java.util.Objects;
049import java.util.Optional;
050import java.util.concurrent.CopyOnWriteArrayList;
051import java.util.stream.Collectors;
052
053/**
054 * @author Olivier Lamy
055 * @since 1.4-M2
056 */
057@Service("indexMerger#default")
058public class DefaultIndexMerger
059    implements IndexMerger
060{
061
062    @Inject
063    RepositoryRegistry repositoryRegistry;
064
065    private Logger log = LoggerFactory.getLogger( getClass() );
066
067
068    private final IndexPacker indexPacker;
069
070    private Indexer indexer;
071
072    private final List<IndexCreator> indexCreators;
073
074    private List<TemporaryGroupIndex> temporaryGroupIndexes = new CopyOnWriteArrayList<>();
075
076    private List<IndexingContext>  temporaryContextes = new CopyOnWriteArrayList<>(  );
077
078    private List<String> runningGroups = new CopyOnWriteArrayList<>();
079
080    @Inject
081    public DefaultIndexMerger( Indexer indexer, IndexPacker indexPacker, List<IndexCreator> indexCreators )
082    {
083        this.indexer = indexer;
084        this.indexPacker = indexPacker;
085        this.indexCreators = indexCreators;
086    }
087
088    @Override
089    public IndexingContext buildMergedIndex( IndexMergerRequest indexMergerRequest )
090        throws IndexMergerException
091    {
092        String groupId = indexMergerRequest.getGroupId();
093
094        if ( runningGroups.contains( groupId ) )
095        {
096            log.info( "skip build merge remote indexes for id: '{}' as already running", groupId );
097            return null;
098        }
099
100        runningGroups.add( groupId );
101
102        StopWatch stopWatch = new StopWatch();
103        stopWatch.reset();
104        stopWatch.start();
105
106        Path mergedIndexDirectory = indexMergerRequest.getMergedIndexDirectory();
107
108        String tempRepoId = mergedIndexDirectory.getFileName().toString();
109
110        try
111        {
112            Path indexLocation = mergedIndexDirectory.resolve( indexMergerRequest.getMergedIndexPath() );
113
114            List<IndexingContext> members = indexMergerRequest.getRepositoriesIds( ).stream( ).map( id ->
115                repositoryRegistry.getRepository( id ) ).filter( repo -> repo.getType().equals( RepositoryType.MAVEN ) )
116                .map( repo -> {
117                    try
118                    {
119                        return repo.getIndexingContext().getBaseContext( IndexingContext.class );
120                    }
121                    catch ( UnsupportedBaseContextException e )
122                    {
123                        return null;
124                        // Ignore
125                    }
126                } ).filter( Objects::nonNull ).collect( Collectors.toList() );
127            ContextMemberProvider memberProvider = new StaticContextMemberProvider(members);
128            IndexingContext mergedCtx = indexer.createMergedIndexingContext( tempRepoId, tempRepoId, mergedIndexDirectory.toFile(),
129                indexLocation.toFile(), true, memberProvider);
130            mergedCtx.optimize();
131
132            if ( indexMergerRequest.isPackIndex() )
133            {
134                IndexPackingRequest request = new IndexPackingRequest( mergedCtx, //
135                                                                       mergedCtx.acquireIndexSearcher().getIndexReader(), //
136                                                                       indexLocation.toFile() );
137                indexPacker.packIndex( request );
138            }
139
140            if ( indexMergerRequest.isTemporary() )
141            {
142                temporaryGroupIndexes.add( new TemporaryGroupIndex( mergedIndexDirectory, tempRepoId, groupId,
143                                                                    indexMergerRequest.getMergedIndexTtl() ) );
144                temporaryContextes.add(mergedCtx);
145            }
146            stopWatch.stop();
147            log.info( "merged index for repos {} in {} s", indexMergerRequest.getRepositoriesIds(),
148                      stopWatch.getTime() );
149            return mergedCtx;
150        }
151        catch ( IOException e)
152        {
153            throw new IndexMergerException( e.getMessage(), e );
154        }
155        finally
156        {
157            runningGroups.remove( groupId );
158        }
159    }
160
161    @Async
162    @Override
163    public void cleanTemporaryGroupIndex( TemporaryGroupIndex temporaryGroupIndex )
164    {
165        if ( temporaryGroupIndex == null )
166        {
167            return;
168        }
169
170        try
171        {
172
173            Optional<IndexingContext> ctxOpt = temporaryContextes.stream( ).filter( ctx -> ctx.getId( ).equals( temporaryGroupIndex.getIndexId( ) ) ).findFirst( );
174            if (ctxOpt.isPresent()) {
175                IndexingContext ctx = ctxOpt.get();
176                indexer.closeIndexingContext( ctx, true );
177                temporaryGroupIndexes.remove( temporaryGroupIndex );
178                temporaryContextes.remove( ctx );
179                Path directory = temporaryGroupIndex.getDirectory();
180                if ( directory != null && Files.exists(directory) )
181                {
182                    FileUtils.deleteDirectory( directory );
183                }
184            }
185        }
186        catch ( IOException e )
187        {
188            log.warn( "fail to delete temporary group index {}", temporaryGroupIndex.getIndexId(), e );
189        }
190    }
191
192    @Override
193    public Collection<TemporaryGroupIndex> getTemporaryGroupIndexes()
194    {
195        return this.temporaryGroupIndexes;
196    }
197}