View Javadoc

1   package org.apache.maven.index;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0    
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.Set;
27  
28  import org.apache.lucene.document.Document;
29  import org.apache.lucene.index.CorruptIndexException;
30  import org.apache.lucene.index.IndexReader;
31  import org.apache.lucene.index.Term;
32  import org.apache.lucene.search.IndexSearcher;
33  import org.apache.lucene.search.TermQuery;
34  import org.apache.lucene.search.TopScoreDocCollector;
35  import org.apache.maven.index.context.IndexingContext;
36  import org.codehaus.plexus.logging.AbstractLogEnabled;
37  
38  /**
39   * A default scanning listener
40   * 
41   * @author Eugene Kuleshov
42   */
43  public class DefaultScannerListener
44      extends AbstractLogEnabled
45      implements ArtifactScanningListener
46  {
47      private final IndexingContext context;
48  
49      private final IndexerEngine indexerEngine;
50  
51      private final boolean update;
52  
53      private final ArtifactScanningListener listener;
54  
55      private final Set<String> uinfos = new HashSet<String>();
56  
57      private final Set<String> processedUinfos = new HashSet<String>();
58  
59      private final Set<String> allGroups = new HashSet<String>();
60  
61      private final Set<String> groups = new HashSet<String>();
62  
63      private final List<Exception> exceptions = new ArrayList<Exception>();
64  
65      private int count = 0;
66  
67      public DefaultScannerListener( IndexingContext context, //
68                              IndexerEngine indexerEngine, boolean update, //
69                              ArtifactScanningListener listener )
70      {
71          this.context = context;
72          this.indexerEngine = indexerEngine;
73          this.update = update;
74          this.listener = listener;
75      }
76  
77      public void scanningStarted( IndexingContext ctx )
78      {
79          try
80          {
81              if ( update )
82              {
83                  initialize( ctx );
84              }
85          }
86          catch ( IOException ex )
87          {
88              exceptions.add( ex );
89          }
90  
91          if ( listener != null )
92          {
93              listener.scanningStarted( ctx );
94          }
95      }
96  
97      public void artifactDiscovered( ArtifactContext ac )
98      {
99          String uinfo = ac.getArtifactInfo().getUinfo();
100 
101         // TODO: scattered across commented out changes while I was fixing NEXUS-2712, cstamas
102         // These changes should be applied by borks too much the fragile indexer
103 
104         // if ( VersionUtils.isSnapshot( ac.getArtifactInfo().version ) && processedUinfos.contains( uinfo ) )
105         if ( processedUinfos.contains( uinfo ) )
106         {
107             return; // skip individual snapshots
108         }
109 
110         boolean adding = processedUinfos.add( uinfo );
111 
112         if ( uinfos.contains( uinfo ) )
113         {
114             // already indexed
115             uinfos.remove( uinfo );
116             return;
117         }
118 
119         try
120         {
121             if ( listener != null )
122             {
123                 listener.artifactDiscovered( ac );
124             }
125 
126             if ( adding )
127             {
128                 indexerEngine.index( context, ac );
129             }
130             else
131             {
132                 indexerEngine.update( context, ac );
133             }
134 
135             for ( Exception e : ac.getErrors() )
136             {
137                 artifactError( ac, e );
138             }
139 
140             groups.add( ac.getArtifactInfo().getRootGroup() );
141             allGroups.add( ac.getArtifactInfo().groupId );
142 
143             count++;
144         }
145         catch ( IOException ex )
146         {
147             artifactError( ac, ex );
148         }
149     }
150 
151     public void scanningFinished( IndexingContext ctx, ScanningResult result )
152     {
153         result.setTotalFiles( count );
154 
155         for ( Exception ex : exceptions )
156         {
157             result.addException( ex );
158         }
159 
160         try
161         {
162             context.optimize();
163 
164             context.setRootGroups( groups );
165 
166             context.setAllGroups( allGroups );
167 
168             if ( update && !context.isReceivingUpdates() )
169             {
170                 removeDeletedArtifacts( context, result, result.getRequest().getStartingPath() );
171             }
172         }
173         catch ( IOException ex )
174         {
175             result.addException( ex );
176         }
177 
178         if ( listener != null )
179         {
180             listener.scanningFinished( ctx, result );
181         }
182 
183         if ( result.getDeletedFiles() > 0 || result.getTotalFiles() > 0 )
184         {
185             try
186             {
187                 context.updateTimestamp( true );
188 
189                 context.optimize();
190             }
191             catch ( Exception ex )
192             {
193                 result.addException( ex );
194             }
195         }
196     }
197 
198     public void artifactError( ArtifactContext ac, Exception e )
199     {
200         exceptions.add( e );
201 
202         if ( listener != null )
203         {
204             listener.artifactError( ac, e );
205         }
206     }
207 
208     private void initialize( IndexingContext ctx )
209         throws IOException, CorruptIndexException
210     {
211         final IndexSearcher indexSearcher = ctx.acquireIndexSearcher();
212         try
213         {
214             final IndexReader r = indexSearcher.getIndexReader();
215 
216             for ( int i = 0; i < r.maxDoc(); i++ )
217             {
218                 if ( !r.isDeleted( i ) )
219                 {
220                     Document d = r.document( i );
221 
222                     String uinfo = d.get( ArtifactInfo.UINFO );
223 
224                     if ( uinfo != null )
225                     {
226                         // if ctx is receiving updates (in other words, is a proxy),
227                         // there is no need to build a huge Set of strings with all uinfo's
228                         // as deletion detection in those cases have no effect. Also, the
229                         // removeDeletedArtifacts() method, that uses info gathered in this set
230                         // is invoked with same condition. As indexes of Central are getting huge,
231                         // the set grows enormously too, but is actually not used
232                         if ( !ctx.isReceivingUpdates() )
233                         {
234                             uinfos.add( uinfo );
235                         }
236 
237                         // add all existing groupIds to the lists, as they will
238                         // not be "discovered" and would be missing from the new list..
239                         String groupId = uinfo.substring( 0, uinfo.indexOf( '|' ) );
240                         int n = groupId.indexOf( '.' );
241                         groups.add( n == -1 ? groupId : groupId.substring( 0, n ) );
242                         allGroups.add( groupId );
243                     }
244                 }
245             }
246         }
247         finally
248         {
249             ctx.releaseIndexSearcher( indexSearcher );
250         }
251     }
252 
253     private void removeDeletedArtifacts( IndexingContext context, ScanningResult result, String contextPath )
254         throws IOException
255     {
256         int deleted = 0;
257 
258         final IndexSearcher indexSearcher = context.acquireIndexSearcher();
259         try
260         {
261             for ( String uinfo : uinfos )
262             {
263                 TopScoreDocCollector collector = TopScoreDocCollector.create( 1, false );
264 
265                 indexSearcher.search( new TermQuery( new Term( ArtifactInfo.UINFO, uinfo ) ), collector );
266 
267                 if ( collector.getTotalHits() > 0 )
268                 {
269                     String[] ra = ArtifactInfo.FS_PATTERN.split( uinfo );
270 
271                     ArtifactInfo ai = new ArtifactInfo();
272 
273                     ai.repository = context.getRepositoryId();
274 
275                     ai.groupId = ra[0];
276 
277                     ai.artifactId = ra[1];
278 
279                     ai.version = ra[2];
280 
281                     if ( ra.length > 3 )
282                     {
283                         ai.classifier = ArtifactInfo.renvl( ra[3] );
284                     }
285 
286                     if ( ra.length > 4 )
287                     {
288                         ai.packaging = ArtifactInfo.renvl( ra[4] );
289                     }
290 
291                     // minimal ArtifactContext for removal
292                     ArtifactContext ac = new ArtifactContext( null, null, null, ai, ai.calculateGav() );
293 
294                     for ( int i = 0; i < collector.getTotalHits(); i++ )
295                     {
296                         if ( contextPath == null
297                             || context.getGavCalculator().gavToPath( ac.getGav() ).startsWith( contextPath ) )
298                         {
299                             indexerEngine.remove( context, ac );
300                         }
301 
302                         deleted++;
303                     }
304                 }
305             }
306         }
307         finally
308         {
309             context.releaseIndexSearcher( indexSearcher );
310         }
311 
312         if ( deleted > 0 )
313         {
314             context.commit();
315         }
316 
317         result.setDeletedFiles( deleted );
318     }
319 
320 }