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.RepositoryAdminException;
22 import org.apache.archiva.admin.model.beans.NetworkProxy;
23 import org.apache.archiva.admin.model.beans.RemoteRepository;
24 import org.apache.archiva.admin.model.remote.RemoteRepositoryAdmin;
25 import org.apache.archiva.proxy.common.WagonFactory;
26 import org.apache.archiva.proxy.common.WagonFactoryException;
27 import org.apache.archiva.proxy.common.WagonFactoryRequest;
28 import org.apache.commons.io.FileUtils;
29 import org.apache.commons.lang.time.StopWatch;
30 import org.apache.maven.index.context.IndexingContext;
31 import org.apache.maven.index.updater.IndexUpdateRequest;
32 import org.apache.maven.index.updater.IndexUpdater;
33 import org.apache.maven.index.updater.ResourceFetcher;
34 import org.apache.maven.wagon.ConnectionException;
35 import org.apache.maven.wagon.ResourceDoesNotExistException;
36 import org.apache.maven.wagon.StreamWagon;
37 import org.apache.maven.wagon.TransferFailedException;
38 import org.apache.maven.wagon.Wagon;
39 import org.apache.maven.wagon.authentication.AuthenticationException;
40 import org.apache.maven.wagon.authentication.AuthenticationInfo;
41 import org.apache.maven.wagon.authorization.AuthorizationException;
42 import org.apache.maven.wagon.events.TransferEvent;
43 import org.apache.maven.wagon.events.TransferListener;
44 import org.apache.maven.wagon.providers.http.AbstractHttpClientWagon;
45 import org.apache.maven.wagon.providers.http.HttpConfiguration;
46 import org.apache.maven.wagon.providers.http.HttpMethodConfiguration;
47 import org.apache.maven.wagon.proxy.ProxyInfo;
48 import org.apache.maven.wagon.repository.Repository;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
53 import java.io.FileInputStream;
54 import java.io.FileNotFoundException;
55 import java.io.IOException;
56 import java.io.InputStream;
57 import java.net.MalformedURLException;
59 import java.util.List;
63 * @author Olivier Lamy
66 public class DownloadRemoteIndexTask
69 private Logger log = LoggerFactory.getLogger( getClass() );
71 private RemoteRepository remoteRepository;
73 private RemoteRepositoryAdmin remoteRepositoryAdmin;
75 private WagonFactory wagonFactory;
77 private NetworkProxy networkProxy;
79 private boolean fullDownload;
81 private List<String> runningRemoteDownloadIds;
83 private IndexUpdater indexUpdater;
86 public DownloadRemoteIndexTask( DownloadRemoteIndexTaskRequest downloadRemoteIndexTaskRequest,
87 List<String> runningRemoteDownloadIds )
89 this.remoteRepository = downloadRemoteIndexTaskRequest.getRemoteRepository();
90 this.wagonFactory = downloadRemoteIndexTaskRequest.getWagonFactory();
91 this.networkProxy = downloadRemoteIndexTaskRequest.getNetworkProxy();
92 this.fullDownload = downloadRemoteIndexTaskRequest.isFullDownload();
93 this.runningRemoteDownloadIds = runningRemoteDownloadIds;
94 this.indexUpdater = downloadRemoteIndexTaskRequest.getIndexUpdater();
95 this.remoteRepositoryAdmin = downloadRemoteIndexTaskRequest.getRemoteRepositoryAdmin();
102 // so short lock : not sure we need it
103 synchronized ( this.runningRemoteDownloadIds )
105 if ( this.runningRemoteDownloadIds.contains( this.remoteRepository.getId() ) )
107 // skip it as it's running
108 log.info( "skip download index remote for repo {} it's already running",
109 this.remoteRepository.getId() );
112 this.runningRemoteDownloadIds.add( this.remoteRepository.getId() );
114 File tempIndexDirectory = null;
115 StopWatch stopWatch = new StopWatch();
119 log.info( "start download remote index for remote repository {}", this.remoteRepository.getId() );
120 IndexingContext indexingContext = remoteRepositoryAdmin.createIndexContext( this.remoteRepository );
122 // create a temp directory to download files
123 tempIndexDirectory = new File( indexingContext.getIndexDirectoryFile().getParent(), ".tmpIndex" );
124 File indexCacheDirectory = new File( indexingContext.getIndexDirectoryFile().getParent(), ".indexCache" );
125 indexCacheDirectory.mkdirs();
126 if ( tempIndexDirectory.exists() )
128 FileUtils.deleteDirectory( tempIndexDirectory );
130 tempIndexDirectory.mkdirs();
131 tempIndexDirectory.deleteOnExit();
132 String baseIndexUrl = indexingContext.getIndexUpdateUrl();
134 String wagonProtocol = new URL( this.remoteRepository.getUrl() ).getProtocol();
136 final StreamWagon wagon = (StreamWagon) wagonFactory.getWagon(
137 new WagonFactoryRequest( wagonProtocol, this.remoteRepository.getExtraHeaders() ).networkProxy(
138 this.networkProxy ) );
139 // FIXME olamy having 2 config values
140 wagon.setReadTimeout( remoteRepository.getRemoteDownloadTimeout() * 1000 );
141 wagon.setTimeout( remoteRepository.getTimeout() * 1000 );
143 if ( wagon instanceof AbstractHttpClientWagon )
145 HttpConfiguration httpConfiguration = new HttpConfiguration();
146 HttpMethodConfiguration httpMethodConfiguration = new HttpMethodConfiguration();
147 httpMethodConfiguration.setUsePreemptive( true );
148 httpMethodConfiguration.setReadTimeout( remoteRepository.getRemoteDownloadTimeout() * 1000 );
149 httpConfiguration.setGet( httpMethodConfiguration );
150 AbstractHttpClientWagon.class.cast( wagon ).setHttpConfiguration( httpConfiguration );
153 wagon.addTransferListener( new DownloadListener() );
154 ProxyInfo proxyInfo = null;
155 if ( this.networkProxy != null )
157 proxyInfo = new ProxyInfo();
158 proxyInfo.setHost( this.networkProxy.getHost() );
159 proxyInfo.setPort( this.networkProxy.getPort() );
160 proxyInfo.setUserName( this.networkProxy.getUsername() );
161 proxyInfo.setPassword( this.networkProxy.getPassword() );
163 AuthenticationInfo authenticationInfo = null;
164 if ( this.remoteRepository.getUserName() != null )
166 authenticationInfo = new AuthenticationInfo();
167 authenticationInfo.setUserName( this.remoteRepository.getUserName() );
168 authenticationInfo.setPassword( this.remoteRepository.getPassword() );
170 wagon.connect( new Repository( this.remoteRepository.getId(), baseIndexUrl ), authenticationInfo,
173 File indexDirectory = indexingContext.getIndexDirectoryFile();
174 if ( !indexDirectory.exists() )
176 indexDirectory.mkdirs();
179 ResourceFetcher resourceFetcher =
180 new WagonResourceFetcher( log, tempIndexDirectory, wagon, remoteRepository );
181 IndexUpdateRequest request = new IndexUpdateRequest( indexingContext, resourceFetcher );
182 request.setForceFullUpdate( this.fullDownload );
183 request.setLocalIndexCacheDir( indexCacheDirectory );
185 this.indexUpdater.fetchAndUpdateIndex( request );
187 log.info( "time update index from remote for repository {}: {} s", this.remoteRepository.getId(),
188 ( stopWatch.getTime() / 1000 ) );
190 // index packing optionnal ??
191 //IndexPackingRequest indexPackingRequest =
192 // new IndexPackingRequest( indexingContext, indexingContext.getIndexDirectoryFile() );
193 //indexPacker.packIndex( indexPackingRequest );
194 indexingContext.updateTimestamp( true );
197 catch ( MalformedURLException e )
199 log.error( e.getMessage(), e );
200 throw new RuntimeException( e.getMessage(), e );
202 catch ( WagonFactoryException e )
204 log.error( e.getMessage(), e );
205 throw new RuntimeException( e.getMessage(), e );
207 catch ( ConnectionException e )
209 log.error( e.getMessage(), e );
210 throw new RuntimeException( e.getMessage(), e );
212 catch ( AuthenticationException e )
214 log.error( e.getMessage(), e );
215 throw new RuntimeException( e.getMessage(), e );
217 catch ( IOException e )
219 log.error( e.getMessage(), e );
220 throw new RuntimeException( e.getMessage(), e );
222 catch ( RepositoryAdminException e )
224 log.error( e.getMessage(), e );
225 throw new RuntimeException( e.getMessage(), e );
229 deleteDirectoryQuiet( tempIndexDirectory );
230 this.runningRemoteDownloadIds.remove( this.remoteRepository.getId() );
232 log.info( "end download remote index for remote repository {}", this.remoteRepository.getId() );
235 private void deleteDirectoryQuiet( File f )
239 FileUtils.deleteDirectory( f );
241 catch ( IOException e )
243 log.warn( "skip error delete {} : {}", f, e.getMessage() );
248 private static final class DownloadListener
249 implements TransferListener
251 private Logger log = LoggerFactory.getLogger( getClass() );
253 private String resourceName;
255 private long startTime;
257 private int totalLength = 0;
260 public void transferInitiated( TransferEvent transferEvent )
262 startTime = System.currentTimeMillis();
263 resourceName = transferEvent.getResource().getName();
264 log.debug( "initiate transfer of {}", resourceName );
268 public void transferStarted( TransferEvent transferEvent )
270 this.totalLength = 0;
271 resourceName = transferEvent.getResource().getName();
272 log.info( "start transfer of {}", transferEvent.getResource().getName() );
276 public void transferProgress( TransferEvent transferEvent, byte[] buffer, int length )
278 log.debug( "transfer of {} : {}/{}", transferEvent.getResource().getName(), buffer.length, length );
279 this.totalLength += length;
283 public void transferCompleted( TransferEvent transferEvent )
285 resourceName = transferEvent.getResource().getName();
286 long endTime = System.currentTimeMillis();
287 log.info( "end of transfer file {} {} kb: {}s", transferEvent.getResource().getName(),
288 this.totalLength / 1024, ( endTime - startTime ) / 1000 );
292 public void transferError( TransferEvent transferEvent )
294 log.info( "error of transfer file {}: {}", transferEvent.getResource().getName(),
295 transferEvent.getException().getMessage(), transferEvent.getException() );
299 public void debug( String message )
301 log.debug( "transfer debug {}", message );
305 private static class WagonResourceFetcher
306 implements ResourceFetcher
311 File tempIndexDirectory;
315 RemoteRepository remoteRepository;
317 private WagonResourceFetcher( Logger log, File tempIndexDirectory, Wagon wagon,
318 RemoteRepository remoteRepository )
321 this.tempIndexDirectory = tempIndexDirectory;
323 this.remoteRepository = remoteRepository;
327 public void connect( String id, String url )
334 public void disconnect()
341 public InputStream retrieve( String name )
342 throws IOException, FileNotFoundException
346 log.info( "index update retrieve file, name:{}", name );
347 File file = new File( tempIndexDirectory, name );
353 wagon.get( addParameters( name, this.remoteRepository ), file );
354 return new FileInputStream( file );
356 catch ( AuthorizationException e )
358 throw new IOException( e.getMessage(), e );
360 catch ( TransferFailedException e )
362 throw new IOException( e.getMessage(), e );
364 catch ( ResourceDoesNotExistException e )
366 FileNotFoundException fnfe = new FileNotFoundException( e.getMessage() );
372 // FIXME remove crappy copy/paste
373 protected String addParameters( String path, RemoteRepository remoteRepository )
375 if ( remoteRepository.getExtraParameters().isEmpty() )
380 boolean question = false;
382 StringBuilder res = new StringBuilder( path == null ? "" : path );
384 for ( Map.Entry<String, String> entry : remoteRepository.getExtraParameters().entrySet() )
388 res.append( '?' ).append( entry.getKey() ).append( '=' ).append( entry.getValue() );
392 return res.toString();