]> source.dussan.org Git - archiva.git/blob
eb8053c6f1864a73c94a1cfb68f2bb2422b6db39
[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.packer.IndexPacker;
32 import org.apache.maven.index.packer.IndexPackingRequest;
33 import org.apache.maven.index.updater.IndexUpdateRequest;
34 import org.apache.maven.index.updater.IndexUpdater;
35 import org.apache.maven.index.updater.ResourceFetcher;
36 import org.apache.maven.wagon.ConnectionException;
37 import org.apache.maven.wagon.ResourceDoesNotExistException;
38 import org.apache.maven.wagon.StreamWagon;
39 import org.apache.maven.wagon.TransferFailedException;
40 import org.apache.maven.wagon.Wagon;
41 import org.apache.maven.wagon.authentication.AuthenticationException;
42 import org.apache.maven.wagon.authentication.AuthenticationInfo;
43 import org.apache.maven.wagon.authorization.AuthorizationException;
44 import org.apache.maven.wagon.events.TransferEvent;
45 import org.apache.maven.wagon.events.TransferListener;
46 import org.apache.maven.wagon.proxy.ProxyInfo;
47 import org.apache.maven.wagon.repository.Repository;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 import java.io.File;
52 import java.io.FileInputStream;
53 import java.io.FileNotFoundException;
54 import java.io.IOException;
55 import java.io.InputStream;
56 import java.net.MalformedURLException;
57 import java.net.URL;
58 import java.util.Arrays;
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     private IndexPacker indexPacker;
86
87     public DownloadRemoteIndexTask( DownloadRemoteIndexTaskRequest downloadRemoteIndexTaskRequest,
88                                     List<String> runningRemoteDownloadIds )
89     {
90         this.remoteRepository = downloadRemoteIndexTaskRequest.getRemoteRepository();
91         this.wagonFactory = downloadRemoteIndexTaskRequest.getWagonFactory();
92         this.networkProxy = downloadRemoteIndexTaskRequest.getNetworkProxy();
93         this.fullDownload = downloadRemoteIndexTaskRequest.isFullDownload();
94         this.runningRemoteDownloadIds = runningRemoteDownloadIds;
95         this.indexUpdater = downloadRemoteIndexTaskRequest.getIndexUpdater();
96         this.remoteRepositoryAdmin = downloadRemoteIndexTaskRequest.getRemoteRepositoryAdmin();
97         this.indexPacker = downloadRemoteIndexTaskRequest.getIndexPacker();
98     }
99
100     public void run()
101     {
102
103         // so short lock : not sure we need it
104         synchronized ( this.runningRemoteDownloadIds )
105         {
106             if ( this.runningRemoteDownloadIds.contains( this.remoteRepository.getId() ) )
107             {
108                 // skip it as it's running
109                 log.info( "skip download index remote for repo {} it's already running",
110                           this.remoteRepository.getId() );
111                 return;
112             }
113             this.runningRemoteDownloadIds.add( this.remoteRepository.getId() );
114         }
115         File tempIndexDirectory = null;
116         StopWatch stopWatch = new StopWatch();
117         stopWatch.start();
118         try
119         {
120             log.info( "start download remote index for remote repository {}", this.remoteRepository.getId() );
121             IndexingContext indexingContext = remoteRepositoryAdmin.createIndexContext( this.remoteRepository );
122
123             // create a temp directory to download files
124             tempIndexDirectory = new File( indexingContext.getIndexDirectoryFile().getParent(), ".tmpIndex" );
125             File indexCacheDirectory = new File( indexingContext.getIndexDirectoryFile().getParent(), ".indexCache" );
126             indexCacheDirectory.mkdirs();
127             if ( tempIndexDirectory.exists() )
128             {
129                 FileUtils.deleteDirectory( tempIndexDirectory );
130             }
131             tempIndexDirectory.mkdirs();
132             tempIndexDirectory.deleteOnExit();
133             String baseIndexUrl = indexingContext.getIndexUpdateUrl();
134
135             String wagonProtocol = new URL( this.remoteRepository.getUrl() ).getProtocol();
136
137             final StreamWagon wagon = (StreamWagon) wagonFactory.getWagon(
138                 new WagonFactoryRequest( wagonProtocol, this.remoteRepository.getExtraHeaders() ).networkProxy(
139                     this.networkProxy ) );
140             int timeoutInMilliseconds = remoteRepository.getTimeout() * 1000;
141             // FIXME olamy having 2 config values
142             wagon.setReadTimeout( timeoutInMilliseconds );
143             wagon.setTimeout( timeoutInMilliseconds );
144
145             wagon.addTransferListener( new DownloadListener() );
146             ProxyInfo proxyInfo = null;
147             if ( this.networkProxy != null )
148             {
149                 proxyInfo = new ProxyInfo();
150                 proxyInfo.setHost( this.networkProxy.getHost() );
151                 proxyInfo.setPort( this.networkProxy.getPort() );
152                 proxyInfo.setUserName( this.networkProxy.getUsername() );
153                 proxyInfo.setPassword( this.networkProxy.getPassword() );
154             }
155             AuthenticationInfo authenticationInfo = null;
156             if ( this.remoteRepository.getUserName() != null )
157             {
158                 authenticationInfo = new AuthenticationInfo();
159                 authenticationInfo.setUserName( this.remoteRepository.getUserName() );
160                 authenticationInfo.setPassword( this.remoteRepository.getPassword() );
161             }
162             wagon.connect( new Repository( this.remoteRepository.getId(), baseIndexUrl ), authenticationInfo,
163                            proxyInfo );
164
165             File indexDirectory = indexingContext.getIndexDirectoryFile();
166             if ( !indexDirectory.exists() )
167             {
168                 indexDirectory.mkdirs();
169             }
170
171             ResourceFetcher resourceFetcher =
172                 new WagonResourceFetcher( log, tempIndexDirectory, wagon, remoteRepository );
173             IndexUpdateRequest request = new IndexUpdateRequest( indexingContext, resourceFetcher );
174             request.setForceFullUpdate( this.fullDownload );
175             request.setLocalIndexCacheDir( indexCacheDirectory );
176
177             this.indexUpdater.fetchAndUpdateIndex( request );
178             stopWatch.stop();
179             log.info( "time to download remote repository index for repository {}: {} s", this.remoteRepository.getId(),
180                       ( stopWatch.getTime() / 1000 ) );
181
182             // index packing optionnal ??
183             IndexPackingRequest indexPackingRequest =
184                 new IndexPackingRequest( indexingContext, indexingContext.getIndexDirectoryFile() );
185             indexPacker.packIndex( indexPackingRequest );
186             indexingContext.updateTimestamp( true );
187
188         }
189         catch ( MalformedURLException e )
190         {
191             log.error( e.getMessage(), e );
192             throw new RuntimeException( e.getMessage(), e );
193         }
194         catch ( WagonFactoryException e )
195         {
196             log.error( e.getMessage(), e );
197             throw new RuntimeException( e.getMessage(), e );
198         }
199         catch ( ConnectionException e )
200         {
201             log.error( e.getMessage(), e );
202             throw new RuntimeException( e.getMessage(), e );
203         }
204         catch ( AuthenticationException e )
205         {
206             log.error( e.getMessage(), e );
207             throw new RuntimeException( e.getMessage(), e );
208         }
209         catch ( IOException e )
210         {
211             log.error( e.getMessage(), e );
212             throw new RuntimeException( e.getMessage(), e );
213         }
214         catch ( RepositoryAdminException e )
215         {
216             log.error( e.getMessage(), e );
217             throw new RuntimeException( e.getMessage(), e );
218         }
219         finally
220         {
221             deleteDirectoryQuiet( tempIndexDirectory );
222             this.runningRemoteDownloadIds.remove( this.remoteRepository.getId() );
223         }
224         log.info( "end download remote index for remote repository " + this.remoteRepository.getId() );
225     }
226
227     private void deleteDirectoryQuiet( File f )
228     {
229         try
230         {
231             FileUtils.deleteDirectory( f );
232         }
233         catch ( IOException e )
234         {
235             log.warn( "skip error delete {} : {}", f, e.getMessage() );
236         }
237     }
238
239
240     public static class DownloadListener
241         implements TransferListener
242     {
243         private Logger log = LoggerFactory.getLogger( getClass() );
244
245         String resourceName;
246
247         long startTime;
248
249         public void transferInitiated( TransferEvent transferEvent )
250         {
251             resourceName = transferEvent.getResource().getName();
252             log.debug( "initiate transfer of {}", resourceName );
253         }
254
255         public void transferStarted( TransferEvent transferEvent )
256         {
257             resourceName = transferEvent.getResource().getName();
258             startTime = System.currentTimeMillis();
259             log.info( "start transfer of {}", transferEvent.getResource().getName() );
260         }
261
262         public void transferProgress( TransferEvent transferEvent, byte[] buffer, int length )
263         {
264             log.debug( "transfer of {} : {}/{}",
265                        Arrays.asList( transferEvent.getResource().getName(), buffer.length, length ).toArray() );
266         }
267
268         public void transferCompleted( TransferEvent transferEvent )
269         {
270             resourceName = transferEvent.getResource().getName();
271             long endTime = System.currentTimeMillis();
272             log.info( "end of transfer file {}: {}s", transferEvent.getResource().getName(),
273                       ( endTime - startTime ) / 1000 );
274         }
275
276         public void transferError( TransferEvent transferEvent )
277         {
278             log.info( "error of transfer file {}: {}", Arrays.asList( transferEvent.getResource().getName(),
279                                                                       transferEvent.getException().getMessage() ).toArray(
280                 new Object[2] ), transferEvent.getException() );
281         }
282
283         public void debug( String message )
284         {
285             log.debug( "transfer debug {}", message );
286         }
287     }
288
289     private static class WagonResourceFetcher
290         implements ResourceFetcher
291     {
292
293         Logger log;
294
295         File tempIndexDirectory;
296
297         Wagon wagon;
298
299         RemoteRepository remoteRepository;
300
301         private WagonResourceFetcher( Logger log, File tempIndexDirectory, Wagon wagon,
302                                       RemoteRepository remoteRepository )
303         {
304             this.log = log;
305             this.tempIndexDirectory = tempIndexDirectory;
306             this.wagon = wagon;
307             this.remoteRepository = remoteRepository;
308         }
309
310         public void connect( String id, String url )
311             throws IOException
312         {
313             //no op  
314         }
315
316         public void disconnect()
317             throws IOException
318         {
319             // no op
320         }
321
322         public InputStream retrieve( String name )
323             throws IOException, FileNotFoundException
324         {
325             try
326             {
327                 log.info( "index update retrieve file, name:{}", name );
328                 File file = new File( tempIndexDirectory, name );
329                 if ( file.exists() )
330                 {
331                     file.delete();
332                 }
333                 file.deleteOnExit();
334                 wagon.get( addParameters( name, this.remoteRepository ), file );
335                 return new FileInputStream( file );
336             }
337             catch ( AuthorizationException e )
338             {
339                 throw new IOException( e.getMessage() );
340             }
341             catch ( TransferFailedException e )
342             {
343                 throw new IOException( e.getMessage() );
344             }
345             catch ( ResourceDoesNotExistException e )
346             {
347                 throw new FileNotFoundException( e.getMessage() );
348             }
349         }
350
351         // FIXME remove crappy copy/paste
352         protected String addParameters( String path, RemoteRepository remoteRepository )
353         {
354             if ( remoteRepository.getExtraParameters().isEmpty() )
355             {
356                 return path;
357             }
358
359             boolean question = false;
360
361             StringBuilder res = new StringBuilder( path == null ? "" : path );
362
363             for ( Map.Entry<String, String> entry : remoteRepository.getExtraParameters().entrySet() )
364             {
365                 if ( !question )
366                 {
367                     res.append( '?' ).append( entry.getKey() ).append( '=' ).append( entry.getValue() );
368                 }
369             }
370
371             return res.toString();
372         }
373
374     }
375
376
377 }
378
379