1 package org.apache.archiva.scheduler.indexing.maven;
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.maven.common.proxy.WagonFactory;
22 import org.apache.archiva.maven.common.proxy.WagonFactoryRequest;
23 import org.apache.archiva.proxy.model.NetworkProxy;
24 import org.apache.archiva.repository.base.PasswordCredentials;
25 import org.apache.archiva.repository.RemoteRepository;
26 import org.apache.archiva.repository.RepositoryException;
27 import org.apache.archiva.repository.RepositoryType;
28 import org.apache.archiva.repository.features.RemoteIndexFeature;
29 import org.apache.commons.lang3.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.IndexUpdateResult;
33 import org.apache.maven.index.updater.IndexUpdater;
34 import org.apache.maven.index.updater.ResourceFetcher;
35 import org.apache.maven.index_shaded.lucene.index.IndexNotFoundException;
36 import org.apache.maven.wagon.ResourceDoesNotExistException;
37 import org.apache.maven.wagon.StreamWagon;
38 import org.apache.maven.wagon.TransferFailedException;
39 import org.apache.maven.wagon.Wagon;
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.proxy.ProxyInfo;
45 import org.apache.maven.wagon.repository.Repository;
46 import org.apache.maven.wagon.shared.http.AbstractHttpClientWagon;
47 import org.apache.maven.wagon.shared.http.HttpConfiguration;
48 import org.apache.maven.wagon.shared.http.HttpMethodConfiguration;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
52 import java.io.FileNotFoundException;
53 import java.io.IOException;
54 import java.io.InputStream;
55 import java.nio.file.Files;
56 import java.nio.file.Path;
57 import java.nio.file.Paths;
58 import java.util.List;
62 * @author Olivier Lamy
65 public class DownloadRemoteIndexTask
68 private Logger log = LoggerFactory.getLogger( getClass() );
70 private RemoteRepository remoteRepository;
72 private WagonFactory wagonFactory;
74 private NetworkProxy networkProxy;
76 private boolean fullDownload;
78 private List<String> runningRemoteDownloadIds;
80 private IndexUpdater indexUpdater;
83 public DownloadRemoteIndexTask( DownloadRemoteIndexTaskRequest downloadRemoteIndexTaskRequest,
84 List<String> runningRemoteDownloadIds )
86 this.remoteRepository = downloadRemoteIndexTaskRequest.getRemoteRepository();
87 this.wagonFactory = downloadRemoteIndexTaskRequest.getWagonFactory();
88 this.networkProxy = downloadRemoteIndexTaskRequest.getNetworkProxy();
89 this.fullDownload = downloadRemoteIndexTaskRequest.isFullDownload();
90 this.runningRemoteDownloadIds = runningRemoteDownloadIds;
91 this.indexUpdater = downloadRemoteIndexTaskRequest.getIndexUpdater();
98 // so short lock : not sure we need it
99 synchronized ( this.runningRemoteDownloadIds )
101 if ( this.runningRemoteDownloadIds.contains( this.remoteRepository.getId() ) )
103 // skip it as it's running
104 log.info( "skip download index remote for repo {} it's already running",
105 this.remoteRepository.getId() );
108 this.runningRemoteDownloadIds.add( this.remoteRepository.getId() );
110 Path tempIndexDirectory = null;
111 StopWatch stopWatch = new StopWatch();
115 log.info( "start download remote index for remote repository {}", this.remoteRepository.getId() );
116 if (this.remoteRepository.getIndexingContext()==null) {
117 throw new IndexNotFoundException("No index context set for repository "+remoteRepository.getId());
119 if (this.remoteRepository.getType()!= RepositoryType.MAVEN) {
120 throw new RepositoryException("Bad repository type");
122 if (!this.remoteRepository.supportsFeature(RemoteIndexFeature.class)) {
123 throw new RepositoryException("Repository does not support RemotIndexFeature "+remoteRepository.getId());
125 RemoteIndexFeature rif = this.remoteRepository.getFeature(RemoteIndexFeature.class).get();
126 IndexingContext indexingContext = this.remoteRepository.getIndexingContext().getBaseContext(IndexingContext.class);
127 // create a temp directory to download files
128 tempIndexDirectory = Paths.get(indexingContext.getIndexDirectoryFile().getParent(), ".tmpIndex" );
129 Path indexCacheDirectory = Paths.get( indexingContext.getIndexDirectoryFile().getParent(), ".indexCache" );
130 Files.createDirectories( indexCacheDirectory );
131 if ( Files.exists(tempIndexDirectory) )
133 org.apache.archiva.common.utils.FileUtils.deleteDirectory( tempIndexDirectory );
135 Files.createDirectories( tempIndexDirectory );
136 tempIndexDirectory.toFile().deleteOnExit();
137 String baseIndexUrl = indexingContext.getIndexUpdateUrl();
139 String wagonProtocol = this.remoteRepository.getLocation().getScheme();
141 final StreamWagon wagon = (StreamWagon) wagonFactory.getWagon(
142 new WagonFactoryRequest( wagonProtocol, this.remoteRepository.getExtraHeaders() ).networkProxy(
145 // FIXME olamy having 2 config values
146 wagon.setReadTimeout( (int)rif.getDownloadTimeout().toMillis());
147 wagon.setTimeout( (int)remoteRepository.getTimeout().toMillis());
149 if ( wagon instanceof AbstractHttpClientWagon )
151 HttpConfiguration httpConfiguration = new HttpConfiguration();
152 HttpMethodConfiguration httpMethodConfiguration = new HttpMethodConfiguration();
153 httpMethodConfiguration.setUsePreemptive( true );
154 httpMethodConfiguration.setReadTimeout( (int)rif.getDownloadTimeout().toMillis() );
155 httpConfiguration.setGet( httpMethodConfiguration );
156 AbstractHttpClientWagon.class.cast( wagon ).setHttpConfiguration( httpConfiguration );
159 wagon.addTransferListener( new DownloadListener() );
160 ProxyInfo proxyInfo = null;
161 if ( this.networkProxy != null )
163 proxyInfo = new ProxyInfo();
164 proxyInfo.setType( this.networkProxy.getProtocol() );
165 proxyInfo.setHost( this.networkProxy.getHost() );
166 proxyInfo.setPort( this.networkProxy.getPort() );
167 proxyInfo.setUserName( this.networkProxy.getUsername() );
168 proxyInfo.setPassword( new String(this.networkProxy.getPassword()) );
170 AuthenticationInfo authenticationInfo = null;
171 if ( this.remoteRepository.getLoginCredentials()!=null && this.remoteRepository.getLoginCredentials() instanceof PasswordCredentials )
173 PasswordCredentials creds = (PasswordCredentials) this.remoteRepository.getLoginCredentials();
174 authenticationInfo = new AuthenticationInfo();
175 authenticationInfo.setUserName( creds.getUsername());
176 authenticationInfo.setPassword( new String(creds.getPassword()) );
178 log.debug("Connection to {}, authInfo={}", this.remoteRepository.getId(), authenticationInfo);
179 wagon.connect( new Repository( this.remoteRepository.getId(), baseIndexUrl ), authenticationInfo,
182 Path indexDirectory = indexingContext.getIndexDirectoryFile().toPath();
183 if ( !Files.exists(indexDirectory) )
185 Files.createDirectories( indexDirectory );
187 log.debug("Downloading index file to {}", indexDirectory);
188 log.debug("Index cache dir {}", indexCacheDirectory);
190 ResourceFetcher resourceFetcher =
191 new WagonResourceFetcher( log, tempIndexDirectory, wagon, remoteRepository );
192 IndexUpdateRequest request = new IndexUpdateRequest( indexingContext, resourceFetcher );
193 request.setForceFullUpdate( this.fullDownload );
194 request.setLocalIndexCacheDir( indexCacheDirectory.toFile() );
196 IndexUpdateResult result = this.indexUpdater.fetchAndUpdateIndex(request);
197 log.debug("Update result success: {}", result.isSuccessful());
199 log.info( "time update index from remote for repository {}: {}ms", this.remoteRepository.getId(),
200 ( stopWatch.getTime() ) );
202 // index packing optionnal ??
203 //IndexPackingRequest indexPackingRequest =
204 // new IndexPackingRequest( indexingContext, indexingContext.getIndexDirectoryFile() );
205 //indexPacker.packIndex( indexPackingRequest );
206 indexingContext.updateTimestamp( true );
209 catch ( Exception e )
211 log.error( e.getMessage(), e );
212 throw new RuntimeException( e.getMessage(), e );
216 deleteDirectoryQuiet( tempIndexDirectory );
217 this.runningRemoteDownloadIds.remove( this.remoteRepository.getId() );
219 log.info( "end download remote index for remote repository {}", this.remoteRepository.getId() );
222 private void deleteDirectoryQuiet( Path f )
226 org.apache.archiva.common.utils.FileUtils.deleteDirectory( f );
228 catch ( IOException e )
230 log.warn( "skip error delete {} : {}", f, e.getMessage() );
235 private static final class DownloadListener
236 implements TransferListener
238 private Logger log = LoggerFactory.getLogger( getClass() );
240 private String resourceName;
242 private long startTime;
244 private int totalLength = 0;
247 public void transferInitiated( TransferEvent transferEvent )
249 startTime = System.currentTimeMillis();
250 resourceName = transferEvent.getResource().getName();
251 log.debug( "initiate transfer of {}", resourceName );
255 public void transferStarted( TransferEvent transferEvent )
257 this.totalLength = 0;
258 resourceName = transferEvent.getResource().getName();
259 log.info("Transferring: {}, {}", transferEvent.getResource().getContentLength(), transferEvent.getLocalFile().toString());
260 log.info( "start transfer of {}", transferEvent.getResource().getName() );
264 public void transferProgress( TransferEvent transferEvent, byte[] buffer, int length )
266 log.debug( "transfer of {} : {}/{}", transferEvent.getResource().getName(), buffer.length, length );
267 this.totalLength += length;
271 public void transferCompleted( TransferEvent transferEvent )
273 resourceName = transferEvent.getResource().getName();
274 long endTime = System.currentTimeMillis();
275 log.info( "end of transfer file {}: {}b, {}ms", transferEvent.getResource().getName(),
276 this.totalLength, ( endTime - startTime ) );
280 public void transferError( TransferEvent transferEvent )
282 log.info( "error of transfer file {}: {}", transferEvent.getResource().getName(),
283 transferEvent.getException().getMessage(), transferEvent.getException() );
287 public void debug( String message )
289 log.debug( "transfer debug {}", message );
293 private static class WagonResourceFetcher
294 implements ResourceFetcher
299 Path tempIndexDirectory;
303 RemoteRepository remoteRepository;
305 private WagonResourceFetcher( Logger log, Path tempIndexDirectory, Wagon wagon,
306 RemoteRepository remoteRepository )
309 this.tempIndexDirectory = tempIndexDirectory;
311 this.remoteRepository = remoteRepository;
315 public void connect( String id, String url )
322 public void disconnect()
329 public InputStream retrieve( String name )
330 throws IOException, FileNotFoundException
334 log.info( "index update retrieve file, name:{}", name );
335 Path file = tempIndexDirectory.resolve( name );
336 Files.deleteIfExists( file );
337 file.toFile().deleteOnExit();
338 wagon.get( addParameters( name, this.remoteRepository ), file.toFile() );
339 return Files.newInputStream( file );
341 catch ( AuthorizationException | TransferFailedException e )
343 throw new IOException( e.getMessage(), e );
345 catch ( ResourceDoesNotExistException e )
347 FileNotFoundException fnfe = new FileNotFoundException( e.getMessage() );
353 // FIXME remove crappy copy/paste
354 protected String addParameters( String path, RemoteRepository remoteRepository )
356 if ( remoteRepository.getExtraParameters().isEmpty() )
361 boolean question = false;
363 StringBuilder res = new StringBuilder( path == null ? "" : path );
365 for ( Map.Entry<String, String> entry : remoteRepository.getExtraParameters().entrySet() )
369 res.append( '?' ).append( entry.getKey() ).append( '=' ).append( entry.getValue() );
373 return res.toString();