1 package org.apache.archiva.scheduler.indexing;
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
21 import org.apache.archiva.admin.model.beans.NetworkProxy;
22 import org.apache.archiva.admin.model.beans.RemoteRepository;
23 import org.apache.archiva.proxy.common.WagonFactory;
24 import org.apache.archiva.proxy.common.WagonFactoryException;
25 import org.apache.commons.compress.compressors.CompressorException;
26 import org.apache.commons.io.FileUtils;
27 import org.apache.maven.index.NexusIndexer;
28 import org.apache.maven.index.context.IndexingContext;
29 import org.apache.maven.index.updater.IndexUpdateRequest;
30 import org.apache.maven.index.updater.IndexUpdater;
31 import org.apache.maven.index.updater.ResourceFetcher;
32 import org.apache.maven.wagon.ConnectionException;
33 import org.apache.maven.wagon.ResourceDoesNotExistException;
34 import org.apache.maven.wagon.TransferFailedException;
35 import org.apache.maven.wagon.Wagon;
36 import org.apache.maven.wagon.authentication.AuthenticationException;
37 import org.apache.maven.wagon.authentication.AuthenticationInfo;
38 import org.apache.maven.wagon.authorization.AuthorizationException;
39 import org.apache.maven.wagon.events.TransferEvent;
40 import org.apache.maven.wagon.events.TransferListener;
41 import org.apache.maven.wagon.proxy.ProxyInfo;
42 import org.apache.maven.wagon.repository.Repository;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
47 import java.io.FileInputStream;
48 import java.io.FileNotFoundException;
49 import java.io.IOException;
50 import java.io.InputStream;
51 import java.net.MalformedURLException;
53 import java.util.Arrays;
54 import java.util.List;
57 * @author Olivier Lamy
60 public class DownloadRemoteIndexTask
63 private Logger log = LoggerFactory.getLogger( getClass() );
65 private RemoteRepository remoteRepository;
67 private NexusIndexer nexusIndexer;
69 private WagonFactory wagonFactory;
71 private NetworkProxy networkProxy;
73 private boolean fullDownload;
75 private List<String> runningRemoteDownloadIds;
77 private IndexUpdater indexUpdater;
79 public DownloadRemoteIndexTask( DownloadRemoteIndexTaskRequest downloadRemoteIndexTaskRequest,
80 List<String> runningRemoteDownloadIds )
82 this.remoteRepository = downloadRemoteIndexTaskRequest.getRemoteRepository();
83 this.nexusIndexer = downloadRemoteIndexTaskRequest.getNexusIndexer();
84 this.wagonFactory = downloadRemoteIndexTaskRequest.getWagonFactory();
85 this.networkProxy = downloadRemoteIndexTaskRequest.getNetworkProxy();
86 this.fullDownload = downloadRemoteIndexTaskRequest.isFullDownload();
87 this.runningRemoteDownloadIds = runningRemoteDownloadIds;
88 this.indexUpdater = downloadRemoteIndexTaskRequest.getIndexUpdater();
94 // so short lock : not sure we need it
95 synchronized ( this.runningRemoteDownloadIds )
97 if ( this.runningRemoteDownloadIds.contains( this.remoteRepository.getId() ) )
99 // skip it as it's running
100 log.info( "skip download index remote for repo {} it's already running",
101 this.remoteRepository.getId() );
104 log.info( "start download remote index for remote repository " + this.remoteRepository.getId() );
105 this.runningRemoteDownloadIds.add( this.remoteRepository.getId() );
107 IndexingContext indexingContext =
108 nexusIndexer.getIndexingContexts().get( "remote-" + remoteRepository.getId() );
110 // TODO check if null ? normally not as created by DefaultDownloadRemoteIndexScheduler#startup
112 // create a temp directory to download files
113 final File tempIndexDirectory = new File( indexingContext.getIndexDirectoryFile().getParent(), ".tmpIndex" );
116 if ( tempIndexDirectory.exists() )
118 FileUtils.deleteDirectory( tempIndexDirectory );
120 tempIndexDirectory.mkdirs();
121 String baseIndexUrl = indexingContext.getIndexUpdateUrl();
123 final Wagon wagon = wagonFactory.getWagon( new URL( this.remoteRepository.getUrl() ).getProtocol() );
124 // TODO transferListener
125 wagon.addTransferListener( new DownloadListener() );
126 ProxyInfo proxyInfo = null;
127 if ( this.networkProxy != null )
129 proxyInfo = new ProxyInfo();
130 proxyInfo.setHost( this.networkProxy.getHost() );
131 proxyInfo.setPort( this.networkProxy.getPort() );
132 proxyInfo.setUserName( this.networkProxy.getUsername() );
133 proxyInfo.setPassword( this.networkProxy.getPassword() );
135 AuthenticationInfo authenticationInfo = null;
136 if ( this.remoteRepository.getUserName() != null )
138 authenticationInfo = new AuthenticationInfo();
139 authenticationInfo.setUserName( this.remoteRepository.getUserName() );
140 authenticationInfo.setPassword( this.remoteRepository.getPassword() );
142 wagon.connect( new Repository( this.remoteRepository.getId(), baseIndexUrl ), authenticationInfo,
145 File indexDirectory = indexingContext.getIndexDirectoryFile();
146 if ( !indexDirectory.exists() )
148 indexDirectory.mkdirs();
152 File[] indexFiles = indexDirectory.listFiles( new FileFilter()
154 public boolean accept( File file )
156 return !file.isDirectory();
160 List<String> indexFileNames = new ArrayList<String>( indexFiles == null ? 0 : indexFiles.length );
162 for ( File f : indexFiles == null ? new File[0] : indexFiles )
164 indexFileNames.add( f.getName() );
168 //List<String> files = wagon.getFileList( "" );
170 // take care about time stamp : no need to rebuild index
171 // TODO incremental honor fullDownload true !!
172 // FIXME dont fail all if one file fail ?
174 for ( String file : files )
176 if ( !indexFileNames.contains( file ) && StringUtils.endsWith( file, ".gz" ) )
178 downloadFile( wagon, file, tempIndexDirectory );
179 File compressIndexUpdate = new File( tempIndexDirectory, file );
180 mergeCompressIndex( indexingContext, compressIndexUpdate, wagon );
183 ResourceFetcher resourceFetcher = new ResourceFetcher()
185 public void connect( String id, String url )
191 public void disconnect()
197 public InputStream retrieve( String name )
198 throws IOException, FileNotFoundException
202 log.debug( "resourceFetcher#retrieve, name:{}", name );
203 //TODO check those files are deleted !!
204 File file = new File( tempIndexDirectory, name );
209 //file.deleteOnExit();
210 wagon.get( name, file );
211 return new FileInputStream( file );
213 catch ( AuthorizationException e )
215 throw new IOException( e.getMessage(), e );
217 catch ( TransferFailedException e )
219 throw new IOException( e.getMessage(), e );
221 catch ( ResourceDoesNotExistException e )
223 throw new FileNotFoundException( e.getMessage() );
228 IndexUpdateRequest request = new IndexUpdateRequest( indexingContext, resourceFetcher );
230 this.indexUpdater.fetchAndUpdateIndex( request );
234 catch ( MalformedURLException e )
236 log.error( e.getMessage(), e );
237 throw new RuntimeException( e.getMessage(), e );
239 catch ( WagonFactoryException e )
241 log.error( e.getMessage(), e );
242 throw new RuntimeException( e.getMessage(), e );
244 catch ( ConnectionException e )
246 log.error( e.getMessage(), e );
247 throw new RuntimeException( e.getMessage(), e );
249 catch ( AuthenticationException e )
251 log.error( e.getMessage(), e );
252 throw new RuntimeException( e.getMessage(), e );
254 catch ( IOException e )
256 log.error( e.getMessage(), e );
257 throw new RuntimeException( e.getMessage(), e );
261 //deleteDirectoryQuiet( tempIndexDirectory );
262 this.runningRemoteDownloadIds.remove( this.remoteRepository.getId() );
264 log.info( "end download remote index for remote repository " + this.remoteRepository.getId() );
267 private void deleteDirectoryQuiet( File f )
271 FileUtils.deleteDirectory( f );
273 catch ( IOException e )
275 log.warn( "skip error delete " + f + ": " + e.getMessage() );
279 protected void mergeCompressIndex( IndexingContext context, final File compressedIndexUpdate, final Wagon wagon )
280 throws IOException, CompressorException
285 final File tmpUncompressDirectory = new File( compressedIndexUpdate.getParent(),
286 StringUtils.substringBeforeLast( compressedIndexUpdate.getName(),
288 tmpUncompressDirectory.deleteOnExit();
289 final FileOutputStream fos =
290 new FileOutputStream( new File( tmpUncompressDirectory, compressedIndexUpdate.getName() ) );
293 if ( tmpUncompressDirectory.exists() )
295 tmpUncompressDirectory.delete();
297 tmpUncompressDirectory.mkdirs();
299 // gunzip the file to a directory and merge
302 final InputStream in = new FileInputStream( compressedIndexUpdate );
303 CompressorInputStream cis =
304 new CompressorStreamFactory().createCompressorInputStream( CompressorStreamFactory.GZIP, in );
305 IOUtils.copy( cis, fos );
314 IOUtils.closeQuietly( fos );
315 //deleteDirectoryQuiet( tmpUncompressDirectory );
316 //FileUtils.deleteQuietly( tmpUncompressDirectory );
321 protected void downloadFile( Wagon wagon, String file, File tempIndexDirectory )
325 wagon.get( file, new File( tempIndexDirectory, file ) );
327 catch ( Exception e )
329 log.warn( "skip fail to download " + file + ": " + e.getMessage() );
334 public static class DownloadListener
335 implements TransferListener
337 private Logger log = LoggerFactory.getLogger( getClass() );
339 public void transferInitiated( TransferEvent transferEvent )
341 log.debug( "initiate transfer of {}", transferEvent.getResource().getName() );
344 public void transferStarted( TransferEvent transferEvent )
346 log.debug( "start transfer of {}", transferEvent.getResource().getName() );
349 public void transferProgress( TransferEvent transferEvent, byte[] buffer, int length )
351 log.debug( "transfer of {} : {}/{}",
352 Arrays.asList( transferEvent.getResource().getName(), buffer.length, length ).toArray() );
355 public void transferCompleted( TransferEvent transferEvent )
357 log.info( "end of transfer file " + transferEvent.getResource().getName() );
360 public void transferError( TransferEvent transferEvent )
362 log.info( "error of transfer file {}: {}", Arrays.asList( transferEvent.getResource().getName(),
363 transferEvent.getException().getMessage() ).toArray(
364 new Object[2] ), transferEvent.getException() );
367 public void debug( String message )
369 log.debug( "transfer debug {}", message );