]> source.dussan.org Git - archiva.git/blob
330df16a610bc3d4ff395ea6f034a9c276ccf09f
[archiva.git] /
1 package org.apache.archiva.scheduler.indexing;
2 /*
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
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
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
18  * under the License.
19  */
20
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;
51
52 import java.io.File;
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;
58 import java.net.URL;
59 import java.util.List;
60 import java.util.Map;
61
62 /**
63  * @author Olivier Lamy
64  * @since 1.4-M1
65  */
66 public class DownloadRemoteIndexTask
67     implements Runnable
68 {
69     private Logger log = LoggerFactory.getLogger( getClass() );
70
71     private RemoteRepository remoteRepository;
72
73     private RemoteRepositoryAdmin remoteRepositoryAdmin;
74
75     private WagonFactory wagonFactory;
76
77     private NetworkProxy networkProxy;
78
79     private boolean fullDownload;
80
81     private List<String> runningRemoteDownloadIds;
82
83     private IndexUpdater indexUpdater;
84
85
86     public DownloadRemoteIndexTask( DownloadRemoteIndexTaskRequest downloadRemoteIndexTaskRequest,
87                                     List<String> runningRemoteDownloadIds )
88     {
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();
96     }
97
98     @Override
99     public void run()
100     {
101
102         // so short lock : not sure we need it
103         synchronized ( this.runningRemoteDownloadIds )
104         {
105             if ( this.runningRemoteDownloadIds.contains( this.remoteRepository.getId() ) )
106             {
107                 // skip it as it's running
108                 log.info( "skip download index remote for repo {} it's already running",
109                           this.remoteRepository.getId() );
110                 return;
111             }
112             this.runningRemoteDownloadIds.add( this.remoteRepository.getId() );
113         }
114         File tempIndexDirectory = null;
115         StopWatch stopWatch = new StopWatch();
116         stopWatch.start();
117         try
118         {
119             log.info( "start download remote index for remote repository {}", this.remoteRepository.getId() );
120             IndexingContext indexingContext = remoteRepositoryAdmin.createIndexContext( this.remoteRepository );
121
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() )
127             {
128                 FileUtils.deleteDirectory( tempIndexDirectory );
129             }
130             tempIndexDirectory.mkdirs();
131             tempIndexDirectory.deleteOnExit();
132             String baseIndexUrl = indexingContext.getIndexUpdateUrl();
133
134             String wagonProtocol = new URL( this.remoteRepository.getUrl() ).getProtocol();
135
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 );
142
143             if ( wagon instanceof AbstractHttpClientWagon )
144             {
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 );
151             }
152
153             wagon.addTransferListener( new DownloadListener() );
154             ProxyInfo proxyInfo = null;
155             if ( this.networkProxy != null )
156             {
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() );
162             }
163             AuthenticationInfo authenticationInfo = null;
164             if ( this.remoteRepository.getUserName() != null )
165             {
166                 authenticationInfo = new AuthenticationInfo();
167                 authenticationInfo.setUserName( this.remoteRepository.getUserName() );
168                 authenticationInfo.setPassword( this.remoteRepository.getPassword() );
169             }
170             wagon.connect( new Repository( this.remoteRepository.getId(), baseIndexUrl ), authenticationInfo,
171                            proxyInfo );
172
173             File indexDirectory = indexingContext.getIndexDirectoryFile();
174             if ( !indexDirectory.exists() )
175             {
176                 indexDirectory.mkdirs();
177             }
178
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 );
184
185             this.indexUpdater.fetchAndUpdateIndex( request );
186             stopWatch.stop();
187             log.info( "time update index from remote for repository {}: {} s", this.remoteRepository.getId(),
188                       ( stopWatch.getTime() / 1000 ) );
189
190             // index packing optionnal ??
191             //IndexPackingRequest indexPackingRequest =
192             //    new IndexPackingRequest( indexingContext, indexingContext.getIndexDirectoryFile() );
193             //indexPacker.packIndex( indexPackingRequest );
194             indexingContext.updateTimestamp( true );
195
196         }
197         catch ( MalformedURLException e )
198         {
199             log.error( e.getMessage(), e );
200             throw new RuntimeException( e.getMessage(), e );
201         }
202         catch ( WagonFactoryException e )
203         {
204             log.error( e.getMessage(), e );
205             throw new RuntimeException( e.getMessage(), e );
206         }
207         catch ( ConnectionException e )
208         {
209             log.error( e.getMessage(), e );
210             throw new RuntimeException( e.getMessage(), e );
211         }
212         catch ( AuthenticationException e )
213         {
214             log.error( e.getMessage(), e );
215             throw new RuntimeException( e.getMessage(), e );
216         }
217         catch ( IOException e )
218         {
219             log.error( e.getMessage(), e );
220             throw new RuntimeException( e.getMessage(), e );
221         }
222         catch ( RepositoryAdminException e )
223         {
224             log.error( e.getMessage(), e );
225             throw new RuntimeException( e.getMessage(), e );
226         }
227         finally
228         {
229             deleteDirectoryQuiet( tempIndexDirectory );
230             this.runningRemoteDownloadIds.remove( this.remoteRepository.getId() );
231         }
232         log.info( "end download remote index for remote repository {}", this.remoteRepository.getId() );
233     }
234
235     private void deleteDirectoryQuiet( File f )
236     {
237         try
238         {
239             FileUtils.deleteDirectory( f );
240         }
241         catch ( IOException e )
242         {
243             log.warn( "skip error delete {} : {}", f, e.getMessage() );
244         }
245     }
246
247
248     private static final class DownloadListener
249         implements TransferListener
250     {
251         private Logger log = LoggerFactory.getLogger( getClass() );
252
253         private String resourceName;
254
255         private long startTime;
256
257         private int totalLength = 0;
258
259         @Override
260         public void transferInitiated( TransferEvent transferEvent )
261         {
262             startTime = System.currentTimeMillis();
263             resourceName = transferEvent.getResource().getName();
264             log.debug( "initiate transfer of {}", resourceName );
265         }
266
267         @Override
268         public void transferStarted( TransferEvent transferEvent )
269         {
270             this.totalLength = 0;
271             resourceName = transferEvent.getResource().getName();
272             log.info( "start transfer of {}", transferEvent.getResource().getName() );
273         }
274
275         @Override
276         public void transferProgress( TransferEvent transferEvent, byte[] buffer, int length )
277         {
278             log.debug( "transfer of {} : {}/{}", transferEvent.getResource().getName(), buffer.length, length );
279             this.totalLength += length;
280         }
281
282         @Override
283         public void transferCompleted( TransferEvent transferEvent )
284         {
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 );
289         }
290
291         @Override
292         public void transferError( TransferEvent transferEvent )
293         {
294             log.info( "error of transfer file {}: {}", transferEvent.getResource().getName(),
295                       transferEvent.getException().getMessage(), transferEvent.getException() );
296         }
297
298         @Override
299         public void debug( String message )
300         {
301             log.debug( "transfer debug {}", message );
302         }
303     }
304
305     private static class WagonResourceFetcher
306         implements ResourceFetcher
307     {
308
309         Logger log;
310
311         File tempIndexDirectory;
312
313         Wagon wagon;
314
315         RemoteRepository remoteRepository;
316
317         private WagonResourceFetcher( Logger log, File tempIndexDirectory, Wagon wagon,
318                                       RemoteRepository remoteRepository )
319         {
320             this.log = log;
321             this.tempIndexDirectory = tempIndexDirectory;
322             this.wagon = wagon;
323             this.remoteRepository = remoteRepository;
324         }
325
326         @Override
327         public void connect( String id, String url )
328             throws IOException
329         {
330             //no op  
331         }
332
333         @Override
334         public void disconnect()
335             throws IOException
336         {
337             // no op
338         }
339
340         @Override
341         public InputStream retrieve( String name )
342             throws IOException, FileNotFoundException
343         {
344             try
345             {
346                 log.info( "index update retrieve file, name:{}", name );
347                 File file = new File( tempIndexDirectory, name );
348                 if ( file.exists() )
349                 {
350                     file.delete();
351                 }
352                 file.deleteOnExit();
353                 wagon.get( addParameters( name, this.remoteRepository ), file );
354                 return new FileInputStream( file );
355             }
356             catch ( AuthorizationException e )
357             {
358                 throw new IOException( e.getMessage(), e );
359             }
360             catch ( TransferFailedException e )
361             {
362                 throw new IOException( e.getMessage(), e );
363             }
364             catch ( ResourceDoesNotExistException e )
365             {
366                 FileNotFoundException fnfe = new FileNotFoundException( e.getMessage() );
367                 fnfe.initCause( e );
368                 throw fnfe;
369             }
370         }
371
372         // FIXME remove crappy copy/paste
373         protected String addParameters( String path, RemoteRepository remoteRepository )
374         {
375             if ( remoteRepository.getExtraParameters().isEmpty() )
376             {
377                 return path;
378             }
379
380             boolean question = false;
381
382             StringBuilder res = new StringBuilder( path == null ? "" : path );
383
384             for ( Map.Entry<String, String> entry : remoteRepository.getExtraParameters().entrySet() )
385             {
386                 if ( !question )
387                 {
388                     res.append( '?' ).append( entry.getKey() ).append( '=' ).append( entry.getValue() );
389                 }
390             }
391
392             return res.toString();
393         }
394
395     }
396
397
398 }
399