001    package org.apache.archiva.scheduler.indexing;
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 Li
016     * cense is distributed on an
017     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
018     * KIND, either express or implied.  See the License for the
019     * specific language governing permissions and limitations
020     * under the License.
021     */
022    
023    import org.apache.archiva.admin.model.RepositoryAdminException;
024    import org.apache.archiva.admin.model.beans.ManagedRepository;
025    import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
026    import org.apache.archiva.common.plexusbridge.PlexusSisuBridge;
027    import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException;
028    import org.apache.archiva.redback.components.taskqueue.Task;
029    import org.apache.archiva.redback.components.taskqueue.execution.TaskExecutionException;
030    import org.apache.archiva.redback.components.taskqueue.execution.TaskExecutor;
031    import org.apache.lucene.search.BooleanClause;
032    import org.apache.lucene.search.BooleanQuery;
033    import org.apache.maven.index.ArtifactContext;
034    import org.apache.maven.index.ArtifactContextProducer;
035    import org.apache.maven.index.FlatSearchRequest;
036    import org.apache.maven.index.FlatSearchResponse;
037    import org.apache.maven.index.MAVEN;
038    import org.apache.maven.index.NexusIndexer;
039    import org.apache.maven.index.context.IndexingContext;
040    import org.apache.maven.index.expr.SourcedSearchExpression;
041    import org.apache.maven.index.packer.IndexPacker;
042    import org.apache.maven.index.packer.IndexPackingRequest;
043    import org.slf4j.Logger;
044    import org.slf4j.LoggerFactory;
045    import org.springframework.stereotype.Service;
046    
047    import javax.annotation.PostConstruct;
048    import javax.inject.Inject;
049    import java.io.File;
050    import java.io.IOException;
051    
052    /**
053     * ArchivaIndexingTaskExecutor Executes all indexing tasks. Adding, updating and removing artifacts from the index are
054     * all performed by this executor. Add and update artifact in index tasks are added in the indexing task queue by the
055     * NexusIndexerConsumer while remove artifact from index tasks are added by the LuceneCleanupRemoveIndexedConsumer.
056     */
057    @Service ( "taskExecutor#indexing" )
058    public class ArchivaIndexingTaskExecutor
059        implements TaskExecutor
060    {
061        private Logger log = LoggerFactory.getLogger( ArchivaIndexingTaskExecutor.class );
062    
063        /**
064         *
065         */
066        private IndexPacker indexPacker;
067    
068        private ArtifactContextProducer artifactContextProducer;
069    
070        @Inject
071        private PlexusSisuBridge plexusSisuBridge;
072    
073        @Inject
074        private ManagedRepositoryAdmin managedRepositoryAdmin;
075    
076        private NexusIndexer nexusIndexer;
077    
078        @PostConstruct
079        public void initialize()
080            throws PlexusSisuBridgeException
081        {
082            log.info( "Initialized {}", this.getClass().getName() );
083    
084            artifactContextProducer = plexusSisuBridge.lookup( ArtifactContextProducer.class );
085    
086            indexPacker = plexusSisuBridge.lookup( IndexPacker.class, "default" );
087    
088            nexusIndexer = plexusSisuBridge.lookup( NexusIndexer.class );
089    
090        }
091    
092        /**
093         * depending on current {@link Task} you have.
094         * If {@link org.apache.archiva.scheduler.indexing.ArtifactIndexingTask.Action.FINISH} && isExecuteOnEntireRepo:
095         * repository will be scanned.
096         *
097         * @param task
098         * @throws TaskExecutionException
099         */
100        public void executeTask( Task task )
101            throws TaskExecutionException
102        {
103            ArtifactIndexingTask indexingTask = (ArtifactIndexingTask) task;
104    
105            ManagedRepository repository = indexingTask.getRepository();
106            IndexingContext context = indexingTask.getContext();
107    
108            if ( ArtifactIndexingTask.Action.FINISH.equals( indexingTask.getAction() )
109                && indexingTask.isExecuteOnEntireRepo() )
110            {
111                try
112                {
113                    long start = System.currentTimeMillis();
114                    nexusIndexer.scan( context, null, indexingTask.isOnlyUpdate() );
115                    long end = System.currentTimeMillis();
116                    log.info( "indexed maven repository: {}, onlyUpdate: {}, time {} ms", repository.getId(),
117                              indexingTask.isOnlyUpdate(), ( end - start ) );
118                }
119                catch ( IOException e )
120                {
121                    throw new TaskExecutionException( "Error scan repository " + repository, e );
122                }
123                log.debug( "Finishing indexing task on repo: {}", repository.getId() );
124                finishIndexingTask( indexingTask, repository, context );
125            }
126            else
127            {
128                // create context if not a repo scan request
129                if ( !indexingTask.isExecuteOnEntireRepo() )
130                {
131                    try
132                    {
133                        log.debug( "Creating indexing context on resource: {}", ( indexingTask.getResourceFile() == null
134                            ? "none"
135                            : indexingTask.getResourceFile().getPath() ) );
136                        context = managedRepositoryAdmin.createIndexContext( repository );
137                    }
138                    catch ( RepositoryAdminException e )
139                    {
140                        log.error( "Error occurred while creating context: " + e.getMessage() );
141                        throw new TaskExecutionException( "Error occurred while creating context: " + e.getMessage(), e );
142                    }
143                }
144    
145                if ( context == null || context.getIndexDirectory() == null )
146                {
147                    throw new TaskExecutionException( "Trying to index an artifact but the context is already closed" );
148                }
149    
150                try
151                {
152                    File artifactFile = indexingTask.getResourceFile();
153                    if ( artifactFile == null )
154                    {
155                        log.debug( "no artifact pass in indexing task so skip it" );
156                    }
157                    else
158                    {
159                        ArtifactContext ac = artifactContextProducer.getArtifactContext( context, artifactFile );
160    
161                        if ( ac != null )
162                        {
163                            if ( indexingTask.getAction().equals( ArtifactIndexingTask.Action.ADD ) )
164                            {
165                                //IndexSearcher s = context.getIndexSearcher();
166                                //String uinfo = ac.getArtifactInfo().getUinfo();
167                                //TopDocs d = s.search( new TermQuery( new Term( ArtifactInfo.UINFO, uinfo ) ), 1 );
168    
169                                BooleanQuery q = new BooleanQuery();
170                                q.add( nexusIndexer.constructQuery( MAVEN.GROUP_ID, new SourcedSearchExpression(
171                                    ac.getArtifactInfo().groupId ) ), BooleanClause.Occur.MUST );
172                                q.add( nexusIndexer.constructQuery( MAVEN.ARTIFACT_ID, new SourcedSearchExpression(
173                                    ac.getArtifactInfo().artifactId ) ), BooleanClause.Occur.MUST );
174                                q.add( nexusIndexer.constructQuery( MAVEN.VERSION, new SourcedSearchExpression(
175                                    ac.getArtifactInfo().version ) ), BooleanClause.Occur.MUST );
176                                if ( ac.getArtifactInfo().classifier != null )
177                                {
178                                    q.add( nexusIndexer.constructQuery( MAVEN.CLASSIFIER, new SourcedSearchExpression(
179                                        ac.getArtifactInfo().classifier ) ), BooleanClause.Occur.MUST );
180                                }
181                                if ( ac.getArtifactInfo().packaging != null )
182                                {
183                                    q.add( nexusIndexer.constructQuery( MAVEN.PACKAGING, new SourcedSearchExpression(
184                                        ac.getArtifactInfo().packaging ) ), BooleanClause.Occur.MUST );
185                                }
186                                FlatSearchRequest flatSearchRequest = new FlatSearchRequest( q, context );
187                                FlatSearchResponse flatSearchResponse = nexusIndexer.searchFlat( flatSearchRequest );
188                                if ( flatSearchResponse.getResults().isEmpty() )
189                                {
190                                    log.debug( "Adding artifact '{}' to index..", ac.getArtifactInfo() );
191                                    nexusIndexer.addArtifactToIndex( ac, context );
192                                }
193                                else
194                                {
195                                    log.debug( "Updating artifact '{}' in index..", ac.getArtifactInfo() );
196                                    // TODO check if update exists !!
197                                    nexusIndexer.deleteArtifactFromIndex( ac, context );
198                                    nexusIndexer.addArtifactToIndex( ac, context );
199                                }
200    
201                                context.updateTimestamp();
202                                context.commit();
203    
204    
205                            }
206                            else
207                            {
208                                log.debug( "Removing artifact '{}' from index..", ac.getArtifactInfo() );
209                                nexusIndexer.deleteArtifactFromIndex( ac, context );
210                            }
211                        }
212                    }
213                    // close the context if not a repo scan request
214                    if ( !indexingTask.isExecuteOnEntireRepo() )
215                    {
216                        log.debug( "Finishing indexing task on resource file : {}", indexingTask.getResourceFile() != null
217                            ? indexingTask.getResourceFile().getPath()
218                            : " none " );
219                        finishIndexingTask( indexingTask, repository, context );
220                    }
221                }
222                catch ( IOException e )
223                {
224                    log.error( "Error occurred while executing indexing task '" + indexingTask + "': " + e.getMessage(),
225                               e );
226                    throw new TaskExecutionException( "Error occurred while executing indexing task '" + indexingTask + "'",
227                                                      e );
228                }
229            }
230    
231        }
232    
233        private void finishIndexingTask( ArtifactIndexingTask indexingTask, ManagedRepository repository,
234                                         IndexingContext context )
235            throws TaskExecutionException
236        {
237            try
238            {
239    
240                context.optimize();
241    
242                if ( !repository.isSkipPackedIndexCreation() )
243                {
244    
245                    IndexPackingRequest request = new IndexPackingRequest( context, context.getIndexDirectoryFile() );
246                    indexPacker.packIndex( request );
247                    context.updateTimestamp( true );
248    
249                    log.debug( "Index file packaged at '{}'.", context.getIndexDirectoryFile() );
250                }
251                else
252                {
253                    log.debug( "skip packed index creation" );
254                }
255            }
256            catch ( IOException e )
257            {
258                log.error( "Error occurred while executing indexing task '" + indexingTask + "': " + e.getMessage() );
259                throw new TaskExecutionException( "Error occurred while executing indexing task '" + indexingTask + "'",
260                                                  e );
261            }
262        }
263    
264        public void setIndexPacker( IndexPacker indexPacker )
265        {
266            this.indexPacker = indexPacker;
267        }
268    
269        public PlexusSisuBridge getPlexusSisuBridge()
270        {
271            return plexusSisuBridge;
272        }
273    
274        public void setPlexusSisuBridge( PlexusSisuBridge plexusSisuBridge )
275        {
276            this.plexusSisuBridge = plexusSisuBridge;
277        }
278    }