1 | |
package org.apache.maven.index.updater; |
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
import java.io.BufferedInputStream; |
23 | |
import java.io.BufferedOutputStream; |
24 | |
import java.io.BufferedReader; |
25 | |
import java.io.File; |
26 | |
import java.io.FileInputStream; |
27 | |
import java.io.FileNotFoundException; |
28 | |
import java.io.FileOutputStream; |
29 | |
import java.io.IOException; |
30 | |
import java.io.InputStream; |
31 | |
import java.io.InputStreamReader; |
32 | |
import java.io.OutputStream; |
33 | |
import java.io.OutputStreamWriter; |
34 | |
import java.io.Writer; |
35 | |
import java.text.ParseException; |
36 | |
import java.text.SimpleDateFormat; |
37 | |
import java.util.ArrayList; |
38 | |
import java.util.Date; |
39 | |
import java.util.List; |
40 | |
import java.util.Properties; |
41 | |
import java.util.TimeZone; |
42 | |
import java.util.zip.ZipEntry; |
43 | |
import java.util.zip.ZipInputStream; |
44 | |
|
45 | |
import org.apache.lucene.document.Document; |
46 | |
import org.apache.lucene.index.CorruptIndexException; |
47 | |
import org.apache.lucene.index.IndexReader; |
48 | |
import org.apache.lucene.index.IndexWriter; |
49 | |
import org.apache.lucene.store.Directory; |
50 | |
import org.apache.lucene.store.FSDirectory; |
51 | |
import org.apache.lucene.store.IndexOutput; |
52 | |
import org.apache.lucene.store.LockObtainFailedException; |
53 | |
import org.apache.maven.index.context.DocumentFilter; |
54 | |
import org.apache.maven.index.context.IndexUtils; |
55 | |
import org.apache.maven.index.context.IndexingContext; |
56 | |
import org.apache.maven.index.context.NexusAnalyzer; |
57 | |
import org.apache.maven.index.context.NexusIndexWriter; |
58 | |
import org.apache.maven.index.fs.Lock; |
59 | |
import org.apache.maven.index.fs.Locker; |
60 | |
import org.apache.maven.index.incremental.IncrementalHandler; |
61 | |
import org.apache.maven.index.updater.IndexDataReader.IndexDataReadResult; |
62 | |
import org.codehaus.plexus.component.annotations.Component; |
63 | |
import org.codehaus.plexus.component.annotations.Requirement; |
64 | |
import org.codehaus.plexus.logging.AbstractLogEnabled; |
65 | |
import org.codehaus.plexus.util.FileUtils; |
66 | |
import org.codehaus.plexus.util.IOUtil; |
67 | |
import org.codehaus.plexus.util.io.RawInputStreamFacade; |
68 | |
|
69 | |
|
70 | |
|
71 | |
|
72 | |
|
73 | |
|
74 | |
|
75 | |
@Component( role = IndexUpdater.class ) |
76 | 135 | public class DefaultIndexUpdater |
77 | |
extends AbstractLogEnabled |
78 | |
implements IndexUpdater |
79 | |
{ |
80 | |
|
81 | |
@Requirement( role = IncrementalHandler.class ) |
82 | |
IncrementalHandler incrementalHandler; |
83 | |
|
84 | |
@Requirement( role = IndexUpdateSideEffect.class ) |
85 | |
private List<IndexUpdateSideEffect> sideEffects; |
86 | |
|
87 | |
public DefaultIndexUpdater( final IncrementalHandler handler, final List<IndexUpdateSideEffect> mySideeffects ) |
88 | 0 | { |
89 | 0 | incrementalHandler = handler; |
90 | 0 | sideEffects = mySideeffects; |
91 | 0 | } |
92 | |
|
93 | |
public DefaultIndexUpdater() |
94 | 22 | { |
95 | |
|
96 | 22 | } |
97 | |
|
98 | |
public IndexUpdateResult fetchAndUpdateIndex( final IndexUpdateRequest updateRequest ) |
99 | |
throws IOException |
100 | |
{ |
101 | 27 | IndexUpdateResult result = new IndexUpdateResult(); |
102 | |
|
103 | 27 | IndexingContext context = updateRequest.getIndexingContext(); |
104 | |
|
105 | 27 | ResourceFetcher fetcher = null; |
106 | |
|
107 | 27 | if ( !updateRequest.isOffline() ) |
108 | |
{ |
109 | 25 | fetcher = updateRequest.getResourceFetcher(); |
110 | |
|
111 | |
|
112 | |
|
113 | 25 | if ( fetcher == null ) |
114 | |
{ |
115 | 0 | throw new IOException( "Update of the index without provided ResourceFetcher is impossible." ); |
116 | |
} |
117 | |
|
118 | 25 | fetcher.connect( context.getId(), context.getIndexUpdateUrl() ); |
119 | |
} |
120 | |
|
121 | 27 | File cacheDir = updateRequest.getLocalIndexCacheDir(); |
122 | 27 | Locker locker = updateRequest.getLocker(); |
123 | 27 | Lock lock = locker != null && cacheDir != null ? locker.lock( cacheDir ) : null; |
124 | |
try |
125 | |
{ |
126 | 27 | if ( cacheDir != null ) |
127 | |
{ |
128 | 17 | LocalCacheIndexAdaptor cache = new LocalCacheIndexAdaptor( cacheDir, result ); |
129 | |
|
130 | 17 | if ( !updateRequest.isOffline() ) |
131 | |
{ |
132 | 15 | cacheDir.mkdirs(); |
133 | |
|
134 | |
try |
135 | |
{ |
136 | 15 | fetchAndUpdateIndex( updateRequest, fetcher, cache ); |
137 | 14 | cache.commit(); |
138 | |
} |
139 | |
finally |
140 | |
{ |
141 | 15 | fetcher.disconnect(); |
142 | 14 | } |
143 | |
} |
144 | |
|
145 | 16 | fetcher = cache.getFetcher(); |
146 | 16 | } |
147 | 10 | else if ( updateRequest.isOffline() ) |
148 | |
{ |
149 | 0 | throw new IllegalArgumentException( "LocalIndexCacheDir can not be null in offline mode" ); |
150 | |
} |
151 | |
|
152 | |
try |
153 | |
{ |
154 | 26 | if ( !updateRequest.isCacheOnly() ) |
155 | |
{ |
156 | 26 | LuceneIndexAdaptor target = new LuceneIndexAdaptor( updateRequest ); |
157 | 26 | result.setTimestamp( fetchAndUpdateIndex( updateRequest, fetcher, target ) ); |
158 | 26 | target.commit(); |
159 | |
} |
160 | |
} |
161 | |
finally |
162 | |
{ |
163 | 26 | fetcher.disconnect(); |
164 | 26 | } |
165 | |
} |
166 | |
finally |
167 | |
{ |
168 | 27 | if ( lock != null ) |
169 | |
{ |
170 | 0 | lock.release(); |
171 | |
} |
172 | |
} |
173 | |
|
174 | 26 | return result; |
175 | |
} |
176 | |
|
177 | |
private Date loadIndexDirectory( final IndexUpdateRequest updateRequest, final ResourceFetcher fetcher, |
178 | |
final boolean merge, final String remoteIndexFile ) |
179 | |
throws IOException |
180 | |
{ |
181 | 24 | File indexDir = File.createTempFile( remoteIndexFile, ".dir" ); |
182 | 24 | indexDir.delete(); |
183 | 24 | indexDir.mkdirs(); |
184 | |
|
185 | 24 | FSDirectory directory = FSDirectory.open( indexDir ); |
186 | |
|
187 | 24 | BufferedInputStream is = null; |
188 | |
|
189 | |
try |
190 | |
{ |
191 | 24 | is = new BufferedInputStream( fetcher.retrieve( remoteIndexFile ) ); |
192 | |
|
193 | 23 | Date timestamp = null; |
194 | |
|
195 | 23 | if ( remoteIndexFile.endsWith( ".gz" ) ) |
196 | |
{ |
197 | 22 | timestamp = unpackIndexData( is, directory, |
198 | |
updateRequest.getIndexingContext() ); |
199 | |
} |
200 | |
else |
201 | |
{ |
202 | |
|
203 | 1 | timestamp = unpackIndexArchive( is, directory, |
204 | |
updateRequest.getIndexingContext() ); |
205 | |
} |
206 | |
|
207 | 23 | if ( updateRequest.getDocumentFilter() != null ) |
208 | |
{ |
209 | 1 | filterDirectory( directory, updateRequest.getDocumentFilter() ); |
210 | |
} |
211 | |
|
212 | 23 | if ( merge ) |
213 | |
{ |
214 | 5 | updateRequest.getIndexingContext().merge( directory ); |
215 | |
} |
216 | |
else |
217 | |
{ |
218 | 18 | updateRequest.getIndexingContext().replace( directory ); |
219 | |
} |
220 | 23 | if ( sideEffects != null && sideEffects.size() > 0 ) |
221 | |
{ |
222 | 0 | getLogger().info( IndexUpdateSideEffect.class.getName() + " extensions found: " + sideEffects.size() ); |
223 | 0 | for ( IndexUpdateSideEffect sideeffect : sideEffects ) |
224 | |
{ |
225 | 0 | sideeffect.updateIndex( directory, updateRequest.getIndexingContext(), merge ); |
226 | |
} |
227 | |
} |
228 | |
|
229 | 23 | return timestamp; |
230 | |
} |
231 | |
finally |
232 | |
{ |
233 | 24 | IOUtil.close( is ); |
234 | |
|
235 | 24 | if ( directory != null ) |
236 | |
{ |
237 | 24 | directory.close(); |
238 | |
} |
239 | |
|
240 | |
try |
241 | |
{ |
242 | 24 | FileUtils.deleteDirectory( indexDir ); |
243 | |
} |
244 | 0 | catch ( IOException ex ) |
245 | |
{ |
246 | |
|
247 | 48 | } |
248 | |
} |
249 | |
} |
250 | |
|
251 | |
|
252 | |
|
253 | |
|
254 | |
|
255 | |
|
256 | |
|
257 | |
|
258 | |
public static Date unpackIndexArchive( final InputStream is, final Directory directory, |
259 | |
final IndexingContext context ) |
260 | |
throws IOException |
261 | |
{ |
262 | 17 | File indexArchive = File.createTempFile( "nexus-index", "" ); |
263 | |
|
264 | 17 | File indexDir = new File( indexArchive.getAbsoluteFile().getParentFile(), indexArchive.getName() + ".dir" ); |
265 | |
|
266 | 17 | indexDir.mkdirs(); |
267 | |
|
268 | 17 | FSDirectory fdir = FSDirectory.open( indexDir ); |
269 | |
|
270 | |
try |
271 | |
{ |
272 | 17 | unpackDirectory( fdir, is ); |
273 | 17 | copyUpdatedDocuments( fdir, directory, context ); |
274 | |
|
275 | 17 | Date timestamp = IndexUtils.getTimestamp( fdir ); |
276 | 17 | IndexUtils.updateTimestamp( directory, timestamp ); |
277 | 17 | return timestamp; |
278 | |
} |
279 | |
finally |
280 | |
{ |
281 | 17 | IndexUtils.close( fdir ); |
282 | 17 | indexArchive.delete(); |
283 | 17 | IndexUtils.delete( indexDir ); |
284 | |
} |
285 | |
} |
286 | |
|
287 | |
private static void unpackDirectory( final Directory directory, final InputStream is ) |
288 | |
throws IOException |
289 | |
{ |
290 | 17 | byte[] buf = new byte[4096]; |
291 | |
|
292 | |
ZipEntry entry; |
293 | |
|
294 | 17 | ZipInputStream zis = null; |
295 | |
|
296 | |
try |
297 | |
{ |
298 | 17 | zis = new ZipInputStream( is ); |
299 | |
|
300 | 160 | while ( ( entry = zis.getNextEntry() ) != null ) |
301 | |
{ |
302 | 143 | if ( entry.isDirectory() || entry.getName().indexOf( '/' ) > -1 ) |
303 | |
{ |
304 | 0 | continue; |
305 | |
} |
306 | |
|
307 | 143 | IndexOutput io = directory.createOutput( entry.getName() ); |
308 | |
try |
309 | |
{ |
310 | 143 | int n = 0; |
311 | |
|
312 | 848 | while ( ( n = zis.read( buf ) ) != -1 ) |
313 | |
{ |
314 | 705 | io.writeBytes( buf, n ); |
315 | |
} |
316 | |
} |
317 | |
finally |
318 | |
{ |
319 | 143 | IndexUtils.close( io ); |
320 | 143 | } |
321 | 143 | } |
322 | |
} |
323 | |
finally |
324 | |
{ |
325 | 17 | IndexUtils.close( zis ); |
326 | 17 | } |
327 | 17 | } |
328 | |
|
329 | |
private static void copyUpdatedDocuments( final Directory sourcedir, final Directory targetdir, |
330 | |
final IndexingContext context ) |
331 | |
throws CorruptIndexException, LockObtainFailedException, IOException |
332 | |
{ |
333 | 17 | IndexWriter w = null; |
334 | 17 | IndexReader r = null; |
335 | |
try |
336 | |
{ |
337 | 17 | r = IndexReader.open( sourcedir ); |
338 | 17 | w = new NexusIndexWriter( targetdir, new NexusAnalyzer(), true ); |
339 | |
|
340 | 631 | for ( int i = 0; i < r.maxDoc(); i++ ) |
341 | |
{ |
342 | 614 | if ( !r.isDeleted( i ) ) |
343 | |
{ |
344 | 614 | w.addDocument( IndexUtils.updateDocument( r.document( i ), context ) ); |
345 | |
} |
346 | |
} |
347 | |
|
348 | 17 | w.optimize(); |
349 | 17 | w.commit(); |
350 | |
} |
351 | |
finally |
352 | |
{ |
353 | 17 | IndexUtils.close( w ); |
354 | 17 | IndexUtils.close( r ); |
355 | 17 | } |
356 | 17 | } |
357 | |
|
358 | |
private static void filterDirectory( final Directory directory, final DocumentFilter filter ) |
359 | |
throws IOException |
360 | |
{ |
361 | 1 | IndexReader r = null; |
362 | |
try |
363 | |
{ |
364 | |
|
365 | 1 | r = IndexReader.open( directory, false ); |
366 | |
|
367 | 1 | int numDocs = r.maxDoc(); |
368 | |
|
369 | 6 | for ( int i = 0; i < numDocs; i++ ) |
370 | |
{ |
371 | 5 | if ( r.isDeleted( i ) ) |
372 | |
{ |
373 | 0 | continue; |
374 | |
} |
375 | |
|
376 | 5 | Document d = r.document( i ); |
377 | |
|
378 | 5 | if ( !filter.accept( d ) ) |
379 | |
{ |
380 | 0 | r.deleteDocument( i ); |
381 | |
} |
382 | |
} |
383 | |
} |
384 | |
finally |
385 | |
{ |
386 | 1 | IndexUtils.close( r ); |
387 | 1 | } |
388 | |
|
389 | 1 | IndexWriter w = null; |
390 | |
try |
391 | |
{ |
392 | |
|
393 | 1 | w = new NexusIndexWriter( directory, new NexusAnalyzer(), false ); |
394 | |
|
395 | 1 | w.optimize(); |
396 | |
|
397 | 1 | w.commit(); |
398 | |
} |
399 | |
finally |
400 | |
{ |
401 | 1 | IndexUtils.close( w ); |
402 | 1 | } |
403 | 1 | } |
404 | |
|
405 | |
private Properties loadIndexProperties( final File indexDirectoryFile, final String remoteIndexPropertiesName ) |
406 | |
{ |
407 | 30 | File indexProperties = new File( indexDirectoryFile, remoteIndexPropertiesName ); |
408 | |
|
409 | 30 | FileInputStream fis = null; |
410 | |
|
411 | |
try |
412 | |
{ |
413 | 30 | Properties properties = new Properties(); |
414 | |
|
415 | 30 | fis = new FileInputStream( indexProperties ); |
416 | |
|
417 | 13 | properties.load( fis ); |
418 | |
|
419 | 13 | return properties; |
420 | |
} |
421 | 17 | catch ( IOException e ) |
422 | |
{ |
423 | 17 | getLogger().debug( "Unable to read remote properties stored locally", e ); |
424 | |
} |
425 | |
finally |
426 | |
{ |
427 | 30 | IOUtil.close( fis ); |
428 | 17 | } |
429 | |
|
430 | 17 | return null; |
431 | |
} |
432 | |
|
433 | |
private void storeIndexProperties( final File dir, final String indexPropertiesName, final Properties properties ) |
434 | |
throws IOException |
435 | |
{ |
436 | 40 | File file = new File( dir, indexPropertiesName ); |
437 | |
|
438 | 40 | if ( properties != null ) |
439 | |
{ |
440 | 40 | OutputStream os = new BufferedOutputStream( new FileOutputStream( file ) ); |
441 | |
try |
442 | |
{ |
443 | 40 | properties.store( os, null ); |
444 | |
} |
445 | |
finally |
446 | |
{ |
447 | 40 | IOUtil.close( os ); |
448 | 40 | } |
449 | 40 | } |
450 | |
else |
451 | |
{ |
452 | 0 | file.delete(); |
453 | |
} |
454 | 40 | } |
455 | |
|
456 | |
private Properties downloadIndexProperties( final ResourceFetcher fetcher ) |
457 | |
throws IOException |
458 | |
{ |
459 | 41 | InputStream fis = fetcher.retrieve( IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ); |
460 | |
|
461 | |
try |
462 | |
{ |
463 | 41 | Properties properties = new Properties(); |
464 | |
|
465 | 41 | properties.load( fis ); |
466 | |
|
467 | 41 | return properties; |
468 | |
} |
469 | |
finally |
470 | |
{ |
471 | 41 | IOUtil.close( fis ); |
472 | |
} |
473 | |
} |
474 | |
|
475 | |
public Date getTimestamp( final Properties properties, final String key ) |
476 | |
{ |
477 | 43 | String indexTimestamp = properties.getProperty( key ); |
478 | |
|
479 | 43 | if ( indexTimestamp != null ) |
480 | |
{ |
481 | |
try |
482 | |
{ |
483 | 41 | SimpleDateFormat df = new SimpleDateFormat( IndexingContext.INDEX_TIME_FORMAT ); |
484 | 41 | df.setTimeZone( TimeZone.getTimeZone( "GMT" ) ); |
485 | 41 | return df.parse( indexTimestamp ); |
486 | |
} |
487 | 0 | catch ( ParseException ex ) |
488 | |
{ |
489 | |
} |
490 | |
} |
491 | 2 | return null; |
492 | |
} |
493 | |
|
494 | |
|
495 | |
|
496 | |
|
497 | |
|
498 | |
|
499 | |
|
500 | |
|
501 | |
public static Date unpackIndexData( final InputStream is, final Directory d, final IndexingContext context ) |
502 | |
throws IOException |
503 | |
{ |
504 | 35 | NexusIndexWriter w = new NexusIndexWriter( d, new NexusAnalyzer(), true ); |
505 | |
try |
506 | |
{ |
507 | 35 | IndexDataReader dr = new IndexDataReader( is ); |
508 | |
|
509 | 35 | IndexDataReadResult result = dr.readIndex( w, context ); |
510 | |
|
511 | 35 | return result.getTimestamp(); |
512 | |
} |
513 | |
finally |
514 | |
{ |
515 | 35 | IndexUtils.close( w ); |
516 | |
} |
517 | |
} |
518 | |
|
519 | |
|
520 | |
|
521 | |
|
522 | |
public static class FileFetcher |
523 | |
implements ResourceFetcher |
524 | |
{ |
525 | |
private final File basedir; |
526 | |
|
527 | |
public FileFetcher( File basedir ) |
528 | 32 | { |
529 | 32 | this.basedir = basedir; |
530 | 32 | } |
531 | |
|
532 | |
public void connect( String id, String url ) |
533 | |
throws IOException |
534 | |
{ |
535 | |
|
536 | 15 | } |
537 | |
|
538 | |
public void disconnect() |
539 | |
throws IOException |
540 | |
{ |
541 | |
|
542 | 31 | } |
543 | |
|
544 | |
public void retrieve( String name, File targetFile ) |
545 | |
throws IOException, FileNotFoundException |
546 | |
{ |
547 | 0 | FileUtils.copyFile( getFile( name ), targetFile ); |
548 | |
|
549 | 0 | } |
550 | |
|
551 | |
public InputStream retrieve( String name ) |
552 | |
throws IOException, FileNotFoundException |
553 | |
{ |
554 | 56 | return new FileInputStream( getFile( name ) ); |
555 | |
} |
556 | |
|
557 | |
private File getFile( String name ) |
558 | |
{ |
559 | 56 | return new File( basedir, name ); |
560 | |
} |
561 | |
|
562 | |
} |
563 | |
|
564 | |
private abstract class IndexAdaptor |
565 | |
{ |
566 | |
protected final File dir; |
567 | |
|
568 | |
protected Properties properties; |
569 | |
|
570 | |
protected IndexAdaptor( File dir ) |
571 | 43 | { |
572 | 43 | this.dir = dir; |
573 | 43 | } |
574 | |
|
575 | |
public abstract Properties getProperties(); |
576 | |
|
577 | |
public abstract void storeProperties() |
578 | |
throws IOException; |
579 | |
|
580 | |
public abstract void addIndexChunk( ResourceFetcher source, String filename ) |
581 | |
throws IOException; |
582 | |
|
583 | |
public abstract Date setIndexFile( ResourceFetcher source, String string ) |
584 | |
throws IOException; |
585 | |
|
586 | |
public Properties setProperties( ResourceFetcher source ) |
587 | |
throws IOException |
588 | |
{ |
589 | 41 | this.properties = downloadIndexProperties( source ); |
590 | 41 | return properties; |
591 | |
} |
592 | |
|
593 | |
public abstract Date getTimestamp(); |
594 | |
|
595 | |
public void commit() |
596 | |
throws IOException |
597 | |
{ |
598 | 40 | storeProperties(); |
599 | 40 | } |
600 | |
} |
601 | |
|
602 | |
private class LuceneIndexAdaptor |
603 | |
extends IndexAdaptor |
604 | |
{ |
605 | |
private final IndexUpdateRequest updateRequest; |
606 | |
|
607 | |
public LuceneIndexAdaptor( IndexUpdateRequest updateRequest ) |
608 | 26 | { |
609 | 26 | super( updateRequest.getIndexingContext().getIndexDirectoryFile() ); |
610 | 26 | this.updateRequest = updateRequest; |
611 | 26 | } |
612 | |
|
613 | |
public Properties getProperties() |
614 | |
{ |
615 | 18 | if ( properties == null ) |
616 | |
{ |
617 | 18 | properties = loadIndexProperties( dir, IndexingContext.INDEX_UPDATER_PROPERTIES_FILE ); |
618 | |
} |
619 | 18 | return properties; |
620 | |
} |
621 | |
|
622 | |
public void storeProperties() |
623 | |
throws IOException |
624 | |
{ |
625 | 26 | storeIndexProperties( dir, IndexingContext.INDEX_UPDATER_PROPERTIES_FILE, properties ); |
626 | 26 | } |
627 | |
|
628 | |
public Date getTimestamp() |
629 | |
{ |
630 | 0 | return updateRequest.getIndexingContext().getTimestamp(); |
631 | |
} |
632 | |
|
633 | |
public void addIndexChunk( ResourceFetcher source, String filename ) |
634 | |
throws IOException |
635 | |
{ |
636 | 5 | loadIndexDirectory( updateRequest, source, true, filename ); |
637 | 5 | } |
638 | |
|
639 | |
public Date setIndexFile( ResourceFetcher source, String filename ) |
640 | |
throws IOException |
641 | |
{ |
642 | 19 | return loadIndexDirectory( updateRequest, source, false, filename ); |
643 | |
} |
644 | |
|
645 | |
public void commit() |
646 | |
throws IOException |
647 | |
{ |
648 | 26 | super.commit(); |
649 | |
|
650 | 26 | updateRequest.getIndexingContext().commit(); |
651 | 26 | } |
652 | |
|
653 | |
} |
654 | |
|
655 | |
private class LocalCacheIndexAdaptor |
656 | |
extends IndexAdaptor |
657 | |
{ |
658 | |
private static final String CHUNKS_FILENAME = "chunks.lst"; |
659 | |
|
660 | |
private static final String CHUNKS_FILE_ENCODING = "UTF-8"; |
661 | |
|
662 | |
private final IndexUpdateResult result; |
663 | |
|
664 | 17 | private final ArrayList<String> newChunks = new ArrayList<String>(); |
665 | |
|
666 | |
public LocalCacheIndexAdaptor( File dir, IndexUpdateResult result ) |
667 | 17 | { |
668 | 17 | super( dir ); |
669 | 17 | this.result = result; |
670 | 17 | } |
671 | |
|
672 | |
public Properties getProperties() |
673 | |
{ |
674 | 12 | if ( properties == null ) |
675 | |
{ |
676 | 12 | properties = loadIndexProperties( dir, IndexingContext.INDEX_REMOTE_PROPERTIES_FILE ); |
677 | |
} |
678 | 12 | return properties; |
679 | |
} |
680 | |
|
681 | |
public void storeProperties() |
682 | |
throws IOException |
683 | |
{ |
684 | 14 | storeIndexProperties( dir, IndexingContext.INDEX_REMOTE_PROPERTIES_FILE, properties ); |
685 | 14 | } |
686 | |
|
687 | |
public Date getTimestamp() |
688 | |
{ |
689 | 0 | Properties properties = getProperties(); |
690 | 0 | if ( properties == null ) |
691 | |
{ |
692 | 0 | return null; |
693 | |
} |
694 | |
|
695 | 0 | Date timestamp = DefaultIndexUpdater.this.getTimestamp( properties, IndexingContext.INDEX_TIMESTAMP ); |
696 | |
|
697 | 0 | if ( timestamp == null ) |
698 | |
{ |
699 | 0 | timestamp = DefaultIndexUpdater.this.getTimestamp( properties, IndexingContext.INDEX_LEGACY_TIMESTAMP ); |
700 | |
} |
701 | |
|
702 | 0 | return timestamp; |
703 | |
} |
704 | |
|
705 | |
public void addIndexChunk( ResourceFetcher source, String filename ) |
706 | |
throws IOException |
707 | |
{ |
708 | 2 | File chunk = new File( dir, filename ); |
709 | 2 | FileUtils.copyStreamToFile( new RawInputStreamFacade( source.retrieve( filename ) ), chunk ); |
710 | 2 | newChunks.add( filename ); |
711 | 2 | } |
712 | |
|
713 | |
public Date setIndexFile( ResourceFetcher source, String filename ) |
714 | |
throws IOException |
715 | |
{ |
716 | 11 | cleanCacheDirectory( dir ); |
717 | |
|
718 | 11 | result.setFullUpdate( true ); |
719 | |
|
720 | 11 | File target = new File( dir, filename ); |
721 | 11 | FileUtils.copyStreamToFile( new RawInputStreamFacade( source.retrieve( filename ) ), target ); |
722 | |
|
723 | 9 | return null; |
724 | |
} |
725 | |
|
726 | |
@Override |
727 | |
public void commit() |
728 | |
throws IOException |
729 | |
{ |
730 | 14 | File chunksFile = new File( dir, CHUNKS_FILENAME ); |
731 | 14 | BufferedOutputStream os = new BufferedOutputStream( new FileOutputStream( chunksFile, true ) ); |
732 | 14 | Writer w = new OutputStreamWriter( os, CHUNKS_FILE_ENCODING ); |
733 | |
try |
734 | |
{ |
735 | 14 | for ( String filename : newChunks ) |
736 | |
{ |
737 | 2 | w.write( filename + "\n" ); |
738 | |
} |
739 | 14 | w.flush(); |
740 | |
} |
741 | |
finally |
742 | |
{ |
743 | 14 | IOUtil.close( w ); |
744 | 14 | IOUtil.close( os ); |
745 | 14 | } |
746 | 14 | super.commit(); |
747 | 14 | } |
748 | |
|
749 | |
public List<String> getChunks() |
750 | |
throws IOException |
751 | |
{ |
752 | 11 | ArrayList<String> chunks = new ArrayList<String>(); |
753 | |
|
754 | 11 | File chunksFile = new File( dir, CHUNKS_FILENAME ); |
755 | 11 | BufferedReader r = |
756 | |
new BufferedReader( new InputStreamReader( new FileInputStream( chunksFile ), CHUNKS_FILE_ENCODING ) ); |
757 | |
try |
758 | |
{ |
759 | |
String str; |
760 | 13 | while ( ( str = r.readLine() ) != null ) |
761 | |
{ |
762 | 2 | chunks.add( str ); |
763 | |
} |
764 | |
} |
765 | |
finally |
766 | |
{ |
767 | 11 | IOUtil.close( r ); |
768 | 11 | } |
769 | 11 | return chunks; |
770 | |
} |
771 | |
|
772 | |
public ResourceFetcher getFetcher() |
773 | |
{ |
774 | 16 | return new LocalIndexCacheFetcher( dir ) |
775 | 16 | { |
776 | |
@Override |
777 | |
public List<String> getChunks() |
778 | |
throws IOException |
779 | |
{ |
780 | 11 | return LocalCacheIndexAdaptor.this.getChunks(); |
781 | |
} |
782 | |
}; |
783 | |
} |
784 | |
} |
785 | |
|
786 | |
abstract static class LocalIndexCacheFetcher |
787 | |
extends FileFetcher |
788 | |
{ |
789 | |
public LocalIndexCacheFetcher( File basedir ) |
790 | |
{ |
791 | 16 | super( basedir ); |
792 | 16 | } |
793 | |
|
794 | |
public abstract List<String> getChunks() |
795 | |
throws IOException; |
796 | |
} |
797 | |
|
798 | |
private Date fetchAndUpdateIndex( final IndexUpdateRequest updateRequest, ResourceFetcher source, |
799 | |
IndexAdaptor target ) |
800 | |
throws IOException |
801 | |
{ |
802 | 41 | if ( !updateRequest.isForceFullUpdate() ) |
803 | |
{ |
804 | 30 | Properties localProperties = target.getProperties(); |
805 | 30 | Date localTimestamp = null; |
806 | |
|
807 | 30 | if ( localProperties != null ) |
808 | |
{ |
809 | 13 | localTimestamp = getTimestamp( localProperties, IndexingContext.INDEX_TIMESTAMP ); |
810 | |
} |
811 | |
|
812 | |
|
813 | |
|
814 | 30 | Properties remoteProperties = target.setProperties( source ); |
815 | |
|
816 | 30 | Date updateTimestamp = getTimestamp( remoteProperties, IndexingContext.INDEX_TIMESTAMP ); |
817 | |
|
818 | |
|
819 | 30 | if ( updateTimestamp != null ) |
820 | |
{ |
821 | 30 | List<String> filenames = |
822 | |
incrementalHandler.loadRemoteIncrementalUpdates( updateRequest, localProperties, remoteProperties ); |
823 | |
|
824 | |
|
825 | 30 | if ( filenames != null ) |
826 | |
{ |
827 | 7 | for ( String filename : filenames ) |
828 | |
{ |
829 | 5 | target.addIndexChunk( source, filename ); |
830 | |
} |
831 | |
|
832 | 7 | return updateTimestamp; |
833 | |
} |
834 | 23 | } |
835 | |
else |
836 | |
{ |
837 | 0 | updateTimestamp = getTimestamp( remoteProperties, IndexingContext.INDEX_LEGACY_TIMESTAMP ); |
838 | |
} |
839 | |
|
840 | |
|
841 | |
|
842 | |
|
843 | 23 | if ( localTimestamp != null ) |
844 | |
{ |
845 | |
|
846 | |
|
847 | |
|
848 | 6 | if ( updateTimestamp != null && localTimestamp != null && !updateTimestamp.after( localTimestamp ) ) |
849 | |
{ |
850 | 6 | return null; |
851 | |
} |
852 | |
} |
853 | 17 | } |
854 | |
else |
855 | |
{ |
856 | |
|
857 | 11 | target.setProperties( source ); |
858 | |
} |
859 | |
|
860 | |
try |
861 | |
{ |
862 | 28 | Date timestamp = target.setIndexFile( source, IndexingContext.INDEX_FILE_PREFIX + ".gz" ); |
863 | 26 | if ( source instanceof LocalIndexCacheFetcher ) |
864 | |
{ |
865 | |
|
866 | |
|
867 | 11 | for ( String filename : ( (LocalIndexCacheFetcher) source ).getChunks() ) |
868 | |
{ |
869 | 2 | target.addIndexChunk( source, filename ); |
870 | |
} |
871 | |
} |
872 | 26 | return timestamp; |
873 | |
} |
874 | 2 | catch ( IOException ex ) |
875 | |
{ |
876 | |
|
877 | |
try |
878 | |
{ |
879 | 2 | return target.setIndexFile( source, IndexingContext.INDEX_FILE_PREFIX + ".zip" ); |
880 | |
} |
881 | 1 | catch ( IOException ex2 ) |
882 | |
{ |
883 | 1 | getLogger().error( "Fallback to *.zip also failed: " + ex2 ); |
884 | |
|
885 | 1 | throw ex; |
886 | |
} |
887 | |
} |
888 | |
} |
889 | |
|
890 | |
|
891 | |
|
892 | |
|
893 | |
protected void cleanCacheDirectory( File dir ) |
894 | |
throws IOException |
895 | |
{ |
896 | 11 | File[] members = dir.listFiles(); |
897 | 11 | if ( members == null ) |
898 | |
{ |
899 | 0 | return; |
900 | |
} |
901 | |
|
902 | 21 | for ( File member : members ) |
903 | |
{ |
904 | 10 | if ( !Locker.LOCK_FILE.equals( member.getName() ) ) |
905 | |
{ |
906 | 9 | FileUtils.forceDelete( member ); |
907 | |
} |
908 | |
} |
909 | 11 | } |
910 | |
|
911 | |
} |