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.admin.model.remote.RemoteRepositoryAdmin;
24 import org.apache.archiva.proxy.common.WagonFactory;
25 import org.apache.archiva.proxy.common.WagonFactoryRequest;
26 import org.apache.commons.lang.time.StopWatch;
27 import org.apache.maven.index.context.IndexingContext;
28 import org.apache.maven.index.updater.IndexUpdateRequest;
29 import org.apache.maven.index.updater.IndexUpdater;
30 import org.apache.maven.index.updater.ResourceFetcher;
31 import org.apache.maven.wagon.ResourceDoesNotExistException;
32 import org.apache.maven.wagon.StreamWagon;
33 import org.apache.maven.wagon.TransferFailedException;
34 import org.apache.maven.wagon.Wagon;
35 import org.apache.maven.wagon.authentication.AuthenticationInfo;
36 import org.apache.maven.wagon.authorization.AuthorizationException;
37 import org.apache.maven.wagon.events.TransferEvent;
38 import org.apache.maven.wagon.events.TransferListener;
39 import org.apache.maven.wagon.proxy.ProxyInfo;
40 import org.apache.maven.wagon.repository.Repository;
41 import org.apache.maven.wagon.shared.http.AbstractHttpClientWagon;
42 import org.apache.maven.wagon.shared.http.HttpConfiguration;
43 import org.apache.maven.wagon.shared.http.HttpMethodConfiguration;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
47 import java.io.FileNotFoundException;
48 import java.io.IOException;
49 import java.io.InputStream;
51 import java.nio.file.Files;
52 import java.nio.file.Path;
53 import java.nio.file.Paths;
54 import java.util.List;
58 * @author Olivier Lamy
61 public class DownloadRemoteIndexTask
64 private Logger log = LoggerFactory.getLogger( getClass() );
66 private RemoteRepository remoteRepository;
68 private RemoteRepositoryAdmin remoteRepositoryAdmin;
70 private WagonFactory wagonFactory;
72 private NetworkProxy networkProxy;
74 private boolean fullDownload;
76 private List<String> runningRemoteDownloadIds;
78 private IndexUpdater indexUpdater;
81 public DownloadRemoteIndexTask( DownloadRemoteIndexTaskRequest downloadRemoteIndexTaskRequest,
82 List<String> runningRemoteDownloadIds )
84 this.remoteRepository = downloadRemoteIndexTaskRequest.getRemoteRepository();
85 this.wagonFactory = downloadRemoteIndexTaskRequest.getWagonFactory();
86 this.networkProxy = downloadRemoteIndexTaskRequest.getNetworkProxy();
87 this.fullDownload = downloadRemoteIndexTaskRequest.isFullDownload();
88 this.runningRemoteDownloadIds = runningRemoteDownloadIds;
89 this.indexUpdater = downloadRemoteIndexTaskRequest.getIndexUpdater();
90 this.remoteRepositoryAdmin = downloadRemoteIndexTaskRequest.getRemoteRepositoryAdmin();
97 // so short lock : not sure we need it
98 synchronized ( this.runningRemoteDownloadIds )
100 if ( this.runningRemoteDownloadIds.contains( this.remoteRepository.getId() ) )
102 // skip it as it's running
103 log.info( "skip download index remote for repo {} it's already running",
104 this.remoteRepository.getId() );
107 this.runningRemoteDownloadIds.add( this.remoteRepository.getId() );
109 Path tempIndexDirectory = null;
110 StopWatch stopWatch = new StopWatch();
114 log.info( "start download remote index for remote repository {}", this.remoteRepository.getId() );
115 IndexingContext indexingContext = remoteRepositoryAdmin.createIndexContext( this.remoteRepository );
117 // create a temp directory to download files
118 tempIndexDirectory = Paths.get(indexingContext.getIndexDirectoryFile().getParent(), ".tmpIndex" );
119 Path indexCacheDirectory = Paths.get( indexingContext.getIndexDirectoryFile().getParent(), ".indexCache" );
120 Files.createDirectories( indexCacheDirectory );
121 if ( Files.exists(tempIndexDirectory) )
123 org.apache.archiva.common.utils.FileUtils.deleteDirectory( tempIndexDirectory );
125 Files.createDirectories( tempIndexDirectory );
126 tempIndexDirectory.toFile().deleteOnExit();
127 String baseIndexUrl = indexingContext.getIndexUpdateUrl();
129 String wagonProtocol = new URL( this.remoteRepository.getUrl() ).getProtocol();
131 final StreamWagon wagon = (StreamWagon) wagonFactory.getWagon(
132 new WagonFactoryRequest( wagonProtocol, this.remoteRepository.getExtraHeaders() ).networkProxy(
135 // FIXME olamy having 2 config values
136 wagon.setReadTimeout( remoteRepository.getRemoteDownloadTimeout() * 1000 );
137 wagon.setTimeout( remoteRepository.getTimeout() * 1000 );
139 if ( wagon instanceof AbstractHttpClientWagon )
141 HttpConfiguration httpConfiguration = new HttpConfiguration();
142 HttpMethodConfiguration httpMethodConfiguration = new HttpMethodConfiguration();
143 httpMethodConfiguration.setUsePreemptive( true );
144 httpMethodConfiguration.setReadTimeout( remoteRepository.getRemoteDownloadTimeout() * 1000 );
145 httpConfiguration.setGet( httpMethodConfiguration );
146 AbstractHttpClientWagon.class.cast( wagon ).setHttpConfiguration( httpConfiguration );
149 wagon.addTransferListener( new DownloadListener() );
150 ProxyInfo proxyInfo = null;
151 if ( this.networkProxy != null )
153 proxyInfo = new ProxyInfo();
154 proxyInfo.setType( this.networkProxy.getProtocol() );
155 proxyInfo.setHost( this.networkProxy.getHost() );
156 proxyInfo.setPort( this.networkProxy.getPort() );
157 proxyInfo.setUserName( this.networkProxy.getUsername() );
158 proxyInfo.setPassword( this.networkProxy.getPassword() );
160 AuthenticationInfo authenticationInfo = null;
161 if ( this.remoteRepository.getUserName() != null )
163 authenticationInfo = new AuthenticationInfo();
164 authenticationInfo.setUserName( this.remoteRepository.getUserName() );
165 authenticationInfo.setPassword( this.remoteRepository.getPassword() );
167 wagon.connect( new Repository( this.remoteRepository.getId(), baseIndexUrl ), authenticationInfo,
170 Path indexDirectory = indexingContext.getIndexDirectoryFile().toPath();
171 if ( !Files.exists(indexDirectory) )
173 Files.createDirectories( indexDirectory );
176 ResourceFetcher resourceFetcher =
177 new WagonResourceFetcher( log, tempIndexDirectory, wagon, remoteRepository );
178 IndexUpdateRequest request = new IndexUpdateRequest( indexingContext, resourceFetcher );
179 request.setForceFullUpdate( this.fullDownload );
180 request.setLocalIndexCacheDir( indexCacheDirectory.toFile() );
182 this.indexUpdater.fetchAndUpdateIndex( request );
184 log.info( "time update index from remote for repository {}: {} s", this.remoteRepository.getId(),
185 ( stopWatch.getTime() / 1000 ) );
187 // index packing optionnal ??
188 //IndexPackingRequest indexPackingRequest =
189 // new IndexPackingRequest( indexingContext, indexingContext.getIndexDirectoryFile() );
190 //indexPacker.packIndex( indexPackingRequest );
191 indexingContext.updateTimestamp( true );
194 catch ( Exception e )
196 log.error( e.getMessage(), e );
197 throw new RuntimeException( e.getMessage(), e );
201 deleteDirectoryQuiet( tempIndexDirectory );
202 this.runningRemoteDownloadIds.remove( this.remoteRepository.getId() );
204 log.info( "end download remote index for remote repository {}", this.remoteRepository.getId() );
207 private void deleteDirectoryQuiet( Path f )
211 org.apache.archiva.common.utils.FileUtils.deleteDirectory( f );
213 catch ( IOException e )
215 log.warn( "skip error delete {} : {}", f, e.getMessage() );
220 private static final class DownloadListener
221 implements TransferListener
223 private Logger log = LoggerFactory.getLogger( getClass() );
225 private String resourceName;
227 private long startTime;
229 private int totalLength = 0;
232 public void transferInitiated( TransferEvent transferEvent )
234 startTime = System.currentTimeMillis();
235 resourceName = transferEvent.getResource().getName();
236 log.debug( "initiate transfer of {}", resourceName );
240 public void transferStarted( TransferEvent transferEvent )
242 this.totalLength = 0;
243 resourceName = transferEvent.getResource().getName();
244 log.info( "start transfer of {}", transferEvent.getResource().getName() );
248 public void transferProgress( TransferEvent transferEvent, byte[] buffer, int length )
250 log.debug( "transfer of {} : {}/{}", transferEvent.getResource().getName(), buffer.length, length );
251 this.totalLength += length;
255 public void transferCompleted( TransferEvent transferEvent )
257 resourceName = transferEvent.getResource().getName();
258 long endTime = System.currentTimeMillis();
259 log.info( "end of transfer file {} {} kb: {}s", transferEvent.getResource().getName(),
260 this.totalLength / 1024, ( endTime - startTime ) / 1000 );
264 public void transferError( TransferEvent transferEvent )
266 log.info( "error of transfer file {}: {}", transferEvent.getResource().getName(),
267 transferEvent.getException().getMessage(), transferEvent.getException() );
271 public void debug( String message )
273 log.debug( "transfer debug {}", message );
277 private static class WagonResourceFetcher
278 implements ResourceFetcher
283 Path tempIndexDirectory;
287 RemoteRepository remoteRepository;
289 private WagonResourceFetcher( Logger log, Path tempIndexDirectory, Wagon wagon,
290 RemoteRepository remoteRepository )
293 this.tempIndexDirectory = tempIndexDirectory;
295 this.remoteRepository = remoteRepository;
299 public void connect( String id, String url )
306 public void disconnect()
313 public InputStream retrieve( String name )
314 throws IOException, FileNotFoundException
318 log.info( "index update retrieve file, name:{}", name );
319 Path file = tempIndexDirectory.resolve( name );
320 Files.deleteIfExists( file );
321 file.toFile().deleteOnExit();
322 wagon.get( addParameters( name, this.remoteRepository ), file.toFile() );
323 return Files.newInputStream( file );
325 catch ( AuthorizationException | TransferFailedException e )
327 throw new IOException( e.getMessage(), e );
329 catch ( ResourceDoesNotExistException e )
331 FileNotFoundException fnfe = new FileNotFoundException( e.getMessage() );
337 // FIXME remove crappy copy/paste
338 protected String addParameters( String path, RemoteRepository remoteRepository )
340 if ( remoteRepository.getExtraParameters().isEmpty() )
345 boolean question = false;
347 StringBuilder res = new StringBuilder( path == null ? "" : path );
349 for ( Map.Entry<String, String> entry : remoteRepository.getExtraParameters().entrySet() )
353 res.append( '?' ).append( entry.getKey() ).append( '=' ).append( entry.getValue() );
357 return res.toString();