diff -Nru eclipse-aether-0.9.0.M2/aether-api/pom.xml eclipse-aether-1.0.2/aether-api/pom.xml --- eclipse-aether-0.9.0.M2/aether-api/pom.xml 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-api/pom.xml 2015-01-14 12:56:17.000000000 +0000 @@ -1,7 +1,7 @@ - - - 4.0.0 - - - org.eclipse.aether - aether - 0.9.0.M2 - - - aether-connector-asynchttpclient - - Aether Connector AsyncHttpClient - - A repository connector implementation based on AsyncHttpClient. - - - - org.eclipse.aether.connector.asynchttpclient - - - - - org.eclipse.aether - aether-api - - - org.eclipse.aether - aether-spi - - - org.eclipse.aether - aether-util - - - com.ning - async-http-client - 1.7.6 - - - javax.inject - javax.inject - provided - true - - - org.codehaus.plexus - plexus-component-annotations - provided - true - - - org.eclipse.aether - aether-test-util - test - - - org.sonatype.sisu - sisu-inject-plexus - test - - - org.mortbay.jetty - jetty - 6.1.25 - test - - - org.sonatype.http-testing-harness - junit-runner - 0.4.1 - test - - - org.sonatype.http-testing-harness - server-provider - 0.4.1 - test - - - - - - - org.codehaus.mojo - animal-sniffer-maven-plugin - - - org.codehaus.plexus - plexus-component-metadata - - - org.sonatype.plugins - sisu-maven-plugin - - - org.apache.felix - maven-bundle-plugin - - - - diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/AsyncRepositoryConnectorFactory.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/AsyncRepositoryConnectorFactory.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/AsyncRepositoryConnectorFactory.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/AsyncRepositoryConnectorFactory.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,127 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import javax.inject.Inject; -import javax.inject.Named; - -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; -import org.eclipse.aether.spi.io.FileProcessor; -import org.eclipse.aether.spi.locator.Service; -import org.eclipse.aether.spi.locator.ServiceLocator; -import org.eclipse.aether.spi.log.Logger; -import org.eclipse.aether.spi.log.LoggerFactory; -import org.eclipse.aether.spi.log.NullLoggerFactory; -import org.eclipse.aether.transfer.NoRepositoryConnectorException; - -/** - * A repository connector factory that uses Async Http Client for the transfers. - */ -@Named -@Component( role = RepositoryConnectorFactory.class, hint = "async-http" ) -public final class AsyncRepositoryConnectorFactory - implements RepositoryConnectorFactory, Service -{ - - @Requirement( role = LoggerFactory.class ) - private Logger logger = NullLoggerFactory.LOGGER; - - @Requirement - private FileProcessor fileProcessor; - - private float priority = 100; - - /** - * Creates an (uninitialized) instance of this connector factory. Note: In case of manual instantiation by - * clients, the new factory needs to be configured via its various mutators before first use or runtime errors will - * occur. - */ - public AsyncRepositoryConnectorFactory() - { - // enables default constructor - } - - @Inject - AsyncRepositoryConnectorFactory( FileProcessor fileProcessor, LoggerFactory loggerFactory ) - { - setFileProcessor( fileProcessor ); - setLoggerFactory( loggerFactory ); - } - - public void initService( ServiceLocator locator ) - { - setLoggerFactory( locator.getService( LoggerFactory.class ) ); - setFileProcessor( locator.getService( FileProcessor.class ) ); - } - - /** - * Sets the logger factory to use for this component. - * - * @param loggerFactory The logger factory to use, may be {@code null} to disable logging. - * @return This component for chaining, never {@code null}. - */ - public AsyncRepositoryConnectorFactory setLoggerFactory( LoggerFactory loggerFactory ) - { - this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, AsyncRepositoryConnector.class ); - return this; - } - - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - - /** - * Sets the file processor to use for this component. - * - * @param fileProcessor The file processor to use, must not be {@code null}. - * @return This component for chaining, never {@code null}. - */ - public AsyncRepositoryConnectorFactory setFileProcessor( FileProcessor fileProcessor ) - { - if ( fileProcessor == null ) - { - throw new IllegalArgumentException( "file processor has not been specified" ); - } - this.fileProcessor = fileProcessor; - return this; - } - - public float getPriority() - { - return priority; - } - - /** - * Sets the priority of this component. - * - * @param priority The priority. - * @return This component for chaining, never {@code null}. - */ - public AsyncRepositoryConnectorFactory setPriority( float priority ) - { - this.priority = priority; - return this; - } - - public RepositoryConnector newInstance( RepositorySystemSession session, RemoteRepository repository ) - throws NoRepositoryConnectorException - { - return new AsyncRepositoryConnector( repository, session, fileProcessor, logger ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/AsyncRepositoryConnector.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/AsyncRepositoryConnector.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/AsyncRepositoryConnector.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/AsyncRepositoryConnector.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,1607 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.AsyncHttpProvider; -import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.HttpResponseHeaders; -import com.ning.http.client.ProxyServer; -import com.ning.http.client.ProxyServer.Protocol; -import com.ning.http.client.Realm; -import com.ning.http.client.Request; -import com.ning.http.client.RequestBuilder; -import com.ning.http.client.Response; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; - -import org.eclipse.aether.ConfigurationProperties; -import org.eclipse.aether.RepositoryCache; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.repository.AuthenticationContext; -import org.eclipse.aether.repository.Proxy; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.repository.RepositoryPolicy; -import org.eclipse.aether.spi.connector.ArtifactDownload; -import org.eclipse.aether.spi.connector.ArtifactTransfer; -import org.eclipse.aether.spi.connector.ArtifactUpload; -import org.eclipse.aether.spi.connector.MetadataDownload; -import org.eclipse.aether.spi.connector.MetadataTransfer; -import org.eclipse.aether.spi.connector.MetadataUpload; -import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.aether.spi.connector.Transfer; -import org.eclipse.aether.spi.io.FileProcessor; -import org.eclipse.aether.spi.log.Logger; -import org.eclipse.aether.transfer.ArtifactNotFoundException; -import org.eclipse.aether.transfer.ArtifactTransferException; -import org.eclipse.aether.transfer.ChecksumFailureException; -import org.eclipse.aether.transfer.MetadataNotFoundException; -import org.eclipse.aether.transfer.MetadataTransferException; -import org.eclipse.aether.transfer.NoRepositoryConnectorException; -import org.eclipse.aether.transfer.TransferEvent; -import org.eclipse.aether.transfer.TransferListener; -import org.eclipse.aether.transfer.TransferResource; -import org.eclipse.aether.transfer.TransferEvent.EventType; -import org.eclipse.aether.transfer.TransferEvent.RequestType; -import org.eclipse.aether.util.ChecksumUtils; -import org.eclipse.aether.util.ConfigUtils; -import org.eclipse.aether.util.StringUtils; -import org.eclipse.aether.util.repository.layout.MavenDefaultLayout; -import org.eclipse.aether.util.repository.layout.RepositoryLayout; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.RandomAccessFile; -import java.lang.reflect.InvocationTargetException; -import java.net.ConnectException; -import java.net.HttpURLConnection; -import java.nio.channels.FileLock; -import java.nio.channels.OverlappingFileLockException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * A repository connector that uses the Async Http Client. - */ -class AsyncRepositoryConnector - implements RepositoryConnector -{ - private final Logger logger; - - private final FileProcessor fileProcessor; - - private final RemoteRepository repository; - - private final AsyncHttpClient httpClient; - - private final Map checksumAlgos; - - private final AtomicBoolean closed = new AtomicBoolean( false ); - - private final RepositoryLayout layout = new MavenDefaultLayout(); - - private final TransferListener listener; - - private final RepositorySystemSession session; - - private final AuthenticationContext repoAuthContext; - - private final AuthenticationContext proxyAuthContext; - - private boolean useCache = false; - - private final boolean disableResumeSupport; - - private final static ConcurrentHashMap activeDownloadFiles = - new ConcurrentHashMap(); - - private final int maxIOExceptionRetry; - - private final FluentCaseInsensitiveStringsMap headers; - - /** - * Create an {@link org.eclipse.aether.connector.async.AsyncRepositoryConnector} instance which connect to the - * {@link RemoteRepository} - * - * @param repository the remote repository - * @param session the {@link RepositorySystemSession} - * @param logger the logger. - * @throws NoRepositoryConnectorException - */ - public AsyncRepositoryConnector( RemoteRepository repository, RepositorySystemSession session, - FileProcessor fileProcessor, Logger logger ) - throws NoRepositoryConnectorException - { - if ( !"default".equals( repository.getContentType() ) ) - { - throw new NoRepositoryConnectorException( repository ); - } - - if ( !repository.getProtocol().regionMatches( true, 0, "http", 0, "http".length() ) && - !repository.getProtocol().regionMatches( true, 0, "dav", 0, "dav".length() ) ) - { - throw new NoRepositoryConnectorException( repository ); - } - - this.logger = logger; - this.repository = repository; - this.listener = session.getTransferListener(); - this.fileProcessor = fileProcessor; - this.session = session; - - repoAuthContext = AuthenticationContext.forRepository( session, repository ); - proxyAuthContext = AuthenticationContext.forProxy( session, repository ); - - AsyncHttpClientConfig config = createConfig( session, repository, true ); - - httpClient = new AsyncHttpClient( getProvider( session, config ), config ); - - checksumAlgos = new LinkedHashMap(); - checksumAlgos.put( "SHA-1", ".sha1" ); - checksumAlgos.put( "MD5", ".md5" ); - - disableResumeSupport = ConfigUtils.getBoolean( session, false, "aether.connector.ahc.disableResumable" ); - maxIOExceptionRetry = ConfigUtils.getInteger( session, 3, "aether.connector.ahc.resumeRetry" ); - - this.headers = new FluentCaseInsensitiveStringsMap(); - Map headers = - ConfigUtils.getMap( session, null, ConfigurationProperties.HTTP_HEADERS + "." + repository.getId(), - ConfigurationProperties.HTTP_HEADERS ); - if ( headers != null ) - { - for ( Map.Entry entry : headers.entrySet() ) - { - if ( entry.getKey() instanceof String && entry.getValue() instanceof String ) - { - this.headers.add( entry.getKey().toString(), entry.getValue().toString() ); - } - } - } - } - - private AsyncHttpProvider getProvider( RepositorySystemSession session, AsyncHttpClientConfig config ) - { - String className = ConfigUtils.getString( session, "", "aether.connector.ahc.provider" ); - - if ( className != null && className.length() > 0 ) - { - if ( "netty".equals( className ) ) - { - className = "com.ning.http.client.providers.netty.NettyAsyncHttpProvider"; - } - else if ( "jdk".equals( className ) ) - { - className = "com.ning.http.client.providers.jdk.JDKAsyncHttpProvider"; - } - else if ( "apache".equals( className ) ) - { - className = "com.ning.http.client.providers.apache.ApacheAsyncHttpProvider"; - } - - RepositoryCache cache = session.getCache(); - - try - { - if ( cache == null || cache.get( session, className ) == null ) - { - logger.debug( "Using AHC provider " + className ); - - Class providerClass = getClass().getClassLoader().loadClass( className ); - - Object inst = providerClass.getConstructor( AsyncHttpClientConfig.class ).newInstance( config ); - - return (AsyncHttpProvider) inst; - } - } - catch ( LinkageError e ) - { - warn( "Could not load AHC provider " + className + ", falling back to default", e ); - } - catch ( ClassNotFoundException e ) - { - logger.warn( "Could not load AHC provider " + className + ", falling back to default" ); - } - catch ( ClassCastException e ) - { - logger.warn( "Could not load type-compatible AHC provider " + className + ", falling back to default" ); - } - catch ( Exception e ) - { - Throwable cause = e; - if ( e instanceof InvocationTargetException && e.getCause() != null ) - { - cause = e.getCause(); - } - warn( "Could not instantiate AHC provider " + className + ", falling back to default", cause ); - } - - if ( cache != null ) - { - cache.put( session, className, Boolean.TRUE ); - } - } - - return getDefaultProvider( config ); - } - - private AsyncHttpProvider getDefaultProvider( AsyncHttpClientConfig config ) - { - return new NettyAsyncHttpProvider( config ); - } - - private void warn( String message, Throwable cause ) - { - String msg = message; - if ( cause != null ) - { - msg += ": " + cause; - } - if ( logger.isDebugEnabled() ) - { - logger.warn( msg, cause ); - } - else - { - logger.warn( msg ); - } - } - - private Realm getRealm( RemoteRepository repository, String credentialEncoding ) - { - Realm realm = null; - - if ( repoAuthContext != null ) - { - Realm.RealmBuilder builder = new Realm.RealmBuilder(); - builder.setUsePreemptiveAuth( false ).setEnconding( credentialEncoding ); - builder.setPrincipal( repoAuthContext.get( AuthenticationContext.USERNAME ) ); - builder.setPassword( repoAuthContext.get( AuthenticationContext.PASSWORD ) ); - realm = builder.build(); - } - - return realm; - } - - private ProxyServer getProxy( RemoteRepository repository, String credentialEncoding ) - { - ProxyServer proxyServer = null; - - Proxy p = repository.getProxy(); - if ( p != null ) - { - boolean useSSL = repository.getProtocol().equalsIgnoreCase( "https" ) || - repository.getProtocol().equalsIgnoreCase( "dav:https" ); - if ( proxyAuthContext == null ) - { - proxyServer = new ProxyServer( useSSL ? Protocol.HTTPS : Protocol.HTTP, p.getHost(), p.getPort() ); - } - else - { - proxyServer = new ProxyServer( useSSL ? Protocol.HTTPS : Protocol.HTTP, p.getHost(), p.getPort() ) - { - @Override - public String getPrincipal() - { - return proxyAuthContext.get( AuthenticationContext.USERNAME ); - } - - @Override - public String getPassword() - { - return proxyAuthContext.get( AuthenticationContext.PASSWORD ); - } - - @Override - public String getNtlmDomain() - { - return proxyAuthContext.get( AuthenticationContext.NTLM_DOMAIN ); - } - }; - proxyServer.setEncoding( credentialEncoding ); - } - } - - return proxyServer; - } - - /** - * Create an {@link AsyncHttpClientConfig} instance based on the values from {@link RepositorySystemSession} - * - * @param session {link RepositorySystemSession} - * @return a configured instance of - */ - private AsyncHttpClientConfig createConfig( RepositorySystemSession session, RemoteRepository repository, - boolean useCompression ) - { - AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder(); - - String userAgent = - ConfigUtils.getString( session, ConfigurationProperties.DEFAULT_USER_AGENT, ConfigurationProperties.USER_AGENT ); - if ( !StringUtils.isEmpty( userAgent ) ) - { - configBuilder.setUserAgent( userAgent ); - } - int connectTimeout = - ConfigUtils.getInteger( session, ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT, - ConfigurationProperties.CONNECT_TIMEOUT ); - String credentialEncoding = - ConfigUtils.getString( session, ConfigurationProperties.DEFAULT_HTTP_CREDENTIAL_ENCODING, - ConfigurationProperties.HTTP_CREDENTIAL_ENCODING + "." + repository.getId(), - ConfigurationProperties.HTTP_CREDENTIAL_ENCODING ); - - configBuilder.setConnectionTimeoutInMs( connectTimeout ); - configBuilder.setCompressionEnabled( useCompression ); - configBuilder.setFollowRedirects( true ); - configBuilder.setMaxRequestRetry( 0 ); - configBuilder.setRequestTimeoutInMs( ConfigUtils.getInteger( session, ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT, - ConfigurationProperties.REQUEST_TIMEOUT ) ); - - configBuilder.setProxyServer( getProxy( repository, credentialEncoding ) ); - configBuilder.setRealm( getRealm( repository, credentialEncoding ) ); - - return configBuilder.build(); - } - - private void await( CountDownLatch latch ) - { - boolean interrupted = false; - while ( latch.getCount() > 0 ) - { - try - { - latch.await(); - } - catch ( InterruptedException e ) - { - interrupted = true; - } - } - if ( interrupted ) - { - Thread.currentThread().interrupt(); - } - } - - /** - * Use the async http client library to download artifacts and metadata. - * - * @param artifactDownloads The artifact downloads to perform, may be {@code null} or empty. - * @param metadataDownloads The metadata downloads to perform, may be {@code null} or empty. - */ - public void get( Collection artifactDownloads, - Collection metadataDownloads ) - { - if ( closed.get() ) - { - throw new IllegalStateException( "connector closed" ); - } - - artifactDownloads = safe( artifactDownloads ); - metadataDownloads = safe( metadataDownloads ); - - CountDownLatch latch = new CountDownLatch( artifactDownloads.size() + metadataDownloads.size() ); - - Collection> tasks = new ArrayList>(); - - for ( MetadataDownload download : metadataDownloads ) - { - String resource = layout.getPath( download.getMetadata() ).getPath(); - GetTask task = - new GetTask( resource, download.getFile(), download.getChecksumPolicy(), latch, - download, METADATA, false ); - tasks.add( task ); - task.run(); - } - - for ( ArtifactDownload download : artifactDownloads ) - { - String resource = layout.getPath( download.getArtifact() ).getPath(); - GetTask task = - new GetTask( resource, download.isExistenceCheck() ? null : download.getFile(), - download.getChecksumPolicy(), latch, download, ARTIFACT, true ); - tasks.add( task ); - task.run(); - } - - await( latch ); - - for ( GetTask task : tasks ) - { - task.flush(); - } - } - - /** - * Use the async http client library to upload artifacts and metadata. - * - * @param artifactUploads The artifact uploads to perform, may be {@code null} or empty. - * @param metadataUploads The metadata uploads to perform, may be {@code null} or empty. - */ - public void put( Collection artifactUploads, - Collection metadataUploads ) - { - if ( closed.get() ) - { - throw new IllegalStateException( "connector closed" ); - } - - artifactUploads = safe( artifactUploads ); - metadataUploads = safe( metadataUploads ); - - CountDownLatch latch = new CountDownLatch( artifactUploads.size() + metadataUploads.size() ); - - Collection> tasks = new ArrayList>(); - - for ( ArtifactUpload upload : artifactUploads ) - { - String path = layout.getPath( upload.getArtifact() ).getPath(); - - PutTask task = new PutTask( path, upload.getFile(), latch, upload, ARTIFACT ); - tasks.add( task ); - task.run(); - } - - for ( MetadataUpload upload : metadataUploads ) - { - String path = layout.getPath( upload.getMetadata() ).getPath(); - - PutTask task = new PutTask( path, upload.getFile(), latch, upload, METADATA ); - tasks.add( task ); - task.run(); - } - - await( latch ); - - for ( PutTask task : tasks ) - { - task.flush(); - } - } - - private void handleResponseCode( String url, int responseCode, String responseMsg ) - throws AuthorizationException, ResourceDoesNotExistException, TransferException - { - if ( responseCode == HttpURLConnection.HTTP_NOT_FOUND ) - { - throw new ResourceDoesNotExistException( - String.format( "Unable to locate resource %s. Error code %s", url, responseCode ) ); - } - - if ( responseCode == HttpURLConnection.HTTP_FORBIDDEN || responseCode == HttpURLConnection.HTTP_UNAUTHORIZED || - responseCode == HttpURLConnection.HTTP_PROXY_AUTH ) - { - throw new AuthorizationException( - String.format( "Access denied to %s. Error code %s, %s", url, responseCode, responseMsg ) ); - } - - if ( responseCode >= HttpURLConnection.HTTP_MULT_CHOICE ) - { - throw new TransferException( - String.format( "Failed to transfer %s. Error code %s, %s", url, responseCode, responseMsg ) ); - } - } - - private TransferEvent newEvent( TransferResource resource, Exception e, TransferEvent.RequestType requestType, - TransferEvent.EventType eventType ) - { - TransferEvent.Builder event = new TransferEvent.Builder( session, resource ); - event.setType( eventType ); - event.setRequestType( requestType ); - event.setException( e ); - return event.build(); - } - - class GetTask - implements Runnable - { - - private final T download; - - private final String path; - - private final File file; - - private final String checksumPolicy; - - private final LatchGuard latch; - - private volatile Exception exception; - - private final ExceptionWrapper wrapper; - - private final AtomicBoolean deleteFile = new AtomicBoolean( true ); - - private final boolean allowResumable; - - public GetTask( String path, File file, String checksumPolicy, CountDownLatch latch, T download, - ExceptionWrapper wrapper, boolean allowResumable ) - { - this.path = path; - this.file = file; - this.checksumPolicy = checksumPolicy; - this.allowResumable = allowResumable; - this.latch = new LatchGuard( latch ); - this.download = download; - this.wrapper = wrapper; - } - - public T getDownload() - { - return download; - } - - public Exception getException() - { - return exception; - } - - public void run() - { - download.setState( Transfer.State.ACTIVE ); - final String uri = validateUri( path ); - final TransferResource transferResource = - new TransferResource( repository.getUrl(), path, file, download.getTrace() ); - final RequestType requestType = ( file != null ) ? RequestType.GET : RequestType.GET_EXISTENCE; - final boolean ignoreChecksum = RepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals( checksumPolicy ); - CompletionHandler completionHandler = null; - - final FileLockCompanion fileLockCompanion = ( file != null ) - ? createOrGetTmpFile( file.getPath(), allowResumable ) - : new FileLockCompanion( null, null ); - - try - { - long length = 0; - if ( fileLockCompanion.getFile() != null ) - { - fileProcessor.mkdirs( fileLockCompanion.getFile().getParentFile() ); - } - - // Position the file to the end in case we are resuming an aborded download. - final RandomAccessFile resumableFile = fileLockCompanion.getFile() == null - ? null - : new RandomAccessFile( fileLockCompanion.getFile(), "rw" ); - if ( resumableFile != null ) - { - length = resumableFile.length(); - } - - FluentCaseInsensitiveStringsMap headers = new FluentCaseInsensitiveStringsMap(); - if ( !useCache ) - { - headers.add( "Pragma", "no-cache" ); - } - headers.add( "Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2" ); - headers.replaceAll( AsyncRepositoryConnector.this.headers ); - - Request request = null; - final AtomicInteger maxRequestTry = new AtomicInteger(); - AsyncHttpClient client = httpClient; - final AtomicBoolean closeOnComplete = new AtomicBoolean( false ); - - /** - * If length > 0, it means we are resuming a interrupted download. If that's the case, - * we can't re-use the current httpClient because compression is enabled, and supporting - * compression per request is not supported in ahc and may never has it could have - * a performance impact. - */ - if ( length > 0 ) - { - AsyncHttpClientConfig config = createConfig( session, repository, false ); - client = new AsyncHttpClient( new NettyAsyncHttpProvider( config ) ); - request = client.prepareGet( uri ).setRangeOffset( length ).setHeaders( headers ).build(); - closeOnComplete.set( true ); - } - else - { - request = httpClient.prepareGet( uri ).setHeaders( headers ).build(); - } - - final Request activeRequest = request; - final AsyncHttpClient activeHttpClient = client; - completionHandler = new CompletionHandler( transferResource, httpClient, logger, requestType, session ) - { - private final AtomicBoolean handleTmpFile = new AtomicBoolean( true ); - - private final AtomicBoolean localException = new AtomicBoolean ( false ); - - /** - * {@inheritDoc} - */ - @Override - public STATE onHeadersReceived( final HttpResponseHeaders headers ) - throws Exception - { - FluentCaseInsensitiveStringsMap h = headers.getHeaders(); - String rangeByteValue = h.getFirstValue( "Content-Range" ); - // Make sure the server acceptance of the range requests headers - if ( rangeByteValue != null && rangeByteValue.compareToIgnoreCase( "none" ) != 0 ) - { - resumableFile.seek( resumableFile.length() ); - } - else - { - resumableFile.seek( 0 ); - } - return super.onHeadersReceived( headers ); - } - - @Override - public void onThrowable( Throwable t ) - { - boolean resume = false; - try - { - logger.debug("onThrowable", t); - - /** - * If an IOException occurs, let's try to resume the request based on how much bytes has - * been so far downloaded. Fail after IOException. - */ - try - { - if ( !disableResumeSupport && !localException.get() - && maxRequestTry.get() < maxIOExceptionRetry && isResumeWorthy( t ) ) - { - logger.debug( "Trying to recover from an IOException " + activeRequest ); - maxRequestTry.incrementAndGet(); - Request newRequest = - new RequestBuilder( activeRequest ).setRangeOffset( resumableFile.length() ).build(); - activeHttpClient.executeRequest( newRequest, this ); - resume = true; - return; - } - } - catch ( Throwable rt ) - { - logger.warn( "Could not resume download", rt ); - } - - localException.set( false ); - - if ( Exception.class.isAssignableFrom( t.getClass() ) ) - { - exception = Exception.class.cast( t ); - } - else - { - exception = new Exception( t ); - } - - if ( closeOnComplete.get() ) - { - activeHttpClient.close(); - } - - super.onThrowable( t ); - - fireTransferFailed(); - } - catch ( Throwable ex ) - { - logger.warn( "Unexpected exception", ex ); - } - finally - { - if ( resume ) - { - return; - } - if ( resumableFile != null ) - { - try - { - resumableFile.close(); - } - catch ( IOException ex ) - { - } - } - deleteFile( fileLockCompanion ); - - latch.countDown(); - removeListeners(); - } - } - - private void removeListeners() - { - removeTransferListener( listener ); - } - - public STATE onBodyPartReceived( final HttpResponseBodyPart content ) - throws Exception - { - if ( status() != null && - ( status().getStatusCode() == 200 || status().getStatusCode() == 206 ) ) - { - byte[] bytes = content.getBodyPartBytes(); - try - { - resumableFile.write( bytes ); - } - catch ( IOException ex ) - { - logger.debug("onBodyPartReceived", ex); - exception = ex; - localException.set(true); - throw ex; - } - } - return super.onBodyPartReceived( content ); - } - - @Override - public Response onCompleted( Response r ) - throws Exception - { - try - { - deleteFile.set( true ); - try - { - resumableFile.close(); - } - catch ( IOException ex ) - { - } - - final Response response = super.onCompleted( r ); - - handleResponseCode( uri, response.getStatusCode(), response.getStatusText() ); - - if ( !ignoreChecksum ) - { - activeHttpClient.getConfig().executorService().execute( new Runnable() - { - public void run() - { - try - { - try - { - Map checksums = - ChecksumUtils.calc( fileLockCompanion.getFile(), - checksumAlgos.keySet() ); - if ( !verifyChecksum( file, uri, (String) checksums.get( "SHA-1" ), - ".sha1" ) && - !verifyChecksum( file, uri, (String) checksums.get( "MD5" ), - ".md5" ) ) - { - throw new ChecksumFailureException( "Checksum validation failed" + - ", no checksums available from the repository" ); - } - } - catch ( ChecksumFailureException e ) - { - if ( RepositoryPolicy.CHECKSUM_POLICY_FAIL.equals( checksumPolicy ) ) - { - throw e; - } - if ( listener != null ) - { - listener.transferCorrupted( newEvent( transferResource, e, - requestType, - EventType.CORRUPTED ) ); - } - } - } - catch ( Exception ex ) - { - exception = ex; - } - finally - { - if ( exception == null ) - { - try - { - rename( fileLockCompanion.getFile(), file ); - releaseLock( fileLockCompanion ); - } - catch ( IOException e ) - { - exception = e; - } - } - else - { - deleteFile( fileLockCompanion ); - } - - latch.countDown(); - if ( closeOnComplete.get() ) - { - activeHttpClient.close(); - } - } - } - } ); - } - else - { - - rename( fileLockCompanion.getFile(), file ); - releaseLock( fileLockCompanion ); - handleTmpFile.set( false ); - - // asyncHttpClient.close may takes time before all connections get closed. - // We unlatch first. - latch.countDown(); - if ( closeOnComplete.get() ) - { - activeHttpClient.close(); - } - } - removeListeners(); - - return response; - } - catch ( Exception ex ) - { - exception = ex; - localException.set(true); - throw ex; - } - finally - { - try - { - if ( handleTmpFile.get() && fileLockCompanion.getFile() != null ) - { - if ( exception != null ) - { - deleteFile( fileLockCompanion ); - } - else if ( ignoreChecksum ) - { - rename( fileLockCompanion.getFile(), file ); - releaseLock( fileLockCompanion ); - } - } - } - catch ( IOException ex ) - { - exception = ex; - } - } - } - - }; - - try - { - if ( file == null ) - { - if ( !resourceExist( uri ) ) - { - throw new ResourceDoesNotExistException( - "Could not find " + uri + " in " + repository.getUrl() ); - } - latch.countDown(); - } - else - { - if ( listener != null ) - { - completionHandler.addTransferListener( listener ); - listener.transferInitiated( newEvent( transferResource, null, requestType, - EventType.INITIATED ) ); - } - - activeHttpClient.executeRequest( request, completionHandler ); - } - } - catch ( Exception ex ) - { - try - { - if ( resumableFile != null ) - { - resumableFile.close(); - } - } - catch ( IOException ex2 ) - { - } - deleteFile( fileLockCompanion ); - exception = ex; - latch.countDown(); - } - } - catch ( Throwable t ) - { - deleteFile( fileLockCompanion ); - try - { - if ( Exception.class.isAssignableFrom( t.getClass() ) ) - { - exception = Exception.class.cast( t ); - } - else - { - exception = new Exception( t ); - } - if ( listener != null ) - { - listener.transferFailed( - newEvent( transferResource, exception, requestType, EventType.FAILED ) ); - } - } - finally - { - latch.countDown(); - } - } - } - - private boolean isResumeWorthy( Throwable t ) - { - if ( t instanceof IOException ) - { - if ( t instanceof ConnectException ) - { - return false; - } - return true; - } - return false; - } - - private void deleteFile( FileLockCompanion fileLockCompanion ) - { - if ( fileLockCompanion.getFile() != null && deleteFile.get() ) - { - releaseLock( fileLockCompanion ); - activeDownloadFiles.remove( fileLockCompanion.getFile() ); - fileLockCompanion.getFile().delete(); - } - } - - private boolean verifyChecksum( File file, String path, String actual, String ext ) - throws ChecksumFailureException - { - File tmp = getTmpFile( file.getPath() + ext ); - try - { - try - { - Response response = httpClient.prepareGet( path + ext ).setHeaders( headers ).execute().get(); - - if ( response.getStatusCode() == HttpURLConnection.HTTP_NOT_FOUND ) - { - return false; - } - - OutputStream fs = new BufferedOutputStream( new FileOutputStream( tmp ) ); - try - { - InputStream is = response.getResponseBodyAsStream(); - final byte[] buffer = new byte[4 * 1024]; - int n = 0; - while ( -1 != ( n = is.read( buffer ) ) ) - { - fs.write( buffer, 0, n ); - } - fs.flush(); - } - finally - { - fs.close(); - } - - } - catch ( Exception ex ) - { - throw new ChecksumFailureException( ex ); - } - - String expected; - - try - { - expected = ChecksumUtils.read( tmp ); - } - catch ( IOException e ) - { - throw new ChecksumFailureException( e ); - } - - if ( expected.equalsIgnoreCase( actual ) ) - { - try - { - rename( tmp, new File( file.getPath() + ext ) ); - } - catch ( IOException e ) - { - // ignored, non-critical - } - } - else - { - throw new ChecksumFailureException( expected, actual ); - } - } - finally - { - tmp.delete(); - } - - return true; - } - - public void flush() - { - wrapper.wrap( download, exception, repository ); - download.setState( Transfer.State.DONE ); - } - - private void rename( File from, File to ) - throws IOException - { - fileProcessor.move( from, to ); - } - } - - class PutTask - implements Runnable - { - - private final T upload; - - private final ExceptionWrapper wrapper; - - private final String path; - - private final File file; - - private volatile Exception exception; - - private final LatchGuard latch; - - public PutTask( String path, File file, CountDownLatch latch, T upload, ExceptionWrapper wrapper ) - { - this.path = path; - this.file = file; - this.upload = upload; - this.wrapper = wrapper; - this.latch = new LatchGuard( latch ); - } - - public Exception getException() - { - return exception; - } - - public void run() - { - upload.setState( Transfer.State.ACTIVE ); - final TransferResource transferResource = - new TransferResource( repository.getUrl(), path, file, upload.getTrace() ); - - try - { - final String uri = validateUri( path ); - - final CompletionHandler completionHandler = - new CompletionHandler( transferResource, httpClient, logger, RequestType.PUT, session ) - { - @Override - public void onThrowable( Throwable t ) - { - try - { - super.onThrowable( t ); - if ( Exception.class.isAssignableFrom( t.getClass() ) ) - { - exception = Exception.class.cast( t ); - } - else - { - exception = new Exception( t ); - } - - if ( listener != null ) - { - listener.transferFailed( - newEvent( transferResource, exception, RequestType.PUT, EventType.FAILED ) ); - } - } - finally - { - latch.countDown(); - } - } - - @Override - public Response onCompleted( Response r ) - throws Exception - { - try - { - Response response = super.onCompleted( r ); - handleResponseCode( uri, response.getStatusCode(), response.getStatusText() ); - - httpClient.getConfig().executorService().execute( new Runnable() - { - public void run() - { - try - { - uploadChecksums( file, uri ); - } - catch ( Exception ex ) - { - exception = ex; - } - finally - { - latch.countDown(); - } - } - } ); - - return r; - } - - catch ( Exception ex ) - { - exception = ex; - throw ex; - } - - } - }; - - if ( listener != null ) - - { - completionHandler.addTransferListener( listener ); - listener.transferInitiated( - newEvent( transferResource, null, RequestType.PUT, EventType.INITIATED ) ); - } - - if ( file == null ) - { - throw new IllegalArgumentException( "no source file specified for upload" ); - } - transferResource.setContentLength( file.length() ); - - httpClient.preparePut( uri ).setHeaders( headers ).setBody( - new ProgressingFileBodyGenerator( file, completionHandler ) ).execute( completionHandler ); - } - catch ( Exception e ) - { - try - { - if ( listener != null ) - { - listener.transferFailed( newEvent( transferResource, e, RequestType.PUT, EventType.FAILED ) ); - } - exception = e; - } - finally - { - latch.countDown(); - } - } - } - - public void flush() - { - wrapper.wrap( upload, exception, repository ); - upload.setState( Transfer.State.DONE ); - } - - private void uploadChecksums( File file, String path ) - { - try - { - Map checksums = ChecksumUtils.calc( file, checksumAlgos.keySet() ); - for ( Map.Entry entry : checksums.entrySet() ) - { - uploadChecksum( file, path, entry.getKey(), entry.getValue() ); - } - } - catch ( IOException e ) - { - logger.debug( "Failed to upload checksums for " + file + ": " + e.getMessage(), e ); - } - } - - private void uploadChecksum( File file, String path, String algo, Object checksum ) - { - try - { - if ( checksum instanceof Exception ) - { - throw (Exception) checksum; - } - - String ext = checksumAlgos.get( algo ); - - // Here we go blocking as this is a simple request. - Response response = - httpClient.preparePut( path + ext ).setHeaders( headers ).setBody( String.valueOf( checksum ) ).execute().get(); - - if ( response == null || response.getStatusCode() >= HttpURLConnection.HTTP_BAD_REQUEST ) - { - throw new TransferException( - String.format( "Checksum failed for %s with status code %s", path + ext, response == null - ? HttpURLConnection.HTTP_INTERNAL_ERROR - : response.getStatusCode() ) ); - } - } - catch ( Exception e ) - { - String msg = "Failed to upload " + algo + " checksum for " + file + ": " + e.getMessage(); - if ( logger.isDebugEnabled() ) - { - logger.warn( msg, e ); - } - else - { - logger.warn( msg ); - } - } - } - - } - - /** - * Builds a complete URL string from the repository URL and the relative path passed. - * - * @param path the relative path - * @return the complete URL - */ - private String buildUrl( String path ) - { - final String repoUrl = repository.getUrl(); - path = path.replace( ' ', '+' ); - - if ( repoUrl.charAt( repoUrl.length() - 1 ) != '/' ) - { - return repoUrl + '/' + path; - } - return repoUrl + path; - } - - private String validateUri( String path ) - { - String tmpUri = buildUrl( path ); - // If we get dav request here, switch to http as no need for dav method. - String dav = "dav"; - String davHttp = "dav:http"; - if ( tmpUri.startsWith( dav ) ) - { - if ( tmpUri.startsWith( davHttp ) ) - { - tmpUri = tmpUri.substring( dav.length() + 1 ); - } - else - { - tmpUri = "http" + tmpUri.substring( dav.length() ); - } - } - return tmpUri; - } - - private boolean resourceExist( String url ) - throws IOException, ExecutionException, InterruptedException, TransferException, AuthorizationException - { - int statusCode = httpClient.prepareHead( url ).setHeaders( headers ).execute().get().getStatusCode(); - - switch ( statusCode ) - { - case HttpURLConnection.HTTP_OK: - return true; - - case HttpURLConnection.HTTP_FORBIDDEN: - throw new AuthorizationException( - String.format( "Access denied to %s . Status code %s", url, statusCode ) ); - - case HttpURLConnection.HTTP_NOT_FOUND: - return false; - - case HttpURLConnection.HTTP_UNAUTHORIZED: - throw new AuthorizationException( - String.format( "Access denied to %s . Status code %s", url, statusCode ) ); - - default: - throw new TransferException( - "Failed to look for file: " + buildUrl( url ) + ". Return code is: " + statusCode ); - } - } - - static interface ExceptionWrapper - { - void wrap( T transfer, Exception e, RemoteRepository repository ); - } - - public void close() - { - closed.set( true ); - AuthenticationContext.close( repoAuthContext ); - AuthenticationContext.close( proxyAuthContext ); - httpClient.close(); - } - - private Collection safe( Collection items ) - { - return ( items != null ) ? items : Collections.emptyList(); - } - - /** - * Create a {@link FileLockCompanion} containing a reference to a temporary {@link File} used when downloading - * a remote file. If a local and incomplete version of a file is available, use that file and resume bytes downloading. - * To prevent multiple process trying to resume the same file, a {@link FileLock} companion to the tmeporary file is - * created and used to prevent concurrency issue. - * - * @param path The downloaded path - * @param allowResumable Allow resumable download, or not. - * @return - */ - private FileLockCompanion createOrGetTmpFile( String path, boolean allowResumable ) - { - if ( !disableResumeSupport && allowResumable ) - { - File f = new File( path ); - File parentFile = f.getParentFile(); - if ( parentFile.isDirectory() ) - { - for ( File tmpFile : parentFile.listFiles( new FilenameFilter() - { - public boolean accept( File dir, String name ) - { - if ( name.indexOf( "." ) > 0 && name.lastIndexOf( "." ) == name.indexOf( ".ahc" ) ) - { - return true; - } - return false; - } - } ) ) - { - - if ( tmpFile.length() > 0 ) - { - String realPath = tmpFile.getPath().substring( 0, tmpFile.getPath().lastIndexOf( "." ) ); - - FileLockCompanion fileLockCompanion = null; - if ( realPath.equals( path ) ) - { - File newFile = tmpFile; - synchronized ( activeDownloadFiles ) - { - fileLockCompanion = lockFile( tmpFile ); - logger.debug( String.format( "Found an incomplete download for file %s.", path ) ); - - if ( fileLockCompanion.getLock() == null ) - { - /** - * Lock failed so we need to regenerate a new tmp file. - */ - newFile = getTmpFile( path ); - fileLockCompanion = lockFile( newFile ); - - } - return fileLockCompanion; - } - } - } - } - } - } - return new FileLockCompanion( getTmpFile( path ), null ); - } - - /** - * Simple placeholder for a File and it's associated lock. - */ - private static class FileLockCompanion - { - - private final File file; - - private final FileLock lock; - - private final String lockPathName; - - public FileLockCompanion( File file, FileLock lock ) - { - this.file = file; - this.lock = lock; - this.lockPathName = null; - } - - public FileLockCompanion( File file, FileLock lock, String lockPathName ) - { - this.file = file; - this.lock = lock; - this.lockPathName = lockPathName; - } - - public File getFile() - { - return file; - } - - public FileLock getLock() - { - return lock; - } - - public String getLockedPathFile() - { - return lockPathName; - } - - } - - /** - * Create a temporary file used to lock ({@link FileLock}) an associated incomplete file {@link File}. The {@link FileLock}'s name - * is derived from the original file, appending ".lock" at the end. Usually this method gets executed when a - * download fail to complete because the JVM goes down. In that case we resume the incomplete download and to prevent - * multiple process to work on the same file, we use a dedicated {@link FileLock}. - * - * @param tmpFile a file on which we want to create a temporary lock file. - * @return a {@link FileLockCompanion} contains the {@link File} and a {@link FileLock} if it was possible to lock the file. - */ - private FileLockCompanion lockFile( File tmpFile ) - { - try - { - // On Unix tmpLock.getChannel().tryLock may not fail inside the same process, so we must keep track - // of current resumable file. - if ( activeDownloadFiles.containsKey( tmpFile ) ) - { - return new FileLockCompanion( tmpFile, null ); - } - - RandomAccessFile tmpLock = new RandomAccessFile( tmpFile.getPath() + ".lock", "rw" ); - FileLock lock = tmpLock.getChannel().tryLock( 0, 1, false ); - - if ( lock != null ) - { - activeDownloadFiles.put( tmpLock, Boolean.TRUE ); - } - else if ( lock == null ) - { - try - { - tmpLock.close(); - } - catch ( IOException ex ) - { - - } - } - - return new FileLockCompanion( tmpFile, lock, tmpFile.getPath() + ".lock" ); - } - catch ( OverlappingFileLockException ex ) - { - return new FileLockCompanion( tmpFile, null ); - } - catch ( IOException ex ) - { - return new FileLockCompanion( tmpFile, null ); - } - } - - private void releaseLock( FileLockCompanion fileLockCompanion ) - { - try - { - if ( fileLockCompanion.getLock() != null ) - { - try - { - fileLockCompanion.getLock().channel().close(); - fileLockCompanion.getLock().release(); - } - finally - { - if ( fileLockCompanion.getLockedPathFile() != null ) - { - new File( fileLockCompanion.getLockedPathFile() ).delete(); - } - } - } - } - catch ( IOException e ) - { - // Ignore. - } - } - - private File getTmpFile( String path ) - { - File file; - do - { - file = new File( path + ".ahc" + UUID.randomUUID().toString().replace( "-", "" ).substring( 0, 16 ) ); - } - while ( file.exists() ); - return file; - } - - private static final ExceptionWrapper METADATA = new ExceptionWrapper() - { - public void wrap( MetadataTransfer transfer, Exception e, RemoteRepository repository ) - { - MetadataTransferException ex = null; - if ( e instanceof ResourceDoesNotExistException ) - { - ex = new MetadataNotFoundException( transfer.getMetadata(), repository ); - } - else if ( e != null ) - { - ex = new MetadataTransferException( transfer.getMetadata(), repository, e ); - } - transfer.setException( ex ); - } - }; - - private static final ExceptionWrapper ARTIFACT = new ExceptionWrapper() - { - public void wrap( ArtifactTransfer transfer, Exception e, RemoteRepository repository ) - { - ArtifactTransferException ex = null; - if ( e instanceof ResourceDoesNotExistException ) - { - ex = new ArtifactNotFoundException( transfer.getArtifact(), repository ); - } - else if ( e != null ) - { - ex = new ArtifactTransferException( transfer.getArtifact(), repository, e ); - } - transfer.setException( ex ); - } - }; - - private class LatchGuard - { - - private final CountDownLatch latch; - - private final AtomicBoolean done = new AtomicBoolean( false ); - - public LatchGuard( CountDownLatch latch ) - { - this.latch = latch; - } - - public void countDown() - { - if ( !done.getAndSet( true ) ) - { - latch.countDown(); - } - } - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/AuthorizationException.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/AuthorizationException.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/AuthorizationException.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/AuthorizationException.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -class AuthorizationException - extends Exception -{ - - public AuthorizationException( final String message ) - { - super( message ); - } - - public AuthorizationException( final String message, final Throwable cause ) - { - super( message, cause ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/CompletionHandler.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/CompletionHandler.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/CompletionHandler.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/CompletionHandler.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,303 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import com.ning.http.client.AsyncHandler; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.HttpResponseHeaders; -import com.ning.http.client.HttpResponseStatus; -import com.ning.http.client.ProgressAsyncHandler; -import com.ning.http.client.Response; - -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.spi.log.Logger; -import org.eclipse.aether.transfer.TransferCancelledException; -import org.eclipse.aether.transfer.TransferEvent; -import org.eclipse.aether.transfer.TransferListener; -import org.eclipse.aether.transfer.TransferResource; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.nio.ByteBuffer; -import java.util.Collections; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; - -/** - * An {@link AsyncHandler} for handling asynchronous download an upload. - */ -class CompletionHandler - implements ProgressAsyncHandler -{ - private final Logger logger; - - private HttpResponseStatus status; - - private HttpResponseHeaders headers; - - private final ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue(); - - private final AsyncHttpClient httpClient; - - private final AtomicLong byteTransfered = new AtomicLong(); - - private final AtomicReference exception = new AtomicReference(); - - private final TransferResource transferResource; - - private final TransferEvent.RequestType requestType; - - private final TransferEvent.Builder eventBuilder; - - public CompletionHandler( TransferResource transferResource, AsyncHttpClient httpClient, Logger logger, - TransferEvent.RequestType requestType, RepositorySystemSession session ) - { - this.httpClient = httpClient; - this.transferResource = transferResource; - this.logger = logger; - this.requestType = requestType; - eventBuilder = new TransferEvent.Builder( session, transferResource ).setRequestType( requestType ); - } - - public STATE onHeaderWriteCompleted() - { - if ( TransferEvent.RequestType.PUT.equals( requestType ) ) - { - byteTransfered.set( 0 ); - try - { - fireTransferStarted(); - } - catch ( TransferCancelledException e ) - { - return STATE.ABORT; - } - } - return STATE.CONTINUE; - } - - public STATE onContentWriteCompleted() - { - return STATE.CONTINUE; - } - - public STATE onContentWriteProgress( long amount, long current, long total ) - { - return STATE.CONTINUE; - } - - /** - * {@inheritDoc} - */ - /* @Override */ - public STATE onBodyPartReceived( final HttpResponseBodyPart content ) - throws Exception - { - try - { - fireTransferProgressed( content.getBodyPartBytes() ); - } - catch ( TransferCancelledException e ) - { - return STATE.ABORT; - } - catch ( Exception ex ) - { - if ( logger.isDebugEnabled() ) - { - logger.debug( "", ex ); - } - } - return STATE.CONTINUE; - } - - /** - * {@inheritDoc} - */ - /* @Override */ - public STATE onStatusReceived( final HttpResponseStatus status ) - throws Exception - { - this.status = status; - - return ( status.getStatusCode() == HttpURLConnection.HTTP_NOT_FOUND ? STATE.ABORT : STATE.CONTINUE ); - } - - /** - * {@inheritDoc} - */ - /* @Override */ - public STATE onHeadersReceived( final HttpResponseHeaders headers ) - throws Exception - { - this.headers = headers; - - if ( !TransferEvent.RequestType.PUT.equals( requestType ) ) - { - if ( status.getStatusCode() >= 200 && status.getStatusCode() < 300 ) - { - try - { - transferResource.setContentLength( Long.parseLong( headers.getHeaders().getFirstValue( "Content-Length" ) ) ); - } - catch ( RuntimeException e ) - { - // oh well, no parsable content length - } - try - { - fireTransferStarted(); - } - catch ( TransferCancelledException e ) - { - return STATE.ABORT; - } - } - } - - return STATE.CONTINUE; - } - - /** - * {@inheritDoc} - */ - /* @Override */ - public final Response onCompleted() - throws Exception - { - // The connection has timed out - if ( status == null ) - { - throw new TransferException( "Invalid AHC State. Response will possibly gets corrupted." ); - } - return onCompleted( httpClient.getProvider().prepareResponse( status, headers, - Collections. emptyList() ) ); - } - - /** - * {@inheritDoc} - */ - /* @Override */ - public void onThrowable( Throwable t ) - { - exception.set( t ); - } - - /** - * Invoked once the HTTP response has been fully read. - * - * @param response The {@link com.ning.http.client.Response} - * @return Type of the value that will be returned by the associated {@link java.util.concurrent.Future} - */ - public Response onCompleted( Response response ) - throws Exception - { - if ( response != null && response.hasResponseStatus() && response.getStatusCode() >= HttpURLConnection.HTTP_OK - && response.getStatusCode() <= HttpURLConnection.HTTP_CREATED ) - { - fireTransferSucceeded( response ); - } - return response; - } - - void fireTransferProgressed( final byte[] buffer ) - throws TransferCancelledException - { - fireTransferProgressed( ByteBuffer.wrap( buffer ) ); - } - - void fireTransferProgressed( final ByteBuffer buffer ) - throws TransferCancelledException - { - final long bytesTransferred = byteTransfered.addAndGet( buffer.remaining() ); - - final TransferEvent transferEvent = - newEvent( TransferEvent.EventType.PROGRESSED ).setTransferredBytes( bytesTransferred ).setDataBuffer( buffer ).build(); - - for ( final TransferListener listener : listeners ) - { - listener.transferProgressed( transferEvent ); - } - } - - void fireTransferSucceeded( final Response response ) - throws IOException - { - final long bytesTransferred = byteTransfered.get(); - - final TransferEvent transferEvent = - newEvent( TransferEvent.EventType.SUCCEEDED ).setTransferredBytes( bytesTransferred ).build(); - - for ( final TransferListener listener : listeners ) - { - listener.transferSucceeded( transferEvent ); - } - } - - void fireTransferFailed() - throws IOException - { - final long bytesTransferred = byteTransfered.get(); - - final TransferEvent transferEvent = - newEvent( TransferEvent.EventType.FAILED ).setTransferredBytes( bytesTransferred ).build(); - - for ( final TransferListener listener : listeners ) - { - listener.transferFailed( transferEvent ); - } - } - - void fireTransferStarted() - throws TransferCancelledException - { - final TransferEvent transferEvent = - newEvent( TransferEvent.EventType.STARTED ).setTransferredBytes( 0 ).build(); - - for ( final TransferListener listener : listeners ) - { - listener.transferStarted( transferEvent ); - } - } - - public boolean addTransferListener( TransferListener listener ) - { - if ( listener == null ) - { - return false; - } - return listeners.offer( listener ); - } - - public boolean removeTransferListener( TransferListener listener ) - { - if ( listener == null ) - { - return false; - } - return listeners.remove( listener ); - } - - protected HttpResponseStatus status() - { - return status; - } - - private TransferEvent.Builder newEvent( TransferEvent.EventType type ) - { - Throwable t = exception.get(); - return eventBuilder.copy().setType( type ).setException( t instanceof Exception ? (Exception) t - : new Exception( t ) ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/ProgressingFileBodyGenerator.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/ProgressingFileBodyGenerator.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/ProgressingFileBodyGenerator.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/ProgressingFileBodyGenerator.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,144 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.WritableByteChannel; - -import com.ning.http.client.generators.FileBodyGenerator; - -import org.eclipse.aether.transfer.TransferCancelledException; - -import com.ning.http.client.RandomAccessBody; - -class ProgressingFileBodyGenerator - extends FileBodyGenerator -{ - - private final CompletionHandler completionHandler; - - public ProgressingFileBodyGenerator( File file, CompletionHandler completionHandler ) - { - super( file ); - this.completionHandler = completionHandler; - } - - @Override - public RandomAccessBody createBody() - throws IOException - { - return new ProgressingBody( super.createBody() ); - } - - final class ProgressingBody - implements RandomAccessBody - { - - final RandomAccessBody delegate; - - private ProgressingWritableByteChannel channel; - - public ProgressingBody( RandomAccessBody delegate ) - { - this.delegate = delegate; - } - - public long getContentLength() - { - return delegate.getContentLength(); - } - - public long read( ByteBuffer buffer ) - throws IOException - { - ByteBuffer event = buffer.slice(); - long read = delegate.read( buffer ); - if ( read > 0 ) - { - try - { - event.limit( (int) read ); - completionHandler.fireTransferProgressed( event ); - } - catch ( TransferCancelledException e ) - { - throw (IOException) new IOException( e.getMessage() ).initCause( e ); - } - } - return read; - } - - public long transferTo( long position, long count, WritableByteChannel target ) - throws IOException - { - ProgressingWritableByteChannel dst = channel; - if ( dst == null || dst.delegate != target ) - { - channel = dst = new ProgressingWritableByteChannel( target ); - } - return delegate.transferTo( position, Math.min( count, 1024 * 16 ), dst ); - } - - public void close() - throws IOException - { - delegate.close(); - } - - } - - final class ProgressingWritableByteChannel - implements WritableByteChannel - { - - final WritableByteChannel delegate; - - public ProgressingWritableByteChannel( WritableByteChannel delegate ) - { - this.delegate = delegate; - } - - public boolean isOpen() - { - return delegate.isOpen(); - } - - public void close() - throws IOException - { - delegate.close(); - } - - public int write( ByteBuffer src ) - throws IOException - { - ByteBuffer event = src.slice(); - int written = delegate.write( src ); - if ( written > 0 ) - { - try - { - event.limit( written ); - completionHandler.fireTransferProgressed( event ); - } - catch ( TransferCancelledException e ) - { - throw (IOException) new IOException( e.getMessage() ).initCause( e ); - } - } - return written; - } - - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/ResourceDoesNotExistException.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/ResourceDoesNotExistException.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/ResourceDoesNotExistException.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/ResourceDoesNotExistException.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -/** - * Simple exception when a resource doesn't exist. - */ -class ResourceDoesNotExistException - extends Exception -{ - - public ResourceDoesNotExistException( final String message ) - { - super( message ); - } - - public ResourceDoesNotExistException( final String message, final Throwable cause ) - { - super( message, cause ); - } -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/TransferException.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/TransferException.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/TransferException.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/java/org/eclipse/aether/connector/async/TransferException.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -/** - * Simple exception when a transfer fail. - */ -class TransferException - extends Exception -{ - public TransferException( final String message ) - { - super( message ); - } - - public TransferException( final String message, final Throwable cause ) - { - super( message, cause ); - } - -} \ No newline at end of file diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/resources/about.html eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/resources/about.html --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/main/resources/about.html 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/main/resources/about.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ - - - - -About - - -

About This Content

- -

September 23, 2011

-

License

- -

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise -indicated below, the Content is provided to you under the terms and conditions of the -Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available -at http://www.eclipse.org/legal/epl-v10.html. -For purposes of the EPL, "Program" will mean the Content.

- -

If you did not receive this Content directly from the Eclipse Foundation, the Content is -being redistributed by another party ("Redistributor") and different terms and conditions may -apply to your use of any object code in the Content. Check the Redistributor's license that was -provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise -indicated below, the terms and conditions of the EPL still apply to any source code in the Content -and such source code may be obtained at http://www.eclipse.org.

- - - diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AetherDefaultTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AetherDefaultTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AetherDefaultTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AetherDefaultTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import java.util.Map; - -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.connector.async.AsyncRepositoryConnectorFactory; -import org.eclipse.aether.internal.test.util.TestFileProcessor; -import org.eclipse.aether.internal.test.util.connector.suite.ConnectorTestSuite; -import org.eclipse.aether.internal.test.util.connector.suite.ConnectorTestSetup.AbstractConnectorTestSetup; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; -import org.sonatype.tests.http.server.jetty.behaviour.ResourceServer; -import org.sonatype.tests.http.server.jetty.impl.JettyServerProvider; - -/** - */ -public class AetherDefaultTest - extends ConnectorTestSuite -{ - - private static class JettyConnectorTestSetup - extends AbstractConnectorTestSetup - { - - private JettyServerProvider provider; - - public RemoteRepository before( RepositorySystemSession session, Map context ) - throws Exception - { - provider = new JettyServerProvider(); - provider.initServer(); - provider.addBehaviour( "/*", new ResourceServer() ); - provider.start(); - return new RemoteRepository.Builder( "jetty-repo", "default", provider.getUrl().toString() + "/repo" ).build(); - } - - public RepositoryConnectorFactory factory() - { - AsyncRepositoryConnectorFactory factory = new AsyncRepositoryConnectorFactory(); - factory.setFileProcessor( new TestFileProcessor() ); - return factory; - } - - @Override - public void after( RepositorySystemSession session, RemoteRepository repository, Map context ) - throws Exception - { - if ( provider != null ) - { - provider.stop(); - provider = null; - } - } - - } - - /** - * @param setup - */ - public AetherDefaultTest() - { - super( new JettyConnectorTestSetup() ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AsyncConnectorSuiteConfiguration.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AsyncConnectorSuiteConfiguration.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AsyncConnectorSuiteConfiguration.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AsyncConnectorSuiteConfiguration.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,220 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import org.eclipse.aether.DefaultRepositorySystemSession; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.connector.async.AsyncRepositoryConnectorFactory; -import org.eclipse.aether.internal.test.util.TestFileProcessor; -import org.eclipse.aether.internal.test.util.TestFileUtils; -import org.eclipse.aether.internal.test.util.TestUtils; -import org.eclipse.aether.metadata.DefaultMetadata; -import org.eclipse.aether.metadata.Metadata; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; -import org.eclipse.aether.transfer.NoRepositoryConnectorException; -import org.junit.After; -import org.junit.Before; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonatype.tests.http.runner.junit.DefaultSuiteConfiguration; -import org.sonatype.tests.http.server.api.ServerProvider; -import org.sonatype.tests.http.server.jetty.behaviour.Expect; -import org.sonatype.tests.http.server.jetty.behaviour.Provide; - -/** - */ -public class AsyncConnectorSuiteConfiguration - extends DefaultSuiteConfiguration -{ - - protected Logger logger = LoggerFactory.getLogger( this.getClass() ); - - private AsyncRepositoryConnectorFactory factory; - - private DefaultRepositorySystemSession session; - - protected RemoteRepository repository; - - private Artifact artifact; - - private Metadata metadata; - - protected Expect expect; - - protected Provide provide = new Provide(); - - protected Generate generate; - - private RepositoryConnector connector; - - @Override - @Before - public void before() - throws Exception - { - super.before(); - - this.factory = new AsyncRepositoryConnectorFactory(); - this.factory.setFileProcessor( new TestFileProcessor() ); - this.session = TestUtils.newSession(); - this.repository = new RemoteRepository.Builder( "async-test-repo", "default", url( "repo" ) ).build(); - - this.artifact = new DefaultArtifact( "gid", "aid", "classifier", "extension", "version", null ); - this.metadata = - new DefaultMetadata( "gid", "aid", "version", "maven-metadata.xml", Metadata.Nature.RELEASE_OR_SNAPSHOT, - null ); - - connector = null; - } - - @Override - @After - public void after() - throws Exception - { - super.after(); - connector().close(); - TestFileUtils.deleteTempFiles(); - } - - protected RepositoryConnectorFactory factory() - { - return factory; - } - - protected RepositoryConnector connector() - throws NoRepositoryConnectorException - { - if ( connector == null ) - { - connector = factory().newInstance( session(), repository() ); - } - return connector; - } - - /** - * @return - */ - protected DefaultRepositorySystemSession session() - { - return session; - } - - /** - * @return - */ - protected RemoteRepository repository() - { - return repository; - } - - protected Artifact artifact() - { - return artifact; - } - - protected Artifact artifact( String content ) - throws IOException - { - return artifact().setFile( TestFileUtils.createTempFile( content ) ); - } - - protected Metadata metadata() - { - return metadata; - } - - protected Metadata metadata( String content ) - throws IOException - { - return metadata().setFile( TestFileUtils.createTempFile( content ) ); - } - - protected String md5( String string ) - throws NoSuchAlgorithmException, UnsupportedEncodingException - { - String algo = "MD5"; - return digest( string, algo ); - } - - private String digest( String string, String algo ) - throws NoSuchAlgorithmException, UnsupportedEncodingException - { - MessageDigest digest = MessageDigest.getInstance( algo ); - byte[] bytes = digest.digest( string.getBytes( "UTF-8" ) ); - StringBuilder buffer = new StringBuilder( 64 ); - - for ( int i = 0; i < bytes.length; i++ ) - { - int b = bytes[i] & 0xFF; - if ( b < 0x10 ) - { - buffer.append( '0' ); - } - buffer.append( Integer.toHexString( b ) ); - } - return buffer.toString(); - } - - protected String sha1( String string ) - throws NoSuchAlgorithmException, UnsupportedEncodingException - { - return digest( string, "SHA-1" ); - } - - protected void assertExpectations() - { - expect.assertExpectations(); - } - - protected Expect addExpectation( String path, String content ) - throws Exception - { - byte[] bytes = content.getBytes( "UTF-8" ); - return addExpectation( path, bytes ); - } - - private Expect addExpectation( String path, byte[] content ) - { - expect.addExpectation( path, content ); - return expect; - } - - protected void addDelivery( String path, String content ) - throws Exception - { - addDelivery( path, content.getBytes( "UTF-8" ) ); - } - - @Override - public void configureProvider( ServerProvider provider ) - { - super.configureProvider( provider ); - expect = new Expect(); - provide = new Provide(); - generate = new Generate(); - provider.addBehaviour( "/repo", generate, expect, provide ); - } - - protected void addDelivery( String path, byte[] content ) - { - provide.addPath( path, content ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AsyncHandlerExceptionTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AsyncHandlerExceptionTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AsyncHandlerExceptionTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AsyncHandlerExceptionTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import org.eclipse.aether.DefaultRepositorySystemSession; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.connector.async.AsyncRepositoryConnector; -import org.eclipse.aether.internal.test.util.TestFileProcessor; -import org.eclipse.aether.internal.test.util.TestLoggerFactory; -import org.eclipse.aether.internal.test.util.TestFileUtils; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.spi.connector.ArtifactDownload; -import org.eclipse.aether.spi.connector.ArtifactUpload; -import org.eclipse.aether.transfer.ArtifactNotFoundException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; - -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -public class AsyncHandlerExceptionTest -{ - - private File baseDir; - - @Before - public void setUp() - throws IOException - { - baseDir = TestFileUtils.createTempDir( getClass().getSimpleName() ); - } - - @Test - public void testIt() - throws Exception - { - HttpServer server = new HttpServer(); - server.addResources( "/", baseDir.getAbsolutePath() ); - server.start(); - - try - { - RemoteRepository repo = new RemoteRepository.Builder( "id", "default", server.getHttpUrl() + "/repo" ).build(); - RepositorySystemSession session = new DefaultRepositorySystemSession(); - - AsyncRepositoryConnector connector = - new AsyncRepositoryConnector( repo, session, new TestFileProcessor(), - new TestLoggerFactory().getLogger( "ahc" ) ); - - try - { - Artifact artifact = new DefaultArtifact( "gid:aid:1.0" ); - for ( int i = 0; i < 16; i++ ) - { - System.out.println( "RUN #" + i ); - TestFileUtils.delete( baseDir ); - - ArtifactDownload download = - new ArtifactDownload( artifact, "project", new File( baseDir, "a.jar" ), "ignore" ); - System.out.println( "GET" ); - connector.get( Arrays.asList( download ), null ); - assertTrue( String.valueOf( download.getException() ), - download.getException() instanceof ArtifactNotFoundException ); - - ArtifactUpload upload = new ArtifactUpload( artifact, new File( "pom.xml" ) ); - System.out.println( "PUT" ); - connector.put( Arrays.asList( upload ), null ); - if ( upload.getException() != null ) - { - upload.getException().printStackTrace(); - } - assertNull( String.valueOf( upload.getException() ), upload.getException() ); - } - } - finally - { - connector.close(); - } - } - finally - { - server.stop(); - } - } - - @After - public void tearDown() - throws IOException - { - TestFileUtils.delete( baseDir ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthGetTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthGetTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthGetTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthGetTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import org.eclipse.aether.repository.Authentication; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.util.repository.AuthenticationBuilder; -import org.junit.Before; -import org.junit.runner.RunWith; -import org.sonatype.tests.http.runner.annotations.ConfiguratorList; -import org.sonatype.tests.http.runner.junit.ConfigurationRunner; - -/** - */ -@RunWith( ConfigurationRunner.class ) -@ConfiguratorList( "AuthSuiteConfigurator.list" ) -public class AuthGetTest - extends GetTest -{ - - @Before - @Override - public void before() - throws Exception - { - super.before(); - - Authentication auth = new AuthenticationBuilder().addUsername( "user" ).addPassword( "password" ).build(); - repository = new RemoteRepository.Builder( repository() ).setAuthentication( auth ).build(); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthPutTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthPutTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthPutTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthPutTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import org.eclipse.aether.repository.Authentication; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.util.repository.AuthenticationBuilder; -import org.junit.Before; -import org.junit.runner.RunWith; -import org.sonatype.tests.http.runner.annotations.ConfiguratorList; -import org.sonatype.tests.http.runner.junit.ConfigurationRunner; - -/** - */ -@RunWith( ConfigurationRunner.class ) -@ConfiguratorList( "AuthSuiteConfigurator.list" ) -public class AuthPutTest - extends PutTest -{ - - @Before - @Override - public void before() - throws Exception - { - super.before(); - - Authentication auth = new AuthenticationBuilder().addUsername( "user" ).addPassword( "password" ).build(); - repository = new RemoteRepository.Builder( repository() ).setAuthentication( auth ).build(); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthWithNonAsciiCredentialsGetTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthWithNonAsciiCredentialsGetTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthWithNonAsciiCredentialsGetTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthWithNonAsciiCredentialsGetTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import org.eclipse.aether.repository.Authentication; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.util.repository.AuthenticationBuilder; -import org.junit.Before; -import org.junit.runner.RunWith; -import org.sonatype.tests.http.runner.annotations.ConfiguratorList; -import org.sonatype.tests.http.runner.junit.ConfigurationRunner; -import org.sonatype.tests.http.server.api.ServerProvider; - -/** - */ -@RunWith( ConfigurationRunner.class ) -@ConfiguratorList( "AuthSuiteConfigurator.list" ) -public class AuthWithNonAsciiCredentialsGetTest - extends GetTest -{ - - @Override - public void configureProvider( ServerProvider provider ) - { - super.configureProvider( provider ); - provider.addUser( "user-non-ascii", "\u00E4\u00DF" ); - } - - @Before - @Override - public void before() - throws Exception - { - super.before(); - - Authentication auth = - new AuthenticationBuilder().addUsername( "user-non-ascii" ).addPassword( "\u00E4\u00DF" ).build(); - repository = new RemoteRepository.Builder( repository() ).setAuthentication( auth ).build(); - } - - @Override - public void testDownloadArtifactWhoseSizeExceedsMaxHeapSize() - throws Exception - { - // this one is slow and doesn't bring anything new to the table in this context so just skip - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthWithNonAsciiCredentialsPutTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthWithNonAsciiCredentialsPutTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthWithNonAsciiCredentialsPutTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/AuthWithNonAsciiCredentialsPutTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import org.eclipse.aether.repository.Authentication; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.util.repository.AuthenticationBuilder; -import org.junit.Before; -import org.junit.runner.RunWith; -import org.sonatype.tests.http.runner.annotations.ConfiguratorList; -import org.sonatype.tests.http.runner.junit.ConfigurationRunner; -import org.sonatype.tests.http.server.api.ServerProvider; - -/** - */ -@RunWith( ConfigurationRunner.class ) -@ConfiguratorList( "AuthSuiteConfigurator.list" ) -public class AuthWithNonAsciiCredentialsPutTest - extends PutTest -{ - - @Override - public void configureProvider( ServerProvider provider ) - { - super.configureProvider( provider ); - provider.addUser( "user-non-ascii", "\u00E4\u00DF" ); - } - - @Before - @Override - public void before() - throws Exception - { - super.before(); - - Authentication auth = - new AuthenticationBuilder().addUsername( "user-non-ascii" ).addPassword( "\u00E4\u00DF" ).build(); - repository = new RemoteRepository.Builder( repository() ).setAuthentication( auth ).build(); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/DavUrlGetTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/DavUrlGetTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/DavUrlGetTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/DavUrlGetTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import org.eclipse.aether.repository.RemoteRepository; - -/* * - */ -public class DavUrlGetTest - extends GetTest -{ - - @Override - protected RemoteRepository repository() - { - RemoteRepository repo = super.repository(); - return new RemoteRepository.Builder( repo ).setUrl( "dav:" + repo.getUrl() ).build(); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/DavUrlPutTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/DavUrlPutTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/DavUrlPutTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/DavUrlPutTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import org.eclipse.aether.repository.RemoteRepository; - -/* * - */ -public class DavUrlPutTest - extends PutTest -{ - - @Override - protected RemoteRepository repository() - { - RemoteRepository repo = super.repository(); - return new RemoteRepository.Builder( repo ).setUrl( "dav:" + repo.getUrl() ).build(); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/Generate.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/Generate.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/Generate.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/Generate.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.sonatype.tests.http.server.api.Behaviour; - -/** - * A behavior that writes a sequence of fixed length to the client upon a GET request. - */ -public class Generate - implements Behaviour -{ - - private static final byte[] bytes = new byte[1024]; - - private final Map lengths = new ConcurrentHashMap(); - - public void addContent( String path, long length ) - { - if ( !path.startsWith( "/" ) ) - { - path = '/' + path; - } - lengths.put( path, Long.valueOf( length ) ); - } - - public boolean execute( HttpServletRequest request, HttpServletResponse response, Map ctx ) - throws Exception - { - if ( "GET".equals( request.getMethod() ) ) - { - String path = request.getPathInfo(); - - Long length = lengths.get( path ); - - if ( length != null ) - { - response.setContentType( "application/octet-stream" ); - response.setContentLength( length.intValue() ); - - ServletOutputStream out = response.getOutputStream(); - for ( int i = length.intValue(); i > 0; ) - { - int n = Math.min( i, bytes.length ); - i -= n; - out.write( bytes, 0, n ); - } - out.close(); - - return false; - } - } - - return true; - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/GetTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/GetTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/GetTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/GetTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,186 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import static org.junit.Assert.*; - -import java.io.File; -import java.util.Arrays; -import java.util.Collection; - -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.internal.test.util.RecordingTransferListener; -import org.eclipse.aether.internal.test.util.TestFileUtils; -import org.eclipse.aether.repository.RepositoryPolicy; -import org.eclipse.aether.spi.connector.ArtifactDownload; -import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.aether.transfer.TransferEvent; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.sonatype.tests.http.runner.junit.ConfigurationRunner; - -/** - */ -@RunWith( ConfigurationRunner.class ) -public class GetTest - extends AsyncConnectorSuiteConfiguration -{ - - @Test - public void testDownloadArtifact() - throws Exception - { - addDelivery( "gid/aid/version/aid-version-classifier.extension", "artifact" ); - addDelivery( "gid/aid/version/aid-version-classifier.extension.sha1", sha1( "artifact" ) ); - addDelivery( "gid/aid/version/aid-version-classifier.extension.md5", md5( "artifact" ) ); - - File f = TestFileUtils.createTempFile( "" ); - Artifact a = artifact( "bla" ); - - ArtifactDownload down = new ArtifactDownload( a, null, f, RepositoryPolicy.CHECKSUM_POLICY_FAIL ); - Collection downs = Arrays.asList( down ); - RepositoryConnector c = connector(); - c.get( downs, null ); - - assertNull( String.valueOf( down.getException() ), down.getException() ); - TestFileUtils.assertContent( "artifact", f ); - } - - @Test - public void testDownloadArtifactChecksumFailure() - throws Exception - { - addDelivery( "gid/aid/version/aid-version-classifier.extension", "artifact" ); - addDelivery( "gid/aid/version/aid-version-classifier.extension.sha1", "foo" ); - addDelivery( "gid/aid/version/aid-version-classifier.extension.md5", "bar" ); - - File f = TestFileUtils.createTempFile( "" ); - Artifact a = artifact( "bla" ); - - ArtifactDownload down = new ArtifactDownload( a, null, f, RepositoryPolicy.CHECKSUM_POLICY_FAIL ); - Collection downs = Arrays.asList( down ); - connector().get( downs, null ); - - assertNotNull( down.getException() ); - } - - @Test - public void testDownloadArtifactNoChecksumAvailable() - throws Exception - { - addDelivery( "gid/aid/version/aid-version-classifier.extension", "artifact" ); - - File f = TestFileUtils.createTempFile( "" ); - Artifact a = artifact( "foo" ); - - ArtifactDownload down = new ArtifactDownload( a, null, f, RepositoryPolicy.CHECKSUM_POLICY_FAIL ); - Collection downs = Arrays.asList( down ); - connector().get( downs, null ); - - TestFileUtils.assertContent( "", f ); - assertNotNull( down.getException() ); - } - - @Test - public void testDownloadCorrupted() - throws Exception - { - RecordingTransferListener transferListener = new RecordingTransferListener(); - session().setTransferListener( transferListener ); - - addDelivery( "gid/aid/version/aid-version-classifier.extension", "artifact" ); - addDelivery( "gid/aid/version/aid-version-classifier.extension.sha1", "foo" ); - addDelivery( "gid/aid/version/aid-version-classifier.extension.md5", "bar" ); - - File f = TestFileUtils.createTempFile( "" ); - Artifact a = artifact( "bla" ); - - ArtifactDownload down = new ArtifactDownload( a, null, f, RepositoryPolicy.CHECKSUM_POLICY_WARN ); - Collection downs = Arrays.asList( down ); - connector().get( downs, null ); - - TransferEvent corruptedEvent = null; - for ( TransferEvent e : transferListener.getEvents() ) - { - if ( TransferEvent.EventType.CORRUPTED.equals( e.getType() ) ) - { - corruptedEvent = e; - break; - } - } - assertNotNull( corruptedEvent ); - } - - @Test - public void testDownloadArtifactWithWait() - throws Exception - { - addDelivery( "gid/aid/version/aid-version-classifier.extension", "artifact" ); - addDelivery( "gid/aid/version/aid-version-classifier.extension.sha1", sha1( "artifact" ) ); - addDelivery( "gid/aid/version/aid-version-classifier.extension.md5", md5( "artifact" ) ); - - File f = TestFileUtils.createTempFile( "" ); - Artifact a = artifact( "foo" ); - - ArtifactDownload down = new ArtifactDownload( a, null, f, RepositoryPolicy.CHECKSUM_POLICY_FAIL ); - Collection downs = Arrays.asList( down ); - connector().get( downs, null ); - - assertNull( String.valueOf( down.getException() ), down.getException() ); - TestFileUtils.assertContent( "foo", a.getFile() ); - TestFileUtils.assertContent( "artifact", f ); - } - - @Test - public void testDownloadArtifactWhoseSizeExceedsMaxHeapSize() - throws Exception - { - long bytes = Runtime.getRuntime().maxMemory() * 5 / 4; - generate.addContent( "gid/aid/version/aid-version-classifier.extension", bytes ); - - File f = TestFileUtils.createTempFile( "" ); - Artifact a = artifact(); - - ArtifactDownload down = new ArtifactDownload( a, null, f, RepositoryPolicy.CHECKSUM_POLICY_IGNORE ); - connector().get( Arrays.asList( down ), null ); - connector().close(); - - assertEquals( bytes, f.length() ); - } - - @Test( expected = IllegalStateException.class ) - public void testClosedGet() - throws Exception - { - connector().close(); - - File f = TestFileUtils.createTempFile( "" ); - Artifact a = artifact( "foo" ); - - ArtifactDownload down = new ArtifactDownload( a, null, f, RepositoryPolicy.CHECKSUM_POLICY_FAIL ); - Collection downs = Arrays.asList( down ); - connector().get( downs, null ); - } - - @Test - public void testCloseAfterArtifactDownload() - throws Exception - { - File f = TestFileUtils.createTempFile( "" ); - Artifact a = artifact( "foo" ); - - ArtifactDownload down = new ArtifactDownload( a, null, f, RepositoryPolicy.CHECKSUM_POLICY_FAIL ); - Collection downs = Arrays.asList( down ); - connector().get( downs, null ); - connector().close(); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/HttpServer.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/HttpServer.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/HttpServer.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/HttpServer.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,869 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import org.mortbay.jetty.Connector; -import org.mortbay.jetty.Handler; -import org.mortbay.jetty.HttpMethods; -import org.mortbay.jetty.Request; -import org.mortbay.jetty.Server; -import org.mortbay.jetty.handler.AbstractHandler; -import org.mortbay.jetty.handler.DefaultHandler; -import org.mortbay.jetty.handler.HandlerList; -import org.mortbay.jetty.nio.SelectChannelConnector; -import org.mortbay.jetty.security.B64Code; -import org.mortbay.jetty.security.Constraint; -import org.mortbay.jetty.security.ConstraintMapping; -import org.mortbay.jetty.security.HashUserRealm; -import org.mortbay.jetty.security.SecurityHandler; -import org.mortbay.jetty.security.SslSocketConnector; -import org.mortbay.util.IO; -import org.mortbay.util.URIUtil; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -/** - * A helper for the tests to start an embedded HTTP server powered by Jetty. Create an instance of this class, use its - * mutators to configure the server and finally call {@link #start()}. - */ -@SuppressWarnings( "synthetic-access" ) -public class HttpServer -{ - - private Server server; - - private int httpPort; - - private int httpsPort = -1; - - private String keyStoreLocation; - - private String keyStorePassword; - - private String trustStoreLocation; - - private String trustStorePassword; - - private boolean needClientAuth; - - private String proxyUsername; - - private String proxyPassword; - - private boolean redirectToHttps; - - private long latency; - - private Map userPasswords = new HashMap(); - - private Map userRoles = new HashMap(); - - private Map securedRealms = new HashMap(); - - private Map resourceDirs = new TreeMap( Collections.reverseOrder() ); - - private Map resourceFilters = new HashMap(); - - private Map filterTokens = new HashMap(); - - private Collection recordedPatterns = new HashSet(); - - private List recordedRequests = new ArrayList(); - - private Map> recordedHeaders = new HashMap>(); - - protected Connector newHttpConnector() - { - SelectChannelConnector connector = new SelectChannelConnector(); - connector.setPort( httpPort ); - return connector; - } - - protected Connector newHttpsConnector() - { - SslSocketConnector connector = new SslSocketConnector(); - connector.setPort( httpsPort ); - connector.setKeystore( new File( keyStoreLocation ).getAbsolutePath() ); - connector.setPassword( keyStorePassword ); - connector.setKeyPassword( keyStorePassword ); - connector.setTruststore( new File( trustStoreLocation ).getAbsolutePath() ); - connector.setTrustPassword( trustStorePassword ); - connector.setNeedClientAuth( needClientAuth ); - return connector; - } - - /** - * Sets the port to use for HTTP connections. - * - * @param httpPort The port to use, may be {@code 0} to pick a random port (default), if negative the HTTP connector - * will be disabled. - * @return This server, never {@code null}. - */ - public HttpServer setHttpPort( int httpPort ) - { - this.httpPort = httpPort; - - return this; - } - - /** - * Gets the port number of the server's HTTP connector. - * - * @return The port number of the server's HTTP connector. - */ - public int getHttpPort() - { - if ( httpPort >= 0 && server != null && server.isRunning() ) - { - return server.getConnectors()[0].getLocalPort(); - } - return httpPort; - } - - /** - * Gets the base URL to the server's HTTP connector, e.g. {@code "http://localhost:8080"}. - * - * @return The base URL without trailing slash to the server's HTTP connector, never {@code null}. - */ - public String getHttpUrl() - { - return "http://localhost:" + getHttpPort(); - } - - /** - * Sets the port to use for HTTPS connections. - * - * @param httpPort The port to use, may be {@code 0} to pick a random port, if negative the HTTPS connector will be - * disabled (default). - * @return This server, never {@code null}. - */ - public HttpServer setHttpsPort( int httpsPort ) - { - this.httpsPort = httpsPort; - - return this; - } - - /** - * Gets the port number of the server's HTTPS connector. - * - * @return The port number of the server's HTTPS connector. - */ - public int getHttpsPort() - { - if ( httpsPort >= 0 && server != null && server.isRunning() ) - { - return server.getConnectors()[( httpPort < 0 ) ? 0 : 1].getLocalPort(); - } - return httpsPort; - } - - /** - * Gets the base URL to the server's HTTPS connector, e.g. {@code "https://localhost:8080"}. - * - * @return The base URL without trailing slash to the server's HTTPS connector, never {@code null}. - */ - public String getHttpsUrl() - { - return "https://localhost:" + getHttpsPort(); - } - - /** - * Sets the keystore to use for the server certificate on the SSL connector. - * - * @param path The path to the keystore to use for the server certificate, may be {@code null}. - * @param password The password for the keystore, may be {@code null}. - * @return This server, never {@code null}. - */ - public HttpServer setKeyStore( String path, String password ) - { - keyStoreLocation = path; - keyStorePassword = password; - return this; - } - - /** - * Sets the truststore to use for validating client credentials via the SSL connector. - * - * @param path The path to the truststore to use for the trusted client certificates, may be {@code null}. - * @param password The password for the truststore, may be {@code null}. - * @return This server, never {@code null}. - */ - public HttpServer setTrustStore( String path, String password ) - { - trustStoreLocation = path; - trustStorePassword = password; - return this; - } - - /** - * Enables/disables client-side certificate authentication. - * - * @param needClientAuth Whether the server should reject clients whose certificate can't be verified via the - * truststore. - * @return This server, never {@code null}. - */ - public HttpServer setNeedClientAuth( boolean needClientAuth ) - { - this.needClientAuth = needClientAuth; - return this; - } - - /** - * Sets the credentials to use for proxy authentication. If either username or password is {@code null}, no proxy - * authentication is required. - * - * @param username The username, may be {@code null}. - * @param password The password, may be {@code null}. - * @return This server, never {@code null}. - */ - public HttpServer setProxyAuth( String username, String password ) - { - this.proxyUsername = username; - this.proxyPassword = password; - - return this; - } - - protected Handler newProxyHandler() - { - return new AbstractHandler() - { - public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch ) - throws IOException - { - String auth = request.getHeader( "Proxy-Authorization" ); - if ( auth != null ) - { - auth = auth.substring( auth.indexOf( ' ' ) + 1 ).trim(); - auth = B64Code.decode( auth ); - } - - if ( !( proxyUsername + ':' + proxyPassword ).equals( auth ) ) - { - response.setStatus( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED ); - response.addHeader( "Proxy-Authenticate", "Basic realm=\"Squid proxy-caching web server\"" ); - response.getWriter().println( "Proxy authentication required" ); - - ( (Request) request ).setHandled( true ); - } - } - }; - } - - /** - * Enforces redirection from HTTP to HTTPS. - * - * @param redirectToHttps {@code true} to redirect any HTTP requests to HTTPS, {@code false} to handle HTTP - * normally. - * @return This server, never {@code null}. - */ - public HttpServer setRedirectToHttps( boolean redirectToHttps ) - { - this.redirectToHttps = redirectToHttps; - - return this; - } - - protected Handler newSslRedirectHandler() - { - return new AbstractHandler() - { - - public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch ) - { - int httpsPort = getHttpsPort(); - if ( !( (Request) request ).isHandled() && request.getServerPort() != httpsPort ) - { - String url = "https://" + request.getServerName() + ":" + httpsPort + request.getRequestURI(); - - response.setStatus( HttpServletResponse.SC_MOVED_PERMANENTLY ); - response.setHeader( "Location", url ); - ( (Request) request ).setHandled( true ); - } - } - - }; - } - - /** - * Registers a user. - * - * @param username The username, must not be {@code null}. - * @param password The password, must not be {@code null}. - * @param roles The roles of the user, may be empty or {@code null}. - * @return This server, never {@code null}. - */ - public HttpServer addUser( String username, String password, String... roles ) - { - userPasswords.put( username, password ); - userRoles.put( username, ( roles == null ) ? new String[0] : roles ); - - return this; - } - - /** - * Sets up a security realm. - * - * @param pathSpec The path to secure, e.g. {@code "/files/*"}, must not be {@code null}. - * @param roles The roles that have access to the realm, may be empty or {@code null}. - * @return This server, never {@code null}. - */ - public HttpServer addSecuredRealm( String pathSpec, String... roles ) - { - securedRealms.put( pathSpec, ( roles == null ) ? new String[0] : roles ); - - return this; - } - - protected Handler newSecurityHandler() - { - List mappings = new ArrayList(); - - for ( String pathSpec : securedRealms.keySet() ) - { - String[] roles = securedRealms.get( pathSpec ); - - Constraint constraint = new Constraint(); - constraint.setName( Constraint.__BASIC_AUTH ); - constraint.setRoles( roles ); - constraint.setAuthenticate( true ); - - ConstraintMapping constraintMapping = new ConstraintMapping(); - constraintMapping.setConstraint( constraint ); - constraintMapping.setPathSpec( pathSpec ); - - mappings.add( constraintMapping ); - } - - HashUserRealm userRealm = new HashUserRealm( "TestRealm" ); - for ( String username : userPasswords.keySet() ) - { - String password = userPasswords.get( username ); - String[] roles = userRoles.get( username ); - - userRealm.put( username, password ); - if ( roles != null ) - { - for ( String role : roles ) - { - userRealm.addUserToRole( username, role ); - } - } - } - - SecurityHandler securityHandler = new SecurityHandler(); - securityHandler.setUserRealm( userRealm ); - securityHandler.setConstraintMappings( mappings.toArray( new ConstraintMapping[mappings.size()] ) ); - - return securityHandler; - } - - /** - * Adds resources to the server. Resources can be filtered upon serving using the tokens set via - * {@link #setFilterToken(String, String)}. The directory mounted into the server via this method will also be used - * to store files sent via PUT. Upon requests, the server will try to match the context roots in reverse - * alphabetical order, thereby giving longer path prefix matches precedence. - * - * @param contextRoot The context root to make the resources accessible at, must not be {@code null}. - * @param baseDirectory The local base directory whose files should be served, must not be {@code null}. - * @param filteredExtensions A list of extensions for files to filter, e.g. {@code "xml, "properties"}, may be - * {@code null}. - * @return This server, never {@code null}. - */ - public HttpServer addResources( String contextRoot, String baseDirectory, String... filteredExtensions ) - { - contextRoot = normalizeContextRoot( contextRoot ); - - File basedir = new File( baseDirectory ).getAbsoluteFile(); - - resourceDirs.put( contextRoot, basedir ); - resourceFilters.put( contextRoot, ( filteredExtensions == null ) ? new String[0] : filteredExtensions ); - - return this; - } - - /** - * Enables request recording for the specified URI patterns. Recorded requests can be retrieved via - * {@link #getRecordedRequests()}. - * - * @param patterns The regular expressions denoting URIs to monitor, e.g. {@code "/context/.*"}, must not be - * {@code null}. - * @return This server, never {@code null}. - */ - public HttpServer enableRecording( String... patterns ) - { - for ( String pattern : patterns ) - { - recordedPatterns.add( pattern ); - } - - return this; - } - - /** - * Gets the sequence of requests that have been issued against context roots for which - * {@link #enableRecording(String...)} was called. A request is encoded in the form {@code }, e.g. - * {@code GET /context/some.jar}. - * - * @return The sequence of requests since the server was started, can be empty but never {@code null}. - */ - public List getRecordedRequests() - { - return recordedRequests; - } - - /** - * Gets the headers sent in the most recent request to the specified path. - * - * @param uri the path - * @return the http request headers - */ - public Map getRecordedHeaders( String uri ) - { - return recordedHeaders.get( uri ); - } - - /** - * Sets a token to replace during resource filtering. Upon server start, the following tokens will be defined - * automatically: @basedir@, @baseurl@, @baseuri@, @port.http@ - * and @port.https@. - * - * @param token The token to replace, e.g. @basedir@, must not be {@code null}. - * @param value The replacement text of the token, may be {@code null}. - * @return This server, never {@code null}. - */ - public HttpServer setFilterToken( String token, String value ) - { - if ( value == null ) - { - filterTokens.remove( token ); - } - else - { - filterTokens.put( token, value ); - } - - return this; - } - - protected Handler newResourceHandler() - { - return new ResHandler(); - } - - /** - * Sets the latency of the server. - * - * @param millis The latency in milliseconds, may be negative for infinite delay. - * @return This server, never {@code null}. - */ - public HttpServer setLatency( long millis ) - { - this.latency = millis; - return this; - } - - protected Handler newSleepHandler( final long millis ) - { - return new AbstractHandler() - { - - public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch ) - { - if ( millis >= 0 ) - { - try - { - Thread.sleep( millis ); - } - catch ( InterruptedException e ) - { - e.printStackTrace(); - } - } - else - { - synchronized ( this ) - { - try - { - wait(); - } - catch ( InterruptedException e ) - { - e.printStackTrace(); - } - } - } - } - - }; - } - - /** - * Starts the server. Trying to start an already running server has no effect. - * - * @return This server, never {@code null}. - * @throws Exception If the server could not be started. - */ - public HttpServer start() - throws Exception - { - if ( server != null ) - { - return this; - } - - recordedRequests.clear(); - - List connectors = new ArrayList(); - if ( httpPort >= 0 ) - { - connectors.add( newHttpConnector() ); - } - if ( httpsPort >= 0 && keyStoreLocation != null ) - { - connectors.add( newHttpsConnector() ); - } - - HandlerList handlerList = new HandlerList(); - if ( !recordedPatterns.isEmpty() ) - { - handlerList.addHandler( new RecordingHandler() ); - } - if ( latency != 0 ) - { - handlerList.addHandler( newSleepHandler( latency ) ); - } - if ( redirectToHttps ) - { - handlerList.addHandler( newSslRedirectHandler() ); - } - if ( proxyUsername != null && proxyPassword != null ) - { - handlerList.addHandler( newProxyHandler() ); - } - if ( !securedRealms.isEmpty() ) - { - handlerList.addHandler( newSecurityHandler() ); - } - if ( !resourceDirs.isEmpty() ) - { - handlerList.addHandler( newResourceHandler() ); - } - handlerList.addHandler( new DefaultHandler() ); - - server = new Server( 0 ); - server.setHandler( handlerList ); - server.setConnectors( connectors.toArray( new Connector[connectors.size()] ) ); - server.start(); - - waitForConnectors(); - - addDefaultFilterTokens(); - - return this; - } - - protected void waitForConnectors() - throws Exception - { - // for unknown reasons, the connectors occasionally don't start properly, this tries hard to ensure they are up - - List badConnectors = new ArrayList( 2 ); - - for ( int r = 10; r > 0; r-- ) - { - // wait some seconds for the connectors to come up - for ( int i = 200; i > 0; i-- ) - { - badConnectors.clear(); - for ( Connector connector : server.getConnectors() ) - { - if ( connector.getLocalPort() < 0 ) - { - badConnectors.add( connector ); - } - } - if ( badConnectors.isEmpty() ) - { - return; - } - try - { - Thread.sleep( 15 ); - } - catch ( InterruptedException e ) - { - return; - } - } - - // restart the broken connectors and hope they make it this time - System.err.println( "WARNING: " + badConnectors + " did not start properly, restarting" ); - for ( Connector connector : badConnectors ) - { - connector.stop(); - connector.start(); - } - } - } - - protected void addDefaultFilterTokens() - { - if ( !filterTokens.containsKey( "@basedir@" ) ) - { - filterTokens.put( "@basedir@", new File( "" ).getAbsolutePath() ); - } - if ( !filterTokens.containsKey( "@baseurl@" ) ) - { - String baseurl = "file://" + new File( "" ).toURI().getPath(); - if ( baseurl.endsWith( "/" ) ) - { - baseurl = baseurl.substring( 0, baseurl.length() - 1 ); - } - filterTokens.put( "@baseurl@", baseurl ); - } - if ( !filterTokens.containsKey( "@baseuri@" ) ) - { - String baseuri = "file://" + new File( "" ).toURI().getRawPath(); - if ( baseuri.endsWith( "/" ) ) - { - baseuri = baseuri.substring( 0, baseuri.length() - 1 ); - } - filterTokens.put( "@baseuri@", baseuri ); - } - if ( !filterTokens.containsKey( "@port.http@" ) ) - { - filterTokens.put( "@port.http@", Integer.toString( getHttpPort() ) ); - } - if ( !filterTokens.containsKey( "@port.https@" ) ) - { - filterTokens.put( "@port.https@", Integer.toString( getHttpsPort() ) ); - } - } - - /** - * Stops the server. Stopping an already stopped server has no effect. - */ - public void stop() - { - if ( server != null ) - { - try - { - server.stop(); - } - catch ( Exception e ) - { - e.printStackTrace(); - } - server = null; - } - } - - class ResHandler - extends AbstractHandler - { - - public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch ) - throws IOException - { - String uri = request.getRequestURI(); - - for ( String contextRoot : resourceDirs.keySet() ) - { - String path = URIUtil.decodePath( trimContextRoot( uri, contextRoot ) ); - if ( path != null ) - { - File basedir = resourceDirs.get( contextRoot ); - File file = new File( basedir, path ); - - if ( HttpMethods.HEAD.equals( request.getMethod() ) ) - { - if ( file.exists() ) - { - response.setStatus( HttpServletResponse.SC_OK ); - } - else - { - response.setStatus( HttpServletResponse.SC_NOT_FOUND ); - } - ( (Request) request ).setHandled( true ); - return; - } - else if ( HttpMethods.PUT.equals( request.getMethod() ) - || HttpMethods.POST.equals( request.getMethod() ) ) - { - int i = 0; - while ( !file.getParentFile().exists() && !file.getParentFile().mkdirs() ) - { - if ( i++ > 5 ) - { - break; - } - } - FileOutputStream os = new FileOutputStream( file ); - try - { - IO.copy( request.getInputStream(), os ); - } - finally - { - os.close(); - } - - response.setStatus( HttpServletResponse.SC_CREATED ); - ( (Request) request ).setHandled( true ); - } - else if ( file.isFile() ) - { - FileInputStream is = new FileInputStream( file ); - - try - { - String filterEncoding = getFilterEncoding( path, resourceFilters.get( contextRoot ) ); - if ( filterEncoding == null ) - { - IO.copy( is, response.getOutputStream() ); - } - else - { - String text = IO.toString( is, filterEncoding ); - text = filter( text, filterTokens ); - response.getOutputStream().write( text.getBytes( filterEncoding ) ); - } - } - finally - { - is.close(); - } - - response.setStatus( HttpServletResponse.SC_OK ); - ( (Request) request ).setHandled( true ); - } - - break; - } - } - - } - - private String getExtension( String path ) - { - return path.substring( path.lastIndexOf( '.' ) + 1 ); - } - - private String getFilterEncoding( String path, String[] filteredExtensions ) - { - String ext = getExtension( path ); - if ( filteredExtensions != null ) - { - for ( String filteredExtension : filteredExtensions ) - { - if ( filteredExtension.startsWith( "." ) ) - { - filteredExtension = filteredExtension.substring( 1 ); - } - if ( filteredExtension.equalsIgnoreCase( ext ) ) - { - return "properties".equalsIgnoreCase( ext ) ? "ISO-8859-1" : "UTF-8"; - } - } - } - return null; - } - - private String filter( String str, Map tokens ) - { - for ( String token : tokens.keySet() ) - { - str = str.replace( token, tokens.get( token ) ); - } - return str; - } - - } - - class RecordingHandler - extends AbstractHandler - { - - public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch ) - { - String uri = request.getRequestURI(); - - for ( String pattern : recordedPatterns ) - { - if ( uri.matches( pattern ) ) - { - String req = request.getMethod() + " " + uri; - recordedRequests.add( req ); - - Map headers = new HashMap(); - recordedHeaders.put( uri, headers ); - for ( @SuppressWarnings( "unchecked" ) - Enumeration h = request.getHeaderNames(); h.hasMoreElements(); ) - { - String headername = h.nextElement(); - headers.put( headername, request.getHeader( headername ) ); - } - } - } - } - - } - - private static String normalizeContextRoot( String contextRoot ) - { - if ( contextRoot.endsWith( "/" ) ) - { - contextRoot = contextRoot.substring( 0, contextRoot.length() - 1 ); - } - if ( !contextRoot.startsWith( "/" ) ) - { - contextRoot = "/" + contextRoot; - } - return contextRoot; - } - - private static String trimContextRoot( String uri, String contextRoot ) - { - if ( uri.startsWith( contextRoot ) ) - { - if ( contextRoot.length() == 1 ) - { - return uri.substring( 1 ); - } - else if ( uri.length() > contextRoot.length() && uri.charAt( contextRoot.length() ) == '/' ) - { - return uri.substring( contextRoot.length() + 1 ); - } - } - return null; - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/PlexusSupportTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/PlexusSupportTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/PlexusSupportTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/PlexusSupportTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import org.codehaus.plexus.ContainerConfiguration; -import org.codehaus.plexus.PlexusTestCase; -import org.eclipse.aether.connector.async.AsyncRepositoryConnectorFactory; -import org.eclipse.aether.internal.test.util.TestFileProcessor; -import org.eclipse.aether.internal.test.util.TestLoggerFactory; -import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; -import org.eclipse.aether.spi.io.FileProcessor; -import org.eclipse.aether.spi.log.LoggerFactory; - -/** - */ -public class PlexusSupportTest - extends PlexusTestCase -{ - - @Override - protected void customizeContainerConfiguration( ContainerConfiguration containerConfiguration ) - { - containerConfiguration.setClassPathScanning( "cache" ); - } - - public void testExistenceOfPlexusComponentMetadata() - throws Exception - { - getContainer().addComponent( new TestLoggerFactory(), LoggerFactory.class, null ); - getContainer().addComponent( new TestFileProcessor(), FileProcessor.class, null ); - - RepositoryConnectorFactory factory = lookup( RepositoryConnectorFactory.class, "async-http" ); - assertNotNull( factory ); - assertEquals( AsyncRepositoryConnectorFactory.class, factory.getClass() ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/ProxyGetTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/ProxyGetTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/ProxyGetTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/ProxyGetTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import java.net.MalformedURLException; -import java.net.URL; - -import org.eclipse.aether.repository.Authentication; -import org.eclipse.aether.repository.Proxy; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.util.repository.AuthenticationBuilder; -import org.junit.Before; -import org.junit.runner.RunWith; -import org.sonatype.tests.http.runner.annotations.Configurators; -import org.sonatype.tests.http.runner.junit.ConfigurationRunner; -import org.sonatype.tests.http.server.jetty.configurations.HttpProxyAuthConfigurator; -import org.sonatype.tests.http.server.jetty.configurations.HttpProxyConfigurator; - -/** - */ -@RunWith( ConfigurationRunner.class ) -@Configurators( { HttpProxyConfigurator.class, HttpProxyAuthConfigurator.class } ) -public class ProxyGetTest - extends GetTest -{ - - @Override - @Before - public void before() - throws Exception - { - super.before(); - - Authentication auth = new AuthenticationBuilder().addUsername( "puser" ).addPassword( "password" ).build(); - Proxy proxy = new Proxy( "http", "localhost", provider().getPort(), auth ); - repository = new RemoteRepository.Builder( repository() ).setProxy( proxy ).build(); - } - - @Override - public String url() - { - URL orig; - try - { - orig = new URL( super.url() ); - return new URL( orig.getProtocol(), "proxiedhost", orig.getPort(), "" ).toString(); - } - catch ( MalformedURLException e ) - { - e.printStackTrace(); - throw new IllegalStateException( e.getMessage(), e ); - } - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/ProxyPutTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/ProxyPutTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/ProxyPutTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/ProxyPutTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import java.net.MalformedURLException; -import java.net.URL; - -import org.eclipse.aether.repository.Authentication; -import org.eclipse.aether.repository.Proxy; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.util.repository.AuthenticationBuilder; -import org.junit.Before; -import org.junit.runner.RunWith; -import org.sonatype.tests.http.runner.annotations.Configurators; -import org.sonatype.tests.http.runner.junit.ConfigurationRunner; -import org.sonatype.tests.http.server.jetty.configurations.HttpProxyAuthConfigurator; -import org.sonatype.tests.http.server.jetty.configurations.HttpProxyConfigurator; - -/** - */ -@RunWith( ConfigurationRunner.class ) -@Configurators( { HttpProxyConfigurator.class, HttpProxyAuthConfigurator.class } ) -public class ProxyPutTest - extends PutTest -{ - - @Override - @Before - public void before() - throws Exception - { - super.before(); - - Authentication auth = new AuthenticationBuilder().addUsername( "puser" ).addPassword( "password" ).build(); - Proxy proxy = new Proxy( "http", "localhost", provider().getPort(), auth ); - repository = new RemoteRepository.Builder( repository() ).setProxy( proxy ).build(); - } - - @Override - public String url() - { - URL orig; - try - { - orig = new URL( super.url() ); - return new URL( orig.getProtocol(), "proxiedhost", orig.getPort(), "" ).toString(); - } - catch ( MalformedURLException e ) - { - e.printStackTrace(); - throw new IllegalStateException( e.getMessage(), e ); - } - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/PutTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/PutTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/PutTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/PutTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,140 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import static org.junit.Assert.*; - -import java.util.Arrays; -import java.util.List; - -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.metadata.Metadata; -import org.eclipse.aether.spi.connector.ArtifactUpload; -import org.eclipse.aether.spi.connector.MetadataUpload; -import org.eclipse.aether.transfer.ArtifactTransferException; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.sonatype.tests.http.runner.junit.ConfigurationRunner; - -/** - */ -@RunWith( ConfigurationRunner.class ) -public class PutTest - extends AsyncConnectorSuiteConfiguration -{ - - @Test - public void testArtifactUpload() - throws Exception - { - addExpectation( "gid/aid/version/aid-version-classifier.extension", "artifact" ); - addExpectation( "gid/aid/version/aid-version-classifier.extension.sha1", sha1( "artifact" ) ); - addExpectation( "gid/aid/version/aid-version-classifier.extension.md5", md5( "artifact" ) ); - - Artifact artifact = artifact( "artifact" ); - ArtifactUpload up = new ArtifactUpload( artifact, artifact.getFile() ); - List uploads = Arrays.asList( up ); - connector().put( uploads, null ); - - ArtifactTransferException ex = up.getException(); - assertNull( ex != null ? ex.getMessage() : "", ex ); - assertExpectations(); - } - - @Test - public void testMetadataUpload() - throws Exception - { - String content = "metadata"; - addExpectation( "gid/aid/version/maven-metadata.xml", content ); - addExpectation( "gid/aid/version/maven-metadata.xml.sha1", sha1( content ) ); - addExpectation( "gid/aid/version/maven-metadata.xml.md5", md5( content ) ); - - Metadata metadata = metadata( content ); - - List uploads = Arrays.asList( new MetadataUpload( metadata, metadata.getFile() ) ); - connector().put( null, uploads ); - - assertExpectations(); - } - - @Test( expected = Exception.class ) - public void testClosedPut() - throws Exception - { - connector().close(); - Metadata metadata = metadata( "metadata" ); - - List uploads = Arrays.asList( new MetadataUpload( metadata, metadata.getFile() ) ); - connector().put( null, uploads ); - } - - @Test - public void testCloseAfterArtifactUpload() - throws Exception - { - Artifact artifact = artifact( "artifact" ); - List uploads = Arrays.asList( new ArtifactUpload( artifact, artifact.getFile() ) ); - connector().put( uploads, null ); - connector().close(); - } - - @Test - public void testCloseAfterMetadataUpload() - throws Exception - { - Metadata metadata = metadata( "metadata" ); - - List uploads = Arrays.asList( new MetadataUpload( metadata, metadata.getFile() ) ); - connector().put( null, uploads ); - connector().close(); - } - - @Test - @Ignore( "https://issues.sonatype.org/browse/AHC-5" ) - public void testArtifactWithZeroBytesFile() - throws Exception - { - String content = ""; - addExpectation( "gid/aid/version/aid-version-classifier.extension", content ); - addExpectation( "gid/aid/version/aid-version-classifier.extension.sha1", sha1( content ) ); - addExpectation( "gid/aid/version/aid-version-classifier.extension.md5", md5( content ) ); - - Artifact artifact = artifact( content ); - ArtifactUpload up = new ArtifactUpload( artifact, artifact.getFile() ); - List uploads = Arrays.asList( up ); - connector().put( uploads, null ); - - ArtifactTransferException ex = up.getException(); - assertNull( ex != null ? ex.getMessage() : "", ex ); - assertExpectations(); - } - - @Test - @Ignore( "https://issues.sonatype.org/browse/AHC-5" ) - public void testMetadataWithZeroBytesFile() - throws Exception - { - String content = ""; - addExpectation( "gid/aid/version/maven-metadata.xml", content ); - addExpectation( "gid/aid/version/maven-metadata.xml.sha1", sha1( content ) ); - addExpectation( "gid/aid/version/maven-metadata.xml.md5", md5( content ) ); - - Metadata metadata = metadata( content ); - - List uploads = Arrays.asList( new MetadataUpload( metadata, metadata.getFile() ) ); - connector().put( null, uploads ); - - assertExpectations(); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/RedirectGetTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/RedirectGetTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/RedirectGetTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/RedirectGetTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import org.eclipse.aether.repository.RemoteRepository; -import org.sonatype.tests.http.server.api.ServerProvider; -import org.sonatype.tests.http.server.jetty.behaviour.Redirect; - -/* * - */ -public class RedirectGetTest - extends GetTest -{ - - @Override - protected RemoteRepository repository() - { - return new RemoteRepository.Builder( super.repository() ).setUrl( url( "redirect" ) ).build(); - } - - @Override - public void configureProvider( ServerProvider provider ) - { - super.configureProvider( provider ); - provider().addBehaviour( "/redirect/*", new Redirect( "^", "/repo" ) ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/ResumeGetTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/ResumeGetTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/ResumeGetTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/ResumeGetTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,213 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import static org.junit.Assert.*; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.util.Arrays; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.aether.DefaultRepositorySystemSession; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.connector.async.AsyncRepositoryConnectorFactory; -import org.eclipse.aether.internal.test.util.TestFileProcessor; -import org.eclipse.aether.internal.test.util.TestLoggerFactory; -import org.eclipse.aether.internal.test.util.TestFileUtils; -import org.eclipse.aether.internal.test.util.TestUtils; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.repository.RepositoryPolicy; -import org.eclipse.aether.spi.connector.ArtifactDownload; -import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * - */ -public class ResumeGetTest -{ - - private AsyncRepositoryConnectorFactory factory; - - private DefaultRepositorySystemSession session; - - private Artifact artifact; - - private Server server; - - // NOTE: Length of pattern should not be divisable by 2 to catch data continuation errors during resume - private static final int[] CONTENT_PATTERN = { 'a', 'B', ' ' }; - - @Before - public void before() - throws Exception - { - factory = new AsyncRepositoryConnectorFactory(); - factory.setFileProcessor( new TestFileProcessor() ); - factory.setLoggerFactory( new TestLoggerFactory() ); - session = TestUtils.newSession(); - artifact = new DefaultArtifact( "gid", "aid", "classifier", "extension", "version" ); - server = new Server( 0 ); - } - - @After - public void after() - throws Exception - { - if ( server != null ) - { - server.stop(); - } - - factory = null; - session = null; - server = null; - - TestFileUtils.deleteTempFiles(); - } - - private String url() - { - return "http://localhost:" + server.getConnectors()[0].getLocalPort() + "/"; - } - - private void assertContentPattern( File file ) - throws IOException - { - byte[] content = TestFileUtils.getContent( file ); - for ( int i = 0; i < content.length; i++ ) - { - assertEquals( file.getAbsolutePath() + " corrupted at offset " + i, CONTENT_PATTERN[i - % CONTENT_PATTERN.length], content[i] ); - } - } - - @Test - public void testResumeInterruptedDownloadUsingRangeRequests() - throws Exception - { - FlakyHandler flakyHandler = new FlakyHandler( 4 ); - server.setHandler( flakyHandler ); - server.start(); - - File file = TestFileUtils.createTempFile( "" ); - file.delete(); - - ArtifactDownload download = new ArtifactDownload( artifact, "", file, RepositoryPolicy.CHECKSUM_POLICY_IGNORE ); - - RemoteRepository repo = new RemoteRepository.Builder( "test", "default", url() ).build(); - RepositoryConnector connector = factory.newInstance( session, repo ); - try - { - connector.get( Arrays.asList( download ), null ); - } - finally - { - connector.close(); - } - - assertNull( String.valueOf( download.getException() ), download.getException() ); - assertTrue( "Missing " + file.getAbsolutePath(), file.isFile() ); - assertEquals( "Bad size of " + file.getAbsolutePath(), flakyHandler.totalSize, file.length() ); - assertContentPattern( file ); - } - - private static class FlakyHandler - extends AbstractHandler - { - - private static final Pattern RANGE = Pattern.compile( "bytes=([0-9]+)-" ); - - private final int requiredRequests; - - private final Map madeRequests; - - private final int totalSize; - - private final int chunkSize; - - public FlakyHandler( int requiredRequests ) - { - this.requiredRequests = requiredRequests; - madeRequests = new ConcurrentHashMap(); - - totalSize = 1024 * 128; - chunkSize = ( requiredRequests > 1 ) ? totalSize / ( requiredRequests - 1 ) - 1 : totalSize; - } - - public void handle( String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) - throws IOException - { - Integer attempts = madeRequests.get( target ); - attempts = ( attempts == null ) ? Integer.valueOf( 1 ) : Integer.valueOf( attempts.intValue() + 1 ); - madeRequests.put( target, attempts ); - - if ( attempts.intValue() > requiredRequests ) - { - response.setStatus( HttpURLConnection.HTTP_BAD_REQUEST ); - response.flushBuffer(); - return; - } - - int lb = 0, ub = totalSize - 1; - - String range = request.getHeader( "Range" ); - if ( range != null && range.matches( RANGE.pattern() ) ) - { - Matcher m = RANGE.matcher( range ); - m.matches(); - lb = Integer.parseInt( m.group( 1 ) ); - } - - response.setStatus( ( lb > 0 ) ? HttpURLConnection.HTTP_PARTIAL : HttpURLConnection.HTTP_OK ); - response.setContentLength( totalSize - lb ); - response.setContentType( "Content-type: text/plain; charset=UTF-8" ); - if ( lb > 0 ) - { - response.setHeader( "Content-Range", "bytes " + lb + "-" + ub + "/" + totalSize ); - } - response.flushBuffer(); - - OutputStream out = response.getOutputStream(); - - for ( int i = lb, j = 0; i <= ub; i++, j++ ) - { - if ( j >= chunkSize ) - { - out.flush(); - - throw new IOException( "oups, we're dead" ); - } - - out.write( CONTENT_PATTERN[i % CONTENT_PATTERN.length] ); - } - - out.close(); - } - - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/StutteringGetTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/StutteringGetTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/StutteringGetTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/StutteringGetTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import org.junit.runner.RunWith; -import org.sonatype.tests.http.runner.junit.ConfigurationRunner; -import org.sonatype.tests.http.server.api.ServerProvider; - -/** - */ -@RunWith( ConfigurationRunner.class ) -public class StutteringGetTest - extends GetTest -{ - - @Override - public void configureProvider( ServerProvider provider ) - { - super.configureProvider( provider ); - provide.setLatency( 100 ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/TimeoutTest.java eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/TimeoutTest.java --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/TimeoutTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/java/org/eclipse/aether/connector/async/TimeoutTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.async; - -import static org.junit.Assert.*; - -import java.io.File; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import org.eclipse.aether.ConfigurationProperties; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.internal.test.util.TestFileUtils; -import org.eclipse.aether.repository.RepositoryPolicy; -import org.eclipse.aether.spi.connector.ArtifactDownload; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.sonatype.tests.http.runner.junit.ConfigurationRunner; -import org.sonatype.tests.http.server.api.ServerProvider; -import org.sonatype.tests.http.server.jetty.behaviour.Pause; - -/** - */ -@RunWith( ConfigurationRunner.class ) -public class TimeoutTest - extends AsyncConnectorSuiteConfiguration -{ - - @Override - public void configureProvider( ServerProvider provider ) - { - provider.addBehaviour( "/repo/*", new Pause( 100000 ) ); - } - - @Test( timeout = 3000 ) - public void testRequestTimeout() - throws Exception - { - Map configProps = new HashMap(); - configProps.put( ConfigurationProperties.CONNECT_TIMEOUT, "60000" ); - configProps.put( ConfigurationProperties.REQUEST_TIMEOUT, "1000" ); - session().setConfigProperties( configProps ); - - File f = TestFileUtils.createTempFile( "" ); - Artifact a = artifact( "foo" ); - - ArtifactDownload down = new ArtifactDownload( a, null, f, RepositoryPolicy.CHECKSUM_POLICY_FAIL ); - Collection downs = Arrays.asList( down ); - connector().get( downs, null ); - - assertNotNull( down.getException() ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/resources/logback-test.xml eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/resources/logback-test.xml --- eclipse-aether-0.9.0.M2/aether-connector-asynchttpclient/src/test/resources/logback-test.xml 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-asynchttpclient/src/test/resources/logback-test.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ - - - - - - - - %d{HH:mm:ss.SSS} [%-18thread] %c{1} [%p] %m%n - - - - - - - - - - - diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/pom.xml eclipse-aether-1.0.2/aether-connector-basic/pom.xml --- eclipse-aether-0.9.0.M2/aether-connector-basic/pom.xml 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/pom.xml 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,92 @@ + + + + + + 4.0.0 + + + org.eclipse.aether + aether + 1.0.2.v20150114 + + + aether-connector-basic + + Aether Connector Basic + + A repository connector implementation for repositories using URI-based layouts. + + + + org.eclipse.aether.connector.basic + + + + + org.eclipse.aether + aether-api + + + org.eclipse.aether + aether-spi + + + org.eclipse.aether + aether-util + + + javax.inject + javax.inject + provided + true + + + org.sonatype.sisu + sisu-guice + no_aop + test + + + junit + junit + test + + + org.hamcrest + hamcrest-library + test + + + org.eclipse.aether + aether-test-util + test + + + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + + + org.eclipse.sisu + sisu-maven-plugin + + + org.apache.felix + maven-bundle-plugin + + + + diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ArtifactTransportListener.java eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ArtifactTransportListener.java --- eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ArtifactTransportListener.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ArtifactTransportListener.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.connector.basic; + +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.ArtifactTransfer; +import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.transfer.ArtifactNotFoundException; +import org.eclipse.aether.transfer.ArtifactTransferException; +import org.eclipse.aether.transfer.TransferEvent; + +final class ArtifactTransportListener + extends TransferTransportListener +{ + + private final RemoteRepository repository; + + public ArtifactTransportListener( ArtifactTransfer transfer, RemoteRepository repository, + TransferEvent.Builder eventBuilder ) + { + super( transfer, eventBuilder ); + this.repository = repository; + } + + @Override + public void transferFailed( Exception exception, int classification ) + { + ArtifactTransferException e; + if ( classification == Transporter.ERROR_NOT_FOUND ) + { + e = new ArtifactNotFoundException( getTransfer().getArtifact(), repository ); + } + else + { + e = new ArtifactTransferException( getTransfer().getArtifact(), repository, exception ); + } + getTransfer().setException( e ); + super.transferFailed( e, classification ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java --- eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,184 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.connector.basic; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.RepositoryConnector; +import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; +import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider; +import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider; +import org.eclipse.aether.spi.connector.transport.TransporterProvider; +import org.eclipse.aether.spi.io.FileProcessor; +import org.eclipse.aether.spi.locator.Service; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.spi.log.NullLoggerFactory; +import org.eclipse.aether.transfer.NoRepositoryConnectorException; + +/** + * A repository connector factory that employs pluggable + * {@link org.eclipse.aether.spi.connector.transport.TransporterFactory transporters} and + * {@link org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory repository layouts} for the transfers. + */ +@Named( "basic" ) +public final class BasicRepositoryConnectorFactory + implements RepositoryConnectorFactory, Service +{ + + private Logger logger = NullLoggerFactory.LOGGER; + + private TransporterProvider transporterProvider; + + private RepositoryLayoutProvider layoutProvider; + + private ChecksumPolicyProvider checksumPolicyProvider; + + private FileProcessor fileProcessor; + + private float priority; + + /** + * Creates an (uninitialized) instance of this connector factory. Note: In case of manual instantiation by + * clients, the new factory needs to be configured via its various mutators before first use or runtime errors will + * occur. + */ + public BasicRepositoryConnectorFactory() + { + // enables default constructor + } + + @Inject + BasicRepositoryConnectorFactory( TransporterProvider transporterProvider, RepositoryLayoutProvider layoutProvider, + ChecksumPolicyProvider checksumPolicyProvider, FileProcessor fileProcessor, + LoggerFactory loggerFactory ) + { + setTransporterProvider( transporterProvider ); + setRepositoryLayoutProvider( layoutProvider ); + setChecksumPolicyProvider( checksumPolicyProvider ); + setFileProcessor( fileProcessor ); + setLoggerFactory( loggerFactory ); + } + + public void initService( ServiceLocator locator ) + { + setLoggerFactory( locator.getService( LoggerFactory.class ) ); + setTransporterProvider( locator.getService( TransporterProvider.class ) ); + setRepositoryLayoutProvider( locator.getService( RepositoryLayoutProvider.class ) ); + setChecksumPolicyProvider( locator.getService( ChecksumPolicyProvider.class ) ); + setFileProcessor( locator.getService( FileProcessor.class ) ); + } + + /** + * Sets the logger factory to use for this component. + * + * @param loggerFactory The logger factory to use, may be {@code null} to disable logging. + * @return This component for chaining, never {@code null}. + */ + public BasicRepositoryConnectorFactory setLoggerFactory( LoggerFactory loggerFactory ) + { + this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, BasicRepositoryConnector.class ); + return this; + } + + /** + * Sets the transporter provider to use for this component. + * + * @param transporterProvider The transporter provider to use, must not be {@code null}. + * @return This component for chaining, never {@code null}. + */ + public BasicRepositoryConnectorFactory setTransporterProvider( TransporterProvider transporterProvider ) + { + if ( transporterProvider == null ) + { + throw new IllegalArgumentException( "transporter provider has not been specified" ); + } + this.transporterProvider = transporterProvider; + return this; + } + + /** + * Sets the repository layout provider to use for this component. + * + * @param layoutProvider The repository layout provider to use, must not be {@code null}. + * @return This component for chaining, never {@code null}. + */ + public BasicRepositoryConnectorFactory setRepositoryLayoutProvider( RepositoryLayoutProvider layoutProvider ) + { + if ( layoutProvider == null ) + { + throw new IllegalArgumentException( "repository layout provider has not been specified" ); + } + this.layoutProvider = layoutProvider; + return this; + } + + /** + * Sets the checksum policy provider to use for this component. + * + * @param checksumPolicyProvider The checksum policy provider to use, must not be {@code null}. + * @return This component for chaining, never {@code null}. + */ + public BasicRepositoryConnectorFactory setChecksumPolicyProvider( ChecksumPolicyProvider checksumPolicyProvider ) + { + if ( checksumPolicyProvider == null ) + { + throw new IllegalArgumentException( "checksum policy provider has not been specified" ); + } + this.checksumPolicyProvider = checksumPolicyProvider; + return this; + } + + /** + * Sets the file processor to use for this component. + * + * @param fileProcessor The file processor to use, must not be {@code null}. + * @return This component for chaining, never {@code null}. + */ + public BasicRepositoryConnectorFactory setFileProcessor( FileProcessor fileProcessor ) + { + if ( fileProcessor == null ) + { + throw new IllegalArgumentException( "file processor has not been specified" ); + } + this.fileProcessor = fileProcessor; + return this; + } + + public float getPriority() + { + return priority; + } + + /** + * Sets the priority of this component. + * + * @param priority The priority. + * @return This component for chaining, never {@code null}. + */ + public BasicRepositoryConnectorFactory setPriority( float priority ) + { + this.priority = priority; + return this; + } + + public RepositoryConnector newInstance( RepositorySystemSession session, RemoteRepository repository ) + throws NoRepositoryConnectorException + { + return new BasicRepositoryConnector( session, repository, transporterProvider, layoutProvider, + checksumPolicyProvider, fileProcessor, logger ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java --- eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,586 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.connector.basic; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.eclipse.aether.ConfigurationProperties; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.ArtifactDownload; +import org.eclipse.aether.spi.connector.ArtifactUpload; +import org.eclipse.aether.spi.connector.MetadataDownload; +import org.eclipse.aether.spi.connector.MetadataUpload; +import org.eclipse.aether.spi.connector.RepositoryConnector; +import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy; +import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider; +import org.eclipse.aether.spi.connector.layout.RepositoryLayout; +import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider; +import org.eclipse.aether.spi.connector.transport.GetTask; +import org.eclipse.aether.spi.connector.transport.PeekTask; +import org.eclipse.aether.spi.connector.transport.PutTask; +import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.connector.transport.TransporterProvider; +import org.eclipse.aether.spi.io.FileProcessor; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.transfer.ChecksumFailureException; +import org.eclipse.aether.transfer.NoRepositoryConnectorException; +import org.eclipse.aether.transfer.NoRepositoryLayoutException; +import org.eclipse.aether.transfer.NoTransporterException; +import org.eclipse.aether.transfer.TransferEvent; +import org.eclipse.aether.transfer.TransferResource; +import org.eclipse.aether.util.ChecksumUtils; +import org.eclipse.aether.util.ConfigUtils; +import org.eclipse.aether.util.concurrency.RunnableErrorForwarder; +import org.eclipse.aether.util.concurrency.WorkerThreadFactory; + +/** + */ +final class BasicRepositoryConnector + implements RepositoryConnector +{ + + private static final String CONFIG_PROP_THREADS = "aether.connector.basic.threads"; + + private static final String CONFIG_PROP_RESUME = "aether.connector.resumeDownloads"; + + private static final String CONFIG_PROP_RESUME_THRESHOLD = "aether.connector.resumeThreshold"; + + private static final String CONFIG_PROP_SMART_CHECKSUMS = "aether.connector.smartChecksums"; + + private final Logger logger; + + private final FileProcessor fileProcessor; + + private final RemoteRepository repository; + + private final RepositorySystemSession session; + + private final Transporter transporter; + + private final RepositoryLayout layout; + + private final ChecksumPolicyProvider checksumPolicyProvider; + + private final PartialFile.Factory partialFileFactory; + + private final int maxThreads; + + private final boolean smartChecksums; + + private final boolean persistedChecksums; + + private Executor executor; + + private boolean closed; + + public BasicRepositoryConnector( RepositorySystemSession session, RemoteRepository repository, + TransporterProvider transporterProvider, RepositoryLayoutProvider layoutProvider, + ChecksumPolicyProvider checksumPolicyProvider, FileProcessor fileProcessor, + Logger logger ) + throws NoRepositoryConnectorException + { + try + { + layout = layoutProvider.newRepositoryLayout( session, repository ); + } + catch ( NoRepositoryLayoutException e ) + { + throw new NoRepositoryConnectorException( repository, e.getMessage(), e ); + } + try + { + transporter = transporterProvider.newTransporter( session, repository ); + } + catch ( NoTransporterException e ) + { + throw new NoRepositoryConnectorException( repository, e.getMessage(), e ); + } + this.checksumPolicyProvider = checksumPolicyProvider; + + this.session = session; + this.repository = repository; + this.fileProcessor = fileProcessor; + this.logger = logger; + + maxThreads = ConfigUtils.getInteger( session, 5, CONFIG_PROP_THREADS, "maven.artifact.threads" ); + smartChecksums = ConfigUtils.getBoolean( session, true, CONFIG_PROP_SMART_CHECKSUMS ); + persistedChecksums = + ConfigUtils.getBoolean( session, ConfigurationProperties.DEFAULT_PERSISTED_CHECKSUMS, + ConfigurationProperties.PERSISTED_CHECKSUMS ); + + boolean resumeDownloads = + ConfigUtils.getBoolean( session, true, CONFIG_PROP_RESUME + '.' + repository.getId(), CONFIG_PROP_RESUME ); + long resumeThreshold = + ConfigUtils.getLong( session, 64 * 1024, CONFIG_PROP_RESUME_THRESHOLD + '.' + repository.getId(), + CONFIG_PROP_RESUME_THRESHOLD ); + int requestTimeout = + ConfigUtils.getInteger( session, ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT, + ConfigurationProperties.REQUEST_TIMEOUT + '.' + repository.getId(), + ConfigurationProperties.REQUEST_TIMEOUT ); + partialFileFactory = new PartialFile.Factory( resumeDownloads, resumeThreshold, requestTimeout, logger ); + } + + private Executor getExecutor( Collection artifacts, Collection metadatas ) + { + if ( maxThreads <= 1 ) + { + return DirectExecutor.INSTANCE; + } + int tasks = safe( artifacts ).size() + safe( metadatas ).size(); + if ( tasks <= 1 ) + { + return DirectExecutor.INSTANCE; + } + if ( executor == null ) + { + executor = + new ThreadPoolExecutor( maxThreads, maxThreads, 3, TimeUnit.SECONDS, + new LinkedBlockingQueue(), + new WorkerThreadFactory( getClass().getSimpleName() + '-' + + repository.getHost() + '-' ) ); + } + return executor; + } + + @Override + protected void finalize() + throws Throwable + { + try + { + close(); + } + finally + { + super.finalize(); + } + } + + public void close() + { + if ( !closed ) + { + closed = true; + if ( executor instanceof ExecutorService ) + { + ( (ExecutorService) executor ).shutdown(); + } + transporter.close(); + } + } + + public void get( Collection artifactDownloads, + Collection metadataDownloads ) + { + if ( closed ) + { + throw new IllegalStateException( "connector closed" ); + } + + Executor executor = getExecutor( artifactDownloads, metadataDownloads ); + RunnableErrorForwarder errorForwarder = new RunnableErrorForwarder(); + + for ( MetadataDownload transfer : safe( metadataDownloads ) ) + { + URI location = layout.getLocation( transfer.getMetadata(), false ); + + TransferResource resource = newTransferResource( location, transfer.getFile(), transfer.getTrace() ); + TransferEvent.Builder builder = newEventBuilder( resource, false, false ); + MetadataTransportListener listener = new MetadataTransportListener( transfer, repository, builder ); + + ChecksumPolicy checksumPolicy = newChecksumPolicy( transfer.getChecksumPolicy(), resource ); + List checksums = null; + if ( checksumPolicy != null ) + { + checksums = layout.getChecksums( transfer.getMetadata(), false, location ); + } + + Runnable task = new GetTaskRunner( location, transfer.getFile(), checksumPolicy, checksums, listener ); + executor.execute( errorForwarder.wrap( task ) ); + } + + for ( ArtifactDownload transfer : safe( artifactDownloads ) ) + { + URI location = layout.getLocation( transfer.getArtifact(), false ); + + TransferResource resource = newTransferResource( location, transfer.getFile(), transfer.getTrace() ); + TransferEvent.Builder builder = newEventBuilder( resource, false, transfer.isExistenceCheck() ); + ArtifactTransportListener listener = new ArtifactTransportListener( transfer, repository, builder ); + + Runnable task; + if ( transfer.isExistenceCheck() ) + { + task = new PeekTaskRunner( location, listener ); + } + else + { + ChecksumPolicy checksumPolicy = newChecksumPolicy( transfer.getChecksumPolicy(), resource ); + List checksums = null; + if ( checksumPolicy != null ) + { + checksums = layout.getChecksums( transfer.getArtifact(), false, location ); + } + + task = new GetTaskRunner( location, transfer.getFile(), checksumPolicy, checksums, listener ); + } + executor.execute( errorForwarder.wrap( task ) ); + } + + errorForwarder.await(); + } + + public void put( Collection artifactUploads, + Collection metadataUploads ) + { + if ( closed ) + { + throw new IllegalStateException( "connector closed" ); + } + + for ( ArtifactUpload transfer : safe( artifactUploads ) ) + { + URI location = layout.getLocation( transfer.getArtifact(), true ); + + TransferResource resource = newTransferResource( location, transfer.getFile(), transfer.getTrace() ); + TransferEvent.Builder builder = newEventBuilder( resource, true, false ); + ArtifactTransportListener listener = new ArtifactTransportListener( transfer, repository, builder ); + + List checksums = layout.getChecksums( transfer.getArtifact(), true, location ); + + Runnable task = new PutTaskRunner( location, transfer.getFile(), checksums, listener ); + task.run(); + } + + for ( MetadataUpload transfer : safe( metadataUploads ) ) + { + URI location = layout.getLocation( transfer.getMetadata(), true ); + + TransferResource resource = newTransferResource( location, transfer.getFile(), transfer.getTrace() ); + TransferEvent.Builder builder = newEventBuilder( resource, true, false ); + MetadataTransportListener listener = new MetadataTransportListener( transfer, repository, builder ); + + List checksums = layout.getChecksums( transfer.getMetadata(), true, location ); + + Runnable task = new PutTaskRunner( location, transfer.getFile(), checksums, listener ); + task.run(); + } + } + + private static Collection safe( Collection items ) + { + return ( items != null ) ? items : Collections. emptyList(); + } + + private TransferResource newTransferResource( URI path, File file, RequestTrace trace ) + { + return new TransferResource( repository.getUrl(), path.toString(), file, trace ); + } + + private TransferEvent.Builder newEventBuilder( TransferResource resource, boolean upload, boolean peek ) + { + TransferEvent.Builder builder = new TransferEvent.Builder( session, resource ); + if ( upload ) + { + builder.setRequestType( TransferEvent.RequestType.PUT ); + } + else if ( !peek ) + { + builder.setRequestType( TransferEvent.RequestType.GET ); + } + else + { + builder.setRequestType( TransferEvent.RequestType.GET_EXISTENCE ); + } + return builder; + } + + private ChecksumPolicy newChecksumPolicy( String policy, TransferResource resource ) + { + return checksumPolicyProvider.newChecksumPolicy( session, repository, resource, policy ); + } + + @Override + public String toString() + { + return String.valueOf( repository ); + } + + abstract class TaskRunner + implements Runnable + { + + protected final URI path; + + protected final TransferTransportListener listener; + + public TaskRunner( URI path, TransferTransportListener listener ) + { + this.path = path; + this.listener = listener; + } + + public void run() + { + try + { + listener.transferInitiated(); + runTask(); + listener.transferSucceeded(); + } + catch ( Exception e ) + { + listener.transferFailed( e, transporter.classify( e ) ); + } + } + + protected abstract void runTask() + throws Exception; + + } + + class PeekTaskRunner + extends TaskRunner + { + + public PeekTaskRunner( URI path, TransferTransportListener listener ) + { + super( path, listener ); + } + + protected void runTask() + throws Exception + { + transporter.peek( new PeekTask( path ) ); + } + + } + + class GetTaskRunner + extends TaskRunner + implements PartialFile.RemoteAccessChecker, ChecksumValidator.ChecksumFetcher + { + + private final File file; + + private final ChecksumValidator checksumValidator; + + public GetTaskRunner( URI path, File file, ChecksumPolicy checksumPolicy, + List checksums, TransferTransportListener listener ) + { + super( path, listener ); + this.file = file; + checksumValidator = + new ChecksumValidator( logger, file, fileProcessor, this, checksumPolicy, safe( checksums ) ); + } + + public void checkRemoteAccess() + throws Exception + { + transporter.peek( new PeekTask( path ) ); + } + + public boolean fetchChecksum( URI remote, File local ) + throws Exception + { + try + { + transporter.get( new GetTask( remote ).setDataFile( local ) ); + } + catch ( Exception e ) + { + if ( transporter.classify( e ) == Transporter.ERROR_NOT_FOUND ) + { + return false; + } + throw e; + } + return true; + } + + protected void runTask() + throws Exception + { + if ( file == null ) + { + throw new IllegalArgumentException( "destination file has not been specified" ); + } + fileProcessor.mkdirs( file.getParentFile() ); + + PartialFile partFile = partialFileFactory.newInstance( file, this ); + if ( partFile == null ) + { + logger.debug( "Concurrent download of " + file + " just finished, skipping download" ); + return; + } + + try + { + File tmp = partFile.getFile(); + listener.setChecksumCalculator( checksumValidator.newChecksumCalculator( tmp ) ); + for ( int firstTrial = 0, lastTrial = 1, trial = firstTrial;; trial++ ) + { + boolean resume = partFile.isResume() && trial <= firstTrial; + GetTask task = new GetTask( path ).setDataFile( tmp, resume ).setListener( listener ); + transporter.get( task ); + try + { + checksumValidator.validate( listener.getChecksums(), smartChecksums ? task.getChecksums() + : null ); + break; + } + catch ( ChecksumFailureException e ) + { + boolean retry = trial < lastTrial && e.isRetryWorthy(); + if ( !retry && !checksumValidator.handle( e ) ) + { + throw e; + } + listener.transferCorrupted( e ); + if ( retry ) + { + checksumValidator.retry(); + } + else + { + break; + } + } + } + fileProcessor.move( tmp, file ); + if ( persistedChecksums ) + { + checksumValidator.commit(); + } + } + finally + { + partFile.close(); + checksumValidator.close(); + } + } + + } + + class PutTaskRunner + extends TaskRunner + { + + private final File file; + + private final Collection checksums; + + public PutTaskRunner( URI path, File file, List checksums, + TransferTransportListener listener ) + { + super( path, listener ); + this.file = file; + this.checksums = safe( checksums ); + } + + protected void runTask() + throws Exception + { + if ( file == null ) + { + throw new IllegalArgumentException( "source file has not been specified" ); + } + transporter.put( new PutTask( path ).setDataFile( file ).setListener( listener ) ); + uploadChecksums( file, path ); + } + + private void uploadChecksums( File file, URI location ) + { + if ( checksums.isEmpty() ) + { + return; + } + try + { + Set algos = new HashSet(); + for ( RepositoryLayout.Checksum checksum : checksums ) + { + algos.add( checksum.getAlgorithm() ); + } + Map sumsByAlgo = ChecksumUtils.calc( file, algos ); + for ( RepositoryLayout.Checksum checksum : checksums ) + { + uploadChecksum( checksum.getLocation(), sumsByAlgo.get( checksum.getAlgorithm() ) ); + } + } + catch ( IOException e ) + { + String msg = "Failed to upload checksums for " + file + ": " + e.getMessage(); + if ( logger.isDebugEnabled() ) + { + logger.warn( msg, e ); + } + else + { + logger.warn( msg ); + } + } + } + + private void uploadChecksum( URI location, Object checksum ) + { + try + { + if ( checksum instanceof Exception ) + { + throw (Exception) checksum; + } + transporter.put( new PutTask( location ).setDataString( (String) checksum ) ); + } + catch ( Exception e ) + { + String msg = "Failed to upload checksum " + location + ": " + e.getMessage(); + if ( logger.isDebugEnabled() ) + { + logger.warn( msg, e ); + } + else + { + logger.warn( msg ); + } + } + } + + } + + private static class DirectExecutor + implements Executor + { + + static final Executor INSTANCE = new DirectExecutor(); + + public void execute( Runnable command ) + { + command.run(); + } + + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumCalculator.java eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumCalculator.java --- eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumCalculator.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumCalculator.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.connector.basic; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.aether.spi.connector.layout.RepositoryLayout; +import org.eclipse.aether.util.ChecksumUtils; + +/** + * Calculates checksums for a downloaded file. + */ +final class ChecksumCalculator +{ + + static class Checksum + { + final String algorithm; + + final MessageDigest digest; + + Exception error; + + public Checksum( String algorithm ) + { + this.algorithm = algorithm; + MessageDigest digest = null; + try + { + digest = MessageDigest.getInstance( algorithm ); + } + catch ( NoSuchAlgorithmException e ) + { + error = e; + } + this.digest = digest; + } + + public void update( ByteBuffer buffer ) + { + if ( digest != null ) + { + digest.update( buffer ); + } + } + + public void reset() + { + if ( digest != null ) + { + digest.reset(); + error = null; + } + } + + public void error( Exception error ) + { + if ( digest != null ) + { + this.error = error; + } + } + + public Object get() + { + if ( error != null ) + { + return error; + } + return ChecksumUtils.toHexString( digest.digest() ); + } + + } + + private final List checksums; + + private final File targetFile; + + public static ChecksumCalculator newInstance( File targetFile, Collection checksums ) + { + if ( checksums == null || checksums.isEmpty() ) + { + return null; + } + return new ChecksumCalculator( targetFile, checksums ); + } + + private ChecksumCalculator( File targetFile, Collection checksums ) + { + this.checksums = new ArrayList(); + Set algos = new HashSet(); + for ( RepositoryLayout.Checksum checksum : checksums ) + { + String algo = checksum.getAlgorithm(); + if ( algos.add( algo ) ) + { + this.checksums.add( new Checksum( algo ) ); + } + } + this.targetFile = targetFile; + } + + public void init( long dataOffset ) + { + for ( Checksum checksum : checksums ) + { + checksum.reset(); + } + if ( dataOffset <= 0 ) + { + return; + } + try + { + FileInputStream fis = new FileInputStream( targetFile ); + try + { + long total = 0; + ByteBuffer buffer = ByteBuffer.allocate( 1024 * 32 ); + for ( byte[] array = buffer.array(); total < dataOffset; ) + { + int read = fis.read( array ); + if ( read < 0 ) + { + if ( total < dataOffset ) + { + throw new IOException( targetFile + " contains only " + total + + " bytes, cannot resume download from offset " + dataOffset ); + } + break; + } + total += read; + if ( total > dataOffset ) + { + read -= total - dataOffset; + } + buffer.rewind(); + buffer.limit( read ); + update( buffer ); + } + } + finally + { + try + { + fis.close(); + } + catch ( IOException e ) + { + // irrelevant + } + } + } + catch ( IOException e ) + { + for ( Checksum checksum : checksums ) + { + checksum.error( e ); + } + } + } + + public void update( ByteBuffer data ) + { + for ( Checksum checksum : checksums ) + { + data.mark(); + checksum.update( data ); + data.reset(); + } + } + + public Map get() + { + Map results = new HashMap(); + for ( Checksum checksum : checksums ) + { + results.put( checksum.algorithm, checksum.get() ); + } + return results; + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java --- eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,256 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.connector.basic; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; + +import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy; +import org.eclipse.aether.spi.connector.layout.RepositoryLayout.Checksum; +import org.eclipse.aether.spi.io.FileProcessor; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.transfer.ChecksumFailureException; +import org.eclipse.aether.util.ChecksumUtils; + +/** + * Performs checksum validation for a downloaded file. + */ +final class ChecksumValidator +{ + + interface ChecksumFetcher + { + + boolean fetchChecksum( URI remote, File local ) + throws Exception; + + } + + private final Logger logger; + + private final File dataFile; + + private final Collection tempFiles; + + private final FileProcessor fileProcessor; + + private final ChecksumFetcher checksumFetcher; + + private final ChecksumPolicy checksumPolicy; + + private final Collection checksums; + + private final Map checksumFiles; + + public ChecksumValidator( Logger logger, File dataFile, FileProcessor fileProcessor, + ChecksumFetcher checksumFetcher, ChecksumPolicy checksumPolicy, + Collection checksums ) + { + this.logger = logger; + this.dataFile = dataFile; + this.tempFiles = new HashSet(); + this.fileProcessor = fileProcessor; + this.checksumFetcher = checksumFetcher; + this.checksumPolicy = checksumPolicy; + this.checksums = checksums; + checksumFiles = new HashMap(); + } + + public ChecksumCalculator newChecksumCalculator( File targetFile ) + { + if ( checksumPolicy != null ) + { + return ChecksumCalculator.newInstance( targetFile, checksums ); + } + return null; + } + + public void validate( Map actualChecksums, Map inlinedChecksums ) + throws ChecksumFailureException + { + if ( checksumPolicy == null ) + { + return; + } + if ( inlinedChecksums != null && validateInlinedChecksums( actualChecksums, inlinedChecksums ) ) + { + return; + } + if ( validateExternalChecksums( actualChecksums ) ) + { + return; + } + checksumPolicy.onNoMoreChecksums(); + } + + private boolean validateInlinedChecksums( Map actualChecksums, Map inlinedChecksums ) + throws ChecksumFailureException + { + for ( Map.Entry entry : inlinedChecksums.entrySet() ) + { + String algo = entry.getKey(); + Object calculated = actualChecksums.get( algo ); + if ( !( calculated instanceof String ) ) + { + continue; + } + + String actual = String.valueOf( calculated ); + String expected = entry.getValue().toString(); + checksumFiles.put( getChecksumFile( algo ), expected ); + + if ( !isEqualChecksum( expected, actual ) ) + { + checksumPolicy.onChecksumMismatch( algo, ChecksumPolicy.KIND_UNOFFICIAL, + new ChecksumFailureException( expected, actual ) ); + } + else if ( checksumPolicy.onChecksumMatch( algo, ChecksumPolicy.KIND_UNOFFICIAL ) ) + { + return true; + } + } + return false; + } + + private boolean validateExternalChecksums( Map actualChecksums ) + throws ChecksumFailureException + { + for ( Checksum checksum : checksums ) + { + String algo = checksum.getAlgorithm(); + Object calculated = actualChecksums.get( algo ); + if ( calculated instanceof Exception ) + { + checksumPolicy.onChecksumError( algo, 0, new ChecksumFailureException( (Exception) calculated ) ); + continue; + } + try + { + File checksumFile = getChecksumFile( checksum.getAlgorithm() ); + File tmp = createTempFile( checksumFile ); + try + { + if ( !checksumFetcher.fetchChecksum( checksum.getLocation(), tmp ) ) + { + continue; + } + } + catch ( Exception e ) + { + checksumPolicy.onChecksumError( algo, 0, new ChecksumFailureException( e ) ); + continue; + } + + String actual = String.valueOf( calculated ); + String expected = ChecksumUtils.read( tmp ); + checksumFiles.put( checksumFile, tmp ); + + if ( !isEqualChecksum( expected, actual ) ) + { + checksumPolicy.onChecksumMismatch( algo, 0, new ChecksumFailureException( expected, actual ) ); + } + else if ( checksumPolicy.onChecksumMatch( algo, 0 ) ) + { + return true; + } + } + catch ( IOException e ) + { + checksumPolicy.onChecksumError( algo, 0, new ChecksumFailureException( e ) ); + } + } + return false; + } + + private static boolean isEqualChecksum( String expected, String actual ) + { + return expected.equalsIgnoreCase( actual ); + } + + private File getChecksumFile( String algorithm ) + { + String ext = algorithm.replace( "-", "" ).toLowerCase( Locale.ENGLISH ); + return new File( dataFile.getPath() + '.' + ext ); + } + + private File createTempFile( File path ) + throws IOException + { + File file = + File.createTempFile( path.getName() + "-" + + UUID.randomUUID().toString().replace( "-", "" ).substring( 0, 8 ), ".tmp", path.getParentFile() ); + tempFiles.add( file ); + return file; + } + + private void clearTempFiles() + { + for ( File file : tempFiles ) + { + if ( !file.delete() && file.exists() ) + { + logger.debug( "Could not delete temorary file " + file ); + } + } + tempFiles.clear(); + } + + public void retry() + { + checksumPolicy.onTransferRetry(); + checksumFiles.clear(); + clearTempFiles(); + } + + public boolean handle( ChecksumFailureException exception ) + { + return checksumPolicy.onTransferChecksumFailure( exception ); + } + + public void commit() + { + for ( Map.Entry entry : checksumFiles.entrySet() ) + { + File checksumFile = entry.getKey(); + Object tmp = entry.getValue(); + try + { + if ( tmp instanceof File ) + { + fileProcessor.move( (File) tmp, checksumFile ); + tempFiles.remove( tmp ); + } + else + { + fileProcessor.write( checksumFile, String.valueOf( tmp ) ); + } + } + catch ( IOException e ) + { + logger.debug( "Failed to write checksum file " + checksumFile + ": " + e.getMessage(), e ); + } + } + checksumFiles.clear(); + } + + public void close() + { + clearTempFiles(); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/MetadataTransportListener.java eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/MetadataTransportListener.java --- eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/MetadataTransportListener.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/MetadataTransportListener.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.connector.basic; + +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.MetadataTransfer; +import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.transfer.MetadataNotFoundException; +import org.eclipse.aether.transfer.MetadataTransferException; +import org.eclipse.aether.transfer.TransferEvent; + +final class MetadataTransportListener + extends TransferTransportListener +{ + + private final RemoteRepository repository; + + public MetadataTransportListener( MetadataTransfer transfer, RemoteRepository repository, + TransferEvent.Builder eventBuilder ) + { + super( transfer, eventBuilder ); + this.repository = repository; + } + + @Override + public void transferFailed( Exception exception, int classification ) + { + MetadataTransferException e; + if ( classification == Transporter.ERROR_NOT_FOUND ) + { + e = new MetadataNotFoundException( getTransfer().getMetadata(), repository ); + } + else + { + e = new MetadataTransferException( getTransfer().getMetadata(), repository, exception ); + } + getTransfer().setException( e ); + super.transferFailed( e, classification ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/package-info.java eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/package-info.java --- eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/package-info.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * Support for downloads/uploads using remote repositories that have a URI-based content structure/layout. + */ +package org.eclipse.aether.connector.basic; + diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/PartialFile.java eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/PartialFile.java --- eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/PartialFile.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/PartialFile.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,292 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.connector.basic; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.channels.FileLock; +import java.nio.channels.OverlappingFileLockException; +import java.util.UUID; + +import org.eclipse.aether.spi.log.Logger; + +/** + * A partially downloaded file with optional support for resume. If resume is enabled, a well-known location is used for + * the partial file in combination with a lock file to prevent concurrent requests from corrupting it (and wasting + * network bandwith). Otherwise, a (non-locked) unique temporary file is used. + */ +final class PartialFile + implements Closeable +{ + + static final String EXT_PART = ".part"; + + static final String EXT_LOCK = ".lock"; + + interface RemoteAccessChecker + { + + void checkRemoteAccess() + throws Exception; + + } + + static class LockFile + { + + private final File lockFile; + + private final FileLock lock; + + private final boolean concurrent; + + public LockFile( File partFile, int requestTimeout, RemoteAccessChecker checker, Logger logger ) + throws Exception + { + lockFile = new File( partFile.getPath() + EXT_LOCK ); + boolean[] concurrent = { false }; + lock = lock( lockFile, partFile, requestTimeout, checker, logger, concurrent ); + this.concurrent = concurrent[0]; + } + + private static FileLock lock( File lockFile, File partFile, int requestTimeout, RemoteAccessChecker checker, + Logger logger, boolean[] concurrent ) + throws Exception + { + boolean interrupted = false; + try + { + for ( long lastLength = -1, lastTime = 0;; ) + { + FileLock lock = tryLock( lockFile ); + if ( lock != null ) + { + return lock; + } + + long currentLength = partFile.length(); + long currentTime = System.currentTimeMillis(); + if ( currentLength != lastLength ) + { + if ( lastLength < 0 ) + { + concurrent[0] = true; + /* + * NOTE: We're going with the optimistic assumption that the other thread is downloading the + * file from an equivalent repository. As a bare minimum, ensure the repository we are given + * at least knows about the file and is accessible to us. + */ + checker.checkRemoteAccess(); + logger.debug( "Concurrent download of " + partFile + " in progress, awaiting completion" ); + } + lastLength = currentLength; + lastTime = currentTime; + } + else if ( requestTimeout > 0 && currentTime - lastTime > Math.max( requestTimeout, 3 * 1000 ) ) + { + throw new IOException( "Timeout while waiting for concurrent download of " + partFile + + " to progress" ); + } + + try + { + Thread.sleep( 100 ); + } + catch ( InterruptedException e ) + { + interrupted = true; + } + } + } + finally + { + if ( interrupted ) + { + Thread.currentThread().interrupt(); + } + } + } + + private static FileLock tryLock( File lockFile ) + throws IOException + { + RandomAccessFile raf = new RandomAccessFile( lockFile, "rw" ); + try + { + FileLock lock = raf.getChannel().tryLock( 0, 1, false ); + if ( lock == null ) + { + close( raf ); + } + return lock; + } + catch ( OverlappingFileLockException e ) + { + close( raf ); + return null; + } + catch ( RuntimeException e ) + { + close( raf ); + lockFile.delete(); + throw e; + } + catch ( IOException e ) + { + close( raf ); + lockFile.delete(); + throw e; + } + } + + private static void close( Closeable file ) + { + try + { + file.close(); + } + catch ( IOException e ) + { + // irrelevant + } + } + + public boolean isConcurrent() + { + return concurrent; + } + + public void close() + { + close( lock.channel() ); + lockFile.delete(); + } + + @Override + public String toString() + { + return lockFile + " - " + lock.isValid(); + } + + } + + static class Factory + { + + private final boolean resume; + + private final long resumeThreshold; + + private final int requestTimeout; + + private final Logger logger; + + public Factory( boolean resume, long resumeThreshold, int requestTimeout, Logger logger ) + { + this.resume = resume; + this.resumeThreshold = resumeThreshold; + this.requestTimeout = requestTimeout; + this.logger = logger; + } + + public PartialFile newInstance( File dstFile, RemoteAccessChecker checker ) + throws Exception + { + if ( resume ) + { + File partFile = new File( dstFile.getPath() + EXT_PART ); + + long reqTimestamp = System.currentTimeMillis(); + LockFile lockFile = new LockFile( partFile, requestTimeout, checker, logger ); + if ( lockFile.isConcurrent() && dstFile.lastModified() >= reqTimestamp - 100 ) + { + lockFile.close(); + return null; + } + try + { + if ( !partFile.createNewFile() && !partFile.isFile() ) + { + throw new IOException( partFile.exists() ? "Path exists but is not a file" : "Unknown error" ); + } + return new PartialFile( partFile, lockFile, resumeThreshold, logger ); + } + catch ( IOException e ) + { + lockFile.close(); + logger.debug( "Cannot create resumable file " + partFile.getAbsolutePath() + ": " + e ); + // fall through and try non-resumable/temporary file location + } + } + + File tempFile = + File.createTempFile( dstFile.getName() + '-' + UUID.randomUUID().toString().replace( "-", "" ), ".tmp", + dstFile.getParentFile() ); + return new PartialFile( tempFile, logger ); + } + + } + + private final File partFile; + + private final LockFile lockFile; + + private final long threshold; + + private final Logger logger; + + private PartialFile( File partFile, Logger logger ) + { + this( partFile, null, 0, logger ); + } + + private PartialFile( File partFile, LockFile lockFile, long threshold, Logger logger ) + { + this.partFile = partFile; + this.lockFile = lockFile; + this.threshold = threshold; + this.logger = logger; + } + + public File getFile() + { + return partFile; + } + + public boolean isResume() + { + return lockFile != null && partFile.length() >= threshold; + } + + public void close() + { + if ( partFile.exists() && !isResume() ) + { + if ( !partFile.delete() && partFile.exists() ) + { + logger.debug( "Could not delete temorary file " + partFile ); + } + } + if ( lockFile != null ) + { + lockFile.close(); + } + } + + @Override + public String toString() + { + return String.valueOf( getFile() ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/TransferTransportListener.java eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/TransferTransportListener.java --- eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/TransferTransportListener.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/src/main/java/org/eclipse/aether/connector/basic/TransferTransportListener.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.connector.basic; + +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.Map; + +import org.eclipse.aether.spi.connector.Transfer; +import org.eclipse.aether.spi.connector.transport.TransportListener; +import org.eclipse.aether.transfer.TransferCancelledException; +import org.eclipse.aether.transfer.TransferEvent; +import org.eclipse.aether.transfer.TransferEvent.EventType; +import org.eclipse.aether.transfer.TransferListener; + +class TransferTransportListener + extends TransportListener +{ + + private final T transfer; + + private final TransferListener listener; + + private final TransferEvent.Builder eventBuilder; + + private ChecksumCalculator checksumCalculator; + + protected TransferTransportListener( T transfer, TransferEvent.Builder eventBuilder ) + { + this.transfer = transfer; + this.listener = transfer.getListener(); + this.eventBuilder = eventBuilder; + } + + protected T getTransfer() + { + return transfer; + } + + public void transferInitiated() + throws TransferCancelledException + { + if ( listener != null ) + { + eventBuilder.resetType( EventType.INITIATED ); + listener.transferInitiated( eventBuilder.build() ); + } + } + + @Override + public void transportStarted( long dataOffset, long dataLength ) + throws TransferCancelledException + { + if ( checksumCalculator != null ) + { + checksumCalculator.init( dataOffset ); + } + if ( listener != null ) + { + eventBuilder.resetType( EventType.STARTED ).setTransferredBytes( dataOffset ); + TransferEvent event = eventBuilder.build(); + event.getResource().setContentLength( dataLength ).setResumeOffset( dataOffset ); + listener.transferStarted( event ); + } + } + + @Override + public void transportProgressed( ByteBuffer data ) + throws TransferCancelledException + { + if ( checksumCalculator != null ) + { + checksumCalculator.update( data ); + } + if ( listener != null ) + { + eventBuilder.resetType( EventType.PROGRESSED ).addTransferredBytes( data.remaining() ).setDataBuffer( data ); + listener.transferProgressed( eventBuilder.build() ); + } + } + + public void transferCorrupted( Exception exception ) + throws TransferCancelledException + { + if ( listener != null ) + { + eventBuilder.resetType( EventType.CORRUPTED ).setException( exception ); + listener.transferCorrupted( eventBuilder.build() ); + } + } + + public void transferFailed( Exception exception, int classification ) + { + if ( listener != null ) + { + eventBuilder.resetType( EventType.FAILED ).setException( exception ); + listener.transferFailed( eventBuilder.build() ); + } + } + + public void transferSucceeded() + { + if ( listener != null ) + { + eventBuilder.resetType( EventType.SUCCEEDED ); + listener.transferSucceeded( eventBuilder.build() ); + } + } + + public Map getChecksums() + { + if ( checksumCalculator == null ) + { + return Collections.emptyMap(); + } + return checksumCalculator.get(); + } + + public void setChecksumCalculator( ChecksumCalculator checksumCalculator ) + { + this.checksumCalculator = checksumCalculator; + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/resources/about.html eclipse-aether-1.0.2/aether-connector-basic/src/main/resources/about.html --- eclipse-aether-0.9.0.M2/aether-connector-basic/src/main/resources/about.html 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/src/main/resources/about.html 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,28 @@ + + + + +About + + +

About This Content

+ +

September 23, 2011

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + + diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumCalculatorTest.java eclipse-aether-1.0.2/aether-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumCalculatorTest.java --- eclipse-aether-0.9.0.M2/aether-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumCalculatorTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumCalculatorTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.connector.basic; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.eclipse.aether.internal.test.util.TestFileUtils; +import org.eclipse.aether.spi.connector.layout.RepositoryLayout; +import org.junit.Before; +import org.junit.Test; + +public class ChecksumCalculatorTest +{ + + private static final String SHA1 = "SHA-1"; + + private static final String MD5 = "MD5"; + + private File file; + + private ChecksumCalculator newCalculator( String... algos ) + { + List checksums = new ArrayList(); + for ( String algo : algos ) + { + checksums.add( new RepositoryLayout.Checksum( algo, URI.create( "irrelevant" ) ) ); + } + return ChecksumCalculator.newInstance( file, checksums ); + } + + private ByteBuffer toBuffer( String data ) + { + try + { + return ByteBuffer.wrap( data.getBytes( "UTF-8" ) ); + } + catch ( UnsupportedEncodingException e ) + { + throw new IllegalStateException( e ); + } + } + + @Before + public void init() + throws Exception + { + file = TestFileUtils.createTempFile( "Hello World!" ); + } + + @Test + public void testNoOffset() + { + ChecksumCalculator calculator = newCalculator( SHA1, MD5 ); + calculator.init( 0 ); + calculator.update( toBuffer( "Hello World!" ) ); + Map digests = calculator.get(); + assertNotNull( digests ); + assertEquals( "2ef7bde608ce5404e97d5f042f95f89f1c232871", digests.get( SHA1 ) ); + assertEquals( "ed076287532e86365e841e92bfc50d8c", digests.get( MD5 ) ); + assertEquals( 2, digests.size() ); + } + + @Test + public void testWithOffset() + { + ChecksumCalculator calculator = newCalculator( SHA1, MD5 ); + calculator.init( 6 ); + calculator.update( toBuffer( "World!" ) ); + Map digests = calculator.get(); + assertNotNull( digests ); + assertEquals( "2ef7bde608ce5404e97d5f042f95f89f1c232871", digests.get( SHA1 ) ); + assertEquals( "ed076287532e86365e841e92bfc50d8c", digests.get( MD5 ) ); + assertEquals( 2, digests.size() ); + } + + @Test + public void testWithExcessiveOffset() + { + ChecksumCalculator calculator = newCalculator( SHA1, MD5 ); + calculator.init( 100 ); + calculator.update( toBuffer( "World!" ) ); + Map digests = calculator.get(); + assertNotNull( digests ); + assertTrue( digests.get( SHA1 ) instanceof IOException ); + assertTrue( digests.get( MD5 ) instanceof IOException ); + assertEquals( 2, digests.size() ); + } + + @Test + public void testUnknownAlgorithm() + { + ChecksumCalculator calculator = newCalculator( "unknown", SHA1 ); + calculator.init( 0 ); + calculator.update( toBuffer( "Hello World!" ) ); + Map digests = calculator.get(); + assertNotNull( digests ); + assertEquals( "2ef7bde608ce5404e97d5f042f95f89f1c232871", digests.get( SHA1 ) ); + assertTrue( digests.get( "unknown" ) instanceof NoSuchAlgorithmException ); + assertEquals( 2, digests.size() ); + } + + @Test + public void testNoInitCall() + { + ChecksumCalculator calculator = newCalculator( SHA1, MD5 ); + calculator.update( toBuffer( "Hello World!" ) ); + Map digests = calculator.get(); + assertNotNull( digests ); + assertEquals( "2ef7bde608ce5404e97d5f042f95f89f1c232871", digests.get( SHA1 ) ); + assertEquals( "ed076287532e86365e841e92bfc50d8c", digests.get( MD5 ) ); + assertEquals( 2, digests.size() ); + } + + @Test + public void testRestart() + { + ChecksumCalculator calculator = newCalculator( SHA1, MD5 ); + calculator.init( 0 ); + calculator.update( toBuffer( "Ignored" ) ); + calculator.init( 0 ); + calculator.update( toBuffer( "Hello World!" ) ); + Map digests = calculator.get(); + assertNotNull( digests ); + assertEquals( "2ef7bde608ce5404e97d5f042f95f89f1c232871", digests.get( SHA1 ) ); + assertEquals( "ed076287532e86365e841e92bfc50d8c", digests.get( MD5 ) ); + assertEquals( 2, digests.size() ); + } + + @Test + public void testRestartAfterError() + { + ChecksumCalculator calculator = newCalculator( SHA1, MD5 ); + calculator.init( 100 ); + calculator.init( 0 ); + calculator.update( toBuffer( "Hello World!" ) ); + Map digests = calculator.get(); + assertNotNull( digests ); + assertEquals( "2ef7bde608ce5404e97d5f042f95f89f1c232871", digests.get( SHA1 ) ); + assertEquals( "ed076287532e86365e841e92bfc50d8c", digests.get( MD5 ) ); + assertEquals( 2, digests.size() ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumValidatorTest.java eclipse-aether-1.0.2/aether-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumValidatorTest.java --- eclipse-aether-0.9.0.M2/aether-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumValidatorTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumValidatorTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,456 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.connector.basic; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.aether.internal.test.util.TestFileProcessor; +import org.eclipse.aether.internal.test.util.TestFileUtils; +import org.eclipse.aether.internal.test.util.TestLoggerFactory; +import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy; +import org.eclipse.aether.spi.connector.layout.RepositoryLayout; +import org.eclipse.aether.transfer.ChecksumFailureException; +import org.junit.Before; +import org.junit.Test; + +public class ChecksumValidatorTest +{ + + private static class StubChecksumPolicy + implements ChecksumPolicy + { + + boolean inspectAll; + + boolean tolerateFailure; + + private List callbacks = new ArrayList(); + + private Object conclusion; + + public boolean onChecksumMatch( String algorithm, int kind ) + { + callbacks.add( String.format( "match(%s, %04x)", algorithm, kind ) ); + if ( inspectAll ) + { + if ( conclusion == null ) + { + conclusion = true; + } + return false; + } + return true; + } + + public void onChecksumMismatch( String algorithm, int kind, ChecksumFailureException exception ) + throws ChecksumFailureException + { + callbacks.add( String.format( "mismatch(%s, %04x)", algorithm, kind ) ); + if ( inspectAll ) + { + conclusion = exception; + return; + } + throw exception; + } + + public void onChecksumError( String algorithm, int kind, ChecksumFailureException exception ) + throws ChecksumFailureException + { + callbacks.add( String.format( "error(%s, %04x, %s)", algorithm, kind, exception.getCause().getMessage() ) ); + } + + public void onNoMoreChecksums() + throws ChecksumFailureException + { + callbacks.add( String.format( "noMore()" ) ); + if ( conclusion instanceof ChecksumFailureException ) + { + throw (ChecksumFailureException) conclusion; + } + else if ( !Boolean.TRUE.equals( conclusion ) ) + { + throw new ChecksumFailureException( "no checksums" ); + } + } + + public void onTransferRetry() + { + callbacks.add( String.format( "retry()" ) ); + } + + public boolean onTransferChecksumFailure( ChecksumFailureException exception ) + { + callbacks.add( String.format( "fail(%s)", exception.getMessage() ) ); + return tolerateFailure; + } + + void assertCallbacks( String... callbacks ) + { + assertEquals( Arrays.asList( callbacks ), this.callbacks ); + } + + } + + private static class StubChecksumFetcher + implements ChecksumValidator.ChecksumFetcher + { + + Map checksums = new HashMap(); + + List checksumFiles = new ArrayList(); + + private List fetchedFiles = new ArrayList(); + + public boolean fetchChecksum( URI remote, File local ) + throws Exception + { + fetchedFiles.add( remote ); + Object checksum = checksums.get( remote ); + if ( checksum == null ) + { + return false; + } + if ( checksum instanceof Exception ) + { + throw (Exception) checksum; + } + TestFileUtils.writeString( local, checksum.toString() ); + checksumFiles.add( local ); + return true; + } + + void mock( String algo, Object value ) + { + checksums.put( toUri( algo ), value ); + } + + void assertFetchedFiles( String... algos ) + { + List expected = new ArrayList(); + for ( String algo : algos ) + { + expected.add( toUri( algo ) ); + } + assertEquals( expected, fetchedFiles ); + } + + private static URI toUri( String algo ) + { + return newChecksum( algo ).getLocation(); + } + + } + + private static final String SHA1 = "SHA-1"; + + private static final String MD5 = "MD5"; + + private StubChecksumPolicy policy; + + private StubChecksumFetcher fetcher; + + private File dataFile; + + private static RepositoryLayout.Checksum newChecksum( String algo ) + { + return RepositoryLayout.Checksum.forLocation( URI.create( "file" ), algo ); + } + + private List newChecksums( String... algos ) + { + List checksums = new ArrayList(); + for ( String algo : algos ) + { + checksums.add( newChecksum( algo ) ); + } + return checksums; + } + + private ChecksumValidator newValidator( String... algos ) + { + return new ChecksumValidator( new TestLoggerFactory().getLogger( "" ), dataFile, new TestFileProcessor(), + fetcher, policy, newChecksums( algos ) ); + } + + private Map checksums( String... algoDigestPairs ) + { + Map checksums = new LinkedHashMap(); + for ( int i = 0; i < algoDigestPairs.length; i += 2 ) + { + String algo = algoDigestPairs[i]; + String digest = algoDigestPairs[i + 1]; + if ( digest == null ) + { + checksums.put( algo, new IOException( "error" ) ); + } + else + { + checksums.put( algo, digest ); + } + } + return checksums; + } + + @Before + public void init() + throws Exception + { + dataFile = TestFileUtils.createTempFile( "" ); + dataFile.delete(); + policy = new StubChecksumPolicy(); + fetcher = new StubChecksumFetcher(); + } + + @Test + public void testValidate_NullPolicy() + throws Exception + { + policy = null; + ChecksumValidator validator = newValidator( SHA1 ); + validator.validate( checksums( SHA1, "ignored" ), null ); + fetcher.assertFetchedFiles(); + } + + @Test + public void testValidate_AcceptOnFirstMatch() + throws Exception + { + ChecksumValidator validator = newValidator( SHA1 ); + fetcher.mock( SHA1, "foo" ); + validator.validate( checksums( SHA1, "foo" ), null ); + fetcher.assertFetchedFiles( SHA1 ); + policy.assertCallbacks( "match(SHA-1, 0000)" ); + } + + @Test + public void testValidate_FailOnFirstMismatch() + throws Exception + { + ChecksumValidator validator = newValidator( SHA1 ); + fetcher.mock( SHA1, "foo" ); + try + { + validator.validate( checksums( SHA1, "not-foo" ), null ); + fail( "expected exception" ); + } + catch ( ChecksumFailureException e ) + { + assertEquals( "foo", e.getExpected() ); + assertEquals( "not-foo", e.getActual() ); + assertTrue( e.isRetryWorthy() ); + } + fetcher.assertFetchedFiles( SHA1 ); + policy.assertCallbacks( "mismatch(SHA-1, 0000)" ); + } + + @Test + public void testValidate_AcceptOnEnd() + throws Exception + { + policy.inspectAll = true; + ChecksumValidator validator = newValidator( SHA1, MD5 ); + fetcher.mock( SHA1, "foo" ); + fetcher.mock( MD5, "bar" ); + validator.validate( checksums( SHA1, "foo", MD5, "bar" ), null ); + fetcher.assertFetchedFiles( SHA1, MD5 ); + policy.assertCallbacks( "match(SHA-1, 0000)", "match(MD5, 0000)", "noMore()" ); + } + + @Test + public void testValidate_FailOnEnd() + throws Exception + { + policy.inspectAll = true; + ChecksumValidator validator = newValidator( SHA1, MD5 ); + fetcher.mock( SHA1, "foo" ); + fetcher.mock( MD5, "bar" ); + try + { + validator.validate( checksums( SHA1, "not-foo", MD5, "bar" ), null ); + fail( "expected exception" ); + } + catch ( ChecksumFailureException e ) + { + assertEquals( "foo", e.getExpected() ); + assertEquals( "not-foo", e.getActual() ); + assertTrue( e.isRetryWorthy() ); + } + fetcher.assertFetchedFiles( SHA1, MD5 ); + policy.assertCallbacks( "mismatch(SHA-1, 0000)", "match(MD5, 0000)", "noMore()" ); + } + + @Test + public void testValidate_InlinedBeforeExternal() + throws Exception + { + policy.inspectAll = true; + ChecksumValidator validator = newValidator( SHA1, MD5 ); + fetcher.mock( SHA1, "foo" ); + fetcher.mock( MD5, "bar" ); + validator.validate( checksums( SHA1, "foo", MD5, "bar" ), checksums( SHA1, "foo", MD5, "bar" ) ); + fetcher.assertFetchedFiles( SHA1, MD5 ); + policy.assertCallbacks( "match(SHA-1, 0001)", "match(MD5, 0001)", "match(SHA-1, 0000)", "match(MD5, 0000)", + "noMore()" ); + } + + @Test + public void testValidate_CaseInsensitive() + throws Exception + { + policy.inspectAll = true; + ChecksumValidator validator = newValidator( SHA1 ); + fetcher.mock( SHA1, "FOO" ); + validator.validate( checksums( SHA1, "foo" ), checksums( SHA1, "foo" ) ); + policy.assertCallbacks( "match(SHA-1, 0001)", "match(SHA-1, 0000)", "noMore()" ); + } + + @Test + public void testValidate_MissingRemoteChecksum() + throws Exception + { + ChecksumValidator validator = newValidator( SHA1, MD5 ); + fetcher.mock( MD5, "bar" ); + validator.validate( checksums( MD5, "bar" ), null ); + fetcher.assertFetchedFiles( SHA1, MD5 ); + policy.assertCallbacks( "match(MD5, 0000)" ); + } + + @Test + public void testValidate_InaccessibleRemoteChecksum() + throws Exception + { + ChecksumValidator validator = newValidator( SHA1, MD5 ); + fetcher.mock( SHA1, new IOException( "inaccessible" ) ); + fetcher.mock( MD5, "bar" ); + validator.validate( checksums( MD5, "bar" ), null ); + fetcher.assertFetchedFiles( SHA1, MD5 ); + policy.assertCallbacks( "error(SHA-1, 0000, inaccessible)", "match(MD5, 0000)" ); + } + + @Test + public void testValidate_InaccessibleLocalChecksum() + throws Exception + { + ChecksumValidator validator = newValidator( SHA1, MD5 ); + fetcher.mock( SHA1, "foo" ); + fetcher.mock( MD5, "bar" ); + validator.validate( checksums( SHA1, null, MD5, "bar" ), null ); + fetcher.assertFetchedFiles( MD5 ); + policy.assertCallbacks( "error(SHA-1, 0000, error)", "match(MD5, 0000)" ); + } + + @Test + public void testHandle_Accept() + throws Exception + { + policy.tolerateFailure = true; + ChecksumValidator validator = newValidator( SHA1 ); + assertEquals( true, validator.handle( new ChecksumFailureException( "accept" ) ) ); + policy.assertCallbacks( "fail(accept)" ); + } + + @Test + public void testHandle_Reject() + throws Exception + { + policy.tolerateFailure = false; + ChecksumValidator validator = newValidator( SHA1 ); + assertEquals( false, validator.handle( new ChecksumFailureException( "reject" ) ) ); + policy.assertCallbacks( "fail(reject)" ); + } + + @Test + public void testRetry_ResetPolicy() + throws Exception + { + ChecksumValidator validator = newValidator( SHA1 ); + validator.retry(); + policy.assertCallbacks( "retry()" ); + } + + @Test + public void testRetry_RemoveTempFiles() + throws Exception + { + ChecksumValidator validator = newValidator( SHA1 ); + fetcher.mock( SHA1, "foo" ); + validator.validate( checksums( SHA1, "foo" ), null ); + fetcher.assertFetchedFiles( SHA1 ); + assertEquals( 1, fetcher.checksumFiles.size() ); + for ( File file : fetcher.checksumFiles ) + { + assertTrue( file.getAbsolutePath(), file.isFile() ); + } + validator.retry(); + for ( File file : fetcher.checksumFiles ) + { + assertFalse( file.getAbsolutePath(), file.exists() ); + } + } + + @Test + public void testCommit_SaveChecksumFiles() + throws Exception + { + policy.inspectAll = true; + ChecksumValidator validator = newValidator( SHA1, MD5 ); + fetcher.mock( MD5, "bar" ); + validator.validate( checksums( SHA1, "foo", MD5, "bar" ), checksums( SHA1, "foo" ) ); + assertEquals( 1, fetcher.checksumFiles.size() ); + for ( File file : fetcher.checksumFiles ) + { + assertTrue( file.getAbsolutePath(), file.isFile() ); + } + validator.commit(); + File checksumFile = new File( dataFile.getPath() + ".sha1" ); + assertTrue( checksumFile.getAbsolutePath(), checksumFile.isFile() ); + assertEquals( "foo", TestFileUtils.readString( checksumFile ) ); + checksumFile = new File( dataFile.getPath() + ".md5" ); + assertTrue( checksumFile.getAbsolutePath(), checksumFile.isFile() ); + assertEquals( "bar", TestFileUtils.readString( checksumFile ) ); + for ( File file : fetcher.checksumFiles ) + { + assertFalse( file.getAbsolutePath(), file.exists() ); + } + } + + @Test + public void testClose_RemoveTempFiles() + throws Exception + { + ChecksumValidator validator = newValidator( SHA1 ); + fetcher.mock( SHA1, "foo" ); + validator.validate( checksums( SHA1, "foo" ), null ); + fetcher.assertFetchedFiles( SHA1 ); + assertEquals( 1, fetcher.checksumFiles.size() ); + for ( File file : fetcher.checksumFiles ) + { + assertTrue( file.getAbsolutePath(), file.isFile() ); + } + validator.close(); + for ( File file : fetcher.checksumFiles ) + { + assertFalse( file.getAbsolutePath(), file.exists() ); + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-basic/src/test/java/org/eclipse/aether/connector/basic/PartialFileTest.java eclipse-aether-1.0.2/aether-connector-basic/src/test/java/org/eclipse/aether/connector/basic/PartialFileTest.java --- eclipse-aether-0.9.0.M2/aether-connector-basic/src/test/java/org/eclipse/aether/connector/basic/PartialFileTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-basic/src/test/java/org/eclipse/aether/connector/basic/PartialFileTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,318 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.connector.basic; + +import static org.junit.Assert.*; +import static org.junit.Assume.*; + +import java.io.Closeable; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.channels.FileLock; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.CountDownLatch; + +import org.eclipse.aether.internal.test.util.TestFileUtils; +import org.eclipse.aether.internal.test.util.TestLoggerFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class PartialFileTest +{ + + private static class StubRemoteAccessChecker + implements PartialFile.RemoteAccessChecker + { + + Exception exception; + + int invocations; + + public void checkRemoteAccess() + throws Exception + { + invocations++; + if ( exception != null ) + { + throw exception; + } + } + + } + + private static class ConcurrentWriter + extends Thread + { + + private final File dstFile; + + private final File partFile; + + private final File lockFile; + + private final CountDownLatch locked; + + private final int sleep; + + volatile int length; + + Exception error; + + public ConcurrentWriter( File dstFile, int sleep, int length ) + throws InterruptedException + { + super( "ConcurrentWriter-" + dstFile.getAbsolutePath() ); + this.dstFile = dstFile; + partFile = new File( dstFile.getPath() + PartialFile.EXT_PART ); + lockFile = new File( partFile.getPath() + PartialFile.EXT_LOCK ); + this.sleep = sleep; + this.length = length; + locked = new CountDownLatch( 1 ); + start(); + locked.await(); + } + + @Override + public void run() + { + try + { + RandomAccessFile raf = new RandomAccessFile( lockFile, "rw" ); + try + { + FileLock lock = raf.getChannel().lock( 0, 1, false ); + locked.countDown(); + FileOutputStream fos = new FileOutputStream( partFile ); + try + { + for ( int i = 0, n = Math.abs( length ); i < n; i++ ) + { + for ( long start = System.currentTimeMillis(); System.currentTimeMillis() - start < sleep; ) + { + Thread.sleep( 10 ); + } + fos.write( 65 ); + fos.flush(); + System.out.println( " " + System.currentTimeMillis() + " Wrote byte " + ( i + 1 ) + "/" + + n ); + } + if ( length >= 0 && !dstFile.setLastModified( System.currentTimeMillis() ) ) + { + throw new IOException( "Could not update destination file" ); + } + } + finally + { + fos.close(); + } + lock.release(); + } + finally + { + raf.close(); + lockFile.delete(); + } + } + catch ( Exception e ) + { + error = e; + } + } + + } + + private static final boolean PROPER_LOCK_SUPPORT; + + static + { + String javaVersion = System.getProperty( "java.version" ).trim(); + boolean notJava5 = !javaVersion.startsWith( "1.5." ); + String osName = System.getProperty( "os.name" ).toLowerCase( Locale.ENGLISH ); + boolean windows = osName.contains( "windows" ); + PROPER_LOCK_SUPPORT = notJava5 || windows; + } + + private StubRemoteAccessChecker remoteAccessChecker; + + private File dstFile; + + private File partFile; + + private File lockFile; + + private List closeables; + + private PartialFile newPartialFile( long resumeThreshold, int requestTimeout ) + throws Exception + { + PartialFile.Factory factory = + new PartialFile.Factory( resumeThreshold >= 0, resumeThreshold, requestTimeout, + new TestLoggerFactory().getLogger( "" ) ); + PartialFile partFile = factory.newInstance( dstFile, remoteAccessChecker ); + if ( partFile != null ) + { + closeables.add( partFile ); + } + return partFile; + } + + @Before + public void init() + throws Exception + { + closeables = new ArrayList(); + remoteAccessChecker = new StubRemoteAccessChecker(); + dstFile = TestFileUtils.createTempFile( "Hello World!" ); + partFile = new File( dstFile.getPath() + PartialFile.EXT_PART ); + lockFile = new File( partFile.getPath() + PartialFile.EXT_LOCK ); + } + + @After + public void exit() + { + for ( Closeable closeable : closeables ) + { + try + { + closeable.close(); + } + catch ( Exception e ) + { + e.printStackTrace(); + } + } + } + + @Test + public void testCloseNonResumableFile() + throws Exception + { + PartialFile partialFile = newPartialFile( -1, 100 ); + assertNotNull( partialFile ); + assertNotNull( partialFile.getFile() ); + assertTrue( partialFile.getFile().getAbsolutePath(), partialFile.getFile().isFile() ); + partialFile.close(); + assertFalse( partialFile.getFile().getAbsolutePath(), partialFile.getFile().exists() ); + } + + @Test + public void testCloseResumableFile() + throws Exception + { + PartialFile partialFile = newPartialFile( 0, 100 ); + assertNotNull( partialFile ); + assertNotNull( partialFile.getFile() ); + assertTrue( partialFile.getFile().getAbsolutePath(), partialFile.getFile().isFile() ); + assertEquals( partFile, partialFile.getFile() ); + assertTrue( lockFile.getAbsolutePath(), lockFile.isFile() ); + partialFile.close(); + assertTrue( partialFile.getFile().getAbsolutePath(), partialFile.getFile().isFile() ); + assertFalse( lockFile.getAbsolutePath(), lockFile.exists() ); + } + + @Test + public void testResumableFileCreationError() + throws Exception + { + assertTrue( partFile.getAbsolutePath(), partFile.mkdirs() ); + PartialFile partialFile = newPartialFile( 0, 100 ); + assertNotNull( partialFile ); + assertFalse( partialFile.isResume() ); + assertFalse( lockFile.getAbsolutePath(), lockFile.exists() ); + } + + @Test + public void testResumeThreshold() + throws Exception + { + PartialFile partialFile = newPartialFile( 0, 100 ); + assertNotNull( partialFile ); + assertTrue( partialFile.isResume() ); + partialFile.close(); + partialFile = newPartialFile( 1, 100 ); + assertNotNull( partialFile ); + assertFalse( partialFile.isResume() ); + partialFile.close(); + } + + @Test( timeout = 10000 ) + public void testResumeConcurrently_RequestTimeout() + throws Exception + { + assumeTrue( PROPER_LOCK_SUPPORT ); + ConcurrentWriter writer = new ConcurrentWriter( dstFile, 5 * 1000, 1 ); + try + { + newPartialFile( 0, 1000 ); + fail( "expected exception" ); + } + catch ( Exception e ) + { + assertTrue( e.getMessage().contains( "Timeout" ) ); + } + writer.interrupt(); + writer.join(); + } + + @Test( timeout = 10000 ) + public void testResumeConcurrently_AwaitCompletion_ConcurrentWriterSucceeds() + throws Exception + { + assumeTrue( PROPER_LOCK_SUPPORT ); + assertTrue( dstFile.setLastModified( System.currentTimeMillis() - 60 * 1000 ) ); + ConcurrentWriter writer = new ConcurrentWriter( dstFile, 100, 10 ); + assertNull( newPartialFile( 0, 500 ) ); + writer.join(); + assertNull( writer.error ); + assertEquals( 1, remoteAccessChecker.invocations ); + } + + @Test( timeout = 10000 ) + public void testResumeConcurrently_AwaitCompletion_ConcurrentWriterFails() + throws Exception + { + assumeTrue( PROPER_LOCK_SUPPORT ); + assertTrue( dstFile.setLastModified( System.currentTimeMillis() - 60 * 1000 ) ); + ConcurrentWriter writer = new ConcurrentWriter( dstFile, 100, -10 ); + PartialFile partialFile = newPartialFile( 0, 500 ); + assertNotNull( partialFile ); + assertTrue( partialFile.isResume() ); + writer.join(); + assertNull( writer.error ); + assertEquals( 1, remoteAccessChecker.invocations ); + } + + @Test( timeout = 10000 ) + public void testResumeConcurrently_CheckRemoteAccess() + throws Exception + { + assumeTrue( PROPER_LOCK_SUPPORT ); + remoteAccessChecker.exception = new IOException( "missing" ); + ConcurrentWriter writer = new ConcurrentWriter( dstFile, 1000, 1 ); + try + { + newPartialFile( 0, 1000 ); + fail( "expected exception" ); + } + catch ( Exception e ) + { + assertSame( remoteAccessChecker.exception, e ); + } + writer.interrupt(); + writer.join(); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-file/pom.xml eclipse-aether-1.0.2/aether-connector-file/pom.xml --- eclipse-aether-0.9.0.M2/aether-connector-file/pom.xml 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-file/pom.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ - - - - - - 4.0.0 - - - org.eclipse.aether - aether - 0.9.0.M2 - - - aether-connector-file - - Aether Connector File - - A repository connector implementation for repositories using file:// URLs. - - - - org.eclipse.aether.connector.file - - - - - org.eclipse.aether - aether-api - - - org.eclipse.aether - aether-spi - - - org.eclipse.aether - aether-util - - - javax.inject - javax.inject - provided - true - - - org.codehaus.plexus - plexus-component-annotations - provided - true - - - org.sonatype.sisu - sisu-inject-plexus - test - - - junit - junit - test - - - org.eclipse.aether - aether-test-util - test - - - - - - - org.codehaus.mojo - animal-sniffer-maven-plugin - - - org.codehaus.plexus - plexus-component-metadata - - - org.sonatype.plugins - sisu-maven-plugin - - - org.apache.felix - maven-bundle-plugin - - - - diff -Nru eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/FileRepositoryConnectorFactory.java eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/FileRepositoryConnectorFactory.java --- eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/FileRepositoryConnectorFactory.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/FileRepositoryConnectorFactory.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.file; - -import javax.inject.Inject; -import javax.inject.Named; - -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; -import org.eclipse.aether.spi.io.FileProcessor; -import org.eclipse.aether.spi.locator.Service; -import org.eclipse.aether.spi.locator.ServiceLocator; -import org.eclipse.aether.spi.log.Logger; -import org.eclipse.aether.spi.log.LoggerFactory; -import org.eclipse.aether.spi.log.NullLoggerFactory; -import org.eclipse.aether.transfer.NoRepositoryConnectorException; - -/** - * Factory to create repository connectors for use with the {@code file} protocol. - */ -@Named -@Component( role = RepositoryConnectorFactory.class, hint = "file" ) -public final class FileRepositoryConnectorFactory - implements RepositoryConnectorFactory, Service -{ - - @Requirement( role = LoggerFactory.class ) - private Logger logger = NullLoggerFactory.LOGGER; - - @Requirement - private FileProcessor fileProcessor; - - private float priority = 1; - - static final String CFG_PREFIX = "aether.connector.file"; - - /** - * Creates an (uninitialized) instance of this connector factory. Note: In case of manual instantiation by - * clients, the new factory needs to be configured via its various mutators before first use or runtime errors will - * occur. - */ - public FileRepositoryConnectorFactory() - { - // enables default constructor - } - - @Inject - FileRepositoryConnectorFactory( FileProcessor fileProcessor, LoggerFactory loggerFactory ) - { - setFileProcessor( fileProcessor ); - setLoggerFactory( loggerFactory ); - } - - public void initService( ServiceLocator locator ) - { - setLoggerFactory( locator.getService( LoggerFactory.class ) ); - setFileProcessor( locator.getService( FileProcessor.class ) ); - } - - /** - * Sets the logger factory to use for this component. - * - * @param loggerFactory The logger factory to use, may be {@code null} to disable logging. - * @return This component for chaining, never {@code null}. - */ - public FileRepositoryConnectorFactory setLoggerFactory( LoggerFactory loggerFactory ) - { - this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, FileRepositoryConnector.class ); - return this; - } - - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - - /** - * Sets the file processor to use for this component. - * - * @param fileProcessor The file processor to use, must not be {@code null}. - * @return This component for chaining, never {@code null}. - */ - public FileRepositoryConnectorFactory setFileProcessor( FileProcessor fileProcessor ) - { - if ( fileProcessor == null ) - { - throw new IllegalArgumentException( "file processor has not been specified" ); - } - this.fileProcessor = fileProcessor; - return this; - } - - public RepositoryConnector newInstance( RepositorySystemSession session, RemoteRepository repository ) - throws NoRepositoryConnectorException - { - if ( "file".equalsIgnoreCase( repository.getProtocol() ) ) - { - FileRepositoryConnector connector = - new FileRepositoryConnector( session, repository, fileProcessor, logger ); - return connector; - } - - throw new NoRepositoryConnectorException( repository ); - } - - public float getPriority() - { - return priority; - } - - /** - * Sets the priority of this component. - * - * @param priority The priority. - * @return This component for chaining, never {@code null}. - */ - public FileRepositoryConnectorFactory setPriority( float priority ) - { - this.priority = priority; - return this; - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/FileRepositoryConnector.java eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/FileRepositoryConnector.java --- eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/FileRepositoryConnector.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/FileRepositoryConnector.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,130 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.file; - -import java.util.Collection; -import java.util.Collections; - -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.spi.connector.ArtifactDownload; -import org.eclipse.aether.spi.connector.ArtifactUpload; -import org.eclipse.aether.spi.connector.MetadataDownload; -import org.eclipse.aether.spi.connector.MetadataUpload; -import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.aether.spi.io.FileProcessor; -import org.eclipse.aether.spi.log.Logger; -import org.eclipse.aether.spi.log.NullLoggerFactory; -import org.eclipse.aether.transfer.NoRepositoryConnectorException; -import org.eclipse.aether.util.concurrency.RunnableErrorForwarder; - -/** - * A connector for file://-URLs. - */ -class FileRepositoryConnector - extends ParallelRepositoryConnector - implements RepositoryConnector -{ - - private RemoteRepository repository; - - private RepositorySystemSession session; - - private Logger logger = NullLoggerFactory.LOGGER; - - private FileProcessor fileProcessor; - - public FileRepositoryConnector( RepositorySystemSession session, RemoteRepository repository, - FileProcessor fileProcessor, Logger logger ) - throws NoRepositoryConnectorException - { - if ( !"default".equals( repository.getContentType() ) ) - { - throw new NoRepositoryConnectorException( repository ); - } - - this.session = session; - this.repository = repository; - this.fileProcessor = fileProcessor; - this.logger = logger; - - initExecutor( session.getConfigProperties() ); - } - - public void get( Collection artifactDownloads, - Collection metadataDownloads ) - { - checkClosed(); - - artifactDownloads = notNull( artifactDownloads ); - metadataDownloads = notNull( metadataDownloads ); - - RunnableErrorForwarder errorForwarder = new RunnableErrorForwarder(); - - for ( ArtifactDownload artifactDownload : artifactDownloads ) - { - FileRepositoryWorker worker = new FileRepositoryWorker( artifactDownload, repository, session ); - worker.setLogger( logger ); - worker.setFileProcessor( fileProcessor ); - executor.execute( errorForwarder.wrap( worker ) ); - } - - for ( MetadataDownload metadataDownload : metadataDownloads ) - { - FileRepositoryWorker worker = new FileRepositoryWorker( metadataDownload, repository, session ); - worker.setLogger( logger ); - worker.setFileProcessor( fileProcessor ); - executor.execute( errorForwarder.wrap( worker ) ); - } - - errorForwarder.await(); - } - - private Collection notNull( Collection col ) - { - return col == null ? Collections. emptyList() : col; - } - - public void put( Collection artifactUploads, - Collection metadataUploads ) - { - checkClosed(); - - artifactUploads = notNull( artifactUploads ); - metadataUploads = notNull( metadataUploads ); - - RunnableErrorForwarder errorForwarder = new RunnableErrorForwarder(); - - for ( ArtifactUpload artifactUpload : artifactUploads ) - { - FileRepositoryWorker worker = new FileRepositoryWorker( artifactUpload, repository, session ); - worker.setLogger( logger ); - worker.setFileProcessor( fileProcessor ); - executor.execute( errorForwarder.wrap( worker ) ); - } - for ( MetadataUpload metadataUpload : metadataUploads ) - { - FileRepositoryWorker worker = new FileRepositoryWorker( metadataUpload, repository, session ); - worker.setLogger( logger ); - worker.setFileProcessor( fileProcessor ); - executor.execute( errorForwarder.wrap( worker ) ); - } - - errorForwarder.await(); - } - - @Override - public String toString() - { - return String.valueOf( repository ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/FileRepositoryWorker.java eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/FileRepositoryWorker.java --- eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/FileRepositoryWorker.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/FileRepositoryWorker.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,453 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.file; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.nio.ByteBuffer; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; - -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.metadata.Metadata; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.repository.RepositoryPolicy; -import org.eclipse.aether.spi.connector.ArtifactDownload; -import org.eclipse.aether.spi.connector.ArtifactUpload; -import org.eclipse.aether.spi.connector.MetadataDownload; -import org.eclipse.aether.spi.connector.MetadataUpload; -import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.aether.spi.connector.Transfer; -import org.eclipse.aether.spi.connector.Transfer.State; -import org.eclipse.aether.spi.io.FileProcessor; -import org.eclipse.aether.spi.log.Logger; -import org.eclipse.aether.spi.log.NullLoggerFactory; -import org.eclipse.aether.transfer.ArtifactNotFoundException; -import org.eclipse.aether.transfer.ArtifactTransferException; -import org.eclipse.aether.transfer.ChecksumFailureException; -import org.eclipse.aether.transfer.MetadataNotFoundException; -import org.eclipse.aether.transfer.MetadataTransferException; -import org.eclipse.aether.transfer.TransferCancelledException; -import org.eclipse.aether.transfer.TransferEvent; -import org.eclipse.aether.transfer.TransferEvent.RequestType; -import org.eclipse.aether.transfer.TransferResource; -import org.eclipse.aether.util.ChecksumUtils; -import org.eclipse.aether.util.repository.layout.MavenDefaultLayout; -import org.eclipse.aether.util.repository.layout.RepositoryLayout; - -/** - * The actual class doing all the work. Handles artifact and metadata up- and downloads. - */ -class FileRepositoryWorker - implements Runnable -{ - - private Logger logger = NullLoggerFactory.LOGGER; - - private FileProcessor fileProcessor; - - private enum Direction - { - UPLOAD, DOWNLOAD; - } - - private static LinkedHashMap checksumAlgos; - - private final RepositoryLayout layout = new MavenDefaultLayout(); - - private final TransferWrapper transfer; - - private final RemoteRepository repository; - - private final TransferEventCatapult catapult; - - private final Direction direction; - - private final TransferResource resource; - - private final TransferEvent.Builder eventBuilder; - - static - { - checksumAlgos = new LinkedHashMap( 4 ); - checksumAlgos.put( "SHA-1", ".sha1" ); - checksumAlgos.put( "MD5", ".md5" ); - } - - private FileRepositoryWorker( TransferWrapper transfer, RemoteRepository repository, Direction direction, - RepositorySystemSession session ) - { - if ( repository == null ) - { - throw new IllegalArgumentException( "RemoteRepository may not be null." ); - } - if ( session == null ) - { - throw new IllegalArgumentException( "RepositorySystemSession may not be null." ); - } - - this.catapult = new TransferEventCatapult( session.getTransferListener() ); - resource = newResource( transfer, repository ); - eventBuilder = new TransferEvent.Builder( session, resource ); - switch ( direction ) - { - case UPLOAD: - eventBuilder.setRequestType( RequestType.PUT ); - break; - case DOWNLOAD: - eventBuilder.setRequestType( transfer.isExistenceCheck() ? RequestType.GET_EXISTENCE : RequestType.GET ); - break; - } - - this.direction = direction; - this.repository = repository; - - this.transfer = transfer; - } - - /** - * Initialize the worker for an artifact upload. - * - * @param transfer The actual {@link Transfer}-object. May not be null. - * @param repository The repository definition. May not be null. - * @param session The current repository system session. May not be null. - */ - public FileRepositoryWorker( ArtifactUpload transfer, RemoteRepository repository, RepositorySystemSession session ) - { - this( new TransferWrapper( transfer ), repository, Direction.UPLOAD, session ); - } - - /** - * Initialize the worker for an artifact download. - * - * @param transfer The actual {@link Transfer}-object. May not be null. - * @param repository The repository definition. May not be null. - * @param session The current repository system session. May not be null. - */ - public FileRepositoryWorker( ArtifactDownload transfer, RemoteRepository repository, RepositorySystemSession session ) - { - this( new TransferWrapper( transfer ), repository, Direction.DOWNLOAD, session ); - } - - /** - * Initialize the worker for an metadata download. - * - * @param transfer The actual {@link Transfer}-object. May not be null. - * @param repository The repository definition. May not be null. - * @param session The current repository system session. May not be null. - */ - public FileRepositoryWorker( MetadataDownload transfer, RemoteRepository repository, RepositorySystemSession session ) - { - this( new TransferWrapper( transfer ), repository, Direction.DOWNLOAD, session ); - } - - /** - * Initialize the worker for an metadata upload. - * - * @param transfer The actual {@link Transfer}-object. May not be null. - * @param repository The repository definition. May not be null. - * @param session The current repository system session. May not be null. - */ - public FileRepositoryWorker( MetadataUpload transfer, RemoteRepository repository, RepositorySystemSession session ) - { - this( new TransferWrapper( transfer ), repository, Direction.UPLOAD, session ); - } - - /** - * Do transfer according to {@link RepositoryConnector} specifications. - * - * @see FileRepositoryConnector - */ - public void run() - { - File target = null; - long totalTransferred = -1; - try - { - transfer.setState( State.ACTIVE ); - TransferEvent.Builder event = newEvent( transfer ); - catapult.fireInitiated( event ); - - File baseDir = new File( PathUtils.basedir( repository.getUrl() ) ); - File localFile = transfer.getFile(); - File repoFile = new File( baseDir, transfer.getRelativePath() ); - File src = null; - - switch ( direction ) - { - case UPLOAD: - src = localFile; - target = repoFile; - break; - case DOWNLOAD: - src = repoFile; - target = localFile; - break; - } - - if ( transfer.isExistenceCheck() ) - { - if ( !src.exists() ) - { - throw new FileNotFoundException( src.getAbsolutePath() ); - } - } - else - { - File tmp = tmpfile( target ); - totalTransferred = copy( src, tmp ); - fileProcessor.move( tmp, target ); - - switch ( direction ) - { - case UPLOAD: - writeChecksum( src, target.getPath() ); - break; - case DOWNLOAD: - verifyChecksum( src ); - break; - } - } - } - catch ( FileNotFoundException e ) - { - switch ( transfer.getType() ) - { - case ARTIFACT: - ArtifactTransferException artEx; - if ( Direction.DOWNLOAD.equals( direction ) ) - { - artEx = new ArtifactNotFoundException( transfer.getArtifact(), repository ); - } - else - { - artEx = new ArtifactTransferException( transfer.getArtifact(), repository, e ); - } - transfer.setException( artEx ); - break; - case METADATA: - MetadataTransferException mdEx; - if ( Direction.DOWNLOAD.equals( direction ) ) - { - mdEx = new MetadataNotFoundException( transfer.getMetadata(), repository ); - } - else - { - mdEx = new MetadataTransferException( transfer.getMetadata(), repository, e ); - } - transfer.setException( mdEx ); - break; - } - - } - catch ( Throwable t ) - { - logger.debug( t.getMessage(), t ); - switch ( transfer.getType() ) - { - case ARTIFACT: - transfer.setException( new ArtifactTransferException( transfer.getArtifact(), repository, t ) ); - break; - case METADATA: - transfer.setException( new MetadataTransferException( transfer.getMetadata(), repository, t ) ); - break; - } - } - finally - { - transfer.setState( State.DONE ); - if ( transfer.getException() == null ) - { - TransferEvent.Builder event = newEvent( transfer ); - event.setTransferredBytes( totalTransferred ); - catapult.fireSucceeded( event ); - } - else - { - // cleanup - if ( direction.equals( Direction.UPLOAD ) ) - { - for ( String ext : checksumAlgos.values() ) - { - new File( target.getPath() + ext ).delete(); - } - } - if ( target != null ) - { - target.delete(); - } - - TransferEvent.Builder event = newEvent( transfer ); - catapult.fireFailed( event ); - } - } - } - - private void writeChecksum( File src, String targetPath ) - throws IOException, Throwable - { - // write checksum files - Map crcs = ChecksumUtils.calc( src, checksumAlgos.keySet() ); - for ( Entry crc : crcs.entrySet() ) - { - String name = crc.getKey(); - Object sum = crc.getValue(); - - if ( sum instanceof Throwable ) - { - throw (Throwable) sum; - } - - File crcTarget = new File( targetPath + checksumAlgos.get( name ) ); - OutputStreamWriter crcWriter = new OutputStreamWriter( new FileOutputStream( crcTarget ), "US-ASCII" ); - crcWriter.write( sum.toString() ); - crcWriter.close(); - } - } - - private void verifyChecksum( File src ) - throws ChecksumFailureException, IOException, TransferCancelledException - { - if ( RepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals( transfer.getChecksumPolicy() ) ) - { - return; - } - Map crcs = ChecksumUtils.calc( src, checksumAlgos.keySet() ); - boolean verified = false; - try - { - for ( Entry entry : checksumAlgos.entrySet() ) - { - try - { - String sum = ChecksumUtils.read( new File( src.getPath() + entry.getValue() ) ); - verified = sum.equalsIgnoreCase( crcs.get( entry.getKey() ).toString() ); - if ( !verified ) - { - throw new ChecksumFailureException( sum, crcs.get( entry.getKey() ).toString() ); - } - break; - } - catch ( IOException e ) - { - // skip verify - try next algorithm - continue; - } - } - - // all algorithms checked - if ( !verified ) - { - throw new ChecksumFailureException( "no supported algorithms found" ); - } - } - catch ( ChecksumFailureException e ) - { - if ( RepositoryPolicy.CHECKSUM_POLICY_FAIL.equals( transfer.getChecksumPolicy() ) ) - { - throw e; - } - - TransferEvent.Builder event = newEvent( transfer ); - event.setException( e ); - catapult.fireCorrupted( event ); - } - } - - private long copy( File src, File target ) - throws TransferCancelledException, IOException - { - if ( src == null ) - { - throw new IllegalArgumentException( "source file not specified" ); - } - if ( !src.isFile() ) - { - throw new FileNotFoundException( src.getAbsolutePath() ); - } - if ( target == null ) - { - throw new IllegalArgumentException( "target file not specified" ); - } - - resource.setContentLength( src.length() ); - TransferEvent.Builder event = newEvent( transfer ); - catapult.fireStarted( event ); - - return fileProcessor.copy( src, target, new FileProcessor.ProgressListener() - { - - int total = 0; - - public void progressed( ByteBuffer buffer ) - throws IOException - { - total += buffer.remaining(); - TransferEvent.Builder event = newEvent( transfer ); - event.setDataBuffer( buffer ).setTransferredBytes( total ); - try - { - catapult.fireProgressed( event ); - } - catch ( TransferCancelledException e ) - { - throw new IOException( "Transfer was cancelled: " + e.getMessage() ); - } - } - } ); - } - - private TransferEvent.Builder newEvent( TransferWrapper transfer ) - { - return eventBuilder.copy().setException( transfer.getException() ); - } - - private TransferResource newResource( TransferWrapper transfer, RemoteRepository repository ) - { - String resourceName = null; - switch ( transfer.getType() ) - { - case ARTIFACT: - Artifact artifact = transfer.getArtifact(); - resourceName = layout.getPath( artifact ).getPath(); - break; - case METADATA: - Metadata metadata = transfer.getMetadata(); - resourceName = layout.getPath( metadata ).getPath(); - break; - } - return new TransferResource( PathUtils.decode( repository.getUrl() ), resourceName, transfer.getFile(), - transfer.getTrace() ); - } - - public void setLogger( Logger logger ) - { - this.logger = logger; - } - - public void setFileProcessor( FileProcessor fileProcessor ) - { - this.fileProcessor = fileProcessor; - } - - private File tmpfile( File target ) - { - return new File( target.getAbsolutePath() + ".tmp" - + UUID.randomUUID().toString().replace( "-", "" ).substring( 0, 16 ) ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/ParallelRepositoryConnector.java eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/ParallelRepositoryConnector.java --- eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/ParallelRepositoryConnector.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/ParallelRepositoryConnector.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.file; - -import static org.eclipse.aether.connector.file.FileRepositoryConnectorFactory.*; - -import java.util.Map; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import org.eclipse.aether.util.ConfigUtils; - -/** - * Provides methods to configure the used {@link ThreadPoolExecutor}. - */ -abstract class ParallelRepositoryConnector -{ - - /* - * Default Configuration - */ - private static final int MAX_POOL_SIZE = 5; - - private boolean closed = false; - - /** - * The executor to use. - * - * @see #initExecutor() - */ - protected Executor executor; - - protected void initExecutor( Map config ) - { - if ( executor == null ) - { - int threads = ConfigUtils.getInteger( config, MAX_POOL_SIZE, CFG_PREFIX + ".threads" ); - - if ( threads <= 1 ) - { - executor = new Executor() - { - public void execute( Runnable command ) - { - command.run(); - } - }; - } - else - { - ThreadFactory threadFactory = new RepositoryConnectorThreadFactory( getClass().getSimpleName() ); - - executor = - new ThreadPoolExecutor( threads, threads, 3, TimeUnit.SECONDS, new LinkedBlockingQueue(), - threadFactory ); - } - } - } - - public void close() - { - this.closed = true; - - if ( executor instanceof ExecutorService ) - { - ( (ExecutorService) executor ).shutdown(); - } - } - - protected void checkClosed() - { - if ( closed ) - { - throw new IllegalStateException( "Connector is closed" ); - } - } - - protected static class RepositoryConnectorThreadFactory - implements ThreadFactory - { - - private final AtomicInteger counter = new AtomicInteger( 1 ); - - private final String threadName; - - public RepositoryConnectorThreadFactory( String threadName ) - { - this.threadName = threadName; - } - - public Thread newThread( Runnable r ) - { - Thread t = new Thread( r, threadName + "-" + counter.getAndIncrement() ); - t.setDaemon( true ); - return t; - } - - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/PathUtils.java eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/PathUtils.java --- eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/PathUtils.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/PathUtils.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,129 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.file; - -/** - * URL handling for file URLs. Based on org.apache.maven.wagon.PathUtils. - */ -final class PathUtils -{ - - private PathUtils() - { - } - - /** - * Return the protocol name.
- * E.g: for input http://www.codehause.org this method will return http - * - * @param url the url - * @return the host name - */ - public static String protocol( final String url ) - { - final int pos = url.indexOf( ":" ); - - if ( pos == -1 ) - { - return ""; - } - return url.substring( 0, pos ).trim(); - } - - /** - * Derive the path portion of the given URL. - * - * @param url the file-repository URL - * @return the basedir of the repository - */ - public static String basedir( String url ) - { - String protocol = PathUtils.protocol( url ); - - String retValue = null; - - if ( protocol.length() > 0 ) - { - retValue = url.substring( protocol.length() + 1 ); - } - else - { - retValue = url; - } - retValue = decode( retValue ); - // special case: if omitted // on protocol, keep path as is - if ( retValue.startsWith( "//" ) ) - { - retValue = retValue.substring( 2 ); - - if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) ) - { - // special case: if there is a windows drive letter, then keep the original return value - retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 ); - } - else - { - // Now we expect the host - int index = retValue.indexOf( "/" ); - if ( index >= 0 ) - { - retValue = retValue.substring( index + 1 ); - } - - // special case: if there is a windows drive letter, then keep the original return value - if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) ) - { - retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 ); - } - else if ( index >= 0 ) - { - // leading / was previously stripped - retValue = "/" + retValue; - } - } - } - - // special case: if there is a windows drive letter using |, switch to : - if ( retValue.length() >= 2 && retValue.charAt( 1 ) == '|' ) - { - retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 ); - } - - return retValue.trim(); - } - - /** - * Decodes the specified (portion of a) URL. Note: This decoder assumes that ISO-8859-1 is used to - * convert URL-encoded octets to characters. - * - * @param url The URL to decode, may be null. - * @return The decoded URL or null if the input was null. - */ - static String decode( String url ) - { - String decoded = url; - if ( url != null ) - { - int pos = -1; - while ( ( pos = decoded.indexOf( '%', pos + 1 ) ) >= 0 ) - { - if ( pos + 2 < decoded.length() ) - { - String hexStr = decoded.substring( pos + 1, pos + 3 ); - char ch = (char) Integer.parseInt( hexStr, 16 ); - decoded = decoded.substring( 0, pos ) + ch + decoded.substring( pos + 3 ); - } - } - } - return decoded; - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/TransferEventCatapult.java eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/TransferEventCatapult.java --- eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/TransferEventCatapult.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/TransferEventCatapult.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.file; - -import org.eclipse.aether.transfer.AbstractTransferListener; -import org.eclipse.aether.transfer.TransferCancelledException; -import org.eclipse.aether.transfer.TransferEvent; -import org.eclipse.aether.transfer.TransferListener; - -/** - * Helper for {@link TransferEvent}-handling. - */ -class TransferEventCatapult -{ - - private TransferListener listener; - - public TransferEventCatapult( TransferListener listener ) - { - if ( listener == null ) - { - this.listener = new NoTransferListener(); - } - else - { - this.listener = listener; - } - } - - protected void fireInitiated( TransferEvent.Builder event ) - throws TransferCancelledException - { - event.setType( TransferEvent.EventType.INITIATED ); - listener.transferInitiated( event.build() ); - } - - protected void fireStarted( TransferEvent.Builder event ) - throws TransferCancelledException - { - event.setType( TransferEvent.EventType.STARTED ); - listener.transferStarted( event.build() ); - } - - protected void fireSucceeded( TransferEvent.Builder event ) - { - event.setType( TransferEvent.EventType.SUCCEEDED ); - listener.transferSucceeded( event.build() ); - } - - protected void fireFailed( TransferEvent.Builder event ) - { - event.setType( TransferEvent.EventType.FAILED ); - listener.transferFailed( event.build() ); - } - - protected void fireCorrupted( TransferEvent.Builder event ) - throws TransferCancelledException - { - event.setType( TransferEvent.EventType.CORRUPTED ); - listener.transferCorrupted( event.build() ); - } - - protected void fireProgressed( TransferEvent.Builder event ) - throws TransferCancelledException - { - event.setType( TransferEvent.EventType.PROGRESSED ); - listener.transferProgressed( event.build() ); - } - - private static final class NoTransferListener - extends AbstractTransferListener - { - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/TransferWrapper.java eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/TransferWrapper.java --- eclipse-aether-0.9.0.M2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/TransferWrapper.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-file/src/main/java/org/eclipse/aether/connector/file/TransferWrapper.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,223 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.file; - -import java.io.File; - -import org.eclipse.aether.RequestTrace; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.metadata.Metadata; -import org.eclipse.aether.spi.connector.ArtifactDownload; -import org.eclipse.aether.spi.connector.ArtifactTransfer; -import org.eclipse.aether.spi.connector.MetadataDownload; -import org.eclipse.aether.spi.connector.MetadataTransfer; -import org.eclipse.aether.spi.connector.Transfer; -import org.eclipse.aether.spi.connector.Transfer.State; -import org.eclipse.aether.transfer.ArtifactTransferException; -import org.eclipse.aether.transfer.MetadataTransferException; -import org.eclipse.aether.util.repository.layout.MavenDefaultLayout; - -/** - * Wrapper object for {@link ArtifactTransfer} and {@link MetadataTransfer} objects. - */ -class TransferWrapper -{ - - public enum Type - { - ARTIFACT, METADATA - } - - private Type type; - - public Type getType() - { - return type; - } - - private MetadataTransfer metadataTransfer; - - private ArtifactTransfer artifactTransfer; - - private Transfer transfer; - - private String checksumPolicy = null; - - private boolean existenceCheck = false; - - public TransferWrapper( ArtifactTransfer transfer ) - { - if ( transfer == null ) - { - throw new IllegalArgumentException( "Transfer may not be null." ); - } - this.artifactTransfer = transfer; - this.transfer = transfer; - this.type = Type.ARTIFACT; - - if ( transfer instanceof ArtifactDownload ) - { - this.checksumPolicy = ( (ArtifactDownload) transfer ).getChecksumPolicy(); - this.existenceCheck = ( (ArtifactDownload) transfer ).isExistenceCheck(); - } - } - - public TransferWrapper( MetadataTransfer transfer ) - { - if ( transfer == null ) - { - throw new IllegalArgumentException( "Transfer may not be null." ); - } - this.metadataTransfer = transfer; - this.transfer = transfer; - this.type = Type.METADATA; - - if ( transfer instanceof MetadataDownload ) - { - this.checksumPolicy = ( (MetadataDownload) transfer ).getChecksumPolicy(); - } - } - - public void setState( State new1 ) - { - transfer.setState( new1 ); - } - - public File getFile() - { - File ret = null; - - if ( metadataTransfer != null ) - { - ret = metadataTransfer.getFile(); - } - else if ( artifactTransfer != null ) - { - ret = artifactTransfer.getFile(); - } - - if ( ret == null ) - { - if ( metadataTransfer != null ) - { - ret = metadataTransfer.getMetadata().getFile(); - } - else if ( artifactTransfer != null ) - { - ret = artifactTransfer.getArtifact().getFile(); - } - } - - return ret; - - } - - public Artifact getArtifact() - { - if ( artifactTransfer != null ) - { - return artifactTransfer.getArtifact(); - } - else - { - throw new IllegalStateException( "TransferWrapper holds the wrong type" ); - } - - } - - public void setException( ArtifactTransferException exception ) - { - if ( artifactTransfer != null ) - { - artifactTransfer.setException( exception ); - } - else - { - throw new IllegalStateException( "TransferWrapper holds the wrong type" ); - } - } - - public void setException( MetadataTransferException exception ) - { - if ( metadataTransfer != null ) - { - metadataTransfer.setException( exception ); - } - else - { - throw new IllegalStateException( "TransferWrapper holds the wrong type" ); - } - } - - public Exception getException() - { - if ( artifactTransfer != null ) - { - return artifactTransfer.getException(); - } - else if ( metadataTransfer != null ) - { - return metadataTransfer.getException(); - } - else - { - throw new IllegalStateException( "TransferWrapper holds the wrong type" ); - } - } - - public Metadata getMetadata() - { - return metadataTransfer.getMetadata(); - } - - public String getChecksumPolicy() - { - return this.checksumPolicy; - } - - public boolean isExistenceCheck() - { - return existenceCheck; - } - - public String getRelativePath() - { - if ( artifactTransfer != null ) - { - return new MavenDefaultLayout().getPath( getArtifact() ).getRawPath(); - } - else if ( metadataTransfer != null ) - { - return new MavenDefaultLayout().getPath( getMetadata() ).getRawPath(); - } - else - { - return null; - } - } - - public RequestTrace getTrace() - { - if ( artifactTransfer != null ) - { - return artifactTransfer.getTrace(); - } - else if ( metadataTransfer != null ) - { - return metadataTransfer.getTrace(); - } - else - { - return null; - } - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-file/src/main/resources/about.html eclipse-aether-1.0.2/aether-connector-file/src/main/resources/about.html --- eclipse-aether-0.9.0.M2/aether-connector-file/src/main/resources/about.html 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-file/src/main/resources/about.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ - - - - -About - - -

About This Content

- -

September 23, 2011

-

License

- -

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise -indicated below, the Content is provided to you under the terms and conditions of the -Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available -at http://www.eclipse.org/legal/epl-v10.html. -For purposes of the EPL, "Program" will mean the Content.

- -

If you did not receive this Content directly from the Eclipse Foundation, the Content is -being redistributed by another party ("Redistributor") and different terms and conditions may -apply to your use of any object code in the Content. Check the Redistributor's license that was -provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise -indicated below, the terms and conditions of the EPL still apply to any source code in the Content -and such source code may be obtained at http://www.eclipse.org.

- - - diff -Nru eclipse-aether-0.9.0.M2/aether-connector-file/src/test/java/org/eclipse/aether/connector/file/ArtifactWorkerTest.java eclipse-aether-1.0.2/aether-connector-file/src/test/java/org/eclipse/aether/connector/file/ArtifactWorkerTest.java --- eclipse-aether-0.9.0.M2/aether-connector-file/src/test/java/org/eclipse/aether/connector/file/ArtifactWorkerTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-file/src/test/java/org/eclipse/aether/connector/file/ArtifactWorkerTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,182 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.file; - -import static org.junit.Assert.*; - -import java.io.File; -import java.io.IOException; -import java.net.URI; - -import org.eclipse.aether.DefaultRepositorySystemSession; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.connector.file.FileRepositoryWorker; -import org.eclipse.aether.internal.test.util.TestFileProcessor; -import org.eclipse.aether.internal.test.util.TestFileUtils; -import org.eclipse.aether.internal.test.util.TestUtils; -import org.eclipse.aether.metadata.DefaultMetadata; -import org.eclipse.aether.metadata.Metadata.Nature; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.repository.RepositoryPolicy; -import org.eclipse.aether.spi.connector.ArtifactDownload; -import org.eclipse.aether.spi.connector.ArtifactUpload; -import org.eclipse.aether.spi.connector.MetadataDownload; -import org.eclipse.aether.spi.connector.MetadataUpload; -import org.eclipse.aether.transfer.ArtifactTransferException; -import org.eclipse.aether.transfer.MetadataTransferException; -import org.eclipse.aether.util.repository.layout.MavenDefaultLayout; -import org.eclipse.aether.util.repository.layout.RepositoryLayout; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class ArtifactWorkerTest -{ - - private RemoteRepository repository; - - private DefaultRepositorySystemSession session; - - private RepositoryLayout layout; - - @Before - public void setup() - throws IOException - { - repository = - new RemoteRepository.Builder( "test", "default", - TestFileUtils.createTempDir( "test-remote-repository" ).toURI().toURL().toString() ).build(); - session = TestUtils.newSession(); - layout = new MavenDefaultLayout(); - } - - @After - public void cleanup() - throws Exception - { - TestFileUtils.delete( new File( new URI( repository.getUrl() ) ) ); - } - - @Test - public void testArtifactTransfer() - throws IOException, ArtifactTransferException - { - DefaultArtifact artifact = new DefaultArtifact( "test", "artId1", "jar", "1" ); - String expectedContent = "Dies ist ein Test."; - - uploadArtifact( artifact, expectedContent ); - - File file = downloadArtifact( artifact ); - - assertContentEquals( file, expectedContent ); - } - - private File downloadArtifact( DefaultArtifact artifact ) - throws IOException, ArtifactTransferException - { - File file = TestFileUtils.createTempFile( "" ); - ArtifactDownload down = new ArtifactDownload( artifact, "", file, "" ); - down.setChecksumPolicy( RepositoryPolicy.CHECKSUM_POLICY_FAIL ); - FileRepositoryWorker worker = new FileRepositoryWorker( down, repository, session ); - worker.setFileProcessor( new TestFileProcessor() ); - worker.run(); - if ( down.getException() != null ) - { - throw down.getException(); - } - return file; - } - - private void uploadArtifact( Artifact artifact, String content ) - throws IOException, ArtifactTransferException - { - File file = TestFileUtils.createTempFile( content ); - - ArtifactUpload transfer = new ArtifactUpload( artifact, file ); - FileRepositoryWorker worker = new FileRepositoryWorker( transfer, repository, session ); - worker.setFileProcessor( new TestFileProcessor() ); - worker.run(); - - TestFileUtils.delete( file ); - if ( transfer.getException() != null ) - { - throw transfer.getException(); - } - } - - @Test - public void testMetadataTransfer() - throws IOException, MetadataTransferException - { - String expectedContent = "Dies ist ein Test."; - File srcFile = TestFileUtils.createTempFile( expectedContent ); - - DefaultMetadata metadata = new DefaultMetadata( "test", "artId1", "1", "jar", Nature.RELEASE_OR_SNAPSHOT ); - MetadataUpload up = new MetadataUpload( metadata, srcFile ); - FileRepositoryWorker worker = new FileRepositoryWorker( up, repository, session ); - worker.setFileProcessor( new TestFileProcessor() ); - worker.run(); - if ( up.getException() != null ) - { - throw up.getException(); - } - - File targetFile = TestFileUtils.createTempFile( "" ); - TestFileUtils.delete( targetFile ); - - MetadataDownload down = new MetadataDownload(); - down.setChecksumPolicy( RepositoryPolicy.CHECKSUM_POLICY_FAIL ); - down.setMetadata( metadata ).setFile( targetFile ); - worker = new FileRepositoryWorker( down, repository, session ); - worker.setFileProcessor( new TestFileProcessor() ); - worker.run(); - - if ( down.getException() != null ) - { - throw down.getException(); - } - - assertTrue( "download did not happen.", targetFile.exists() ); - - assertContentEquals( targetFile, expectedContent ); - } - - private void assertContentEquals( File file, String expectedContent ) - throws IOException - { - byte[] expected = expectedContent.getBytes( "UTF-8" ); - byte[] actual = TestFileUtils.getContent( file ); - - assertArrayEquals( expected, actual ); - } - - @Test - public void testDecodeURL() - throws ArtifactTransferException, IOException - { - String enc = "%72%65%70%6F"; - File dir = TestFileUtils.createTempDir(); - String repoDir = dir.toURI().toURL().toString() + "/" + enc; - repository = new RemoteRepository.Builder( "test", "default", repoDir ).build(); - - Artifact artifact = new DefaultArtifact( "gid", "aid", "jar", "ver" ); - String content = "test content"; - uploadArtifact( artifact, content ); - - File repo = new File( dir, "repo" ); - assertTrue( "Repository from encoded URL does not exist.", repo.exists() ); - assertTrue( "Artifact was not uploaded correctly.", - new File( repo, layout.getPath( artifact ).getRawPath() ).exists() ); - TestFileUtils.delete( dir ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-file/src/test/java/org/eclipse/aether/connector/file/PlexusSupportTest.java eclipse-aether-1.0.2/aether-connector-file/src/test/java/org/eclipse/aether/connector/file/PlexusSupportTest.java --- eclipse-aether-0.9.0.M2/aether-connector-file/src/test/java/org/eclipse/aether/connector/file/PlexusSupportTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-file/src/test/java/org/eclipse/aether/connector/file/PlexusSupportTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.file; - -import org.codehaus.plexus.ContainerConfiguration; -import org.codehaus.plexus.PlexusTestCase; -import org.eclipse.aether.connector.file.FileRepositoryConnectorFactory; -import org.eclipse.aether.internal.test.util.TestFileProcessor; -import org.eclipse.aether.internal.test.util.TestLoggerFactory; -import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; -import org.eclipse.aether.spi.io.FileProcessor; -import org.eclipse.aether.spi.log.LoggerFactory; - -/** - */ -public class PlexusSupportTest - extends PlexusTestCase -{ - - @Override - protected void customizeContainerConfiguration( ContainerConfiguration containerConfiguration ) - { - containerConfiguration.setClassPathScanning( "cache" ); - } - - public void testExistenceOfPlexusComponentMetadata() - throws Exception - { - getContainer().addComponent( new TestLoggerFactory(), LoggerFactory.class, null ); - getContainer().addComponent( new TestFileProcessor(), FileProcessor.class, null ); - - RepositoryConnectorFactory factory = lookup( RepositoryConnectorFactory.class, "file" ); - assertNotNull( factory ); - assertEquals( FileRepositoryConnectorFactory.class, factory.getClass() ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-file/src/test/java/org/eclipse/aether/connector/file/TestSuite.java eclipse-aether-1.0.2/aether-connector-file/src/test/java/org/eclipse/aether/connector/file/TestSuite.java --- eclipse-aether-0.9.0.M2/aether-connector-file/src/test/java/org/eclipse/aether/connector/file/TestSuite.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-file/src/test/java/org/eclipse/aether/connector/file/TestSuite.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.file; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.util.Map; - -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.connector.file.FileRepositoryConnectorFactory; -import org.eclipse.aether.internal.test.util.TestFileProcessor; -import org.eclipse.aether.internal.test.util.TestFileUtils; -import org.eclipse.aether.internal.test.util.connector.suite.ConnectorTestSuite; -import org.eclipse.aether.internal.test.util.connector.suite.ConnectorTestSetup.AbstractConnectorTestSetup; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; - -/** - */ -public class TestSuite - extends ConnectorTestSuite -{ - - private static final class FileConnectorTestSetup - extends AbstractConnectorTestSetup - { - private File repoFile; - - public RepositoryConnectorFactory factory() - { - return new FileRepositoryConnectorFactory().setFileProcessor( new TestFileProcessor() ); - } - - @Override - public void after( RepositorySystemSession session, RemoteRepository repository, Map context ) - throws Exception - { - TestFileUtils.delete( repoFile ); - } - - public RemoteRepository before( RepositorySystemSession session, Map context ) - throws IOException - { - RemoteRepository repo = null; - repoFile = TestFileUtils.createTempDir( "test-repo" ); - try - { - repo = - new RemoteRepository.Builder( "test-file", "default", repoFile.toURI().toURL().toString() ).build(); - } - catch ( MalformedURLException e ) - { - throw new UnsupportedOperationException( "File.toURI().toURL() failed" ); - } - return repo; - } - } - - public TestSuite() - { - super( new FileConnectorTestSetup() ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-wagon/pom.xml eclipse-aether-1.0.2/aether-connector-wagon/pom.xml --- eclipse-aether-0.9.0.M2/aether-connector-wagon/pom.xml 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-wagon/pom.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,127 +0,0 @@ - - - - - - 4.0.0 - - - org.eclipse.aether - aether - 0.9.0.M2 - - - aether-connector-wagon - - Aether Connector Wagon - - A repository connector implementation based on Maven Wagon. - - - - 1.0 - org.eclipse.aether.connector.wagon - - - - - org.eclipse.aether - aether-api - - - org.eclipse.aether - aether-spi - - - org.eclipse.aether - aether-util - - - org.apache.maven.wagon - wagon-provider-api - ${wagonVersion} - - - javax.inject - javax.inject - provided - true - - - org.codehaus.plexus - plexus-component-annotations - provided - true - - - org.codehaus.plexus - plexus-classworlds - 2.4 - true - - - org.codehaus.plexus - plexus-utils - 2.1 - true - - - org.sonatype.sisu - sisu-inject-plexus - true - - - org.eclipse.aether - aether-test-util - test - - - org.apache.maven.wagon - wagon-http-lightweight - ${wagonVersion} - test - - - org.apache.maven.wagon - wagon-http-shared - - - - - org.sonatype.http-testing-harness - server-provider - 0.4.1 - test - - - - - - - org.codehaus.mojo - animal-sniffer-maven-plugin - - - org.codehaus.plexus - plexus-component-metadata - - - org.sonatype.plugins - sisu-maven-plugin - - - org.apache.felix - maven-bundle-plugin - - - - diff -Nru eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonCancelledException.java eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonCancelledException.java --- eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonCancelledException.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonCancelledException.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.wagon; - -import org.eclipse.aether.transfer.TransferCancelledException; - -/** - */ -class WagonCancelledException - extends RuntimeException -{ - - public WagonCancelledException( TransferCancelledException cause ) - { - super( cause ); - } - - public static Exception unwrap( Exception e ) - { - if ( e instanceof WagonCancelledException ) - { - e = (Exception) e.getCause(); - } - return e; - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonConfigurator.java eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonConfigurator.java --- eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonConfigurator.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonConfigurator.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.wagon; - -import org.apache.maven.wagon.Wagon; - -/** - * A component to configure wagon instances with provider-specific parameters. - */ -public interface WagonConfigurator -{ - - /** - * Configures the specified wagon instance with the given configuration. - * - * @param wagon The wagon instance to configure, must not be {@code null}. - * @param configuration The configuration to apply to the wagon instance, must not be {@code null}. - * @throws Exception If the configuration could not be applied to the wagon. - */ - void configure( Wagon wagon, Object configuration ) - throws Exception; - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonProvider.java eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonProvider.java --- eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonProvider.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonProvider.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.wagon; - -import org.apache.maven.wagon.Wagon; - -/** - * A component to acquire and release wagon instances for uploads/downloads. - */ -public interface WagonProvider -{ - - /** - * Acquires a wagon instance that matches the specified role hint. The role hint is derived from the URI scheme, - * e.g. "http" or "file". - * - * @param roleHint The role hint to get a wagon for, must not be {@code null}. - * @return The requested wagon instance, never {@code null}. - * @throws Exception If no wagon could be retrieved for the specified role hint. - */ - Wagon lookup( String roleHint ) - throws Exception; - - /** - * Releases the specified wagon. A wagon provider may either free any resources allocated for the wagon instance or - * return the instance back to a pool for future use. - * - * @param wagon The wagon to release, may be {@code null}. - */ - void release( Wagon wagon ); - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonRepositoryConnectorFactory.java eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonRepositoryConnectorFactory.java --- eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonRepositoryConnectorFactory.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonRepositoryConnectorFactory.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,163 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.wagon; - -import javax.inject.Inject; -import javax.inject.Named; - -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; -import org.eclipse.aether.spi.io.FileProcessor; -import org.eclipse.aether.spi.locator.Service; -import org.eclipse.aether.spi.locator.ServiceLocator; -import org.eclipse.aether.spi.log.Logger; -import org.eclipse.aether.spi.log.LoggerFactory; -import org.eclipse.aether.spi.log.NullLoggerFactory; -import org.eclipse.aether.transfer.NoRepositoryConnectorException; - -/** - * A repository connector factory that uses Maven Wagon for the transfers. - */ -@Named -@Component( role = RepositoryConnectorFactory.class, hint = "wagon" ) -public final class WagonRepositoryConnectorFactory - implements RepositoryConnectorFactory, Service -{ - - @Requirement( role = LoggerFactory.class ) - private Logger logger = NullLoggerFactory.LOGGER; - - @Requirement - private FileProcessor fileProcessor; - - @Requirement - private WagonProvider wagonProvider; - - @Requirement - private WagonConfigurator wagonConfigurator; - - private float priority; - - /** - * Creates an (uninitialized) instance of this connector factory. Note: In case of manual instantiation by - * clients, the new factory needs to be configured via its various mutators before first use or runtime errors will - * occur. - */ - public WagonRepositoryConnectorFactory() - { - // enables default constructor - } - - @Inject - WagonRepositoryConnectorFactory( FileProcessor fileProcessor, WagonProvider wagonProvider, - WagonConfigurator wagonConfigurator, LoggerFactory loggerFactory ) - { - setFileProcessor( fileProcessor ); - setWagonProvider( wagonProvider ); - setWagonConfigurator( wagonConfigurator ); - setLoggerFactory( loggerFactory ); - } - - public void initService( ServiceLocator locator ) - { - setLoggerFactory( locator.getService( LoggerFactory.class ) ); - setFileProcessor( locator.getService( FileProcessor.class ) ); - setWagonProvider( locator.getService( WagonProvider.class ) ); - setWagonConfigurator( locator.getService( WagonConfigurator.class ) ); - } - - /** - * Sets the logger factory to use for this component. - * - * @param loggerFactory The logger factory to use, may be {@code null} to disable logging. - * @return This component for chaining, never {@code null}. - */ - public WagonRepositoryConnectorFactory setLoggerFactory( LoggerFactory loggerFactory ) - { - this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, WagonRepositoryConnector.class ); - return this; - } - - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - - /** - * Sets the file processor to use for this component. - * - * @param fileProcessor The file processor to use, must not be {@code null}. - * @return This component for chaining, never {@code null}. - */ - public WagonRepositoryConnectorFactory setFileProcessor( FileProcessor fileProcessor ) - { - if ( fileProcessor == null ) - { - throw new IllegalArgumentException( "file processor has not been specified" ); - } - this.fileProcessor = fileProcessor; - return this; - } - - /** - * Sets the wagon provider to use to acquire and release wagon instances. - * - * @param wagonProvider The wagon provider to use, may be {@code null}. - * @return This factory for chaining, never {@code null}. - */ - public WagonRepositoryConnectorFactory setWagonProvider( WagonProvider wagonProvider ) - { - this.wagonProvider = wagonProvider; - return this; - } - - /** - * Sets the wagon configurator to use to apply provider-specific configuration to wagon instances. - * - * @param wagonConfigurator The wagon configurator to use, may be {@code null}. - * @return This factory for chaining, never {@code null}. - */ - public WagonRepositoryConnectorFactory setWagonConfigurator( WagonConfigurator wagonConfigurator ) - { - this.wagonConfigurator = wagonConfigurator; - return this; - } - - public float getPriority() - { - return priority; - } - - /** - * Sets the priority of this component. - * - * @param priority The priority. - * @return This component for chaining, never {@code null}. - */ - public WagonRepositoryConnectorFactory setPriority( float priority ) - { - this.priority = priority; - return this; - } - - public RepositoryConnector newInstance( RepositorySystemSession session, RemoteRepository repository ) - throws NoRepositoryConnectorException - { - return new WagonRepositoryConnector( wagonProvider, wagonConfigurator, repository, session, fileProcessor, - logger ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonRepositoryConnector.java eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonRepositoryConnector.java --- eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonRepositoryConnector.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonRepositoryConnector.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,1024 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.wagon; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Properties; -import java.util.Queue; -import java.util.UUID; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import org.apache.maven.wagon.ResourceDoesNotExistException; -import org.apache.maven.wagon.StreamingWagon; -import org.apache.maven.wagon.Wagon; -import org.apache.maven.wagon.WagonException; -import org.apache.maven.wagon.authentication.AuthenticationInfo; -import org.apache.maven.wagon.observers.ChecksumObserver; -import org.apache.maven.wagon.proxy.ProxyInfo; -import org.apache.maven.wagon.proxy.ProxyInfoProvider; -import org.apache.maven.wagon.repository.Repository; -import org.apache.maven.wagon.repository.RepositoryPermissions; -import org.eclipse.aether.ConfigurationProperties; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.repository.AuthenticationContext; -import org.eclipse.aether.repository.Proxy; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.repository.RepositoryPolicy; -import org.eclipse.aether.spi.connector.ArtifactDownload; -import org.eclipse.aether.spi.connector.ArtifactTransfer; -import org.eclipse.aether.spi.connector.ArtifactUpload; -import org.eclipse.aether.spi.connector.MetadataDownload; -import org.eclipse.aether.spi.connector.MetadataTransfer; -import org.eclipse.aether.spi.connector.MetadataUpload; -import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.aether.spi.connector.Transfer; -import org.eclipse.aether.spi.io.FileProcessor; -import org.eclipse.aether.spi.log.Logger; -import org.eclipse.aether.transfer.ArtifactNotFoundException; -import org.eclipse.aether.transfer.ArtifactTransferException; -import org.eclipse.aether.transfer.ChecksumFailureException; -import org.eclipse.aether.transfer.MetadataNotFoundException; -import org.eclipse.aether.transfer.MetadataTransferException; -import org.eclipse.aether.transfer.NoRepositoryConnectorException; -import org.eclipse.aether.transfer.TransferEvent; -import org.eclipse.aether.transfer.TransferListener; -import org.eclipse.aether.util.ChecksumUtils; -import org.eclipse.aether.util.ConfigUtils; -import org.eclipse.aether.util.concurrency.RunnableErrorForwarder; -import org.eclipse.aether.util.repository.layout.MavenDefaultLayout; -import org.eclipse.aether.util.repository.layout.RepositoryLayout; - -/** - * A repository connector that uses Maven Wagon for the transfer. - */ -class WagonRepositoryConnector - implements RepositoryConnector -{ - - private static final String PROP_THREADS = "aether.connector.wagon.threads"; - - private static final String PROP_CONFIG = "aether.connector.wagon.config"; - - private static final String PROP_FILE_MODE = "aether.connector.perms.fileMode"; - - private static final String PROP_DIR_MODE = "aether.connector.perms.dirMode"; - - private static final String PROP_GROUP = "aether.connector.perms.group"; - - private final Logger logger; - - private final FileProcessor fileProcessor; - - private final RemoteRepository repository; - - private final RepositorySystemSession session; - - private final AuthenticationContext repoAuthContext; - - private final AuthenticationContext proxyAuthContext; - - private final WagonProvider wagonProvider; - - private final WagonConfigurator wagonConfigurator; - - private final String wagonHint; - - private final Repository wagonRepo; - - private final AuthenticationInfo wagonAuth; - - private final ProxyInfoProvider wagonProxy; - - private final RepositoryLayout layout = new MavenDefaultLayout(); - - private final TransferListener listener; - - private final Queue wagons = new ConcurrentLinkedQueue(); - - private final Executor executor; - - private boolean closed; - - private final Map checksumAlgos; - - private final Properties headers; - - public WagonRepositoryConnector( WagonProvider wagonProvider, WagonConfigurator wagonConfigurator, - RemoteRepository repository, RepositorySystemSession session, - FileProcessor fileProcessor, Logger logger ) - throws NoRepositoryConnectorException - { - if ( !"default".equals( repository.getContentType() ) ) - { - throw new NoRepositoryConnectorException( repository ); - } - - this.logger = logger; - this.fileProcessor = fileProcessor; - this.wagonProvider = wagonProvider; - this.wagonConfigurator = wagonConfigurator; - this.repository = repository; - this.session = session; - this.listener = session.getTransferListener(); - - wagonRepo = new Repository( repository.getId(), repository.getUrl() ); - wagonRepo.setPermissions( getPermissions( repository.getId(), session ) ); - - wagonHint = wagonRepo.getProtocol().toLowerCase( Locale.ENGLISH ); - if ( wagonHint == null || wagonHint.length() <= 0 ) - { - throw new NoRepositoryConnectorException( repository ); - } - - try - { - wagons.add( lookupWagon() ); - } - catch ( Exception e ) - { - logger.debug( e.getMessage(), e ); - throw new NoRepositoryConnectorException( repository ); - } - - repoAuthContext = AuthenticationContext.forRepository( session, repository ); - proxyAuthContext = AuthenticationContext.forProxy( session, repository ); - - wagonAuth = getAuthenticationInfo( repository, repoAuthContext ); - wagonProxy = getProxy( repository, proxyAuthContext ); - - int threads = ConfigUtils.getInteger( session, 5, PROP_THREADS, "maven.artifact.threads" ); - executor = getExecutor( threads ); - - checksumAlgos = new LinkedHashMap(); - checksumAlgos.put( "SHA-1", ".sha1" ); - checksumAlgos.put( "MD5", ".md5" ); - - headers = new Properties(); - headers.put( "User-Agent", ConfigUtils.getString( session, ConfigurationProperties.DEFAULT_USER_AGENT, - ConfigurationProperties.USER_AGENT ) ); - Map headers = - ConfigUtils.getMap( session, null, ConfigurationProperties.HTTP_HEADERS + "." + repository.getId(), - ConfigurationProperties.HTTP_HEADERS ); - if ( headers != null ) - { - this.headers.putAll( headers ); - } - } - - private Executor getExecutor( int threads ) - { - if ( threads <= 1 ) - { - return new Executor() - { - public void execute( Runnable command ) - { - command.run(); - } - }; - } - else - { - return new ThreadPoolExecutor( threads, threads, 3, TimeUnit.SECONDS, new LinkedBlockingQueue() ); - } - } - - private static RepositoryPermissions getPermissions( String repoId, RepositorySystemSession session ) - { - RepositoryPermissions result = null; - - RepositoryPermissions perms = new RepositoryPermissions(); - - String suffix = '.' + repoId; - - String fileMode = ConfigUtils.getString( session, (String) null, PROP_FILE_MODE + suffix ); - if ( fileMode != null ) - { - perms.setFileMode( fileMode ); - result = perms; - } - - String dirMode = ConfigUtils.getString( session, (String) null, PROP_DIR_MODE + suffix ); - if ( dirMode != null ) - { - perms.setDirectoryMode( dirMode ); - result = perms; - } - - String group = ConfigUtils.getString( session, (String) null, PROP_GROUP + suffix ); - if ( group != null ) - { - perms.setGroup( group ); - result = perms; - } - - return result; - } - - private AuthenticationInfo getAuthenticationInfo( RemoteRepository repository, final AuthenticationContext authContext ) - { - AuthenticationInfo auth = null; - - if ( authContext != null ) - { - auth = new AuthenticationInfo() - { - @Override - public String getUserName() - { - return authContext.get( AuthenticationContext.USERNAME ); - } - - @Override - public String getPassword() - { - return authContext.get( AuthenticationContext.PASSWORD ); - } - - @Override - public String getPrivateKey() - { - return authContext.get( AuthenticationContext.PRIVATE_KEY_PATH ); - } - - @Override - public String getPassphrase() - { - return authContext.get( AuthenticationContext.PRIVATE_KEY_PASSPHRASE ); - } - }; - } - - return auth; - } - - private ProxyInfoProvider getProxy( RemoteRepository repository, final AuthenticationContext authContext ) - { - ProxyInfoProvider proxy = null; - - Proxy p = repository.getProxy(); - if ( p != null ) - { - final ProxyInfo prox; - if ( authContext != null ) - { - prox = new ProxyInfo() - { - @Override - public String getUserName() - { - return authContext.get( AuthenticationContext.USERNAME ); - } - - @Override - public String getPassword() - { - return authContext.get( AuthenticationContext.PASSWORD ); - } - - @Override - public String getNtlmDomain() - { - return authContext.get( AuthenticationContext.NTLM_DOMAIN ); - } - - @Override - public String getNtlmHost() - { - return authContext.get( AuthenticationContext.NTLM_WORKSTATION ); - } - }; - } - else - { - prox = new ProxyInfo(); - } - prox.setType( p.getType() ); - prox.setHost( p.getHost() ); - prox.setPort( p.getPort() ); - - proxy = new ProxyInfoProvider() - { - public ProxyInfo getProxyInfo( String protocol ) - { - return prox; - } - }; - } - - return proxy; - } - - private Wagon lookupWagon() - throws Exception - { - return wagonProvider.lookup( wagonHint ); - } - - private void releaseWagon( Wagon wagon ) - { - wagonProvider.release( wagon ); - } - - private void connectWagon( Wagon wagon ) - throws Exception - { - if ( !headers.isEmpty() ) - { - try - { - Method setHttpHeaders = wagon.getClass().getMethod( "setHttpHeaders", Properties.class ); - setHttpHeaders.invoke( wagon, headers ); - } - catch ( NoSuchMethodException e ) - { - // normal for non-http wagons - } - catch ( Exception e ) - { - logger.debug( "Could not set user agent for wagon " + wagon.getClass().getName() + ": " + e ); - } - } - - int connectTimeout = - ConfigUtils.getInteger( session, ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT, - ConfigurationProperties.CONNECT_TIMEOUT ); - int requestTimeout = - ConfigUtils.getInteger( session, ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT, - ConfigurationProperties.REQUEST_TIMEOUT ); - - wagon.setTimeout( Math.max( Math.max( connectTimeout, requestTimeout ), 0 ) ); - - wagon.setInteractive( ConfigUtils.getBoolean( session, ConfigurationProperties.DEFAULT_INTERACTIVE, - ConfigurationProperties.INTERACTIVE ) ); - - Object configuration = ConfigUtils.getObject( session, null, PROP_CONFIG + "." + repository.getId() ); - if ( configuration != null && wagonConfigurator != null ) - { - try - { - wagonConfigurator.configure( wagon, configuration ); - } - catch ( Exception e ) - { - String msg = - "Could not apply configuration for " + repository.getId() + " to wagon " - + wagon.getClass().getName() + ":" + e.getMessage(); - if ( logger.isDebugEnabled() ) - { - logger.warn( msg, e ); - } - else - { - logger.warn( msg ); - } - } - } - - wagon.connect( wagonRepo, wagonAuth, wagonProxy ); - } - - private void disconnectWagon( Wagon wagon ) - { - try - { - if ( wagon != null ) - { - wagon.disconnect(); - } - } - catch ( Exception e ) - { - // too bad - } - } - - Wagon pollWagon() - throws Exception - { - Wagon wagon = wagons.poll(); - - if ( wagon == null ) - { - try - { - wagon = lookupWagon(); - connectWagon( wagon ); - } - catch ( Exception e ) - { - releaseWagon( wagon ); - throw e; - } - } - else if ( wagon.getRepository() == null ) - { - try - { - connectWagon( wagon ); - } - catch ( Exception e ) - { - wagons.add( wagon ); - throw e; - } - } - - return wagon; - } - - private Collection safe( Collection items ) - { - return ( items != null ) ? items : Collections. emptyList(); - } - - private File getTmpFile( String path ) - { - File file; - do - { - file = new File( path + ".tmp" + UUID.randomUUID().toString().replace( "-", "" ).substring( 0, 16 ) ); - } - while ( file.exists() ); - return file; - } - - public void get( Collection artifactDownloads, - Collection metadataDownloads ) - { - if ( closed ) - { - throw new IllegalStateException( "connector closed" ); - } - - artifactDownloads = safe( artifactDownloads ); - metadataDownloads = safe( metadataDownloads ); - - Collection> tasks = new ArrayList>(); - - RunnableErrorForwarder errorForwarder = new RunnableErrorForwarder(); - - for ( MetadataDownload download : metadataDownloads ) - { - String resource = layout.getPath( download.getMetadata() ).getPath(); - GetTask task = - new GetTask( resource, download.getFile(), download.getChecksumPolicy(), download, - METADATA ); - tasks.add( task ); - executor.execute( errorForwarder.wrap( task ) ); - } - - for ( ArtifactDownload download : artifactDownloads ) - { - String resource = layout.getPath( download.getArtifact() ).getPath(); - GetTask task = - new GetTask( resource, download.isExistenceCheck() ? null : download.getFile(), - download.getChecksumPolicy(), download, ARTIFACT ); - tasks.add( task ); - executor.execute( errorForwarder.wrap( task ) ); - } - - errorForwarder.await(); - } - - public void put( Collection artifactUploads, - Collection metadataUploads ) - { - if ( closed ) - { - throw new IllegalStateException( "connector closed" ); - } - - artifactUploads = safe( artifactUploads ); - metadataUploads = safe( metadataUploads ); - - for ( ArtifactUpload upload : artifactUploads ) - { - String path = layout.getPath( upload.getArtifact() ).getPath(); - - PutTask task = new PutTask( path, upload.getFile(), upload, ARTIFACT ); - task.run(); - } - - for ( MetadataUpload upload : metadataUploads ) - { - String path = layout.getPath( upload.getMetadata() ).getPath(); - - PutTask task = new PutTask( path, upload.getFile(), upload, METADATA ); - task.run(); - } - } - - public void close() - { - closed = true; - - AuthenticationContext.close( repoAuthContext ); - AuthenticationContext.close( proxyAuthContext ); - - for ( Wagon wagon = wagons.poll(); wagon != null; wagon = wagons.poll() ) - { - disconnectWagon( wagon ); - releaseWagon( wagon ); - } - - shutdown( executor ); - } - - private void shutdown( Executor executor ) - { - if ( executor instanceof ExecutorService ) - { - ( (ExecutorService) executor ).shutdown(); - } - } - - @Override - protected void finalize() - throws Throwable - { - try - { - close(); - } - finally - { - super.finalize(); - } - } - - @Override - public String toString() - { - return String.valueOf( repository ); - } - - class GetTask - implements Runnable - { - - private final T download; - - private final String path; - - private final File file; - - private final String checksumPolicy; - - private final ExceptionWrapper wrapper; - - public GetTask( String path, File file, String checksumPolicy, T download, ExceptionWrapper wrapper ) - { - this.path = path; - this.file = file; - this.checksumPolicy = checksumPolicy; - this.download = download; - this.wrapper = wrapper; - } - - public T getDownload() - { - return download; - } - - public void run() - { - download.setState( Transfer.State.ACTIVE ); - - WagonTransferListenerAdapter wagonListener = null; - if ( listener != null ) - { - wagonListener = - new WagonTransferListenerAdapter( listener, wagonRepo.getUrl(), path, file, download.getTrace(), - ( file != null ) ? TransferEvent.RequestType.GET - : TransferEvent.RequestType.GET_EXISTENCE, - session ); - } - - try - { - if ( listener != null ) - { - TransferEvent.Builder event = wagonListener.newEvent( TransferEvent.EventType.INITIATED ); - listener.transferInitiated( event.build() ); - } - - File tmp = ( file != null ) ? getTmpFile( file.getPath() ) : null; - - Wagon wagon = pollWagon(); - - try - { - if ( file == null ) - { - if ( !wagon.resourceExists( path ) ) - { - throw new ResourceDoesNotExistException( "Could not find " + path + " in " - + wagonRepo.getUrl() ); - } - } - else - { - for ( int trial = 1; trial >= 0; trial-- ) - { - ChecksumObserver sha1 = new ChecksumObserver( "SHA-1" ); - ChecksumObserver md5 = new ChecksumObserver( "MD5" ); - try - { - wagon.addTransferListener( wagonListener ); - wagon.addTransferListener( md5 ); - wagon.addTransferListener( sha1 ); - - /* - * NOTE: AbstractWagon.createParentDirectories() uses File.mkdirs() which is not - * thread-safe in all JREs. - */ - fileProcessor.mkdirs( tmp.getParentFile() ); - - wagon.get( path, tmp ); - } - finally - { - wagon.removeTransferListener( wagonListener ); - wagon.removeTransferListener( md5 ); - wagon.removeTransferListener( sha1 ); - } - - if ( RepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals( checksumPolicy ) ) - { - break; - } - else - { - try - { - if ( !verifyChecksum( wagon, sha1.getActualChecksum(), ".sha1" ) - && !verifyChecksum( wagon, md5.getActualChecksum(), ".md5" ) ) - { - trial = 0; - throw new ChecksumFailureException( "Checksum validation failed" - + ", no checksums available from the repository" ); - } - break; - } - catch ( ChecksumFailureException e ) - { - if ( trial <= 0 && RepositoryPolicy.CHECKSUM_POLICY_FAIL.equals( checksumPolicy ) ) - { - throw e; - } - if ( listener != null ) - { - TransferEvent.Builder event = - wagonListener.newEvent( TransferEvent.EventType.CORRUPTED ); - event.setException( e ); - listener.transferCorrupted( event.build() ); - } - } - } - } - - rename( tmp, file ); - } - - wrapper.wrap( download, null, repository ); - - if ( listener != null ) - { - TransferEvent.Builder event = wagonListener.newEvent( TransferEvent.EventType.SUCCEEDED ); - listener.transferSucceeded( event.build() ); - } - } - finally - { - if ( tmp != null ) - { - tmp.delete(); - } - wagons.add( wagon ); - } - } - catch ( Exception e ) - { - e = wrapper.wrap( download, e, repository ); - - if ( listener != null ) - { - TransferEvent.Builder event = wagonListener.newEvent( TransferEvent.EventType.FAILED ); - event.setException( e ); - listener.transferFailed( event.build() ); - } - } - finally - { - download.setState( Transfer.State.DONE ); - } - } - - private boolean verifyChecksum( Wagon wagon, String actual, String ext ) - throws ChecksumFailureException - { - File tmp = getTmpFile( file.getPath() + ext ); - - try - { - try - { - wagon.get( path + ext, tmp ); - } - catch ( ResourceDoesNotExistException e ) - { - return false; - } - catch ( WagonException e ) - { - throw new ChecksumFailureException( e ); - } - - String expected; - - try - { - expected = ChecksumUtils.read( tmp ); - } - catch ( IOException e ) - { - if ( !tmp.exists() ) - { // see comment in rename() - expected = ""; - } - else - { - throw new ChecksumFailureException( e ); - } - } - - if ( expected.equalsIgnoreCase( actual ) ) - { - try - { - rename( tmp, new File( file.getPath() + ext ) ); - } - catch ( IOException e ) - { - logger.debug( "Failed to write checksum file " + file.getPath() + ext + ": " + e.getMessage(), - e ); - } - } - else - { - throw new ChecksumFailureException( expected, actual ); - } - } - finally - { - tmp.delete(); - } - - return true; - } - - private void rename( File from, File to ) - throws IOException - { - if ( !from.exists() ) - { - /* - * NOTE: Wagon (1.0-beta-6) doesn't create the destination file when transferring a 0-byte resource. So - * if the resource we asked for didn't cause any exception but doesn't show up in the tmp file either, - * Wagon tells us in its weird way the file is empty. - */ - fileProcessor.write( to, "" ); - } - else - { - fileProcessor.move( from, to ); - } - } - - } - - class PutTask - implements Runnable - { - - private final T upload; - - private final ExceptionWrapper wrapper; - - private final String path; - - private final File file; - - public PutTask( String path, File file, T upload, ExceptionWrapper wrapper ) - { - this.path = path; - this.file = file; - this.upload = upload; - this.wrapper = wrapper; - } - - public void run() - { - upload.setState( Transfer.State.ACTIVE ); - - WagonTransferListenerAdapter wagonListener = null; - if ( listener != null ) - { - wagonListener = - new WagonTransferListenerAdapter( listener, wagonRepo.getUrl(), path, file, upload.getTrace(), - TransferEvent.RequestType.PUT, session ); - } - - try - { - if ( listener != null ) - { - TransferEvent.Builder event = wagonListener.newEvent( TransferEvent.EventType.INITIATED ); - listener.transferInitiated( event.build() ); - } - - Wagon wagon = pollWagon(); - - try - { - try - { - wagon.addTransferListener( wagonListener ); - - wagon.put( file, path ); - } - finally - { - wagon.removeTransferListener( wagonListener ); - } - - uploadChecksums( wagon, file, path ); - - wrapper.wrap( upload, null, repository ); - - if ( listener != null ) - { - TransferEvent.Builder event = wagonListener.newEvent( TransferEvent.EventType.SUCCEEDED ); - listener.transferSucceeded( event.build() ); - } - } - finally - { - wagons.add( wagon ); - } - } - catch ( Exception e ) - { - e = wrapper.wrap( upload, e, repository ); - - if ( listener != null ) - { - TransferEvent.Builder event = wagonListener.newEvent( TransferEvent.EventType.FAILED ); - event.setException( e ); - listener.transferFailed( event.build() ); - } - } - finally - { - upload.setState( Transfer.State.DONE ); - } - } - - private void uploadChecksums( Wagon wagon, File file, String path ) - { - try - { - Map checksums = ChecksumUtils.calc( file, checksumAlgos.keySet() ); - for ( Map.Entry entry : checksums.entrySet() ) - { - uploadChecksum( wagon, file, path, entry.getKey(), entry.getValue() ); - } - } - catch ( IOException e ) - { - logger.debug( "Failed to upload checksums for " + file + ": " + e.getMessage(), e ); - } - } - - private void uploadChecksum( Wagon wagon, File file, String path, String algo, Object checksum ) - { - try - { - if ( checksum instanceof Exception ) - { - throw (Exception) checksum; - } - - String ext = checksumAlgos.get( algo ); - String dst = path + ext; - String sum = String.valueOf( checksum ); - - if ( wagon instanceof StreamingWagon ) - { - // NOTE: Be sure to declare content length to avoid HTTP 411 from nginx (no chunked encoding) - byte[] data = sum.getBytes( "UTF-8" ); - ( (StreamingWagon) wagon ).putFromStream( new ByteArrayInputStream( data ), dst, data.length, -1 ); - } - else - { - File tmpFile = File.createTempFile( "wagon" + UUID.randomUUID().toString().replace( "-", "" ), ext ); - try - { - fileProcessor.write( tmpFile, sum ); - wagon.put( tmpFile, dst ); - } - finally - { - tmpFile.delete(); - } - } - } - catch ( Exception e ) - { - String msg = "Failed to upload " + algo + " checksum for " + file + ": " + e.getMessage(); - if ( logger.isDebugEnabled() ) - { - logger.warn( msg, e ); - } - else - { - logger.warn( msg ); - } - } - } - - } - - static interface ExceptionWrapper - { - - Exception wrap( T transfer, Exception e, RemoteRepository repository ); - - } - - private static final ExceptionWrapper METADATA = new ExceptionWrapper() - { - - public Exception wrap( MetadataTransfer transfer, Exception e, RemoteRepository repository ) - { - MetadataTransferException ex = null; - e = WagonCancelledException.unwrap( e ); - if ( e instanceof ResourceDoesNotExistException ) - { - ex = new MetadataNotFoundException( transfer.getMetadata(), repository ); - } - else if ( e != null ) - { - ex = new MetadataTransferException( transfer.getMetadata(), repository, e ); - } - transfer.setException( ex ); - return ex; - } - - }; - - private static final ExceptionWrapper ARTIFACT = new ExceptionWrapper() - { - - public Exception wrap( ArtifactTransfer transfer, Exception e, RemoteRepository repository ) - { - ArtifactTransferException ex = null; - e = WagonCancelledException.unwrap( e ); - if ( e instanceof ResourceDoesNotExistException ) - { - ex = new ArtifactNotFoundException( transfer.getArtifact(), repository ); - } - else if ( e != null ) - { - ex = new ArtifactTransferException( transfer.getArtifact(), repository, e ); - } - transfer.setException( ex ); - return ex; - } - - }; - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonTransferListenerAdapter.java eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonTransferListenerAdapter.java --- eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonTransferListenerAdapter.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/connector/wagon/WagonTransferListenerAdapter.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.wagon; - -import java.io.File; - -import org.apache.maven.wagon.events.TransferEvent; -import org.apache.maven.wagon.observers.AbstractTransferListener; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.RequestTrace; -import org.eclipse.aether.transfer.TransferCancelledException; -import org.eclipse.aether.transfer.TransferEvent.Builder; -import org.eclipse.aether.transfer.TransferEvent.EventType; -import org.eclipse.aether.transfer.TransferEvent.RequestType; -import org.eclipse.aether.transfer.TransferListener; -import org.eclipse.aether.transfer.TransferResource; - -/** - * An adapter to transform transfer events from Wagon into events for the repository system. - */ -class WagonTransferListenerAdapter - extends AbstractTransferListener -{ - - private final TransferResource resource; - - private final TransferListener delegate; - - private final Builder eventBuilder; - - public WagonTransferListenerAdapter( TransferListener delegate, String repositoryUrl, String resourceName, - File file, RequestTrace trace, RequestType requestType, - RepositorySystemSession session ) - { - this.delegate = delegate; - resource = new TransferResource( repositoryUrl, resourceName, file, trace ); - eventBuilder = new Builder( session, resource ).setRequestType( requestType ); - } - - @Override - public void transferStarted( TransferEvent event ) - { - eventBuilder.setTransferredBytes( 0 ); - resource.setContentLength( event.getResource().getContentLength() ); - try - { - delegate.transferStarted( newEvent( EventType.STARTED ).build() ); - } - catch ( TransferCancelledException e ) - { - /* - * NOTE: Wagon transfers are not freely abortable. In particular, aborting from - * AbstractWagon.fire(Get|Put)Started() would result in unclosed streams so we avoid this case. - */ - } - } - - @Override - public void transferProgress( TransferEvent event, byte[] buffer, int length ) - { - eventBuilder.addTransferredBytes( length ); - try - { - delegate.transferProgressed( newEvent( EventType.PROGRESSED ).setDataBuffer( buffer, 0, length ).build() ); - } - catch ( TransferCancelledException e ) - { - throw new WagonCancelledException( e ); - } - } - - public Builder newEvent( EventType type ) - { - return eventBuilder.copy().setType( type ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/internal/connector/wagon/PlexusWagonConfigurator.java eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/internal/connector/wagon/PlexusWagonConfigurator.java --- eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/internal/connector/wagon/PlexusWagonConfigurator.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/internal/connector/wagon/PlexusWagonConfigurator.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.internal.connector.wagon; - -import org.apache.maven.wagon.Wagon; -import org.codehaus.plexus.PlexusContainer; -import org.codehaus.plexus.classworlds.realm.ClassRealm; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; -import org.codehaus.plexus.component.configurator.AbstractComponentConfigurator; -import org.codehaus.plexus.component.configurator.ComponentConfigurationException; -import org.codehaus.plexus.component.configurator.ConfigurationListener; -import org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter; -import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; -import org.codehaus.plexus.configuration.PlexusConfiguration; -import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; -import org.codehaus.plexus.util.xml.Xpp3Dom; -import org.eclipse.aether.connector.wagon.WagonConfigurator; - -/** - * A wagon configurator based on the Plexus component configuration framework. - */ -@Component( role = WagonConfigurator.class, hint = "plexus" ) -public class PlexusWagonConfigurator - implements WagonConfigurator -{ - - @Requirement - private PlexusContainer container; - - public void configure( Wagon wagon, Object configuration ) - throws Exception - { - PlexusConfiguration config = null; - if ( configuration instanceof PlexusConfiguration ) - { - config = (PlexusConfiguration) configuration; - } - else if ( configuration instanceof Xpp3Dom ) - { - config = new XmlPlexusConfiguration( (Xpp3Dom) configuration ); - } - else if ( configuration == null ) - { - return; - } - else - { - throw new IllegalArgumentException( "Unexpected configuration type: " + configuration.getClass().getName() ); - } - - WagonComponentConfigurator configurator = new WagonComponentConfigurator(); - - configurator.configureComponent( wagon, config, container.getContainerRealm() ); - } - - static class WagonComponentConfigurator - extends AbstractComponentConfigurator - { - - @Override - public void configureComponent( Object component, PlexusConfiguration configuration, - ExpressionEvaluator expressionEvaluator, ClassRealm containerRealm, - ConfigurationListener listener ) - throws ComponentConfigurationException - { - ObjectWithFieldsConverter converter = new ObjectWithFieldsConverter(); - - converter.processConfiguration( converterLookup, component, containerRealm, configuration, - expressionEvaluator, listener ); - } - - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/internal/connector/wagon/PlexusWagonProvider.java eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/internal/connector/wagon/PlexusWagonProvider.java --- eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/java/org/eclipse/aether/internal/connector/wagon/PlexusWagonProvider.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-wagon/src/main/java/org/eclipse/aether/internal/connector/wagon/PlexusWagonProvider.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.internal.connector.wagon; - -import org.apache.maven.wagon.Wagon; -import org.codehaus.plexus.PlexusContainer; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; -import org.eclipse.aether.connector.wagon.WagonProvider; - -/** - * A wagon provider backed by a Plexus container and the wagons registered with this container. - */ -@Component( role = WagonProvider.class, hint = "plexus" ) -public class PlexusWagonProvider - implements WagonProvider -{ - - @Requirement - private PlexusContainer container; - - public Wagon lookup( String roleHint ) - throws Exception - { - return container.lookup( Wagon.class, roleHint ); - } - - public void release( Wagon wagon ) - { - try - { - if ( wagon != null ) - { - container.release( wagon ); - } - } - catch ( Exception e ) - { - // too bad - } - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/resources/about.html eclipse-aether-1.0.2/aether-connector-wagon/src/main/resources/about.html --- eclipse-aether-0.9.0.M2/aether-connector-wagon/src/main/resources/about.html 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-wagon/src/main/resources/about.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ - - - - -About - - -

About This Content

- -

September 23, 2011

-

License

- -

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise -indicated below, the Content is provided to you under the terms and conditions of the -Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available -at http://www.eclipse.org/legal/epl-v10.html. -For purposes of the EPL, "Program" will mean the Content.

- -

If you did not receive this Content directly from the Eclipse Foundation, the Content is -being redistributed by another party ("Redistributor") and different terms and conditions may -apply to your use of any object code in the Content. Check the Redistributor's license that was -provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise -indicated below, the terms and conditions of the EPL still apply to any source code in the Content -and such source code may be obtained at http://www.eclipse.org.

- - - diff -Nru eclipse-aether-0.9.0.M2/aether-connector-wagon/src/test/java/org/eclipse/aether/connector/wagon/PlexusSupportTest.java eclipse-aether-1.0.2/aether-connector-wagon/src/test/java/org/eclipse/aether/connector/wagon/PlexusSupportTest.java --- eclipse-aether-0.9.0.M2/aether-connector-wagon/src/test/java/org/eclipse/aether/connector/wagon/PlexusSupportTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-wagon/src/test/java/org/eclipse/aether/connector/wagon/PlexusSupportTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.wagon; - -import org.codehaus.plexus.ContainerConfiguration; -import org.codehaus.plexus.PlexusTestCase; -import org.eclipse.aether.connector.wagon.WagonRepositoryConnectorFactory; -import org.eclipse.aether.internal.test.util.TestFileProcessor; -import org.eclipse.aether.internal.test.util.TestLoggerFactory; -import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; -import org.eclipse.aether.spi.io.FileProcessor; -import org.eclipse.aether.spi.log.LoggerFactory; - -/** - */ -public class PlexusSupportTest - extends PlexusTestCase -{ - - @Override - protected void customizeContainerConfiguration( ContainerConfiguration containerConfiguration ) - { - containerConfiguration.setClassPathScanning( "cache" ); - } - - public void testExistenceOfPlexusComponentMetadata() - throws Exception - { - getContainer().addComponent( new TestLoggerFactory(), LoggerFactory.class, null ); - getContainer().addComponent( new TestFileProcessor(), FileProcessor.class, null ); - - RepositoryConnectorFactory factory = lookup( RepositoryConnectorFactory.class, "wagon" ); - assertNotNull( factory ); - assertEquals( WagonRepositoryConnectorFactory.class, factory.getClass() ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-wagon/src/test/java/org/eclipse/aether/connector/wagon/TestSuiteHttpWagon.java eclipse-aether-1.0.2/aether-connector-wagon/src/test/java/org/eclipse/aether/connector/wagon/TestSuiteHttpWagon.java --- eclipse-aether-0.9.0.M2/aether-connector-wagon/src/test/java/org/eclipse/aether/connector/wagon/TestSuiteHttpWagon.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-wagon/src/test/java/org/eclipse/aether/connector/wagon/TestSuiteHttpWagon.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.connector.wagon; - -import java.util.Map; - -import org.apache.maven.wagon.ConnectionException; -import org.apache.maven.wagon.Wagon; -import org.apache.maven.wagon.providers.http.LightweightHttpWagon; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.connector.wagon.WagonProvider; -import org.eclipse.aether.connector.wagon.WagonRepositoryConnector; -import org.eclipse.aether.internal.test.util.TestFileProcessor; -import org.eclipse.aether.internal.test.util.connector.suite.ConnectorTestSuite; -import org.eclipse.aether.internal.test.util.connector.suite.ConnectorTestSetup.AbstractConnectorTestSetup; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; -import org.eclipse.aether.spi.log.NullLoggerFactory; -import org.eclipse.aether.transfer.NoRepositoryConnectorException; -import org.sonatype.tests.http.server.jetty.behaviour.ResourceServer; -import org.sonatype.tests.http.server.jetty.impl.JettyServerProvider; - -/** - */ -public class TestSuiteHttpWagon - extends ConnectorTestSuite -{ - - private static class JettyConnectorTestSetup - extends AbstractConnectorTestSetup - { - - private JettyServerProvider provider; - - public RemoteRepository before( RepositorySystemSession session, Map context ) - throws Exception - { - provider = new JettyServerProvider(); - provider.initServer(); - provider.addBehaviour( "/*", new ResourceServer() ); - provider.start(); - return new RemoteRepository.Builder( "jetty-repo", "default", provider.getUrl().toString() + "/repo" ).build(); - } - - public RepositoryConnectorFactory factory() - { - return new RepositoryConnectorFactory() - { - - public RepositoryConnector newInstance( RepositorySystemSession session, RemoteRepository repository ) - throws NoRepositoryConnectorException - { - return new WagonRepositoryConnector( new WagonProvider() - { - - public void release( Wagon wagon ) - { - try - { - wagon.disconnect(); - } - catch ( ConnectionException e ) - { - throw new RuntimeException( e.getMessage(), e ); - } - } - - public Wagon lookup( String roleHint ) - throws Exception - { - return new LightweightHttpWagon(); - } - - }, null, repository, session, new TestFileProcessor(), NullLoggerFactory.LOGGER ); - } - - public float getPriority() - { - return 0; - } - }; - } - - @Override - public void after( RepositorySystemSession session, RemoteRepository repository, Map context ) - throws Exception - { - if ( provider != null ) - { - provider.stop(); - provider = null; - } - } - - } - - public TestSuiteHttpWagon() - { - super( new JettyConnectorTestSetup() ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-connector-wagon/src/test/resources/logback-test.xml eclipse-aether-1.0.2/aether-connector-wagon/src/test/resources/logback-test.xml --- eclipse-aether-0.9.0.M2/aether-connector-wagon/src/test/resources/logback-test.xml 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-connector-wagon/src/test/resources/logback-test.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ - - - - - - - - %d{HH:mm:ss.SSS} [%-18thread] %c{1} [%p] %m%n - - - - - - - - - - - diff -Nru eclipse-aether-0.9.0.M2/aether-impl/pom.xml eclipse-aether-1.0.2/aether-impl/pom.xml --- eclipse-aether-0.9.0.M2/aether-impl/pom.xml 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/pom.xml 2015-01-14 12:56:17.000000000 +0000 @@ -1,7 +1,7 @@ + com.google.inject.*;version="[1.3,2)",* diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/AetherModule.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/AetherModule.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/AetherModule.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/AetherModule.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2012 Sonatype, Inc. + * Copyright (c) 2011, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,142 +10,17 @@ *******************************************************************************/ package org.eclipse.aether.impl; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import javax.inject.Named; -import javax.inject.Singleton; - -import org.eclipse.aether.RepositoryListener; -import org.eclipse.aether.RepositorySystem; -import org.eclipse.aether.internal.impl.DefaultArtifactResolver; -import org.eclipse.aether.internal.impl.DefaultDependencyCollector; -import org.eclipse.aether.internal.impl.DefaultDeployer; -import org.eclipse.aether.internal.impl.DefaultFileProcessor; -import org.eclipse.aether.internal.impl.DefaultInstaller; -import org.eclipse.aether.internal.impl.DefaultLocalRepositoryProvider; -import org.eclipse.aether.internal.impl.DefaultMetadataResolver; -import org.eclipse.aether.internal.impl.DefaultOfflineController; -import org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager; -import org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider; -import org.eclipse.aether.internal.impl.DefaultRepositoryEventDispatcher; -import org.eclipse.aether.internal.impl.DefaultRepositorySystem; -import org.eclipse.aether.internal.impl.DefaultSyncContextFactory; -import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager; -import org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer; -import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory; -import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory; -import org.eclipse.aether.internal.impl.Slf4jLoggerFactory; -import org.eclipse.aether.spi.io.FileProcessor; -import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory; -import org.eclipse.aether.spi.log.LoggerFactory; -import org.eclipse.aether.spi.log.NullLoggerFactory; -import org.slf4j.ILoggerFactory; - -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.name.Names; - /** * A ready-made Guice module that sets up bindings for all components from this library. To acquire a complete * repository system, clients need to bind an artifact descriptor reader, a version resolver, a version range resolver, - * zero or more metadata generator factories and some repository connectors to access remote repositories. + * zero or more metadata generator factories, some repository connector and transporter factories to access remote + * repositories. + * + * @deprecated Use {@link org.eclipse.aether.impl.guice.AetherModule} instead. */ +@Deprecated public final class AetherModule - extends AbstractModule + extends org.eclipse.aether.impl.guice.AetherModule { - @Override - protected void configure() - { - bind( RepositorySystem.class ) // - .to( DefaultRepositorySystem.class ).in( Singleton.class ); - bind( ArtifactResolver.class ) // - .to( DefaultArtifactResolver.class ).in( Singleton.class ); - bind( DependencyCollector.class ) // - .to( DefaultDependencyCollector.class ).in( Singleton.class ); - bind( Deployer.class ) // - .to( DefaultDeployer.class ).in( Singleton.class ); - bind( Installer.class ) // - .to( DefaultInstaller.class ).in( Singleton.class ); - bind( MetadataResolver.class ) // - .to( DefaultMetadataResolver.class ).in( Singleton.class ); - bind( RepositoryConnectorProvider.class ) // - .to( DefaultRepositoryConnectorProvider.class ).in( Singleton.class ); - bind( RemoteRepositoryManager.class ) // - .to( DefaultRemoteRepositoryManager.class ).in( Singleton.class ); - bind( UpdateCheckManager.class ) // - .to( DefaultUpdateCheckManager.class ).in( Singleton.class ); - bind( UpdatePolicyAnalyzer.class ) // - .to( DefaultUpdatePolicyAnalyzer.class ).in( Singleton.class ); - bind( FileProcessor.class ) // - .to( DefaultFileProcessor.class ).in( Singleton.class ); - bind( SyncContextFactory.class ) // - .to( DefaultSyncContextFactory.class ).in( Singleton.class ); - bind( RepositoryEventDispatcher.class ) // - .to( DefaultRepositoryEventDispatcher.class ).in( Singleton.class ); - bind( OfflineController.class ) // - .to( DefaultOfflineController.class ).in( Singleton.class ); - bind( LocalRepositoryProvider.class ) // - .to( DefaultLocalRepositoryProvider.class ).in( Singleton.class ); - bind( LocalRepositoryManagerFactory.class ).annotatedWith( Names.named( "simple" ) ) // - .to( SimpleLocalRepositoryManagerFactory.class ).in( Singleton.class ); - bind( LocalRepositoryManagerFactory.class ).annotatedWith( Names.named( "enhanced" ) ) // - .to( EnhancedLocalRepositoryManagerFactory.class ).in( Singleton.class ); - if ( Slf4jLoggerFactory.isSlf4jAvailable() ) - { - bindSlf4j(); - } - else - { - bind( LoggerFactory.class ) // - .toInstance( NullLoggerFactory.INSTANCE ); - } - - } - - private void bindSlf4j() - { - install( new Slf4jModule() ); - } - - @Provides - @Singleton - Set provideLocalRepositoryManagerFactories( @Named( "simple" ) LocalRepositoryManagerFactory simple, - @Named( "enhanced" ) LocalRepositoryManagerFactory enhanced ) - { - Set factories = new HashSet(); - factories.add( simple ); - factories.add( enhanced ); - return Collections.unmodifiableSet( factories ); - } - - @Provides - @Singleton - Set providesRepositoryListeners() - { - return Collections.emptySet(); - } - - private static class Slf4jModule - extends AbstractModule - { - - @Override - protected void configure() - { - bind( LoggerFactory.class ) // - .to( Slf4jLoggerFactory.class ); - } - - @Provides - @Singleton - ILoggerFactory getLoggerFactory() - { - return org.slf4j.LoggerFactory.getILoggerFactory(); - } - - } - } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/ArtifactDescriptorReader.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/ArtifactDescriptorReader.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/ArtifactDescriptorReader.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/ArtifactDescriptorReader.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,23 +10,31 @@ *******************************************************************************/ package org.eclipse.aether.impl; +import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.resolution.ArtifactDescriptorException; import org.eclipse.aether.resolution.ArtifactDescriptorRequest; import org.eclipse.aether.resolution.ArtifactDescriptorResult; /** + * Provides information about an artifact that is relevant to transitive dependency resolution. Each artifact is expected + * to have an accompanying artifact descriptor that among others lists the direct dependencies of the artifact. + * + * @provisional This type is provisional and can be changed, moved or removed without prior notice. */ public interface ArtifactDescriptorReader { /** - * Gets information about an artifact like its direct dependencies. + * Gets information about an artifact like its direct dependencies and potential relocations. Implementations must + * respect the {@link RepositorySystemSession#getArtifactDescriptorPolicy() artifact descriptor policy} of the + * session when dealing with certain error cases. * * @param session The repository session, must not be {@code null}. * @param request The descriptor request, must not be {@code null} * @return The descriptor result, never {@code null}. * @throws ArtifactDescriptorException If the artifact descriptor could not be read. + * @see RepositorySystem#readArtifactDescriptor(RepositorySystemSession, ArtifactDescriptorRequest) */ ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session, ArtifactDescriptorRequest request ) throws ArtifactDescriptorException; diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/ArtifactResolver.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/ArtifactResolver.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/ArtifactResolver.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/ArtifactResolver.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -13,26 +13,49 @@ import java.util.Collection; import java.util.List; +import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.resolution.ArtifactRequest; import org.eclipse.aether.resolution.ArtifactResolutionException; import org.eclipse.aether.resolution.ArtifactResult; /** + * Resolves artifacts, that is gets a local filesystem path to their binary contents. + * * @noimplement This interface is not intended to be implemented by clients. * @noextend This interface is not intended to be extended by clients. + * @provisional This type is provisional and can be changed, moved or removed without prior notice. */ public interface ArtifactResolver { /** - * Resolves the path for an artifact. The artifact will be downloaded if necessary. + * Resolves the path for an artifact. The artifact will be downloaded to the local repository if necessary. An + * artifact that is already resolved will be skipped and is not re-resolved. Note that this method assumes that any + * relocations have already been processed and the artifact coordinates are used as-is. + * + * @param session The repository session, must not be {@code null}. + * @param request The resolution request, must not be {@code null}. + * @return The resolution result, never {@code null}. + * @throws ArtifactResolutionException If the artifact could not be resolved. + * @see Artifact#getFile() + * @see RepositorySystem#resolveArtifact(RepositorySystemSession, ArtifactRequest) */ ArtifactResult resolveArtifact( RepositorySystemSession session, ArtifactRequest request ) throws ArtifactResolutionException; /** - * Resolves the paths for a collection of artifacts. Artifacts will be downloaded if necessary. + * Resolves the paths for a collection of artifacts. Artifacts will be downloaded to the local repository if + * necessary. Artifacts that are already resolved will be skipped and are not re-resolved. Note that this method + * assumes that any relocations have already been processed and the artifact coordinates are used as-is. + * + * @param session The repository session, must not be {@code null}. + * @param requests The resolution requests, must not be {@code null}. + * @return The resolution results (in request order), never {@code null}. + * @throws ArtifactResolutionException If any artifact could not be resolved. + * @see Artifact#getFile() + * @see RepositorySystem#resolveArtifacts(RepositorySystemSession, Collection) */ List resolveArtifacts( RepositorySystemSession session, Collection requests ) diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/DefaultServiceLocator.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/DefaultServiceLocator.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/DefaultServiceLocator.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/DefaultServiceLocator.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -22,6 +22,7 @@ import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.internal.impl.DefaultArtifactResolver; +import org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider; import org.eclipse.aether.internal.impl.DefaultDependencyCollector; import org.eclipse.aether.internal.impl.DefaultDeployer; import org.eclipse.aether.internal.impl.DefaultFileProcessor; @@ -32,13 +33,20 @@ import org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager; import org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider; import org.eclipse.aether.internal.impl.DefaultRepositoryEventDispatcher; +import org.eclipse.aether.internal.impl.DefaultRepositoryLayoutProvider; import org.eclipse.aether.internal.impl.DefaultRepositorySystem; import org.eclipse.aether.internal.impl.DefaultSyncContextFactory; +import org.eclipse.aether.internal.impl.DefaultTransporterProvider; import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager; import org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer; import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory; +import org.eclipse.aether.internal.impl.Maven2RepositoryLayoutFactory; import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory; -import org.eclipse.aether.internal.impl.Slf4jLoggerFactory; +import org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory; +import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider; +import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory; +import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider; +import org.eclipse.aether.spi.connector.transport.TransporterProvider; import org.eclipse.aether.spi.io.FileProcessor; import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory; import org.eclipse.aether.spi.locator.Service; @@ -48,8 +56,8 @@ /** * A simple service locator that is already setup with all components from this library. To acquire a complete * repository system, clients need to add an artifact descriptor reader, a version resolver, a version range resolver - * and optionally some repository connectors to access remote repositories. Once the locator is fully populated, the - * repository system can be created like this: + * and optionally some repository connector and transporter factories to access remote repositories. Once the locator is + * fully populated, the repository system can be created like this: * *
  * RepositorySystem repoSystem = serviceLocator.getService( RepositorySystem.class );
@@ -194,6 +202,10 @@
         addService( Deployer.class, DefaultDeployer.class );
         addService( Installer.class, DefaultInstaller.class );
         addService( MetadataResolver.class, DefaultMetadataResolver.class );
+        addService( RepositoryLayoutProvider.class, DefaultRepositoryLayoutProvider.class );
+        addService( RepositoryLayoutFactory.class, Maven2RepositoryLayoutFactory.class );
+        addService( TransporterProvider.class, DefaultTransporterProvider.class );
+        addService( ChecksumPolicyProvider.class, DefaultChecksumPolicyProvider.class );
         addService( RepositoryConnectorProvider.class, DefaultRepositoryConnectorProvider.class );
         addService( RemoteRepositoryManager.class, DefaultRemoteRepositoryManager.class );
         addService( UpdateCheckManager.class, DefaultUpdateCheckManager.class );
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/DependencyCollector.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/DependencyCollector.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/DependencyCollector.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/DependencyCollector.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,16 +17,31 @@
 import org.eclipse.aether.collection.DependencyCollectionException;
 
 /**
- * This collector fulfills the contract of
- * {@link RepositorySystem#collectDependencies(RepositorySystemSession, CollectRequest)}.
+ * Given a collection of direct dependencies, recursively gathers their transitive dependencies and calculates the
+ * dependency graph.
  * 
  * @noimplement This interface is not intended to be implemented by clients.
  * @noextend This interface is not intended to be extended by clients.
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface DependencyCollector
 {
 
     /**
+     * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is
+     * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the
+     * artifact files. The supplied session carries various hooks to customize the dependency graph that must be invoked
+     * throughout the operation.
+     * 
+     * @param session The repository session, must not be {@code null}.
+     * @param request The collection request, must not be {@code null}.
+     * @return The collection result, never {@code null}.
+     * @throws DependencyCollectionException If the dependency tree could not be built.
+     * @see RepositorySystemSession#getDependencyTraverser()
+     * @see RepositorySystemSession#getDependencyManager()
+     * @see RepositorySystemSession#getDependencySelector()
+     * @see RepositorySystemSession#getVersionFilter()
+     * @see RepositorySystemSession#getDependencyGraphTransformer()
      * @see RepositorySystem#collectDependencies(RepositorySystemSession, CollectRequest)
      */
     CollectResult collectDependencies( RepositorySystemSession session, CollectRequest request )
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/Deployer.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/Deployer.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/Deployer.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/Deployer.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,8 +17,11 @@
 import org.eclipse.aether.deployment.DeploymentException;
 
 /**
+ * Publishes artifacts to a remote repository.
+ * 
  * @noimplement This interface is not intended to be implemented by clients.
  * @noextend This interface is not intended to be extended by clients.
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface Deployer
 {
@@ -31,6 +34,7 @@
      * @return The deployment result, never {@code null}.
      * @throws DeploymentException If any artifact/metadata from the request could not be deployed.
      * @see RepositorySystem#deploy(RepositorySystemSession, DeployRequest)
+     * @see MetadataGeneratorFactory#newInstance(RepositorySystemSession, DeployRequest)
      */
     DeployResult deploy( RepositorySystemSession session, DeployRequest request )
         throws DeploymentException;
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java	1970-01-01 00:00:00.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java	2015-01-14 12:56:17.000000000 +0000
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.impl.guice;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.eclipse.aether.RepositoryListener;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.impl.ArtifactResolver;
+import org.eclipse.aether.impl.DependencyCollector;
+import org.eclipse.aether.impl.Deployer;
+import org.eclipse.aether.impl.Installer;
+import org.eclipse.aether.impl.LocalRepositoryProvider;
+import org.eclipse.aether.impl.MetadataResolver;
+import org.eclipse.aether.impl.OfflineController;
+import org.eclipse.aether.impl.RemoteRepositoryManager;
+import org.eclipse.aether.impl.RepositoryConnectorProvider;
+import org.eclipse.aether.impl.RepositoryEventDispatcher;
+import org.eclipse.aether.impl.SyncContextFactory;
+import org.eclipse.aether.impl.UpdateCheckManager;
+import org.eclipse.aether.impl.UpdatePolicyAnalyzer;
+import org.eclipse.aether.internal.impl.DefaultArtifactResolver;
+import org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider;
+import org.eclipse.aether.internal.impl.DefaultDependencyCollector;
+import org.eclipse.aether.internal.impl.DefaultDeployer;
+import org.eclipse.aether.internal.impl.DefaultFileProcessor;
+import org.eclipse.aether.internal.impl.DefaultInstaller;
+import org.eclipse.aether.internal.impl.DefaultLocalRepositoryProvider;
+import org.eclipse.aether.internal.impl.DefaultMetadataResolver;
+import org.eclipse.aether.internal.impl.DefaultOfflineController;
+import org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager;
+import org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider;
+import org.eclipse.aether.internal.impl.DefaultRepositoryEventDispatcher;
+import org.eclipse.aether.internal.impl.DefaultRepositoryLayoutProvider;
+import org.eclipse.aether.internal.impl.DefaultRepositorySystem;
+import org.eclipse.aether.internal.impl.DefaultSyncContextFactory;
+import org.eclipse.aether.internal.impl.DefaultTransporterProvider;
+import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager;
+import org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer;
+import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory;
+import org.eclipse.aether.internal.impl.Maven2RepositoryLayoutFactory;
+import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
+import org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory;
+import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
+import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory;
+import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider;
+import org.eclipse.aether.spi.connector.transport.TransporterProvider;
+import org.eclipse.aether.spi.io.FileProcessor;
+import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory;
+import org.eclipse.aether.spi.log.LoggerFactory;
+import org.eclipse.aether.spi.log.NullLoggerFactory;
+import org.slf4j.ILoggerFactory;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+import com.google.inject.name.Names;
+
+/**
+ * A ready-made Guice module that sets up bindings
+ * for all components from this library. To acquire a complete repository system, clients need to bind an artifact
+ * descriptor reader, a version resolver, a version range resolver, zero or more metadata generator factories, some
+ * repository connector and transporter factories to access remote repositories.
+ * 
+ * @noextend This class must not be extended by clients and will eventually be marked {@code final} without prior
+ *           notice.
+ */
+public class AetherModule
+    extends AbstractModule
+{
+
+    /**
+     * Creates a new instance of this Guice module, typically for invoking
+     * {@link com.google.inject.Binder#install(com.google.inject.Module)}.
+     */
+    public AetherModule()
+    {
+    }
+
+    /**
+     * Configures Guice with bindings for Aether components provided by this library.
+     */
+    @Override
+    protected void configure()
+    {
+        bind( RepositorySystem.class ) //
+        .to( DefaultRepositorySystem.class ).in( Singleton.class );
+        bind( ArtifactResolver.class ) //
+        .to( DefaultArtifactResolver.class ).in( Singleton.class );
+        bind( DependencyCollector.class ) //
+        .to( DefaultDependencyCollector.class ).in( Singleton.class );
+        bind( Deployer.class ) //
+        .to( DefaultDeployer.class ).in( Singleton.class );
+        bind( Installer.class ) //
+        .to( DefaultInstaller.class ).in( Singleton.class );
+        bind( MetadataResolver.class ) //
+        .to( DefaultMetadataResolver.class ).in( Singleton.class );
+        bind( RepositoryLayoutProvider.class ) //
+        .to( DefaultRepositoryLayoutProvider.class ).in( Singleton.class );
+        bind( RepositoryLayoutFactory.class ).annotatedWith( Names.named( "maven2" ) ) //
+        .to( Maven2RepositoryLayoutFactory.class ).in( Singleton.class );
+        bind( TransporterProvider.class ) //
+        .to( DefaultTransporterProvider.class ).in( Singleton.class );
+        bind( ChecksumPolicyProvider.class ) //
+        .to( DefaultChecksumPolicyProvider.class ).in( Singleton.class );
+        bind( RepositoryConnectorProvider.class ) //
+        .to( DefaultRepositoryConnectorProvider.class ).in( Singleton.class );
+        bind( RemoteRepositoryManager.class ) //
+        .to( DefaultRemoteRepositoryManager.class ).in( Singleton.class );
+        bind( UpdateCheckManager.class ) //
+        .to( DefaultUpdateCheckManager.class ).in( Singleton.class );
+        bind( UpdatePolicyAnalyzer.class ) //
+        .to( DefaultUpdatePolicyAnalyzer.class ).in( Singleton.class );
+        bind( FileProcessor.class ) //
+        .to( DefaultFileProcessor.class ).in( Singleton.class );
+        bind( SyncContextFactory.class ) //
+        .to( DefaultSyncContextFactory.class ).in( Singleton.class );
+        bind( RepositoryEventDispatcher.class ) //
+        .to( DefaultRepositoryEventDispatcher.class ).in( Singleton.class );
+        bind( OfflineController.class ) //
+        .to( DefaultOfflineController.class ).in( Singleton.class );
+        bind( LocalRepositoryProvider.class ) //
+        .to( DefaultLocalRepositoryProvider.class ).in( Singleton.class );
+        bind( LocalRepositoryManagerFactory.class ).annotatedWith( Names.named( "simple" ) ) //
+        .to( SimpleLocalRepositoryManagerFactory.class ).in( Singleton.class );
+        bind( LocalRepositoryManagerFactory.class ).annotatedWith( Names.named( "enhanced" ) ) //
+        .to( EnhancedLocalRepositoryManagerFactory.class ).in( Singleton.class );
+        if ( Slf4jLoggerFactory.isSlf4jAvailable() )
+        {
+            bindSlf4j();
+        }
+        else
+        {
+            bind( LoggerFactory.class ) //
+            .toInstance( NullLoggerFactory.INSTANCE );
+        }
+
+    }
+
+    private void bindSlf4j()
+    {
+        install( new Slf4jModule() );
+    }
+
+    @Provides
+    @Singleton
+    Set provideLocalRepositoryManagerFactories( @Named( "simple" ) LocalRepositoryManagerFactory simple,
+                                                                               @Named( "enhanced" ) LocalRepositoryManagerFactory enhanced )
+    {
+        Set factories = new HashSet();
+        factories.add( simple );
+        factories.add( enhanced );
+        return Collections.unmodifiableSet( factories );
+    }
+
+    @Provides
+    @Singleton
+    Set provideRepositoryLayoutFactories( @Named( "maven2" ) RepositoryLayoutFactory maven2 )
+    {
+        Set factories = new HashSet();
+        factories.add( maven2 );
+        return Collections.unmodifiableSet( factories );
+    }
+
+    @Provides
+    @Singleton
+    Set providesRepositoryListeners()
+    {
+        return Collections.emptySet();
+    }
+
+    private static class Slf4jModule
+        extends AbstractModule
+    {
+
+        @Override
+        protected void configure()
+        {
+            bind( LoggerFactory.class ) //
+            .to( Slf4jLoggerFactory.class );
+        }
+
+        @Provides
+        @Singleton
+        ILoggerFactory getLoggerFactory()
+        {
+            return org.slf4j.LoggerFactory.getILoggerFactory();
+        }
+
+    }
+
+}
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/guice/package-info.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/guice/package-info.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/guice/package-info.java	1970-01-01 00:00:00.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/guice/package-info.java	2015-01-14 12:56:17.000000000 +0000
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+/**
+ * The integration with the dependency injection framework Google Guice. 
+ */
+package org.eclipse.aether.impl.guice;
+
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/Installer.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/Installer.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/Installer.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/Installer.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,8 +17,11 @@
 import org.eclipse.aether.installation.InstallationException;
 
 /**
+ * Publishes artifacts to the local repository.
+ * 
  * @noimplement This interface is not intended to be implemented by clients.
  * @noextend This interface is not intended to be extended by clients.
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface Installer
 {
@@ -31,6 +34,7 @@
      * @return The installation result, never {@code null}.
      * @throws InstallationException If any artifact/metadata from the request could not be installed.
      * @see RepositorySystem#install(RepositorySystemSession, InstallRequest)
+     * @see MetadataGeneratorFactory#newInstance(RepositorySystemSession, InstallRequest)
      */
     InstallResult install( RepositorySystemSession session, InstallRequest request )
         throws InstallationException;
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/LocalRepositoryProvider.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/LocalRepositoryProvider.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/LocalRepositoryProvider.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/LocalRepositoryProvider.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.aether.impl;
 
+import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.repository.LocalRepository;
 import org.eclipse.aether.repository.LocalRepositoryManager;
@@ -20,10 +21,24 @@
  * 
  * @noimplement This interface is not intended to be implemented by clients.
  * @noextend This interface is not intended to be extended by clients.
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface LocalRepositoryProvider
 {
 
+    /**
+     * Creates a new manager for the specified local repository. If the specified local repository has no type, the
+     * default local repository type of the system will be used. Note: It is expected that this method
+     * invocation is one of the last steps of setting up a new session, in particular any configuration properties
+     * should have been set already.
+     * 
+     * @param session The repository system session from which to configure the manager, must not be {@code null}.
+     * @param localRepository The local repository to create a manager for, must not be {@code null}.
+     * @return The local repository manager, never {@code null}.
+     * @throws NoLocalRepositoryManagerException If the specified repository type is not recognized or no base directory
+     *             is given.
+     * @see RepositorySystem#newLocalRepositoryManager(RepositorySystemSession, LocalRepository)
+     */
     LocalRepositoryManager newLocalRepositoryManager( RepositorySystemSession session, LocalRepository localRepository )
         throws NoLocalRepositoryManagerException;
 
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/MetadataGeneratorFactory.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/MetadataGeneratorFactory.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/MetadataGeneratorFactory.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/MetadataGeneratorFactory.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,6 +17,8 @@
 /**
  * A factory to create metadata generators. Metadata generators can contribute additional metadata during the
  * installation/deployment of artifacts.
+ * 
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface MetadataGeneratorFactory
 {
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/MetadataGenerator.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/MetadataGenerator.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/MetadataGenerator.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/MetadataGenerator.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,6 +17,8 @@
 
 /**
  * A metadata generator that participates in the installation/deployment of artifacts.
+ * 
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface MetadataGenerator
 {
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/MetadataResolver.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/MetadataResolver.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/MetadataResolver.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/MetadataResolver.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,19 +13,31 @@
 import java.util.Collection;
 import java.util.List;
 
+import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.metadata.Metadata;
 import org.eclipse.aether.resolution.MetadataRequest;
 import org.eclipse.aether.resolution.MetadataResult;
 
 /**
+ * Resolves metadata, that is gets a local filesystem path to their binary contents.
+ * 
  * @noimplement This interface is not intended to be implemented by clients.
  * @noextend This interface is not intended to be extended by clients.
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface MetadataResolver
 {
 
     /**
-     * Resolves the paths for a collection of metadata. Metadata will be downloaded if necessary.
+     * Resolves the paths for a collection of metadata. Metadata will be downloaded to the local repository if
+     * necessary, e.g. because it hasn't been cached yet or the cache is deemed outdated.
+     * 
+     * @param session The repository session, must not be {@code null}.
+     * @param requests The resolution requests, must not be {@code null}.
+     * @return The resolution results (in request order), never {@code null}.
+     * @see Metadata#getFile()
+     * @see RepositorySystem#resolveMetadata(RepositorySystemSession, Collection)
      */
     List resolveMetadata( RepositorySystemSession session,
                                           Collection requests );
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/OfflineController.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/OfflineController.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/OfflineController.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/OfflineController.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012 Sonatype, Inc.
+ * Copyright (c) 2012, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -19,16 +19,24 @@
  * 
  * @noimplement This interface is not intended to be implemented by clients.
  * @noextend This interface is not intended to be extended by clients.
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface OfflineController
 {
 
     /**
-     * Determines whether the specified repository is accessible according to the offline policy of the given session.
+     * Determines whether the specified repository is accessible if the system was in offline mode. A simple
+     * implementation might unconditionally throw {@link RepositoryOfflineException} to block all remote repository
+     * access when in offline mode. More sophisticated implementations might inspect
+     * {@link RepositorySystemSession#getConfigProperties() configuration properties} of the session to check for some
+     * kind of whitelist that allows certain remote repositories even when offline. At any rate, the session's current
+     * {@link RepositorySystemSession#isOffline() offline state} is irrelevant to the outcome of the check.
      * 
-     * @param session The repository session during which the check is made, must not be {@code null}
-     * @param repository The remote repository to check for accessibility, must not be {@code null}.
-     * @throws RepositoryOfflineException If the session forbids access to the repository.
+     * @param session The repository session during which the check is made, must not be {@code null}.
+     * @param repository The remote repository to check for offline access, must not be {@code null}.
+     * @throws RepositoryOfflineException If the repository is not accessible in offline mode. If the method returns
+     *             normally, the repository is considered accessible even in offline mode.
+     * @see RepositorySystemSession#isOffline()
      */
     void checkOffline( RepositorySystemSession session, RemoteRepository repository )
         throws RepositoryOfflineException;
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/package-info.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/package-info.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/package-info.java	1970-01-01 00:00:00.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/package-info.java	2015-01-14 12:56:17.000000000 +0000
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+/**
+ * The provisional interfaces defining the various sub components that implement the repository system. Aether Core
+ * provides stock implementations for most of these components but not all. To obtain a complete/runnable repository
+ * system, the application needs to provide implementations of the following component contracts:
+ * {@link org.eclipse.aether.impl.ArtifactDescriptorReader}, {@link org.eclipse.aether.impl.VersionResolver},
+ * {@link org.eclipse.aether.impl.VersionRangeResolver} and potentially
+ * {@link org.eclipse.aether.impl.MetadataGeneratorFactory}. Said components basically define the file format of the
+ * metadata that is used to reason about an artifact's dependencies and available versions.
+ */
+package org.eclipse.aether.impl;
+
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/RemoteRepositoryManager.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/RemoteRepositoryManager.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/RemoteRepositoryManager.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/RemoteRepositoryManager.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,16 +17,46 @@
 import org.eclipse.aether.repository.RepositoryPolicy;
 
 /**
+ * Helps dealing with remote repository definitions.
+ * 
  * @noimplement This interface is not intended to be implemented by clients.
  * @noextend This interface is not intended to be extended by clients.
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface RemoteRepositoryManager
 {
 
+    /**
+     * Aggregates repository definitions by merging duplicate repositories and optionally applies mirror, proxy and
+     * authentication settings from the supplied session.
+     * 
+     * @param session The repository session during which the repositories will be accessed, must not be {@code null}.
+     * @param dominantRepositories The current list of remote repositories to merge the new definitions into, must not
+     *            be {@code null}.
+     * @param recessiveRepositories The remote repositories to merge into the existing list, must not be {@code null}.
+     * @param recessiveIsRaw {@code true} if the recessive repository definitions have not yet been subjected to mirror,
+     *            proxy and authentication settings, {@code false} otherwise.
+     * @return The aggregated list of remote repositories, never {@code null}.
+     * @see RepositorySystemSession#getMirrorSelector()
+     * @see RepositorySystemSession#getProxySelector()
+     * @see RepositorySystemSession#getAuthenticationSelector()
+     */
     List aggregateRepositories( RepositorySystemSession session,
                                                   List dominantRepositories,
                                                   List recessiveRepositories, boolean recessiveIsRaw );
 
+    /**
+     * Gets the effective repository policy for the specified remote repository by merging the applicable
+     * snapshot/release policy of the repository with global settings from the supplied session.
+     * 
+     * @param session The repository session during which the repository will be accessed, must not be {@code null}.
+     * @param repository The remote repository to determine the effective policy for, must not be {@code null}.
+     * @param releases {@code true} if the policy for release artifacts needs to be considered, {@code false} if not.
+     * @param snapshots {@code true} if the policy for snapshot artifacts needs to be considered, {@code false} if not.
+     * @return The effective repository policy, never {@code null}.
+     * @see RepositorySystemSession#getChecksumPolicy()
+     * @see RepositorySystemSession#getUpdatePolicy()
+     */
     RepositoryPolicy getPolicy( RepositorySystemSession session, RemoteRepository repository, boolean releases,
                                 boolean snapshots );
 
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/RepositoryConnectorProvider.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/RepositoryConnectorProvider.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/RepositoryConnectorProvider.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/RepositoryConnectorProvider.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012 Sonatype, Inc.
+ * Copyright (c) 2012, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -20,10 +20,20 @@
  * 
  * @noimplement This interface is not intended to be implemented by clients.
  * @noextend This interface is not intended to be extended by clients.
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface RepositoryConnectorProvider
 {
 
+    /**
+     * Tries to create a repository connector for the specified remote repository.
+     * 
+     * @param session The repository system session from which to configure the connector, must not be {@code null}.
+     * @param repository The remote repository to create a connector for, must not be {@code null}.
+     * @return The connector for the given repository, never {@code null}.
+     * @throws NoRepositoryConnectorException If no available factory can create a connector for the specified remote
+     *             repository.
+     */
     RepositoryConnector newRepositoryConnector( RepositorySystemSession session, RemoteRepository repository )
         throws NoRepositoryConnectorException;
 
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/RepositoryEventDispatcher.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/RepositoryEventDispatcher.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/RepositoryEventDispatcher.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/RepositoryEventDispatcher.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,6 +17,7 @@
  * 
  * @noimplement This interface is not intended to be implemented by clients.
  * @noextend This interface is not intended to be extended by clients.
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface RepositoryEventDispatcher
 {
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/SyncContextFactory.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/SyncContextFactory.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/SyncContextFactory.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/SyncContextFactory.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,12 +10,15 @@
  *******************************************************************************/
 package org.eclipse.aether.impl;
 
+import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.SyncContext;
 
 /**
  * A factory to create synchronization contexts. A synchronization context is used to coordinate concurrent access to
  * artifacts or metadata.
+ * 
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface SyncContextFactory
 {
@@ -27,6 +30,7 @@
      * @param shared A flag indicating whether access to the artifacts/metadata associated with the new context can be
      *            shared among concurrent readers or whether access needs to be exclusive to the calling thread.
      * @return The synchronization context, never {@code null}.
+     * @see RepositorySystem#newSyncContext(RepositorySystemSession, boolean)
      */
     SyncContext newInstance( RepositorySystemSession session, boolean shared );
 
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/UpdateCheck.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/UpdateCheck.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/UpdateCheck.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/UpdateCheck.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -19,6 +19,7 @@
  * A request to check if an update of an artifact/metadata from a remote repository is needed.
  * 
  * @see UpdateCheckManager
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public final class UpdateCheck
 {
@@ -42,6 +43,13 @@
     private E exception;
 
     /**
+     * Creates an uninitialized update check request.
+     */
+    public UpdateCheck()
+    {
+    }
+
+    /**
      * Gets the last-modified timestamp of the corresponding item produced by a local installation. If non-zero, a
      * remote update will be surpressed if the local item is up-to-date, even if the remote item has not been cached
      * locally.
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/UpdateCheckManager.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/UpdateCheckManager.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/UpdateCheckManager.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/UpdateCheckManager.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -21,6 +21,7 @@
  * 
  * @noimplement This interface is not intended to be implemented by clients.
  * @noextend This interface is not intended to be extended by clients.
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface UpdateCheckManager
 {
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/UpdatePolicyAnalyzer.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/UpdatePolicyAnalyzer.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/UpdatePolicyAnalyzer.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/UpdatePolicyAnalyzer.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,6 +17,7 @@
  * 
  * @noimplement This interface is not intended to be implemented by clients.
  * @noextend This interface is not intended to be extended by clients.
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface UpdatePolicyAnalyzer
 {
diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/VersionRangeResolver.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/VersionRangeResolver.java
--- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/VersionRangeResolver.java	2013-02-16 19:52:37.000000000 +0000
+++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/VersionRangeResolver.java	2015-01-14 12:56:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,19 +10,35 @@
  *******************************************************************************/
 package org.eclipse.aether.impl;
 
+import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.resolution.VersionRangeRequest;
 import org.eclipse.aether.resolution.VersionRangeResolutionException;
 import org.eclipse.aether.resolution.VersionRangeResult;
 
 /**
+ * Parses and evaluates version ranges encountered in dependency declarations.
+ * 
+ * @provisional This type is provisional and can be changed, moved or removed without prior notice.
  */
 public interface VersionRangeResolver
 {
 
     /**
      * Expands a version range to a list of matching versions, in ascending order. For example, resolves "[3.8,4.0)" to
-     * ["3.8", "3.8.1", "3.8.2"].
+     * "3.8", "3.8.1", "3.8.2". The returned list of versions is only dependent on the configured repositories and their
+     * contents, the list is not processed by the {@link RepositorySystemSession#getVersionFilter() session's version
+     * filter}.
+     * 

+ * The supplied request may also refer to a single concrete version rather than a version range. In this case + * though, the result contains simply the (parsed) input version, regardless of the repositories and their contents. + * + * @param session The repository session, must not be {@code null}. + * @param request The version range request, must not be {@code null}. + * @return The version range result, never {@code null}. + * @throws VersionRangeResolutionException If the requested range could not be parsed. Note that an empty range does + * not raise an exception. + * @see RepositorySystem#resolveVersionRange(RepositorySystemSession, VersionRangeRequest) */ VersionRangeResult resolveVersionRange( RepositorySystemSession session, VersionRangeRequest request ) throws VersionRangeResolutionException; diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/VersionResolver.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/VersionResolver.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/impl/VersionResolver.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/impl/VersionResolver.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,12 +10,16 @@ *******************************************************************************/ package org.eclipse.aether.impl; +import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.resolution.VersionRequest; import org.eclipse.aether.resolution.VersionResolutionException; import org.eclipse.aether.resolution.VersionResult; /** + * Evaluates artifact meta/pseudo versions. + * + * @provisional This type is provisional and can be changed, moved or removed without prior notice. */ public interface VersionResolver { @@ -28,6 +32,7 @@ * @param request The version request, must not be {@code null} * @return The version result, never {@code null}. * @throws VersionResolutionException If the metaversion could not be resolved. + * @see RepositorySystem#resolveVersion(RepositorySystemSession, VersionRequest) */ VersionResult resolveVersion( RepositorySystemSession session, VersionRequest request ) throws VersionResolutionException; diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/AbstractChecksumPolicy.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/AbstractChecksumPolicy.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/AbstractChecksumPolicy.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/AbstractChecksumPolicy.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.spi.log.NullLoggerFactory; +import org.eclipse.aether.transfer.ChecksumFailureException; +import org.eclipse.aether.transfer.TransferResource; + +abstract class AbstractChecksumPolicy + implements ChecksumPolicy + +{ + + protected final Logger logger; + + protected final TransferResource resource; + + protected AbstractChecksumPolicy( LoggerFactory loggerFactory, TransferResource resource ) + { + this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() ); + this.resource = resource; + } + + public boolean onChecksumMatch( String algorithm, int kind ) + { + return true; + } + + public void onChecksumMismatch( String algorithm, int kind, ChecksumFailureException exception ) + throws ChecksumFailureException + { + if ( ( kind & KIND_UNOFFICIAL ) == 0 ) + { + throw exception; + } + } + + public void onChecksumError( String algorithm, int kind, ChecksumFailureException exception ) + throws ChecksumFailureException + { + logger.debug( "Could not validate " + algorithm + " checksum for " + resource.getResourceName(), exception ); + } + + public void onNoMoreChecksums() + throws ChecksumFailureException + { + throw new ChecksumFailureException( "Checksum validation failed, no checksums available" ); + } + + public void onTransferRetry() + { + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/CacheUtils.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/CacheUtils.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/CacheUtils.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/CacheUtils.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. + * Copyright (c) 2010, 2013 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -22,7 +22,9 @@ import org.eclipse.aether.repository.WorkspaceRepository; /** + * @deprecated To be deleted without replacement. */ +@Deprecated public final class CacheUtils { diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DataPool.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DataPool.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DataPool.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DataPool.java 2015-01-14 12:56:17.000000000 +0000 @@ -23,6 +23,7 @@ import org.eclipse.aether.collection.DependencyManager; import org.eclipse.aether.collection.DependencySelector; import org.eclipse.aether.collection.DependencyTraverser; +import org.eclipse.aether.collection.VersionFilter; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.DependencyNode; import org.eclipse.aether.repository.ArtifactRepository; @@ -155,9 +156,9 @@ } public Object toKey( Artifact artifact, List repositories, DependencySelector selector, - DependencyManager manager, DependencyTraverser traverser ) + DependencyManager manager, DependencyTraverser traverser, VersionFilter filter ) { - return new GraphKey( artifact, repositories, selector, manager, traverser ); + return new GraphKey( artifact, repositories, selector, manager, traverser, filter ); } public List getChildren( Object key ) @@ -367,23 +368,27 @@ private final DependencyTraverser traverser; + private final VersionFilter filter; + private final int hashCode; public GraphKey( Artifact artifact, List repositories, DependencySelector selector, - DependencyManager manager, DependencyTraverser traverser ) + DependencyManager manager, DependencyTraverser traverser, VersionFilter filter ) { this.artifact = artifact; this.repositories = repositories; this.selector = selector; this.manager = manager; this.traverser = traverser; + this.filter = filter; int hash = 17; hash = hash * 31 + artifact.hashCode(); hash = hash * 31 + repositories.hashCode(); - hash = hash * 31 + selector.hashCode(); - hash = hash * 31 + manager.hashCode(); - hash = hash * 31 + traverser.hashCode(); + hash = hash * 31 + hash( selector ); + hash = hash * 31 + hash( manager ); + hash = hash * 31 + hash( traverser ); + hash = hash * 31 + hash( filter ); hashCode = hash; } @@ -400,8 +405,8 @@ } GraphKey that = (GraphKey) obj; return artifact.equals( that.artifact ) && repositories.equals( that.repositories ) - && selector.equals( that.selector ) && manager.equals( that.manager ) - && traverser.equals( that.traverser ); + && eq( selector, that.selector ) && eq( manager, that.manager ) && eq( traverser, that.traverser ) + && eq( filter, that.filter ); } @Override @@ -410,6 +415,16 @@ return hashCode; } + private static boolean eq( T o1, T o2 ) + { + return ( o1 != null ) ? o1.equals( o2 ) : o2 == null; + } + + private static int hash( Object o ) + { + return ( o != null ) ? o.hashCode() : 0; + } + } } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -22,13 +22,11 @@ import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.RepositoryEvent.EventType; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.RequestTrace; import org.eclipse.aether.SyncContext; -import org.eclipse.aether.RepositoryEvent.EventType; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.ArtifactProperties; import org.eclipse.aether.impl.ArtifactResolver; @@ -73,36 +71,28 @@ /** */ @Named -@Component( role = ArtifactResolver.class ) public class DefaultArtifactResolver implements ArtifactResolver, Service { - @Requirement( role = LoggerFactory.class ) + private static final String CONFIG_PROP_SNAPSHOT_NORMALIZATION = "aether.artifactResolver.snapshotNormalization"; + private Logger logger = NullLoggerFactory.LOGGER; - @Requirement private FileProcessor fileProcessor; - @Requirement private RepositoryEventDispatcher repositoryEventDispatcher; - @Requirement private VersionResolver versionResolver; - @Requirement private UpdateCheckManager updateCheckManager; - @Requirement private RepositoryConnectorProvider repositoryConnectorProvider; - @Requirement private RemoteRepositoryManager remoteRepositoryManager; - @Requirement private SyncContextFactory syncContextFactory; - @Requirement private OfflineController offlineController; public DefaultArtifactResolver() @@ -147,12 +137,6 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - public DefaultArtifactResolver setFileProcessor( FileProcessor fileProcessor ) { if ( fileProcessor == null ) @@ -389,6 +373,7 @@ logger.debug( "Verifying availability of " + local.getFile() + " from " + repos ); } + AtomicBoolean resolved = new AtomicBoolean( false ); Iterator groupIt = groups.iterator(); for ( RemoteRepository repo : repos ) { @@ -399,7 +384,7 @@ try { - offlineController.checkOffline( session, repo ); + Utils.checkOffline( session, offlineController, repo ); } catch ( RepositoryOfflineException e ) { @@ -427,7 +412,7 @@ groups.add( group ); groupIt = Collections. emptyList().iterator(); } - group.items.add( new ResolutionItem( trace, artifact, result, local, repo ) ); + group.items.add( new ResolutionItem( trace, artifact, resolved, result, local, repo ) ); } } @@ -488,7 +473,7 @@ throws ArtifactTransferException { if ( artifact.isSnapshot() && !artifact.getVersion().equals( artifact.getBaseVersion() ) - && ConfigUtils.getBoolean( session, true, "aether.artifactResolver.snapshotNormalization" ) ) + && ConfigUtils.getBoolean( session, true, CONFIG_PROP_SNAPSHOT_NORMALIZATION ) ) { String name = file.getName().replace( artifact.getVersion(), artifact.getBaseVersion() ); File dst = new File( file.getParent(), name ); @@ -568,6 +553,7 @@ ArtifactDownload download = new ArtifactDownload(); download.setArtifact( artifact ); download.setRequestContext( item.request.getRequestContext() ); + download.setListener( SafeTransferListener.wrap( session, logger ) ); download.setTrace( item.trace ); if ( item.local.getFile() != null ) { @@ -592,7 +578,7 @@ new UpdateCheck(); check.setItem( artifact ); check.setFile( download.getFile() ); - check.setFileValid( !download.isExistenceCheck() ); + check.setFileValid( false ); check.setRepository( group.repository ); check.setPolicy( policy.getUpdatePolicy() ); item.updateCheck = check; @@ -625,40 +611,44 @@ continue; } - if ( item.updateCheck != null ) - { - item.updateCheck.setException( download.getException() ); - updateCheckManager.touchArtifact( session, item.updateCheck ); - } - + Artifact artifact = download.getArtifact(); if ( download.getException() == null ) { item.resolved.set( true ); item.result.setRepository( group.repository ); - Artifact artifact = download.getArtifact(); try { artifact = artifact.setFile( getFile( session, artifact, download.getFile() ) ); item.result.setArtifact( artifact ); + + lrm.add( session, + new LocalArtifactRegistration( artifact, group.repository, download.getSupportedContexts() ) ); } catch ( ArtifactTransferException e ) { + download.setException( e ); item.result.addException( e ); - continue; } - lrm.add( session, - new LocalArtifactRegistration( artifact, group.repository, download.getSupportedContexts() ) ); - - artifactDownloaded( session, download.getTrace(), artifact, group.repository, null ); - - artifactResolved( session, download.getTrace(), artifact, group.repository, null ); } else { item.result.addException( download.getException() ); + } + + /* + * NOTE: Touch after registration with local repo to ensure concurrent resolution is not rejected with + * "already updated" via session data when actual update to local repo is still pending. + */ + if ( item.updateCheck != null ) + { + item.updateCheck.setException( download.getException() ); + updateCheckManager.touchArtifact( session, item.updateCheck ); + } - artifactDownloaded( session, download.getTrace(), download.getArtifact(), group.repository, - download.getException() ); + artifactDownloaded( session, download.getTrace(), artifact, group.repository, download.getException() ); + if ( download.getException() == null ) + { + artifactResolved( session, download.getTrace(), artifact, group.repository, null ); } } } @@ -757,12 +747,12 @@ UpdateCheck updateCheck; - ResolutionItem( RequestTrace trace, Artifact artifact, ArtifactResult result, LocalArtifactResult local, - RemoteRepository repository ) + ResolutionItem( RequestTrace trace, Artifact artifact, AtomicBoolean resolved, ArtifactResult result, + LocalArtifactResult local, RemoteRepository repository ) { this.trace = trace; this.artifact = artifact; - this.resolved = new AtomicBoolean( false ); + this.resolved = resolved; this.result = result; this.request = result.getRequest(); this.local = local; diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultChecksumPolicyProvider.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultChecksumPolicyProvider.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultChecksumPolicyProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultChecksumPolicyProvider.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.repository.RepositoryPolicy; +import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy; +import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider; +import org.eclipse.aether.spi.locator.Service; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.spi.log.NullLoggerFactory; +import org.eclipse.aether.transfer.TransferResource; + +/** + */ +@Named +public final class DefaultChecksumPolicyProvider + implements ChecksumPolicyProvider, Service +{ + + private static final int ORDINAL_IGNORE = 0; + + private static final int ORDINAL_WARN = 1; + + private static final int ORDINAL_FAIL = 2; + + private LoggerFactory loggerFactory = NullLoggerFactory.INSTANCE; + + public DefaultChecksumPolicyProvider() + { + // enables default constructor + } + + @Inject + DefaultChecksumPolicyProvider( LoggerFactory loggerFactory ) + { + setLoggerFactory( loggerFactory ); + } + + public void initService( ServiceLocator locator ) + { + setLoggerFactory( locator.getService( LoggerFactory.class ) ); + } + + public DefaultChecksumPolicyProvider setLoggerFactory( LoggerFactory loggerFactory ) + { + this.loggerFactory = loggerFactory; + return this; + } + + public ChecksumPolicy newChecksumPolicy( RepositorySystemSession session, RemoteRepository repository, + TransferResource resource, String policy ) + { + if ( RepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals( policy ) ) + { + return null; + } + if ( RepositoryPolicy.CHECKSUM_POLICY_FAIL.equals( policy ) ) + { + return new FailChecksumPolicy( loggerFactory, resource ); + } + return new WarnChecksumPolicy( loggerFactory, resource ); + } + + public String getEffectiveChecksumPolicy( RepositorySystemSession session, String policy1, String policy2 ) + { + if ( policy1 != null && policy1.equals( policy2 ) ) + { + return policy1; + } + int ordinal1 = ordinalOfPolicy( policy1 ); + int ordinal2 = ordinalOfPolicy( policy2 ); + if ( ordinal2 < ordinal1 ) + { + return ( ordinal2 != ORDINAL_WARN ) ? policy2 : RepositoryPolicy.CHECKSUM_POLICY_WARN; + } + else + { + return ( ordinal1 != ORDINAL_WARN ) ? policy1 : RepositoryPolicy.CHECKSUM_POLICY_WARN; + } + } + + private static int ordinalOfPolicy( String policy ) + { + if ( RepositoryPolicy.CHECKSUM_POLICY_FAIL.equals( policy ) ) + { + return ORDINAL_FAIL; + } + else if ( RepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals( policy ) ) + { + return ORDINAL_IGNORE; + } + else + { + return ORDINAL_WARN; + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollectionContext.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollectionContext.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollectionContext.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollectionContext.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. + * Copyright (c) 2010, 2013 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -13,25 +13,30 @@ import java.util.List; import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.collection.DependencyCollectionContext; import org.eclipse.aether.graph.Dependency; -/* * @see DefaultDependencyCollector +/** + * @see DefaultDependencyCollector */ -class DefaultDependencyCollectionContext +final class DefaultDependencyCollectionContext implements DependencyCollectionContext { - private RepositorySystemSession session; + private final RepositorySystemSession session; + + private Artifact artifact; private Dependency dependency; private List managedDependencies; - public DefaultDependencyCollectionContext( RepositorySystemSession session, Dependency dependency, - List managedDependencies ) + public DefaultDependencyCollectionContext( RepositorySystemSession session, Artifact artifact, + Dependency dependency, List managedDependencies ) { this.session = session; + this.artifact = ( dependency != null ) ? dependency.getArtifact() : artifact; this.dependency = dependency; this.managedDependencies = managedDependencies; } @@ -41,6 +46,11 @@ return session; } + public Artifact getArtifact() + { + return artifact; + } + public Dependency getDependency() { return dependency; @@ -53,6 +63,7 @@ public void set( Dependency dependency, List managedDependencies ) { + artifact = dependency.getArtifact(); this.dependency = dependency; this.managedDependencies = managedDependencies; } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollector.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollector.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollector.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollector.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -21,8 +21,6 @@ import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositoryException; import org.eclipse.aether.RepositorySystemSession; @@ -37,6 +35,7 @@ import org.eclipse.aether.collection.DependencyManager; import org.eclipse.aether.collection.DependencySelector; import org.eclipse.aether.collection.DependencyTraverser; +import org.eclipse.aether.collection.VersionFilter; import org.eclipse.aether.graph.DefaultDependencyNode; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.DependencyNode; @@ -65,21 +64,20 @@ /** */ @Named -@Component( role = DependencyCollector.class ) public class DefaultDependencyCollector implements DependencyCollector, Service { - @Requirement( role = LoggerFactory.class ) + private static final String CONFIG_PROP_MAX_EXCEPTIONS = "aether.dependencyCollector.maxExceptions"; + + private static final String CONFIG_PROP_MAX_CYCLES = "aether.dependencyCollector.maxCycles"; + private Logger logger = NullLoggerFactory.LOGGER; - @Requirement private RemoteRepositoryManager remoteRepositoryManager; - @Requirement private ArtifactDescriptorReader descriptorReader; - @Requirement private VersionRangeResolver versionRangeResolver; public DefaultDependencyCollector() @@ -112,12 +110,6 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - public DefaultDependencyCollector setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager ) { if ( remoteRepositoryManager == null ) @@ -134,7 +126,7 @@ { throw new IllegalArgumentException( "artifact descriptor reader has not been specified" ); } - this.descriptorReader = artifactDescriptorReader; + descriptorReader = artifactDescriptorReader; return this; } @@ -160,6 +152,7 @@ DependencySelector depSelector = session.getDependencySelector(); DependencyManager depManager = session.getDependencyManager(); DependencyTraverser depTraverser = session.getDependencyTraverser(); + VersionFilter verFilter = session.getVersionFilter(); Dependency root = request.getRoot(); List repositories = request.getRepositories(); @@ -169,22 +162,19 @@ Map stats = logger.isDebugEnabled() ? new LinkedHashMap() : null; long time1 = System.currentTimeMillis(); - DefaultDependencyNode node = null; + DefaultDependencyNode node; if ( root != null ) { + List versions; VersionRangeResult rangeResult; try { VersionRangeRequest rangeRequest = - new VersionRangeRequest( root.getArtifact(), request.getRepositories(), request.getRequestContext() ); + new VersionRangeRequest( root.getArtifact(), request.getRepositories(), + request.getRequestContext() ); rangeRequest.setTrace( trace ); rangeResult = versionRangeResolver.resolveVersionRange( session, rangeRequest ); - - if ( rangeResult.getVersions().isEmpty() ) - { - throw new VersionRangeResolutionException( rangeResult, "No versions available for " - + root.getArtifact() + " within specified range" ); - } + versions = filterVersions( root, rangeResult, verFilter, new DefaultVersionFilterContext( session ) ); } catch ( VersionRangeResolutionException e ) { @@ -192,7 +182,7 @@ throw new DependencyCollectionException( result, e.getMessage() ); } - Version version = rangeResult.getVersions().get( rangeResult.getVersions().size() - 1 ); + Version version = versions.get( versions.size() - 1 ); root = root.setArtifact( root.getArtifact().setVersion( version.toString() ) ); ArtifactDescriptorResult descriptorResult; @@ -222,9 +212,9 @@ if ( !session.isIgnoreArtifactDescriptorRepositories() ) { - repositories = - remoteRepositoryManager.aggregateRepositories( session, repositories, - descriptorResult.getRepositories(), true ); + repositories = remoteRepositoryManager.aggregateRepositories( session, repositories, + descriptorResult.getRepositories(), + true ); } dependencies = mergeDeps( dependencies, descriptorResult.getDependencies() ); managedDependencies = mergeDeps( managedDependencies, descriptorResult.getManagedDependencies() ); @@ -244,7 +234,7 @@ result.setRoot( node ); - boolean traverse = ( root == null ) || depTraverser.traverseDependency( root ); + boolean traverse = root == null || depTraverser == null || depTraverser.traverseDependency( root ); String errorPath = null; if ( traverse && !dependencies.isEmpty() ) { @@ -254,29 +244,38 @@ nodes.push( node ); DefaultDependencyCollectionContext context = - new DefaultDependencyCollectionContext( session, root, managedDependencies ); + new DefaultDependencyCollectionContext( session, request.getRootArtifact(), root, managedDependencies ); + + DefaultVersionFilterContext versionContext = new DefaultVersionFilterContext( session ); - Args args = new Args( result, session, trace, pool, nodes, context ); + Args args = new Args( session, trace, pool, nodes, context, versionContext, request ); + Results results = new Results( result, session ); - process( args, dependencies, repositories, depSelector.deriveChildSelector( context ), - depManager.deriveChildManager( context ), depTraverser.deriveChildTraverser( context ) ); + process( args, results, dependencies, repositories, + depSelector != null ? depSelector.deriveChildSelector( context ) : null, + depManager != null ? depManager.deriveChildManager( context ) : null, + depTraverser != null ? depTraverser.deriveChildTraverser( context ) : null, + verFilter != null ? verFilter.deriveChildFilter( context ) : null ); - errorPath = args.errorPath; + errorPath = results.errorPath; } long time2 = System.currentTimeMillis(); DependencyGraphTransformer transformer = session.getDependencyGraphTransformer(); - try - { - DefaultDependencyGraphTransformationContext context = - new DefaultDependencyGraphTransformationContext( session ); - context.put( TransformationContextKeys.STATS, stats ); - result.setRoot( transformer.transformGraph( node, context ) ); - } - catch ( RepositoryException e ) + if ( transformer != null ) { - result.addException( e ); + try + { + DefaultDependencyGraphTransformationContext context = + new DefaultDependencyGraphTransformationContext( session ); + context.put( TransformationContextKeys.STATS, stats ); + result.setRoot( transformer.transformGraph( node, context ) ); + } + catch ( RepositoryException e ) + { + result.addException( e ); + } } if ( stats != null ) @@ -299,7 +298,7 @@ return result; } - private RepositorySystemSession optimizeSession( RepositorySystemSession session ) + private static RepositorySystemSession optimizeSession( RepositorySystemSession session ) { DefaultRepositorySystemSession optimized = new DefaultRepositorySystemSession( session ); optimized.setArtifactTypeRegistry( CachingArtifactTypeRegistry.newInstance( session ) ); @@ -319,8 +318,9 @@ } else { - result = new ArrayList( dominant.size() + recessive.size() ); - Collection ids = new HashSet(); + int initialCapacity = dominant.size() + recessive.size(); + result = new ArrayList( initialCapacity ); + Collection ids = new HashSet(initialCapacity, 1.0f); for ( Dependency dependency : dominant ) { ids.add( getId( dependency.getArtifact() ) ); @@ -337,317 +337,355 @@ return result; } - private String getId( Artifact a ) + private static String getId( Artifact a ) { return a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getClassifier() + ':' + a.getExtension(); } - private void process( final Args args, List dependencies, List repositories, - DependencySelector depSelector, DependencyManager depManager, DependencyTraverser depTraverser ) + private void process( final Args args, Results results, List dependencies, + List repositories, DependencySelector depSelector, + DependencyManager depManager, DependencyTraverser depTraverser, VersionFilter verFilter ) { - nextDependency: for ( Dependency dependency : dependencies ) + for ( Dependency dependency : dependencies ) { - boolean disableVersionManagement = false; + processDependency( args, results, repositories, depSelector, depManager, depTraverser, verFilter, + dependency ); + } + } - List relocations = Collections.emptyList(); + private void processDependency( Args args, Results results, List repositories, + DependencySelector depSelector, DependencyManager depManager, + DependencyTraverser depTraverser, VersionFilter verFilter, Dependency dependency ) + { - thisDependency: while ( true ) - { - if ( !depSelector.selectDependency( dependency ) ) - { - continue nextDependency; - } + List relocations = Collections.emptyList(); + boolean disableVersionManagement = false; + processDependency( args, results, repositories, depSelector, depManager, depTraverser, verFilter, dependency, + relocations, disableVersionManagement ); + } - DependencyManagement depMngt = depManager.manageDependency( dependency ); - int managedBits = 0; - String premanagedVersion = null; - String premanagedScope = null; - Boolean premanagedOptional = null; + private void processDependency( Args args, Results results, List repositories, + DependencySelector depSelector, DependencyManager depManager, + DependencyTraverser depTraverser, VersionFilter verFilter, Dependency dependency, + List relocations, boolean disableVersionManagement ) + { - if ( depMngt != null ) - { - if ( depMngt.getVersion() != null && !disableVersionManagement ) - { - Artifact artifact = dependency.getArtifact(); - premanagedVersion = artifact.getVersion(); - dependency = dependency.setArtifact( artifact.setVersion( depMngt.getVersion() ) ); - managedBits |= DependencyNode.MANAGED_VERSION; - } - if ( depMngt.getProperties() != null ) - { - Artifact artifact = dependency.getArtifact(); - dependency = dependency.setArtifact( artifact.setProperties( depMngt.getProperties() ) ); - managedBits |= DependencyNode.MANAGED_PROPERTIES; - } - if ( depMngt.getScope() != null ) - { - premanagedScope = dependency.getScope(); - dependency = dependency.setScope( depMngt.getScope() ); - managedBits |= DependencyNode.MANAGED_SCOPE; - } - if ( depMngt.getOptional() != null ) - { - premanagedOptional = dependency.isOptional(); - dependency = dependency.setOptional( depMngt.getOptional() ); - managedBits |= DependencyNode.MANAGED_OPTIONAL; - } - if ( depMngt.getExclusions() != null ) - { - dependency = dependency.setExclusions( depMngt.getExclusions() ); - managedBits |= DependencyNode.MANAGED_EXCLUSIONS; - } - } - disableVersionManagement = false; + if ( depSelector != null && !depSelector.selectDependency( dependency ) ) + { + return; + } - boolean noDescriptor = isLackingDescriptor( dependency.getArtifact() ); + PremanagedDependency preManaged = + PremanagedDependency.create( depManager, dependency, disableVersionManagement, args.premanagedState ); + dependency = preManaged.managedDependency; - boolean traverse = !noDescriptor && depTraverser.traverseDependency( dependency ); + boolean noDescriptor = isLackingDescriptor( dependency.getArtifact() ); - VersionRangeResult rangeResult; - try - { - VersionRangeRequest rangeRequest = new VersionRangeRequest(); - rangeRequest.setArtifact( dependency.getArtifact() ); - rangeRequest.setRepositories( repositories ); - rangeRequest.setRequestContext( args.result.getRequest().getRequestContext() ); - rangeRequest.setTrace( args.trace ); + boolean traverse = !noDescriptor && ( depTraverser == null || depTraverser.traverseDependency( dependency ) ); - Object key = args.pool.toKey( rangeRequest ); - rangeResult = args.pool.getConstraint( key, rangeRequest ); - if ( rangeResult == null ) - { - rangeResult = versionRangeResolver.resolveVersionRange( args.session, rangeRequest ); - args.pool.putConstraint( key, rangeResult ); - } + List versions; + VersionRangeResult rangeResult; + try + { + VersionRangeRequest rangeRequest = createVersionRangeRequest( args, repositories, dependency ); - if ( rangeResult.getVersions().isEmpty() ) - { - throw new VersionRangeResolutionException( rangeResult, "No versions available for " - + dependency.getArtifact() + " within specified range" ); - } - } - catch ( VersionRangeResolutionException e ) - { - addException( args, dependency, e ); - continue nextDependency; - } + rangeResult = cachedResolveRangeResult( rangeRequest, args.pool, args.session ); - List versions = rangeResult.getVersions(); - for ( Version version : versions ) - { - Artifact originalArtifact = dependency.getArtifact().setVersion( version.toString() ); - Dependency d = dependency.setArtifact( originalArtifact ); + versions = filterVersions( dependency, rangeResult, verFilter, args.versionContext ); + } + catch ( VersionRangeResolutionException e ) + { + results.addException( dependency, e, args.nodes ); + return; + } - ArtifactDescriptorResult descriptorResult; - { - ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest(); - descriptorRequest.setArtifact( d.getArtifact() ); - descriptorRequest.setRepositories( repositories ); - descriptorRequest.setRequestContext( args.result.getRequest().getRequestContext() ); - descriptorRequest.setTrace( args.trace ); + for ( Version version : versions ) + { + Artifact originalArtifact = dependency.getArtifact().setVersion( version.toString() ); + Dependency d = dependency.setArtifact( originalArtifact ); - if ( noDescriptor ) - { - descriptorResult = new ArtifactDescriptorResult( descriptorRequest ); - } - else - { - Object key = args.pool.toKey( descriptorRequest ); - descriptorResult = args.pool.getDescriptor( key, descriptorRequest ); - if ( descriptorResult == null ) - { - try - { - descriptorResult = - descriptorReader.readArtifactDescriptor( args.session, descriptorRequest ); - args.pool.putDescriptor( key, descriptorResult ); - } - catch ( ArtifactDescriptorException e ) - { - addException( args, d, e ); - args.pool.putDescriptor( key, e ); - continue; - } - } - else if ( descriptorResult == DataPool.NO_DESCRIPTOR ) - { - continue; - } - } - } + ArtifactDescriptorRequest descriptorRequest = createArtifactDescriptorRequest( args, repositories, d ); - d = d.setArtifact( descriptorResult.getArtifact() ); + final ArtifactDescriptorResult descriptorResult = + getArtifactDescriptorResult( args, results, noDescriptor, d, descriptorRequest ); + if ( descriptorResult != null ) + { + d = d.setArtifact( descriptorResult.getArtifact() ); - DependencyNode node = args.nodes.top(); + DependencyNode node = args.nodes.top(); - DependencyNode cycleNode = args.nodes.find( d.getArtifact() ); - if ( cycleNode != null ) + int cycleEntry = args.nodes.find( d.getArtifact() ); + if ( cycleEntry >= 0 ) + { + results.addCycle( args.nodes, cycleEntry, d ); + DependencyNode cycleNode = args.nodes.get( cycleEntry ); + if ( cycleNode.getDependency() != null ) { - DefaultDependencyNode child = new DefaultDependencyNode( d ); - child.setChildren( cycleNode.getChildren() ); - child.setManagedBits( managedBits ); - if ( args.premanagedState ) - { - child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_VERSION, premanagedVersion ); - child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_SCOPE, premanagedScope ); - child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_OPTIONAL, premanagedOptional ); - } - child.setRelocations( relocations ); - child.setVersionConstraint( rangeResult.getVersionConstraint() ); - child.setVersion( version ); - child.setAliases( descriptorResult.getAliases() ); - child.setRepositories( cycleNode.getRepositories() ); - child.setRequestContext( cycleNode.getRequestContext() ); - + DefaultDependencyNode child = + createDependencyNode( relocations, preManaged, rangeResult, version, d, descriptorResult, + cycleNode ); node.getChildren().add( child ); - continue; } + } - if ( !descriptorResult.getRelocations().isEmpty() ) - { - relocations = descriptorResult.getRelocations(); - - disableVersionManagement = - originalArtifact.getGroupId().equals( d.getArtifact().getGroupId() ) - && originalArtifact.getArtifactId().equals( d.getArtifact().getArtifactId() ); - - dependency = d; - continue thisDependency; - } - + if ( !descriptorResult.getRelocations().isEmpty() ) + { + boolean disableVersionManagementSubsequently = + originalArtifact.getGroupId().equals( d.getArtifact().getGroupId() ) + && originalArtifact.getArtifactId().equals( d.getArtifact().getArtifactId() ); + + processDependency( args, results, repositories, depSelector, depManager, depTraverser, verFilter, d, + descriptorResult.getRelocations(), disableVersionManagementSubsequently ); + return; + } + else + { d = args.pool.intern( d.setArtifact( args.pool.intern( d.getArtifact() ) ) ); List repos = getRemoteRepositories( rangeResult.getRepository( version ), repositories ); - DefaultDependencyNode child = new DefaultDependencyNode( d ); - child.setManagedBits( managedBits ); - if ( args.premanagedState ) - { - child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_VERSION, premanagedVersion ); - child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_SCOPE, premanagedScope ); - child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_OPTIONAL, premanagedOptional ); - } - child.setRelocations( relocations ); - child.setVersionConstraint( rangeResult.getVersionConstraint() ); - child.setVersion( version ); - child.setAliases( descriptorResult.getAliases() ); - child.setRepositories( repos ); - child.setRequestContext( args.result.getRequest().getRequestContext() ); + DefaultDependencyNode child = + createDependencyNode( relocations, preManaged, rangeResult, version, d, + descriptorResult.getAliases(), repos, args.request.getRequestContext() ); node.getChildren().add( child ); boolean recurse = traverse && !descriptorResult.getDependencies().isEmpty(); if ( recurse ) { - DefaultDependencyCollectionContext context = args.collectionContext; - context.set( d, descriptorResult.getManagedDependencies() ); + doRecurse( args, results, repositories, depSelector, depManager, depTraverser, verFilter, d, + descriptorResult, child ); + } + } + } + else + { + DependencyNode node = args.nodes.top(); + List repos = + getRemoteRepositories( rangeResult.getRepository( version ), repositories ); + DefaultDependencyNode child = + createDependencyNode( relocations, preManaged, rangeResult, version, d, null, repos, + args.request.getRequestContext() ); + node.getChildren().add( child ); + } + } + } - DependencySelector childSelector = depSelector.deriveChildSelector( context ); - DependencyManager childManager = depManager.deriveChildManager( context ); - DependencyTraverser childTraverser = depTraverser.deriveChildTraverser( context ); + private void doRecurse( Args args, Results results, List repositories, + DependencySelector depSelector, DependencyManager depManager, + DependencyTraverser depTraverser, VersionFilter verFilter, Dependency d, + ArtifactDescriptorResult descriptorResult, DefaultDependencyNode child ) + { + DefaultDependencyCollectionContext context = args.collectionContext; + context.set( d, descriptorResult.getManagedDependencies() ); - List childRepos = null; - if ( args.ignoreRepos ) - { - childRepos = repositories; - } - else - { - childRepos = - remoteRepositoryManager.aggregateRepositories( args.session, repositories, - descriptorResult.getRepositories(), true ); - } + DependencySelector childSelector = depSelector != null ? depSelector.deriveChildSelector( context ) : null; + DependencyManager childManager = depManager != null ? depManager.deriveChildManager( context ) : null; + DependencyTraverser childTraverser = depTraverser != null ? depTraverser.deriveChildTraverser( context ) : null; + VersionFilter childFilter = verFilter != null ? verFilter.deriveChildFilter( context ) : null; - Object key = - args.pool.toKey( d.getArtifact(), childRepos, childSelector, childManager, childTraverser ); + final List childRepos = args.ignoreRepos + ? repositories + : remoteRepositoryManager.aggregateRepositories( args.session, repositories, + descriptorResult.getRepositories(), true ); - List children = args.pool.getChildren( key ); - if ( children == null ) - { - args.pool.putChildren( key, child.getChildren() ); + Object key = + args.pool.toKey( d.getArtifact(), childRepos, childSelector, childManager, childTraverser, childFilter ); - args.nodes.push( child ); + List children = args.pool.getChildren( key ); + if ( children == null ) + { + args.pool.putChildren( key, child.getChildren() ); - process( args, descriptorResult.getDependencies(), childRepos, childSelector, childManager, - childTraverser ); + args.nodes.push( child ); - args.nodes.pop(); - } - else - { - child.setChildren( children ); - } - } - } + process( args, results, descriptorResult.getDependencies(), childRepos, childSelector, childManager, + childTraverser, childFilter ); - break; - } + args.nodes.pop(); + } + else + { + child.setChildren( children ); } } - private boolean isLackingDescriptor( Artifact artifact ) + private ArtifactDescriptorResult getArtifactDescriptorResult( Args args, Results results, boolean noDescriptor, + Dependency d, + ArtifactDescriptorRequest descriptorRequest ) { - return artifact.getProperty( ArtifactProperties.LOCAL_PATH, null ) != null; + return noDescriptor + ? new ArtifactDescriptorResult( descriptorRequest ) + : resolveCachedArtifactDescriptor( args.pool, descriptorRequest, args.session, d, results, args ); } - private void addException( Args args, Dependency dependency, Exception e ) + private ArtifactDescriptorResult resolveCachedArtifactDescriptor( DataPool pool, + ArtifactDescriptorRequest descriptorRequest, + RepositorySystemSession session, Dependency d, + Results results, Args args ) { - if ( args.maxExceptions < 0 || args.result.getExceptions().size() < args.maxExceptions ) + Object key = pool.toKey( descriptorRequest ); + ArtifactDescriptorResult descriptorResult = pool.getDescriptor( key, descriptorRequest ); + if ( descriptorResult == null ) { - args.result.addException( e ); - if ( args.errorPath == null ) + try { - StringBuilder buffer = new StringBuilder( 256 ); - for ( int i = 0; i < args.nodes.size(); i++ ) - { - if ( buffer.length() > 0 ) - { - buffer.append( " -> " ); - } - Dependency dep = args.nodes.get( i ).getDependency(); - if ( dep == null ) - { - continue; - } - buffer.append( dep.getArtifact() ); - } - if ( buffer.length() > 0 ) - { - buffer.append( " -> " ); - } - buffer.append( dependency.getArtifact() ); - args.errorPath = buffer.toString(); + descriptorResult = descriptorReader.readArtifactDescriptor( session, descriptorRequest ); + pool.putDescriptor( key, descriptorResult ); } + catch ( ArtifactDescriptorException e ) + { + results.addException( d, e, args.nodes ); + pool.putDescriptor( key, e ); + return null; + } + } + else if ( descriptorResult == DataPool.NO_DESCRIPTOR ) + { + return null; + } + + return descriptorResult; + } + + private static DefaultDependencyNode createDependencyNode( List relocations, + PremanagedDependency preManaged, + VersionRangeResult rangeResult, Version version, + Dependency d, Collection aliases, + List repos, String requestContext ) + { + DefaultDependencyNode child = new DefaultDependencyNode( d ); + preManaged.applyTo( child ); + child.setRelocations( relocations ); + child.setVersionConstraint( rangeResult.getVersionConstraint() ); + child.setVersion( version ); + child.setAliases( aliases ); + child.setRepositories( repos ); + child.setRequestContext( requestContext ); + return child; + } + + private static DefaultDependencyNode createDependencyNode( List relocations, + PremanagedDependency preManaged, + VersionRangeResult rangeResult, Version version, + Dependency d, ArtifactDescriptorResult descriptorResult, + DependencyNode cycleNode ) + { + DefaultDependencyNode child = + createDependencyNode( relocations, preManaged, rangeResult, version, d, descriptorResult.getAliases(), + cycleNode.getRepositories(), cycleNode.getRequestContext() ); + child.setChildren( cycleNode.getChildren() ); + return child; + } + + private static ArtifactDescriptorRequest createArtifactDescriptorRequest( Args args, + List repositories, + Dependency d ) + { + ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest(); + descriptorRequest.setArtifact( d.getArtifact() ); + descriptorRequest.setRepositories( repositories ); + descriptorRequest.setRequestContext( args.request.getRequestContext() ); + descriptorRequest.setTrace( args.trace ); + return descriptorRequest; + } + + private static VersionRangeRequest createVersionRangeRequest( Args args, List repositories, + Dependency dependency ) + { + VersionRangeRequest rangeRequest = new VersionRangeRequest(); + rangeRequest.setArtifact( dependency.getArtifact() ); + rangeRequest.setRepositories( repositories ); + rangeRequest.setRequestContext( args.request.getRequestContext() ); + rangeRequest.setTrace( args.trace ); + return rangeRequest; + } + + private VersionRangeResult cachedResolveRangeResult( VersionRangeRequest rangeRequest, DataPool pool, + RepositorySystemSession session ) + throws VersionRangeResolutionException + { + Object key = pool.toKey( rangeRequest ); + VersionRangeResult rangeResult = pool.getConstraint( key, rangeRequest ); + if ( rangeResult == null ) + { + rangeResult = versionRangeResolver.resolveVersionRange( session, rangeRequest ); + pool.putConstraint( key, rangeResult ); + } + return rangeResult; } - private List getRemoteRepositories( ArtifactRepository repository, - List repositories ) + + private static boolean isLackingDescriptor( Artifact artifact ) + { + return artifact.getProperty( ArtifactProperties.LOCAL_PATH, null ) != null; + } + + private static List getRemoteRepositories( ArtifactRepository repository, + List repositories ) { if ( repository instanceof RemoteRepository ) { return Collections.singletonList( (RemoteRepository) repository ); } - else if ( repository != null ) + if ( repository != null ) { return Collections.emptyList(); } return repositories; } - static class Args + private static List filterVersions( Dependency dependency, VersionRangeResult rangeResult, + VersionFilter verFilter, + DefaultVersionFilterContext verContext ) + throws VersionRangeResolutionException { + if ( rangeResult.getVersions().isEmpty() ) + { + throw new VersionRangeResolutionException( rangeResult, + "No versions available for " + dependency.getArtifact() + + " within specified range" ); + } + + List versions; + if ( verFilter != null && rangeResult.getVersionConstraint().getRange() != null ) + { + verContext.set( dependency, rangeResult ); + try + { + verFilter.filterVersions( verContext ); + } + catch ( RepositoryException e ) + { + throw new VersionRangeResolutionException( rangeResult, + "Failed to filter versions for " + dependency.getArtifact() + + ": " + e.getMessage(), e ); + } + versions = verContext.get(); + if ( versions.isEmpty() ) + { + throw new VersionRangeResolutionException( rangeResult, + "No acceptable versions for " + dependency.getArtifact() + + ": " + rangeResult.getVersions() ); + } + } + else + { + versions = rangeResult.getVersions(); + } + return versions; + } - final CollectResult result; + static class Args + { final RepositorySystemSession session; final boolean ignoreRepos; - final int maxExceptions; - final boolean premanagedState; final RequestTrace trace; @@ -658,22 +696,168 @@ final DefaultDependencyCollectionContext collectionContext; - String errorPath; + final DefaultVersionFilterContext versionContext; + + final CollectRequest request; - public Args( CollectResult result, RepositorySystemSession session, RequestTrace trace, DataPool pool, - NodeStack nodes, DefaultDependencyCollectionContext collectionContext ) + + public Args( RepositorySystemSession session, RequestTrace trace, DataPool pool, NodeStack nodes, + DefaultDependencyCollectionContext collectionContext, DefaultVersionFilterContext versionContext, + CollectRequest request ) { - this.result = result; this.session = session; + this.request = request; this.ignoreRepos = session.isIgnoreArtifactDescriptorRepositories(); - this.maxExceptions = ConfigUtils.getInteger( session, 50, "aether.dependencyCollector.maxExceptions" ); this.premanagedState = ConfigUtils.getBoolean( session, false, DependencyManagerUtils.CONFIG_PROP_VERBOSE ); this.trace = trace; this.pool = pool; this.nodes = nodes; this.collectionContext = collectionContext; + this.versionContext = versionContext; + } + + } + + static class Results + { + + private final CollectResult result; + + final int maxExceptions; + + final int maxCycles; + + String errorPath; + + public Results( CollectResult result, RepositorySystemSession session ) + { + this.result = result; + this.maxExceptions = ConfigUtils.getInteger( session, 50, CONFIG_PROP_MAX_EXCEPTIONS ); + this.maxCycles = ConfigUtils.getInteger( session, 10, CONFIG_PROP_MAX_CYCLES ); + } + + public void addException( Dependency dependency, Exception e, NodeStack nodes ) + { + if ( maxExceptions < 0 || result.getExceptions().size() < maxExceptions ) + { + result.addException( e ); + if ( errorPath == null ) + { + StringBuilder buffer = new StringBuilder( 256 ); + for ( int i = 0; i < nodes.size(); i++ ) + { + if ( buffer.length() > 0 ) + { + buffer.append( " -> " ); + } + Dependency dep = nodes.get( i ).getDependency(); + if ( dep != null ) + { + buffer.append( dep.getArtifact() ); + } + } + if ( buffer.length() > 0 ) + { + buffer.append( " -> " ); + } + buffer.append( dependency.getArtifact() ); + errorPath = buffer.toString(); + } + } + } + + public void addCycle( NodeStack nodes, int cycleEntry, Dependency dependency ) + { + if ( maxCycles < 0 || result.getCycles().size() < maxCycles ) + { + result.addCycle( new DefaultDependencyCycle( nodes, cycleEntry, dependency ) ); + } + } + + } + + static class PremanagedDependency + { + final String premanagedVersion; + + final String premanagedScope; + + final Boolean premanagedOptional; + + final int managedBits; + + final Dependency managedDependency; + + final boolean premanagedState; + + PremanagedDependency( String premanagedVersion, String premanagedScope, Boolean premanagedOptional, + int managedBits, Dependency managedDependency, boolean premanagedState ) + { + this.premanagedVersion = premanagedVersion; + this.premanagedScope = premanagedScope; + this.premanagedOptional = premanagedOptional; + this.managedBits = managedBits; + this.managedDependency = managedDependency; + this.premanagedState = premanagedState; + } + + static PremanagedDependency create( DependencyManager depManager, Dependency dependency, + boolean disableVersionManagement, boolean premanagedState ) + { + DependencyManagement depMngt = depManager != null ? depManager.manageDependency( dependency ) : null; + + int managedBits = 0; + String premanagedVersion = null; + String premanagedScope = null; + Boolean premanagedOptional = null; + + if ( depMngt != null ) + { + if ( depMngt.getVersion() != null && !disableVersionManagement ) + { + Artifact artifact = dependency.getArtifact(); + premanagedVersion = artifact.getVersion(); + dependency = dependency.setArtifact( artifact.setVersion( depMngt.getVersion() ) ); + managedBits |= DependencyNode.MANAGED_VERSION; + } + if ( depMngt.getProperties() != null ) + { + Artifact artifact = dependency.getArtifact(); + dependency = dependency.setArtifact( artifact.setProperties( depMngt.getProperties() ) ); + managedBits |= DependencyNode.MANAGED_PROPERTIES; + } + if ( depMngt.getScope() != null ) + { + premanagedScope = dependency.getScope(); + dependency = dependency.setScope( depMngt.getScope() ); + managedBits |= DependencyNode.MANAGED_SCOPE; + } + if ( depMngt.getOptional() != null ) + { + premanagedOptional = dependency.isOptional(); + dependency = dependency.setOptional( depMngt.getOptional() ); + managedBits |= DependencyNode.MANAGED_OPTIONAL; + } + if ( depMngt.getExclusions() != null ) + { + dependency = dependency.setExclusions( depMngt.getExclusions() ); + managedBits |= DependencyNode.MANAGED_EXCLUSIONS; + } + } + return new PremanagedDependency( premanagedVersion, premanagedScope, premanagedOptional, managedBits, + dependency, premanagedState ); } + public void applyTo( DefaultDependencyNode child ) + { + child.setManagedBits( managedBits ); + if ( premanagedState ) + { + child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_VERSION, premanagedVersion ); + child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_SCOPE, premanagedScope ); + child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_OPTIONAL, premanagedOptional ); + } + } } } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCycle.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCycle.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCycle.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCycle.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.graph.DependencyCycle; +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.util.artifact.ArtifactIdUtils; + +/** + * @see DefaultDependencyCollector + */ +final class DefaultDependencyCycle + implements DependencyCycle +{ + + private final List dependencies; + + private final int cycleEntry; + + public DefaultDependencyCycle( NodeStack nodes, int cycleEntry, Dependency dependency ) + { + // skip root node unless it actually has a dependency or is considered the cycle entry (due to its label) + int offset = ( cycleEntry > 0 && nodes.get( 0 ).getDependency() == null ) ? 1 : 0; + Dependency[] dependencies = new Dependency[nodes.size() - offset + 1]; + for ( int i = 0, n = dependencies.length - 1; i < n; i++ ) + { + DependencyNode node = nodes.get( i + offset ); + dependencies[i] = node.getDependency(); + // when cycle starts at root artifact as opposed to root dependency, synthesize a dependency + if ( dependencies[i] == null ) + { + dependencies[i] = new Dependency( node.getArtifact(), null ); + } + } + dependencies[dependencies.length - 1] = dependency; + this.dependencies = Collections.unmodifiableList( Arrays.asList( dependencies ) ); + this.cycleEntry = cycleEntry; + } + + public List getPrecedingDependencies() + { + return dependencies.subList( 0, cycleEntry ); + } + + public List getCyclicDependencies() + { + return dependencies.subList( cycleEntry, dependencies.size() ); + } + + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder( 256 ); + for ( int i = 0, n = dependencies.size(); i < n; i++ ) + { + if ( i > 0 ) + { + buffer.append( " -> " ); + } + buffer.append( ArtifactIdUtils.toVersionlessId( dependencies.get( i ).getArtifact() ) ); + } + return buffer.toString(); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -22,14 +22,12 @@ import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.RepositoryEvent.EventType; import org.eclipse.aether.RepositoryException; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.RequestTrace; import org.eclipse.aether.SyncContext; -import org.eclipse.aether.RepositoryEvent.EventType; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.deployment.DeployRequest; import org.eclipse.aether.deployment.DeployResult; @@ -53,7 +51,6 @@ import org.eclipse.aether.spi.connector.MetadataDownload; import org.eclipse.aether.spi.connector.MetadataUpload; import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.aether.spi.connector.Transfer; import org.eclipse.aether.spi.io.FileProcessor; import org.eclipse.aether.spi.locator.Service; import org.eclipse.aether.spi.locator.ServiceLocator; @@ -65,40 +62,32 @@ import org.eclipse.aether.transfer.MetadataTransferException; import org.eclipse.aether.transfer.NoRepositoryConnectorException; import org.eclipse.aether.transfer.RepositoryOfflineException; +import org.eclipse.aether.transfer.TransferCancelledException; +import org.eclipse.aether.transfer.TransferEvent; /** */ @Named -@Component( role = Deployer.class ) public class DefaultDeployer implements Deployer, Service { - @Requirement( role = LoggerFactory.class ) private Logger logger = NullLoggerFactory.LOGGER; - @Requirement private FileProcessor fileProcessor; - @Requirement private RepositoryEventDispatcher repositoryEventDispatcher; - @Requirement private RepositoryConnectorProvider repositoryConnectorProvider; - @Requirement private RemoteRepositoryManager remoteRepositoryManager; - @Requirement private UpdateCheckManager updateCheckManager; - @Requirement( role = MetadataGeneratorFactory.class ) private Collection metadataFactories = new ArrayList(); - @Requirement private SyncContextFactory syncContextFactory; - @Requirement private OfflineController offlineController; public DefaultDeployer() @@ -143,12 +132,6 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - public DefaultDeployer setFileProcessor( FileProcessor fileProcessor ) { if ( fileProcessor == null ) @@ -222,12 +205,6 @@ return this; } - DefaultDeployer setMetadataFactories( List metadataFactories ) - { - // plexus support - return setMetadataGeneratorFactories( metadataFactories ); - } - public DefaultDeployer setSyncContextFactory( SyncContextFactory syncContextFactory ) { if ( syncContextFactory == null ) @@ -253,7 +230,7 @@ { try { - offlineController.checkOffline( session, request.getRepository() ); + Utils.checkOffline( session, offlineController, request.getRepository() ); } catch ( RepositoryOfflineException e ) { @@ -294,7 +271,7 @@ try { - List generators = getMetadataGenerators( session, request ); + List generators = getMetadataGenerators( session, request ); List artifactUploads = new ArrayList(); List metadataUploads = new ArrayList(); @@ -325,7 +302,10 @@ artifacts.set( i, artifact ); - artifactUploads.add( new ArtifactUploadEx( artifact, artifact.getFile(), catapult ) ); + ArtifactUpload upload = new ArtifactUpload( artifact, artifact.getFile() ); + upload.setTrace( trace ); + upload.setListener( new ArtifactUploadListener( catapult, upload, logger ) ); + artifactUploads.add( upload ); } connector.put( artifactUploads, null ); @@ -379,15 +359,17 @@ return result; } - private List getMetadataGenerators( RepositorySystemSession session, DeployRequest request ) + private List getMetadataGenerators( RepositorySystemSession session, + DeployRequest request ) { - List factories = Utils.sortMetadataGeneratorFactories( this.metadataFactories ); + PrioritizedComponents factories = + Utils.sortMetadataGeneratorFactories( session, this.metadataFactories ); List generators = new ArrayList(); - for ( MetadataGeneratorFactory factory : factories ) + for ( PrioritizedComponent factory : factories.getEnabled() ) { - MetadataGenerator generator = factory.newInstance( session, request ); + MetadataGenerator generator = factory.getComponent().newInstance( session, request ); if ( generator != null ) { generators.add( generator ); @@ -430,6 +412,8 @@ download.setMetadata( metadata ); download.setFile( dstFile ); download.setChecksumPolicy( policy.getChecksumPolicy() ); + download.setListener( SafeTransferListener.wrap( session, logger ) ); + download.setTrace( catapult.getTrace() ); connector.get( null, Arrays.asList( download ) ); Exception error = download.getException(); @@ -497,7 +481,10 @@ check.setAuthoritativeRepository( repository ); updateCheckManager.touchMetadata( session, check ); - metadataUploads.add( new MetadataUploadEx( metadata, dstFile, catapult ) ); + MetadataUpload upload = new MetadataUpload( metadata, dstFile ); + upload.setTrace( catapult.getTrace() ); + upload.setListener( new MetadataUploadListener( catapult, upload, logger ) ); + metadataUploads.add( upload ); } private RepositoryPolicy getPolicy( RepositorySystemSession session, RemoteRepository repository, @@ -508,7 +495,7 @@ return remoteRepositoryManager.getPolicy( session, repository, releases, snapshots ); } - static class EventCatapult + static final class EventCatapult { private final RepositorySystemSession session; @@ -528,6 +515,11 @@ this.dispatcher = dispatcher; } + public RepositorySystemSession getSession() + { + return session; + } + public RequestTrace getTrace() { return trace; @@ -581,64 +573,80 @@ } - static class ArtifactUploadEx - extends ArtifactUpload + static final class ArtifactUploadListener + extends SafeTransferListener { private final EventCatapult catapult; - public ArtifactUploadEx( Artifact artifact, File file, EventCatapult catapult ) + private final ArtifactUpload transfer; + + public ArtifactUploadListener( EventCatapult catapult, ArtifactUpload transfer, Logger logger ) { - super( artifact, file ); + super( catapult.getSession(), logger ); this.catapult = catapult; + this.transfer = transfer; } @Override - public Transfer setState( State state ) + public void transferInitiated( TransferEvent event ) + throws TransferCancelledException { - super.setState( state ); + super.transferInitiated( event ); + catapult.artifactDeploying( transfer.getArtifact(), transfer.getFile() ); + } - if ( State.ACTIVE.equals( state ) ) - { - catapult.artifactDeploying( getArtifact(), getFile() ); - } - else if ( State.DONE.equals( state ) ) - { - catapult.artifactDeployed( getArtifact(), getFile(), getException() ); - } + @Override + public void transferFailed( TransferEvent event ) + { + super.transferFailed( event ); + catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), transfer.getException() ); + } - return this; + @Override + public void transferSucceeded( TransferEvent event ) + { + super.transferSucceeded( event ); + catapult.artifactDeployed( transfer.getArtifact(), transfer.getFile(), null ); } } - static class MetadataUploadEx - extends MetadataUpload + static final class MetadataUploadListener + extends SafeTransferListener { private final EventCatapult catapult; - public MetadataUploadEx( Metadata metadata, File file, EventCatapult catapult ) + private final MetadataUpload transfer; + + public MetadataUploadListener( EventCatapult catapult, MetadataUpload transfer, Logger logger ) { - super( metadata, file ); + super( catapult.getSession(), logger ); this.catapult = catapult; + this.transfer = transfer; } @Override - public Transfer setState( State state ) + public void transferInitiated( TransferEvent event ) + throws TransferCancelledException { - super.setState( state ); + super.transferInitiated( event ); + catapult.metadataDeploying( transfer.getMetadata(), transfer.getFile() ); + } - if ( State.ACTIVE.equals( state ) ) - { - catapult.metadataDeploying( getMetadata(), getFile() ); - } - else if ( State.DONE.equals( state ) ) - { - catapult.metadataDeployed( getMetadata(), getFile(), getException() ); - } + @Override + public void transferFailed( TransferEvent event ) + { + super.transferFailed( event ); + catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), transfer.getException() ); + } - return this; + @Override + public void transferSucceeded( TransferEvent event ) + { + super.transferSucceeded( event ); + catapult.metadataDeployed( transfer.getMetadata(), transfer.getFile(), null ); } } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultFileProcessor.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultFileProcessor.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultFileProcessor.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultFileProcessor.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,7 +10,6 @@ *******************************************************************************/ package org.eclipse.aether.internal.impl; -import java.io.BufferedOutputStream; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; @@ -22,14 +21,12 @@ import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; import org.eclipse.aether.spi.io.FileProcessor; /** * A utility class helping with file-based operations. */ @Named -@Component( role = FileProcessor.class ) public class DefaultFileProcessor implements FileProcessor { @@ -50,9 +47,9 @@ } /** - * Thread-safe variant of {@link File#mkdirs()}. Adapted from Java 6. Creates the directory named by the given - * abstract pathname, including any necessary but nonexistent parent directories. Note that if this operation fails - * it may have succeeded in creating some of the necessary parent directories. + * Thread-safe variant of {@link File#mkdirs()}. Creates the directory named by the given abstract pathname, + * including any necessary but nonexistent parent directories. Note that if this operation fails it may have + * succeeded in creating some of the necessary parent directories. * * @param directory The directory to create, may be {@code null}. * @return {@code true} if and only if the directory was created, along with all necessary parent directories; @@ -74,7 +71,7 @@ return true; } - File canonDir = null; + File canonDir; try { canonDir = directory.getCanonicalFile(); @@ -120,7 +117,7 @@ OutputStream fos = null; try { - fos = new BufferedOutputStream( new FileOutputStream( target ) ); + fos = new FileOutputStream( target ); copy( fos, source, null ); @@ -152,7 +149,7 @@ mkdirs( target.getAbsoluteFile().getParentFile() ); - fos = new BufferedOutputStream( new FileOutputStream( target ) ); + fos = new FileOutputStream( target ); total = copy( fos, fis, listener ); diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultInstaller.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultInstaller.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultInstaller.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultInstaller.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -20,13 +20,11 @@ import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.RepositoryEvent.EventType; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.RequestTrace; import org.eclipse.aether.SyncContext; -import org.eclipse.aether.RepositoryEvent.EventType; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.impl.Installer; import org.eclipse.aether.impl.MetadataGenerator; @@ -51,24 +49,18 @@ /** */ @Named -@Component( role = Installer.class ) public class DefaultInstaller implements Installer, Service { - @Requirement( role = LoggerFactory.class ) private Logger logger = NullLoggerFactory.LOGGER; - @Requirement private FileProcessor fileProcessor; - @Requirement private RepositoryEventDispatcher repositoryEventDispatcher; - @Requirement( role = MetadataGeneratorFactory.class ) private Collection metadataFactories = new ArrayList(); - @Requirement private SyncContextFactory syncContextFactory; public DefaultInstaller() @@ -103,12 +95,6 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - public DefaultInstaller setFileProcessor( FileProcessor fileProcessor ) { if ( fileProcessor == null ) @@ -152,12 +138,6 @@ return this; } - DefaultInstaller setMetadataFactories( List metadataFactories ) - { - // plexus support - return setMetadataGeneratorFactories( metadataFactories ); - } - public DefaultInstaller setSyncContextFactory( SyncContextFactory syncContextFactory ) { if ( syncContextFactory == null ) @@ -190,7 +170,7 @@ RequestTrace trace = RequestTrace.newChild( request.getTrace(), request ); - List generators = getMetadataGenerators( session, request ); + List generators = getMetadataGenerators( session, request ); List artifacts = new ArrayList( request.getArtifacts() ); @@ -245,15 +225,17 @@ return result; } - private List getMetadataGenerators( RepositorySystemSession session, InstallRequest request ) + private List getMetadataGenerators( RepositorySystemSession session, + InstallRequest request ) { - List factories = Utils.sortMetadataGeneratorFactories( this.metadataFactories ); + PrioritizedComponents factories = + Utils.sortMetadataGeneratorFactories( session, this.metadataFactories ); List generators = new ArrayList(); - for ( MetadataGeneratorFactory factory : factories ) + for ( PrioritizedComponent factory : factories.getEnabled() ) { - MetadataGenerator generator = factory.newInstance( session, request ); + MetadataGenerator generator = factory.getComponent().newInstance( session, request ); if ( generator != null ) { generators.add( generator ); @@ -277,6 +259,11 @@ Exception exception = null; try { + if ( dstFile.equals( srcFile ) ) + { + throw new IllegalArgumentException( "Cannot install " + dstFile + " to same path" ); + } + boolean copy = "pom".equals( artifact.getExtension() ) || srcFile.lastModified() != dstFile.lastModified() || srcFile.length() != dstFile.length() || !srcFile.exists(); @@ -322,6 +309,10 @@ } else { + if ( dstFile.equals( metadata.getFile() ) ) + { + throw new IllegalArgumentException( "Cannot install " + dstFile + " to same path" ); + } fileProcessor.copy( metadata.getFile(), dstFile ); } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultLocalRepositoryProvider.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultLocalRepositoryProvider.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultLocalRepositoryProvider.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultLocalRepositoryProvider.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -12,17 +12,12 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; import java.util.List; -import java.util.ListIterator; import java.util.Set; import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.impl.LocalRepositoryProvider; import org.eclipse.aether.repository.LocalRepository; @@ -38,28 +33,14 @@ /** */ @Named -@Component( role = LocalRepositoryProvider.class ) public class DefaultLocalRepositoryProvider implements LocalRepositoryProvider, Service { - @Requirement( role = LoggerFactory.class ) private Logger logger = NullLoggerFactory.LOGGER; - @Requirement( role = LocalRepositoryManagerFactory.class ) private Collection managerFactories = new ArrayList(); - private static final Comparator COMPARATOR = - new Comparator() - { - - public int compare( LocalRepositoryManagerFactory o1, LocalRepositoryManagerFactory o2 ) - { - return Float.compare( o2.getPriority(), o1.getPriority() ); - } - - }; - public DefaultLocalRepositoryProvider() { // enables default constructor @@ -84,12 +65,6 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - public DefaultLocalRepositoryProvider addLocalRepositoryManagerFactory( LocalRepositoryManagerFactory factory ) { if ( factory == null ) @@ -113,31 +88,30 @@ return this; } - DefaultLocalRepositoryProvider setManagerFactories( List factories ) - { - // plexus support - return setLocalRepositoryManagerFactories( factories ); - } - - public LocalRepositoryManager newLocalRepositoryManager( RepositorySystemSession session, - LocalRepository localRepository ) + public LocalRepositoryManager newLocalRepositoryManager( RepositorySystemSession session, LocalRepository repository ) throws NoLocalRepositoryManagerException { - List factories = new ArrayList( managerFactories ); - Collections.sort( factories, COMPARATOR ); + PrioritizedComponents factories = + new PrioritizedComponents( session ); + for ( LocalRepositoryManagerFactory factory : this.managerFactories ) + { + factories.add( factory, factory.getPriority() ); + } - for ( LocalRepositoryManagerFactory factory : factories ) + List errors = new ArrayList(); + for ( PrioritizedComponent factory : factories.getEnabled() ) { try { - LocalRepositoryManager manager = factory.newInstance( session, localRepository ); + LocalRepositoryManager manager = factory.getComponent().newInstance( session, repository ); if ( logger.isDebugEnabled() ) { StringBuilder buffer = new StringBuilder( 256 ); buffer.append( "Using manager " ).append( manager.getClass().getSimpleName() ); + Utils.appendClassLoader( buffer, manager ); buffer.append( " with priority " ).append( factory.getPriority() ); - buffer.append( " for " ).append( localRepository.getBasedir() ); + buffer.append( " for " ).append( repository.getBasedir() ); logger.debug( buffer.toString() ); } @@ -147,25 +121,33 @@ catch ( NoLocalRepositoryManagerException e ) { // continue and try next factory + errors.add( e ); } } - - StringBuilder buffer = new StringBuilder( 256 ); - buffer.append( "No manager available for local repository " ); - buffer.append( localRepository.getBasedir() ); - buffer.append( " of type " ).append( localRepository.getContentType() ); - buffer.append( " using the available factories " ); - for ( ListIterator it = factories.listIterator(); it.hasNext(); ) - { - LocalRepositoryManagerFactory factory = it.next(); - buffer.append( factory.getClass().getSimpleName() ); - if ( it.hasNext() ) + if ( logger.isDebugEnabled() && errors.size() > 1 ) + { + String msg = "Could not obtain local repository manager for " + repository; + for ( Exception e : errors ) { - buffer.append( ", " ); + logger.debug( msg, e ); } } - throw new NoLocalRepositoryManagerException( localRepository, buffer.toString() ); + StringBuilder buffer = new StringBuilder( 256 ); + if ( factories.isEmpty() ) + { + buffer.append( "No local repository managers registered" ); + } + else + { + buffer.append( "Cannot access " ).append( repository.getBasedir() ); + buffer.append( " with type " ).append( repository.getContentType() ); + buffer.append( " using the available factories " ); + factories.list( buffer ); + } + + throw new NoLocalRepositoryManagerException( repository, buffer.toString(), errors.size() == 1 ? errors.get( 0 ) + : null ); } } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultMetadataResolver.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultMetadataResolver.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultMetadataResolver.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultMetadataResolver.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -27,13 +27,11 @@ import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.RepositoryEvent.EventType; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.RequestTrace; import org.eclipse.aether.SyncContext; -import org.eclipse.aether.RepositoryEvent.EventType; import org.eclipse.aether.impl.MetadataResolver; import org.eclipse.aether.impl.OfflineController; import org.eclipse.aether.impl.RemoteRepositoryManager; @@ -66,34 +64,29 @@ import org.eclipse.aether.transfer.RepositoryOfflineException; import org.eclipse.aether.util.ConfigUtils; import org.eclipse.aether.util.concurrency.RunnableErrorForwarder; +import org.eclipse.aether.util.concurrency.WorkerThreadFactory; /** */ @Named -@Component( role = MetadataResolver.class ) public class DefaultMetadataResolver implements MetadataResolver, Service { - @Requirement( role = LoggerFactory.class ) + private static final String CONFIG_PROP_THREADS = "aether.metadataResolver.threads"; + private Logger logger = NullLoggerFactory.LOGGER; - @Requirement private RepositoryEventDispatcher repositoryEventDispatcher; - @Requirement private UpdateCheckManager updateCheckManager; - @Requirement private RepositoryConnectorProvider repositoryConnectorProvider; - @Requirement private RemoteRepositoryManager remoteRepositoryManager; - @Requirement private SyncContextFactory syncContextFactory; - @Requirement private OfflineController offlineController; public DefaultMetadataResolver() @@ -134,12 +127,6 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - public DefaultMetadataResolver setRepositoryEventDispatcher( RepositoryEventDispatcher repositoryEventDispatcher ) { if ( repositoryEventDispatcher == null ) @@ -281,7 +268,7 @@ try { - offlineController.checkOffline( session, repository ); + Utils.checkOffline( session, offlineController, repository ); } catch ( RepositoryOfflineException e ) { @@ -310,7 +297,7 @@ localLastUpdate = localLastUpdates.get( localFile ); if ( localLastUpdate == null ) { - localLastUpdate = Long.valueOf( localFile != null ? localFile.lastModified() : 0 ); + localLastUpdate = localFile != null ? localFile.lastModified() : 0; localLastUpdates.put( localFile, localLastUpdate ); } } @@ -322,7 +309,7 @@ { UpdateCheck check = new UpdateCheck(); - check.setLocalLastUpdated( ( localLastUpdate != null ) ? localLastUpdate.longValue() : 0 ); + check.setLocalLastUpdated( ( localLastUpdate != null ) ? localLastUpdate : 0 ); check.setItem( metadata ); // use 'main' installation file for the check (-> use requested repository) @@ -384,7 +371,7 @@ if ( !tasks.isEmpty() ) { - int threads = ConfigUtils.getInteger( session, 4, "aether.metadataResolver.threads" ); + int threads = ConfigUtils.getInteger( session, 4, CONFIG_PROP_THREADS ); Executor executor = getExecutor( Math.min( tasks.size(), threads ) ); try { @@ -543,7 +530,8 @@ } else { - return new ThreadPoolExecutor( threads, threads, 3, TimeUnit.SECONDS, new LinkedBlockingQueue() ); + return new ThreadPoolExecutor( threads, threads, 3, TimeUnit.SECONDS, new LinkedBlockingQueue(), + new WorkerThreadFactory( null ) ); } } @@ -609,6 +597,8 @@ download.setFile( metadataFile ); download.setChecksumPolicy( policy ); download.setRepositories( repositories ); + download.setListener( SafeTransferListener.wrap( session, logger ) ); + download.setTrace( trace ); RepositoryConnector connector = repositoryConnectorProvider.newRepositoryConnector( session, requestRepository ); @@ -642,6 +632,10 @@ exception = new MetadataTransferException( metadata, requestRepository, e ); } + /* + * NOTE: Touch after registration with local repo to ensure concurrent resolution is not rejected with + * "already updated" via session data when actual update to local repo is still pending. + */ for ( UpdateCheck check : checks ) { updateCheckManager.touchMetadata( session, check.setException( exception ) ); diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultOfflineController.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultOfflineController.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultOfflineController.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultOfflineController.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012 Sonatype, Inc. + * Copyright (c) 2012, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -15,8 +15,6 @@ import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.impl.OfflineController; import org.eclipse.aether.repository.RemoteRepository; @@ -29,14 +27,16 @@ import org.eclipse.aether.util.ConfigUtils; @Named -@Component( role = OfflineController.class ) public class DefaultOfflineController implements OfflineController, Service { + static final String CONFIG_PROP_OFFLINE_PROTOCOLS = "aether.offline.protocols"; + + static final String CONFIG_PROP_OFFLINE_HOSTS = "aether.offline.hosts"; + private static final Pattern SEP = Pattern.compile( "\\s*,\\s*" ); - @Requirement( role = LoggerFactory.class ) private Logger logger = NullLoggerFactory.LOGGER; public DefaultOfflineController() @@ -61,20 +61,9 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - public void checkOffline( RepositorySystemSession session, RemoteRepository repository ) throws RepositoryOfflineException { - if ( !session.isOffline() ) - { - return; - } - if ( isOfflineProtocol( session, repository ) || isOfflineHost( session, repository ) ) { return; @@ -85,7 +74,7 @@ private boolean isOfflineProtocol( RepositorySystemSession session, RemoteRepository repository ) { - String[] protocols = getConfig( session, "aether.offline.protocols" ); + String[] protocols = getConfig( session, CONFIG_PROP_OFFLINE_PROTOCOLS ); if ( protocols != null ) { String protocol = repository.getProtocol(); @@ -105,7 +94,7 @@ private boolean isOfflineHost( RepositorySystemSession session, RemoteRepository repository ) { - String[] hosts = getConfig( session, "aether.offline.hosts" ); + String[] hosts = getConfig( session, CONFIG_PROP_OFFLINE_HOSTS ); if ( hosts != null ) { String host = repository.getHost(); diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManager.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManager.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManager.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManager.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,14 +11,14 @@ package org.eclipse.aether.internal.impl; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.ListIterator; import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; +import org.eclipse.aether.RepositoryCache; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.impl.RemoteRepositoryManager; import org.eclipse.aether.impl.UpdatePolicyAnalyzer; @@ -29,6 +29,7 @@ import org.eclipse.aether.repository.ProxySelector; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.repository.RepositoryPolicy; +import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider; import org.eclipse.aether.spi.locator.Service; import org.eclipse.aether.spi.locator.ServiceLocator; import org.eclipse.aether.spi.log.Logger; @@ -39,26 +40,60 @@ /** */ @Named -@Component( role = RemoteRepositoryManager.class ) public class DefaultRemoteRepositoryManager implements RemoteRepositoryManager, Service { - @Requirement( role = LoggerFactory.class ) + private static final class LoggedMirror + { + + private final Object[] keys; + + public LoggedMirror( RemoteRepository original, RemoteRepository mirror ) + { + keys = new Object[] { mirror.getId(), mirror.getUrl(), original.getId(), original.getUrl() }; + } + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + { + return true; + } + else if ( !( obj instanceof LoggedMirror ) ) + { + return false; + } + LoggedMirror that = (LoggedMirror) obj; + return Arrays.equals( keys, that.keys ); + } + + @Override + public int hashCode() + { + return Arrays.hashCode( keys ); + } + + } + private Logger logger = NullLoggerFactory.LOGGER; - @Requirement private UpdatePolicyAnalyzer updatePolicyAnalyzer; + private ChecksumPolicyProvider checksumPolicyProvider; + public DefaultRemoteRepositoryManager() { // enables default constructor } @Inject - DefaultRemoteRepositoryManager( UpdatePolicyAnalyzer updatePolicyAnalyzer, LoggerFactory loggerFactory ) + DefaultRemoteRepositoryManager( UpdatePolicyAnalyzer updatePolicyAnalyzer, + ChecksumPolicyProvider checksumPolicyProvider, LoggerFactory loggerFactory ) { setUpdatePolicyAnalyzer( updatePolicyAnalyzer ); + setChecksumPolicyProvider( checksumPolicyProvider ); setLoggerFactory( loggerFactory ); } @@ -66,6 +101,7 @@ { setLoggerFactory( locator.getService( LoggerFactory.class ) ); setUpdatePolicyAnalyzer( locator.getService( UpdatePolicyAnalyzer.class ) ); + setChecksumPolicyProvider( locator.getService( ChecksumPolicyProvider.class ) ); } public DefaultRemoteRepositoryManager setLoggerFactory( LoggerFactory loggerFactory ) @@ -74,12 +110,6 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - public DefaultRemoteRepositoryManager setUpdatePolicyAnalyzer( UpdatePolicyAnalyzer updatePolicyAnalyzer ) { if ( updatePolicyAnalyzer == null ) @@ -90,6 +120,16 @@ return this; } + public DefaultRemoteRepositoryManager setChecksumPolicyProvider( ChecksumPolicyProvider checksumPolicyProvider ) + { + if ( checksumPolicyProvider == null ) + { + throw new IllegalArgumentException( "checksum policy provider has not been specified" ); + } + this.checksumPolicyProvider = checksumPolicyProvider; + return this; + } + public List aggregateRepositories( RepositorySystemSession session, List dominantRepositories, List recessiveRepositories, @@ -114,14 +154,9 @@ { RemoteRepository mirrorRepository = mirrorSelector.getMirror( recessiveRepository ); - if ( mirrorRepository == null ) + if ( mirrorRepository != null ) { - repository = recessiveRepository; - } - else - { - logger.debug( "Using mirror " + mirrorRepository.getId() + " (" + mirrorRepository.getUrl() - + ") for " + recessiveRepository.getId() + " (" + recessiveRepository.getUrl() + ")." ); + logMirror( session, recessiveRepository, mirrorRepository ); repository = mirrorRepository; } } @@ -178,6 +213,26 @@ return result; } + private void logMirror( RepositorySystemSession session, RemoteRepository original, RemoteRepository mirror ) + { + if ( !logger.isDebugEnabled() ) + { + return; + } + RepositoryCache cache = session.getCache(); + if ( cache != null ) + { + Object key = new LoggedMirror( original, mirror ); + if ( cache.get( session, key ) != null ) + { + return; + } + cache.put( session, key, Boolean.TRUE ); + } + logger.debug( "Using mirror " + mirror.getId() + " (" + mirror.getUrl() + ") for " + original.getId() + " (" + + original.getUrl() + ")." ); + } + private String getKey( RemoteRepository repository ) { return repository.getId(); @@ -286,13 +341,11 @@ { // use global override } - else if ( ordinalOfChecksumPolicy( policy2.getChecksumPolicy() ) < ordinalOfChecksumPolicy( policy1.getChecksumPolicy() ) ) - { - checksums = policy2.getChecksumPolicy(); - } else { - checksums = policy1.getChecksumPolicy(); + checksums = + checksumPolicyProvider.getEffectiveChecksumPolicy( session, policy1.getChecksumPolicy(), + policy2.getChecksumPolicy() ); } String updates = session.getUpdatePolicy(); @@ -333,20 +386,4 @@ return policy; } - private int ordinalOfChecksumPolicy( String policy ) - { - if ( RepositoryPolicy.CHECKSUM_POLICY_FAIL.equals( policy ) ) - { - return 2; - } - else if ( RepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals( policy ) ) - { - return 0; - } - else - { - return 1; - } - } - } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryConnectorProvider.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryConnectorProvider.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryConnectorProvider.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryConnectorProvider.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012 Sonatype, Inc. + * Copyright (c) 2012, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -12,17 +12,12 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; import java.util.List; -import java.util.ListIterator; import java.util.Set; import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.impl.RepositoryConnectorProvider; import org.eclipse.aether.repository.Authentication; @@ -40,28 +35,14 @@ /** */ @Named -@Component( role = RepositoryConnectorProvider.class ) public class DefaultRepositoryConnectorProvider implements RepositoryConnectorProvider, Service { - @Requirement( role = LoggerFactory.class ) private Logger logger = NullLoggerFactory.LOGGER; - @Requirement( role = RepositoryConnectorFactory.class ) private Collection connectorFactories = new ArrayList(); - private static final Comparator COMPARATOR = - new Comparator() - { - - public int compare( RepositoryConnectorFactory o1, RepositoryConnectorFactory o2 ) - { - return Float.compare( o2.getPriority(), o1.getPriority() ); - } - - }; - public DefaultRepositoryConnectorProvider() { // enables default constructor @@ -86,12 +67,6 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - public DefaultRepositoryConnectorProvider addRepositoryConnectorFactory( RepositoryConnectorFactory factory ) { if ( factory == null ) @@ -115,12 +90,6 @@ return this; } - DefaultRepositoryConnectorProvider setConnectorFactories( List factories ) - { - // plexus support - return setRepositoryConnectorFactories( factories ); - } - public RepositoryConnector newRepositoryConnector( RepositorySystemSession session, RemoteRepository repository ) throws NoRepositoryConnectorException { @@ -129,19 +98,25 @@ throw new IllegalArgumentException( "remote repository has not been specified" ); } - List factories = new ArrayList( connectorFactories ); - Collections.sort( factories, COMPARATOR ); + PrioritizedComponents factories = + new PrioritizedComponents( session ); + for ( RepositoryConnectorFactory factory : this.connectorFactories ) + { + factories.add( factory, factory.getPriority() ); + } - for ( RepositoryConnectorFactory factory : factories ) + List errors = new ArrayList(); + for ( PrioritizedComponent factory : factories.getEnabled() ) { try { - RepositoryConnector connector = factory.newInstance( session, repository ); + RepositoryConnector connector = factory.getComponent().newInstance( session, repository ); if ( logger.isDebugEnabled() ) { StringBuilder buffer = new StringBuilder( 256 ); buffer.append( "Using connector " ).append( connector.getClass().getSimpleName() ); + Utils.appendClassLoader( buffer, connector ); buffer.append( " with priority " ).append( factory.getPriority() ); buffer.append( " for " ).append( repository.getUrl() ); @@ -171,26 +146,33 @@ catch ( NoRepositoryConnectorException e ) { // continue and try next factory + errors.add( e ); } } - - StringBuilder buffer = new StringBuilder( 256 ); - buffer.append( "No connector available to access repository " ); - buffer.append( repository.getId() ); - buffer.append( " (" ).append( repository.getUrl() ); - buffer.append( ") of type " ).append( repository.getContentType() ); - buffer.append( " using the available factories " ); - for ( ListIterator it = factories.listIterator(); it.hasNext(); ) - { - RepositoryConnectorFactory factory = it.next(); - buffer.append( factory.getClass().getSimpleName() ); - if ( it.hasNext() ) + if ( logger.isDebugEnabled() && errors.size() > 1 ) + { + String msg = "Could not obtain connector factory for " + repository; + for ( Exception e : errors ) { - buffer.append( ", " ); + logger.debug( msg, e ); } } - throw new NoRepositoryConnectorException( repository, buffer.toString() ); + StringBuilder buffer = new StringBuilder( 256 ); + if ( factories.isEmpty() ) + { + buffer.append( "No connector factories available" ); + } + else + { + buffer.append( "Cannot access " ).append( repository.getUrl() ); + buffer.append( " with type " ).append( repository.getContentType() ); + buffer.append( " using the available connector factories: " ); + factories.list( buffer ); + } + + throw new NoRepositoryConnectorException( repository, buffer.toString(), errors.size() == 1 ? errors.get( 0 ) + : null ); } } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryEventDispatcher.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryEventDispatcher.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryEventDispatcher.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryEventDispatcher.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -12,14 +12,11 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.List; import java.util.Set; import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositoryEvent; import org.eclipse.aether.RepositoryListener; import org.eclipse.aether.impl.RepositoryEventDispatcher; @@ -32,15 +29,12 @@ /** */ @Named -@Component( role = RepositoryEventDispatcher.class ) public class DefaultRepositoryEventDispatcher implements RepositoryEventDispatcher, Service { - @Requirement( role = LoggerFactory.class ) private Logger logger = NullLoggerFactory.LOGGER; - @Requirement( role = RepositoryListener.class ) private Collection listeners = new ArrayList(); public DefaultRepositoryEventDispatcher() @@ -61,12 +55,6 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - public DefaultRepositoryEventDispatcher addRepositoryListener( RepositoryListener listener ) { if ( listener == null ) @@ -90,16 +78,10 @@ return this; } - DefaultRepositoryEventDispatcher setListeners( List listeners ) - { - // plexus support - return setRepositoryListeners( listeners ); - } - public void initService( ServiceLocator locator ) { setLoggerFactory( locator.getService( LoggerFactory.class ) ); - setListeners( locator.getServices( RepositoryListener.class ) ); + setRepositoryListeners( locator.getServices( RepositoryListener.class ) ); } public void dispatch( RepositoryEvent event ) diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryLayoutProvider.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryLayoutProvider.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryLayoutProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryLayoutProvider.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.layout.RepositoryLayout; +import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory; +import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider; +import org.eclipse.aether.spi.locator.Service; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.spi.log.NullLoggerFactory; +import org.eclipse.aether.transfer.NoRepositoryLayoutException; + +/** + */ +@Named +public final class DefaultRepositoryLayoutProvider + implements RepositoryLayoutProvider, Service +{ + + private Logger logger = NullLoggerFactory.LOGGER; + + private Collection factories = new ArrayList(); + + public DefaultRepositoryLayoutProvider() + { + // enables default constructor + } + + @Inject + DefaultRepositoryLayoutProvider( Set layoutFactories, LoggerFactory loggerFactory ) + { + setLoggerFactory( loggerFactory ); + setRepositoryLayoutFactories( layoutFactories ); + } + + public void initService( ServiceLocator locator ) + { + setLoggerFactory( locator.getService( LoggerFactory.class ) ); + setRepositoryLayoutFactories( locator.getServices( RepositoryLayoutFactory.class ) ); + } + + public DefaultRepositoryLayoutProvider setLoggerFactory( LoggerFactory loggerFactory ) + { + this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() ); + return this; + } + + public DefaultRepositoryLayoutProvider addRepositoryLayoutFactory( RepositoryLayoutFactory factory ) + { + if ( factory == null ) + { + throw new IllegalArgumentException( "layout factory has not been specified" ); + } + factories.add( factory ); + return this; + } + + public DefaultRepositoryLayoutProvider setRepositoryLayoutFactories( Collection factories ) + { + if ( factories == null ) + { + this.factories = new ArrayList(); + } + else + { + this.factories = factories; + } + return this; + } + + public RepositoryLayout newRepositoryLayout( RepositorySystemSession session, RemoteRepository repository ) + throws NoRepositoryLayoutException + { + if ( repository == null ) + { + throw new IllegalArgumentException( "remote repository has not been specified" ); + } + + PrioritizedComponents factories = + new PrioritizedComponents( session ); + for ( RepositoryLayoutFactory factory : this.factories ) + { + factories.add( factory, factory.getPriority() ); + } + + List errors = new ArrayList(); + for ( PrioritizedComponent factory : factories.getEnabled() ) + { + try + { + RepositoryLayout layout = factory.getComponent().newInstance( session, repository ); + return layout; + } + catch ( NoRepositoryLayoutException e ) + { + // continue and try next factory + errors.add( e ); + } + } + if ( logger.isDebugEnabled() && errors.size() > 1 ) + { + String msg = "Could not obtain layout factory for " + repository; + for ( Exception e : errors ) + { + logger.debug( msg, e ); + } + } + + StringBuilder buffer = new StringBuilder( 256 ); + if ( factories.isEmpty() ) + { + buffer.append( "No layout factories registered" ); + } + else + { + buffer.append( "Cannot access " ).append( repository.getUrl() ); + buffer.append( " with type " ).append( repository.getContentType() ); + buffer.append( " using the available layout factories: " ); + factories.list( buffer ); + } + + throw new NoRepositoryLayoutException( repository, buffer.toString(), errors.size() == 1 ? errors.get( 0 ) + : null ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,14 +10,13 @@ *******************************************************************************/ package org.eclipse.aether.internal.impl; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.RequestTrace; @@ -38,15 +37,19 @@ import org.eclipse.aether.impl.Installer; import org.eclipse.aether.impl.LocalRepositoryProvider; import org.eclipse.aether.impl.MetadataResolver; +import org.eclipse.aether.impl.RemoteRepositoryManager; import org.eclipse.aether.impl.SyncContextFactory; import org.eclipse.aether.impl.VersionRangeResolver; import org.eclipse.aether.impl.VersionResolver; import org.eclipse.aether.installation.InstallRequest; import org.eclipse.aether.installation.InstallResult; import org.eclipse.aether.installation.InstallationException; +import org.eclipse.aether.repository.Authentication; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.LocalRepositoryManager; import org.eclipse.aether.repository.NoLocalRepositoryManagerException; +import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactDescriptorException; import org.eclipse.aether.resolution.ArtifactDescriptorRequest; import org.eclipse.aether.resolution.ArtifactDescriptorResult; @@ -75,44 +78,34 @@ /** */ @Named -@Component( role = RepositorySystem.class ) public class DefaultRepositorySystem implements RepositorySystem, Service { - @Requirement( role = LoggerFactory.class ) private Logger logger = NullLoggerFactory.LOGGER; - @Requirement private VersionResolver versionResolver; - @Requirement private VersionRangeResolver versionRangeResolver; - @Requirement private ArtifactResolver artifactResolver; - @Requirement private MetadataResolver metadataResolver; - @Requirement private ArtifactDescriptorReader artifactDescriptorReader; - @Requirement private DependencyCollector dependencyCollector; - @Requirement private Installer installer; - @Requirement private Deployer deployer; - @Requirement private LocalRepositoryProvider localRepositoryProvider; - @Requirement private SyncContextFactory syncContextFactory; + private RemoteRepositoryManager remoteRepositoryManager; + public DefaultRepositorySystem() { // enables default constructor @@ -124,7 +117,7 @@ ArtifactDescriptorReader artifactDescriptorReader, DependencyCollector dependencyCollector, Installer installer, Deployer deployer, LocalRepositoryProvider localRepositoryProvider, SyncContextFactory syncContextFactory, - LoggerFactory loggerFactory ) + RemoteRepositoryManager remoteRepositoryManager, LoggerFactory loggerFactory ) { setVersionResolver( versionResolver ); setVersionRangeResolver( versionRangeResolver ); @@ -136,6 +129,7 @@ setDeployer( deployer ); setLocalRepositoryProvider( localRepositoryProvider ); setSyncContextFactory( syncContextFactory ); + setRemoteRepositoryManager( remoteRepositoryManager ); setLoggerFactory( loggerFactory ); } @@ -151,6 +145,7 @@ setInstaller( locator.getService( Installer.class ) ); setDeployer( locator.getService( Deployer.class ) ); setLocalRepositoryProvider( locator.getService( LocalRepositoryProvider.class ) ); + setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) ); setSyncContextFactory( locator.getService( SyncContextFactory.class ) ); } @@ -160,12 +155,6 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - public DefaultRepositorySystem setVersionResolver( VersionResolver versionResolver ) { if ( versionResolver == null ) @@ -266,6 +255,16 @@ return this; } + public DefaultRepositorySystem setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager ) + { + if ( remoteRepositoryManager == null ) + { + throw new IllegalArgumentException( "remote repository manager has not been specified" ); + } + this.remoteRepositoryManager = remoteRepositoryManager; + return this; + } + public VersionResult resolveVersion( RepositorySystemSession session, VersionRequest request ) throws VersionResolutionException { @@ -347,6 +346,7 @@ collectResult = e.getResult(); } result.setRoot( collectResult.getRoot() ); + result.setCycles( collectResult.getCycles() ); result.setCollectExceptions( collectResult.getExceptions() ); } else @@ -432,6 +432,27 @@ return syncContextFactory.newInstance( session, shared ); } + public List newResolutionRepositories( RepositorySystemSession session, + List repositories ) + { + validateSession( session ); + repositories = + remoteRepositoryManager.aggregateRepositories( session, new ArrayList(), repositories, + true ); + return repositories; + } + + public RemoteRepository newDeploymentRepository( RepositorySystemSession session, RemoteRepository repository ) + { + validateSession( session ); + RemoteRepository.Builder builder = new RemoteRepository.Builder( repository ); + Authentication auth = session.getAuthenticationSelector().getAuthentication( repository ); + builder.setAuthentication( auth ); + Proxy proxy = session.getProxySelector().getProxy( repository ); + builder.setProxy( proxy ); + return builder.build(); + } + private void validateSession( RepositorySystemSession session ) { if ( session == null ) @@ -470,22 +491,6 @@ { invalidSession( "ArtifactTypeRegistry" ); } - if ( session.getDependencyTraverser() == null ) - { - invalidSession( "DependencyTraverser" ); - } - if ( session.getDependencyManager() == null ) - { - invalidSession( "DependencyManager" ); - } - if ( session.getDependencySelector() == null ) - { - invalidSession( "DependencySelector" ); - } - if ( session.getDependencyGraphTransformer() == null ) - { - invalidSession( "DependencyGraphTransformer" ); - } if ( session.getData() == null ) { invalidSession( "Data" ); diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultSyncContextFactory.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultSyncContextFactory.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultSyncContextFactory.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultSyncContextFactory.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -14,7 +14,6 @@ import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.SyncContext; import org.eclipse.aether.artifact.Artifact; @@ -26,7 +25,6 @@ * synchronization but merely completes the repository system. */ @Named -@Component( role = SyncContextFactory.class ) public class DefaultSyncContextFactory implements SyncContextFactory { diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultTransporterProvider.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultTransporterProvider.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultTransporterProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultTransporterProvider.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.spi.connector.transport.TransporterProvider; +import org.eclipse.aether.spi.locator.Service; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.spi.log.NullLoggerFactory; +import org.eclipse.aether.transfer.NoTransporterException; + +/** + */ +@Named +public final class DefaultTransporterProvider + implements TransporterProvider, Service +{ + + private Logger logger = NullLoggerFactory.LOGGER; + + private Collection factories = new ArrayList(); + + public DefaultTransporterProvider() + { + // enables default constructor + } + + @Inject + DefaultTransporterProvider( Set transporterFactories, LoggerFactory loggerFactory ) + { + setLoggerFactory( loggerFactory ); + setTransporterFactories( transporterFactories ); + } + + public void initService( ServiceLocator locator ) + { + setLoggerFactory( locator.getService( LoggerFactory.class ) ); + setTransporterFactories( locator.getServices( TransporterFactory.class ) ); + } + + public DefaultTransporterProvider setLoggerFactory( LoggerFactory loggerFactory ) + { + this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() ); + return this; + } + + public DefaultTransporterProvider addTransporterFactory( TransporterFactory factory ) + { + if ( factory == null ) + { + throw new IllegalArgumentException( "transporter factory has not been specified" ); + } + factories.add( factory ); + return this; + } + + public DefaultTransporterProvider setTransporterFactories( Collection factories ) + { + if ( factories == null ) + { + this.factories = new ArrayList(); + } + else + { + this.factories = factories; + } + return this; + } + + public Transporter newTransporter( RepositorySystemSession session, RemoteRepository repository ) + throws NoTransporterException + { + if ( repository == null ) + { + throw new IllegalArgumentException( "remote repository has not been specified" ); + } + + PrioritizedComponents factories = new PrioritizedComponents( session ); + for ( TransporterFactory factory : this.factories ) + { + factories.add( factory, factory.getPriority() ); + } + + List errors = new ArrayList(); + for ( PrioritizedComponent factory : factories.getEnabled() ) + { + try + { + Transporter transporter = factory.getComponent().newInstance( session, repository ); + + if ( logger.isDebugEnabled() ) + { + StringBuilder buffer = new StringBuilder( 256 ); + buffer.append( "Using transporter " ).append( transporter.getClass().getSimpleName() ); + Utils.appendClassLoader( buffer, transporter ); + buffer.append( " with priority " ).append( factory.getPriority() ); + buffer.append( " for " ).append( repository.getUrl() ); + logger.debug( buffer.toString() ); + } + + return transporter; + } + catch ( NoTransporterException e ) + { + // continue and try next factory + errors.add( e ); + } + } + if ( logger.isDebugEnabled() && errors.size() > 1 ) + { + String msg = "Could not obtain transporter factory for " + repository; + for ( Exception e : errors ) + { + logger.debug( msg, e ); + } + } + + StringBuilder buffer = new StringBuilder( 256 ); + if ( factories.isEmpty() ) + { + buffer.append( "No transporter factories registered" ); + } + else + { + buffer.append( "Cannot access " ).append( repository.getUrl() ); + buffer.append( " using the registered transporter factories: " ); + factories.list( buffer); + } + + throw new NoTransporterException( repository, buffer.toString(), errors.size() == 1 ? errors.get( 0 ) : null ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultUpdateCheckManager.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultUpdateCheckManager.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultUpdateCheckManager.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultUpdateCheckManager.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -22,8 +22,6 @@ import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.SessionData; import org.eclipse.aether.artifact.Artifact; @@ -44,19 +42,17 @@ import org.eclipse.aether.transfer.ArtifactTransferException; import org.eclipse.aether.transfer.MetadataNotFoundException; import org.eclipse.aether.transfer.MetadataTransferException; +import org.eclipse.aether.util.ConfigUtils; /** */ @Named -@Component( role = UpdateCheckManager.class ) public class DefaultUpdateCheckManager implements UpdateCheckManager, Service { - @Requirement( role = LoggerFactory.class ) private Logger logger = NullLoggerFactory.LOGGER; - @Requirement private UpdatePolicyAnalyzer updatePolicyAnalyzer; private static final String UPDATED_KEY_SUFFIX = ".lastUpdated"; @@ -67,6 +63,14 @@ private static final String SESSION_CHECKS = "updateCheckManager.checks"; + static final String CONFIG_PROP_SESSION_STATE = "aether.updateCheckManager.sessionState"; + + private static final int STATE_ENABLED = 0; + + private static final int STATE_BYPASS = 1; + + private static final int STATE_DISABLED = 2; + public DefaultUpdateCheckManager() { // enables default constructor @@ -91,12 +95,6 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - public DefaultUpdateCheckManager setUpdatePolicyAnalyzer( UpdatePolicyAnalyzer updatePolicyAnalyzer ) { if ( updatePolicyAnalyzer == null ) @@ -114,7 +112,7 @@ { if ( logger.isDebugEnabled() ) { - logger.debug( "Skipped remote update check for " + check.getItem() + logger.debug( "Skipped remote request for " + check.getItem() + ", locally installed artifact up-to-date." ); } @@ -142,14 +140,18 @@ String error = getError( props, dataKey ); long lastUpdated; - if ( fileExists ) - { - lastUpdated = artifactFile.lastModified(); - } - else if ( error == null ) + if ( error == null ) { - // this is the first attempt ever - lastUpdated = 0; + if ( fileExists ) + { + // last update was successful + lastUpdated = artifactFile.lastModified(); + } + else + { + // this is the first attempt ever + lastUpdated = 0; + } } else if ( error.length() <= 0 ) { @@ -163,11 +165,15 @@ lastUpdated = getLastUpdated( props, transferKey ); } - if ( isAlreadyUpdated( session.getData(), updateKey ) ) + if ( lastUpdated == 0 ) + { + check.setRequired( true ); + } + else if ( isAlreadyUpdated( session, updateKey ) ) { if ( logger.isDebugEnabled() ) { - logger.debug( "Skipped remote update check for " + check.getItem() + logger.debug( "Skipped remote request for " + check.getItem() + ", already updated during this session." ); } @@ -177,10 +183,6 @@ check.setException( newException( error, artifact, repository ) ); } } - else if ( lastUpdated == 0 ) - { - check.setRequired( true ); - } else if ( isUpdatedRequired( session, lastUpdated, check.getPolicy() ) ) { check.setRequired( true ); @@ -189,8 +191,7 @@ { if ( logger.isDebugEnabled() ) { - logger.debug( "Skipped remote update check for " + check.getItem() - + ", locally cached artifact up-to-date." ); + logger.debug( "Skipped remote request for " + check.getItem() + ", locally cached artifact up-to-date." ); } check.setRequired( false ); @@ -198,33 +199,31 @@ else { int errorPolicy = Utils.getPolicy( session, artifact, repository ); - if ( error == null || error.length() <= 0 ) + int cacheFlag = getCacheFlag( error ); + if ( ( errorPolicy & cacheFlag ) != 0 ) { - if ( ( errorPolicy & ResolutionErrorPolicy.CACHE_NOT_FOUND ) != 0 ) - { - check.setRequired( false ); - check.setException( newException( error, artifact, repository ) ); - } - else - { - check.setRequired( true ); - } + check.setRequired( false ); + check.setException( newException( error, artifact, repository ) ); } else { - if ( ( errorPolicy & ResolutionErrorPolicy.CACHE_TRANSFER_ERROR ) != 0 ) - { - check.setRequired( false ); - check.setException( newException( error, artifact, repository ) ); - } - else - { - check.setRequired( true ); - } + check.setRequired( true ); } } } + private static int getCacheFlag( String error ) + { + if ( error == null || error.length() <= 0 ) + { + return ResolutionErrorPolicy.CACHE_NOT_FOUND; + } + else + { + return ResolutionErrorPolicy.CACHE_TRANSFER_ERROR; + } + } + private ArtifactTransferException newException( String error, Artifact artifact, RemoteRepository repository ) { if ( error == null || error.length() <= 0 ) @@ -232,14 +231,14 @@ return new ArtifactNotFoundException( artifact, repository, "Failure to find " + artifact + " in " + repository.getUrl() + " was cached in the local repository, " + "resolution will not be reattempted until the update interval of " + repository.getId() - + " has elapsed or updates are forced" ); + + " has elapsed or updates are forced", true ); } else { return new ArtifactTransferException( artifact, repository, "Failure to transfer " + artifact + " from " + repository.getUrl() + " was cached in the local repository, " + "resolution will not be reattempted until the update interval of " + repository.getId() - + " has elapsed or updates are forced. Original error: " + error ); + + " has elapsed or updates are forced. Original error: " + error, true ); } } @@ -250,7 +249,7 @@ { if ( logger.isDebugEnabled() ) { - logger.debug( "Skipped remote update check for " + check.getItem() + logger.debug( "Skipped remote request for " + check.getItem() + ", locally installed metadata up-to-date." ); } @@ -303,11 +302,15 @@ lastUpdated = getLastUpdated( props, transferKey ); } - if ( isAlreadyUpdated( session.getData(), updateKey ) ) + if ( lastUpdated == 0 ) + { + check.setRequired( true ); + } + else if ( isAlreadyUpdated( session, updateKey ) ) { if ( logger.isDebugEnabled() ) { - logger.debug( "Skipped remote update check for " + check.getItem() + logger.debug( "Skipped remote request for " + check.getItem() + ", already updated during this session." ); } @@ -317,10 +320,6 @@ check.setException( newException( error, metadata, repository ) ); } } - else if ( lastUpdated == 0 ) - { - check.setRequired( true ); - } else if ( isUpdatedRequired( session, lastUpdated, check.getPolicy() ) ) { check.setRequired( true ); @@ -329,8 +328,7 @@ { if ( logger.isDebugEnabled() ) { - logger.debug( "Skipped remote update check for " + check.getItem() - + ", locally cached metadata up-to-date." ); + logger.debug( "Skipped remote request for " + check.getItem() + ", locally cached metadata up-to-date." ); } check.setRequired( false ); @@ -338,29 +336,15 @@ else { int errorPolicy = Utils.getPolicy( session, metadata, repository ); - if ( error == null || error.length() <= 0 ) + int cacheFlag = getCacheFlag( error ); + if ( ( errorPolicy & cacheFlag ) != 0 ) { - if ( ( errorPolicy & ResolutionErrorPolicy.CACHE_NOT_FOUND ) != 0 ) - { - check.setRequired( false ); - check.setException( newException( error, metadata, repository ) ); - } - else - { - check.setRequired( true ); - } + check.setRequired( false ); + check.setException( newException( error, metadata, repository ) ); } else { - if ( ( errorPolicy & ResolutionErrorPolicy.CACHE_TRANSFER_ERROR ) != 0 ) - { - check.setRequired( false ); - check.setException( newException( error, metadata, repository ) ); - } - else - { - check.setRequired( true ); - } + check.setRequired( true ); } } } @@ -372,14 +356,14 @@ return new MetadataNotFoundException( metadata, repository, "Failure to find " + metadata + " in " + repository.getUrl() + " was cached in the local repository, " + "resolution will not be reattempted until the update interval of " + repository.getId() - + " has elapsed or updates are forced" ); + + " has elapsed or updates are forced", true ); } else { return new MetadataTransferException( metadata, repository, "Failure to transfer " + metadata + " from " + repository.getUrl() + " was cached in the local repository, " + "resolution will not be reattempted until the update interval of " + repository.getId() - + " has elapsed or updates are forced. Original error: " + error ); + + " has elapsed or updates are forced. Original error: " + error, true ); } } @@ -466,6 +450,7 @@ buffer.append( AuthenticationDigest.forRepository( session, repository ) ).append( '@' ); buffer.append( repository.getContentType() ).append( '-' ); + buffer.append( repository.getId() ).append( '-' ); buffer.append( normalizeRepoUrl( repository.getUrl() ) ); return buffer.toString(); @@ -474,7 +459,7 @@ private String normalizeRepoUrl( String url ) { String result = url; - if ( url != null && !url.endsWith( "/" ) ) + if ( url != null && url.length() > 0 && !url.endsWith( "/" ) ) { result = url + '/'; } @@ -486,8 +471,33 @@ return file.getAbsolutePath() + '|' + getRepoKey( session, repository ); } - private boolean isAlreadyUpdated( SessionData data, Object updateKey ) + private int getSessionState( RepositorySystemSession session ) { + String mode = ConfigUtils.getString( session, "true", CONFIG_PROP_SESSION_STATE ); + if ( Boolean.parseBoolean( mode ) ) + { + // perform update check at most once per session, regardless of update policy + return STATE_ENABLED; + } + else if ( "bypass".equalsIgnoreCase( mode ) ) + { + // evaluate update policy but record update in session to prevent potential future checks + return STATE_BYPASS; + } + else + { + // no session state at all, always evaluate update policy + return STATE_DISABLED; + } + } + + private boolean isAlreadyUpdated( RepositorySystemSession session, Object updateKey ) + { + if ( getSessionState( session ) >= STATE_BYPASS ) + { + return false; + } + SessionData data = session.getData(); Object checkedFiles = data.get( SESSION_CHECKS ); if ( !( checkedFiles instanceof Map ) ) { @@ -497,8 +507,13 @@ } @SuppressWarnings( "unchecked" ) - private void setUpdated( SessionData data, Object updateKey ) + private void setUpdated( RepositorySystemSession session, Object updateKey ) { + if ( getSessionState( session ) >= STATE_DISABLED ) + { + return; + } + SessionData data = session.getData(); Object checkedFiles = data.get( SESSION_CHECKS ); while ( !( checkedFiles instanceof Map ) ) { @@ -534,7 +549,7 @@ String dataKey = getDataKey( artifact, artifactFile, check.getAuthoritativeRepository() ); String transferKey = getTransferKey( session, artifact, artifactFile, check.getRepository() ); - setUpdated( session.getData(), updateKey ); + setUpdated( session, updateKey ); Properties props = write( touchFile, dataKey, transferKey, check.getException() ); if ( artifactFile.exists() && !hasErrors( props ) ) @@ -565,7 +580,7 @@ String dataKey = getDataKey( metadata, metadataFile, check.getAuthoritativeRepository() ); String transferKey = getTransferKey( session, metadata, metadataFile, check.getRepository() ); - setUpdated( session.getData(), updateKey ); + setUpdated( session, updateKey ); write( touchFile, dataKey, transferKey, check.getException() ); } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultUpdatePolicyAnalyzer.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultUpdatePolicyAnalyzer.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultUpdatePolicyAnalyzer.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultUpdatePolicyAnalyzer.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -15,8 +15,6 @@ import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.impl.UpdatePolicyAnalyzer; import org.eclipse.aether.repository.RepositoryPolicy; @@ -29,12 +27,10 @@ /** */ @Named -@Component( role = UpdatePolicyAnalyzer.class ) public class DefaultUpdatePolicyAnalyzer implements UpdatePolicyAnalyzer, Service { - @Requirement( role = LoggerFactory.class ) private Logger logger = NullLoggerFactory.LOGGER; public DefaultUpdatePolicyAnalyzer() @@ -59,12 +55,6 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) - { - // plexus support - setLoggerFactory( loggerFactory ); - } - public String getEffectiveUpdatePolicy( RepositorySystemSession session, String policy1, String policy2 ) { return ordinalOfUpdatePolicy( policy1 ) < ordinalOfUpdatePolicy( policy2 ) ? policy1 : policy2; diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultVersionFilterContext.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultVersionFilterContext.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultVersionFilterContext.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultVersionFilterContext.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,208 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.collection.VersionFilter; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.repository.ArtifactRepository; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.VersionRangeResult; +import org.eclipse.aether.version.Version; +import org.eclipse.aether.version.VersionConstraint; + +/** + * @see DefaultDependencyCollector + */ +final class DefaultVersionFilterContext + implements VersionFilter.VersionFilterContext +{ + + private final Iterator EMPTY = Collections. emptySet().iterator(); + + private final RepositorySystemSession session; + + private Dependency dependency; + + VersionRangeResult result; + + int count; + + byte[] deleted = new byte[64]; + + public DefaultVersionFilterContext( RepositorySystemSession session ) + { + this.session = session; + } + + public void set( Dependency dependency, VersionRangeResult result ) + { + this.dependency = dependency; + this.result = result; + count = result.getVersions().size(); + if ( deleted.length < count ) + { + deleted = new byte[count]; + } + else + { + for ( int i = count - 1; i >= 0; i-- ) + { + deleted[i] = 0; + } + } + } + + public List get() + { + if ( count == result.getVersions().size() ) + { + return result.getVersions(); + } + if ( count <= 1 ) + { + if ( count <= 0 ) + { + return Collections.emptyList(); + } + return Collections.singletonList( iterator().next() ); + } + List versions = new ArrayList( count ); + for ( Version version : this ) + { + versions.add( version ); + } + return versions; + } + + public RepositorySystemSession getSession() + { + return session; + } + + public Dependency getDependency() + { + return dependency; + } + + public VersionConstraint getVersionConstraint() + { + return result.getVersionConstraint(); + } + + public int getCount() + { + return count; + } + + public ArtifactRepository getRepository( Version version ) + { + return result.getRepository( version ); + } + + public List getRepositories() + { + return Collections.unmodifiableList( result.getRequest().getRepositories() ); + } + + public Iterator iterator() + { + return ( count > 0 ) ? new VersionIterator() : EMPTY; + } + + @Override + public String toString() + { + return dependency + " " + result.getVersions(); + } + + private class VersionIterator + implements Iterator + { + + private final List versions; + + private final int size; + + private int count; + + private int index; + + private int next; + + public VersionIterator() + { + count = DefaultVersionFilterContext.this.count; + index = -1; + next = 0; + versions = result.getVersions(); + size = versions.size(); + advance(); + } + + private void advance() + { + for ( next = index + 1; next < size && deleted[next] != 0; next++ ) + { + // just advancing index + } + } + + public boolean hasNext() + { + return next < size; + } + + public Version next() + { + if ( count != DefaultVersionFilterContext.this.count ) + { + throw new ConcurrentModificationException(); + } + if ( next >= size ) + { + throw new NoSuchElementException(); + } + index = next; + advance(); + return versions.get( index ); + } + + public void remove() + { + if ( count != DefaultVersionFilterContext.this.count ) + { + throw new ConcurrentModificationException(); + } + if ( index < 0 || deleted[index] == 1 ) + { + throw new IllegalStateException(); + } + deleted[index] = 1; + count = --DefaultVersionFilterContext.this.count; + } + + @Override + public String toString() + { + return ( index < 0 ) ? "null" : String.valueOf( versions.get( index ) ); + } + + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerFactory.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerFactory.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerFactory.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerFactory.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,10 +10,9 @@ *******************************************************************************/ package org.eclipse.aether.internal.impl; +import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.LocalRepositoryManager; @@ -26,21 +25,32 @@ import org.eclipse.aether.spi.log.NullLoggerFactory; /** - * Creates enhanced local repository managers for repository types {@code "default"} or {@code "" (automatic)}. - * Enhanced local repository manager is built upon the classical Maven 2.0 local repository structure but additionally keeps - * track of from what repositories a cached artifact was resolved. - * Resolution of locally cached artifacts will be rejected in case the current resolution request does not match the - * known source repositories of an artifact, thereby emulating physically separated artifact caches per remote repository. + * Creates enhanced local repository managers for repository types {@code "default"} or {@code "" (automatic)}. Enhanced + * local repository manager is built upon the classical Maven 2.0 local repository structure but additionally keeps + * track of from what repositories a cached artifact was resolved. Resolution of locally cached artifacts will be + * rejected in case the current resolution request does not match the known source repositories of an artifact, thereby + * emulating physically separated artifact caches per remote repository. */ @Named( "enhanced" ) -@Component( role = LocalRepositoryManagerFactory.class, hint = "enhanced" ) public class EnhancedLocalRepositoryManagerFactory implements LocalRepositoryManagerFactory, Service { - @Requirement( role = LoggerFactory.class ) private Logger logger = NullLoggerFactory.LOGGER; + private float priority = 10; + + public EnhancedLocalRepositoryManagerFactory() + { + // enable no-arg constructor + } + + @Inject + EnhancedLocalRepositoryManagerFactory( LoggerFactory loggerFactory ) + { + setLoggerFactory( loggerFactory ); + } + public LocalRepositoryManager newInstance( RepositorySystemSession session, LocalRepository repository ) throws NoLocalRepositoryManagerException { @@ -65,15 +75,21 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) + public float getPriority() { - // plexus support - setLoggerFactory( loggerFactory ); + return priority; } - public float getPriority() + /** + * Sets the priority of this component. + * + * @param priority The priority. + * @return This component for chaining, never {@code null}. + */ + public EnhancedLocalRepositoryManagerFactory setPriority( float priority ) { - return 10; + this.priority = priority; + return this; } } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.transfer.ChecksumFailureException; +import org.eclipse.aether.transfer.TransferResource; + +/** + * Implements {@link org.eclipse.aether.repository.RepositoryPolicy#CHECKSUM_POLICY_FAIL}. + */ +final class FailChecksumPolicy + extends AbstractChecksumPolicy +{ + + public FailChecksumPolicy( LoggerFactory loggerFactory, TransferResource resource ) + { + super( loggerFactory, resource ); + } + + public boolean onTransferChecksumFailure( ChecksumFailureException error ) + { + return false; + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/LoggerFactoryProvider.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/LoggerFactoryProvider.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/LoggerFactoryProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/LoggerFactoryProvider.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.spi.log.NullLoggerFactory; + +/** + * Helps Sisu-based applications to pick the right logger factory depending on the classpath. + */ +@Named +@Singleton +public class LoggerFactoryProvider + implements Provider +{ + + @Inject + @Named( "slf4j" ) + private Provider slf4j; + + public LoggerFactory get() + { + try + { + LoggerFactory factory = slf4j.get(); + if ( factory != null ) + { + return factory; + } + } + catch ( LinkageError e ) + { + // fall through + } + catch ( RuntimeException e ) + { + // fall through + } + return NullLoggerFactory.INSTANCE; + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import javax.inject.Named; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.layout.RepositoryLayout; +import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory; +import org.eclipse.aether.transfer.NoRepositoryLayoutException; +import org.eclipse.aether.util.ConfigUtils; + +/** + * Provides a Maven-2 repository layout for repositories with content type {@code "default"}. + */ +@Named( "maven2" ) +public final class Maven2RepositoryLayoutFactory + implements RepositoryLayoutFactory +{ + + static final String CONFIG_PROP_SIGNATURE_CHECKSUMS = "aether.checksums.forSignature"; + + private float priority; + + public float getPriority() + { + return priority; + } + + /** + * Sets the priority of this component. + * + * @param priority The priority. + * @return This component for chaining, never {@code null}. + */ + public Maven2RepositoryLayoutFactory setPriority( float priority ) + { + this.priority = priority; + return this; + } + + public RepositoryLayout newInstance( RepositorySystemSession session, RemoteRepository repository ) + throws NoRepositoryLayoutException + { + if ( !"default".equals( repository.getContentType() ) ) + { + throw new NoRepositoryLayoutException( repository ); + } + boolean forSignature = ConfigUtils.getBoolean( session, false, CONFIG_PROP_SIGNATURE_CHECKSUMS ); + return forSignature ? Maven2RepositoryLayout.INSTANCE : Maven2RepositoryLayoutEx.INSTANCE; + } + + private static class Maven2RepositoryLayout + implements RepositoryLayout + { + + public static final RepositoryLayout INSTANCE = new Maven2RepositoryLayout(); + + private URI toUri( String path ) + { + try + { + return new URI( null, null, path, null ); + } + catch ( URISyntaxException e ) + { + throw new IllegalStateException( e ); + } + } + + public URI getLocation( Artifact artifact, boolean upload ) + { + StringBuilder path = new StringBuilder( 128 ); + + path.append( artifact.getGroupId().replace( '.', '/' ) ).append( '/' ); + + path.append( artifact.getArtifactId() ).append( '/' ); + + path.append( artifact.getBaseVersion() ).append( '/' ); + + path.append( artifact.getArtifactId() ).append( '-' ).append( artifact.getVersion() ); + + if ( artifact.getClassifier().length() > 0 ) + { + path.append( '-' ).append( artifact.getClassifier() ); + } + + if ( artifact.getExtension().length() > 0 ) + { + path.append( '.' ).append( artifact.getExtension() ); + } + + return toUri( path.toString() ); + } + + public URI getLocation( Metadata metadata, boolean upload ) + { + StringBuilder path = new StringBuilder( 128 ); + + if ( metadata.getGroupId().length() > 0 ) + { + path.append( metadata.getGroupId().replace( '.', '/' ) ).append( '/' ); + + if ( metadata.getArtifactId().length() > 0 ) + { + path.append( metadata.getArtifactId() ).append( '/' ); + + if ( metadata.getVersion().length() > 0 ) + { + path.append( metadata.getVersion() ).append( '/' ); + } + } + } + + path.append( metadata.getType() ); + + return toUri( path.toString() ); + } + + public List getChecksums( Artifact artifact, boolean upload, URI location ) + { + return getChecksums( location ); + } + + public List getChecksums( Metadata metadata, boolean upload, URI location ) + { + return getChecksums( location ); + } + + private List getChecksums( URI location ) + { + return Arrays.asList( Checksum.forLocation( location, "SHA-1" ), Checksum.forLocation( location, "MD5" ) ); + } + + } + + private static class Maven2RepositoryLayoutEx + extends Maven2RepositoryLayout + { + + public static final RepositoryLayout INSTANCE = new Maven2RepositoryLayoutEx(); + + @Override + public List getChecksums( Artifact artifact, boolean upload, URI location ) + { + if ( isSignature( artifact.getExtension() ) ) + { + return Collections.emptyList(); + } + return super.getChecksums( artifact, upload, location ); + } + + private boolean isSignature( String extension ) + { + return extension.endsWith( ".asc" ); + } + + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/NodeStack.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/NodeStack.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/NodeStack.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/NodeStack.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -13,7 +13,6 @@ import java.util.Arrays; import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.DependencyNode; /** @@ -55,19 +54,18 @@ size--; } - public DependencyNode find( Artifact artifact ) + public int find( Artifact artifact ) { for ( int i = size - 1; i >= 0; i-- ) { DependencyNode node = nodes[i]; - Dependency dependency = node.getDependency(); - if ( dependency == null ) + Artifact a = node.getArtifact(); + if ( a == null ) { break; } - Artifact a = dependency.getArtifact(); if ( !a.getArtifactId().equals( artifact.getArtifactId() ) ) { continue; @@ -92,10 +90,10 @@ * a:1. */ - return node; + return i; } - return null; + return -1; } public int size() diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/package-info.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/package-info.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/package-info.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * The various sub components that collectively implement the repository system. + */ +package org.eclipse.aether.internal.impl; + diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/PlexusLoggerFactory.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/PlexusLoggerFactory.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/PlexusLoggerFactory.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/PlexusLoggerFactory.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.internal.impl; - -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; -import org.codehaus.plexus.logging.LoggerManager; -import org.eclipse.aether.spi.log.Logger; -import org.eclipse.aether.spi.log.LoggerFactory; - -/** - * A logger factory that delegates to Plexus logging. - */ -@Component( role = LoggerFactory.class ) -public class PlexusLoggerFactory - implements LoggerFactory -{ - - @Requirement - private LoggerManager loggerManager; - - public Logger getLogger( String name ) - { - return new PlexusLogger( loggerManager.getLoggerForComponent( name ) ); - } - - private static final class PlexusLogger - implements Logger - { - - private final org.codehaus.plexus.logging.Logger logger; - - public PlexusLogger( org.codehaus.plexus.logging.Logger logger ) - { - this.logger = logger; - } - - public boolean isDebugEnabled() - { - return logger.isDebugEnabled(); - } - - public void debug( String msg ) - { - logger.debug( msg ); - } - - public void debug( String msg, Throwable error ) - { - logger.debug( msg, error ); - } - - public boolean isWarnEnabled() - { - return logger.isWarnEnabled(); - } - - public void warn( String msg ) - { - logger.warn( msg ); - } - - public void warn( String msg, Throwable error ) - { - logger.warn( msg, error ); - } - - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/PrioritizedComponent.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/PrioritizedComponent.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/PrioritizedComponent.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/PrioritizedComponent.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +final class PrioritizedComponent + implements Comparable> +{ + + private final T component; + + private final Class type; + + private final float priority; + + private final int index; + + public PrioritizedComponent( T component, Class type, float priority, int index ) + { + this.component = component; + this.type = type; + this.priority = priority; + this.index = index; + } + + public T getComponent() + { + return component; + } + + public Class getType() + { + return type; + } + + public float getPriority() + { + return priority; + } + + public boolean isDisabled() + { + return Float.isNaN( priority ); + } + + public int compareTo( PrioritizedComponent o ) + { + int rel = ( isDisabled() ? 1 : 0 ) - ( o.isDisabled() ? 1 : 0 ); + if ( rel == 0 ) + { + rel = Float.compare( o.priority, priority ); + if ( rel == 0 ) + { + rel = index - o.index; + } + } + return rel; + } + + @Override + public String toString() + { + return priority + " (#" + index + "): " + String.valueOf( component ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/PrioritizedComponents.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/PrioritizedComponents.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/PrioritizedComponents.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/PrioritizedComponents.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.eclipse.aether.ConfigurationProperties; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.util.ConfigUtils; + +/** + * Helps to sort pluggable components by their priority. + */ +final class PrioritizedComponents +{ + + private final static String FACTORY_SUFFIX = "Factory"; + + private final Map configProps; + + private final boolean useInsertionOrder; + + private final List> components; + + private int firstDisabled; + + public PrioritizedComponents( RepositorySystemSession session ) + { + this( session.getConfigProperties() ); + } + + PrioritizedComponents( Map configurationProperties ) + { + configProps = configurationProperties; + useInsertionOrder = + ConfigUtils.getBoolean( configProps, ConfigurationProperties.DEFAULT_IMPLICIT_PRIORITIES, + ConfigurationProperties.IMPLICIT_PRIORITIES ); + components = new ArrayList>(); + firstDisabled = 0; + } + + public void add( T component, float priority ) + { + Class type = getImplClass( component ); + int index = components.size(); + priority = useInsertionOrder ? -index : ConfigUtils.getFloat( configProps, priority, getConfigKeys( type ) ); + PrioritizedComponent pc = new PrioritizedComponent( component, type, priority, index ); + + if ( !useInsertionOrder ) + { + index = Collections.binarySearch( components, pc ); + if ( index < 0 ) + { + index = -index - 1; + } + else + { + index++; + } + } + components.add( index, pc ); + + if ( index <= firstDisabled && !pc.isDisabled() ) + { + firstDisabled++; + } + } + + private static Class getImplClass( Object component ) + { + Class type = component.getClass(); + // detect and ignore CGLIB-based proxy classes employed by Guice for AOP (cf. BytecodeGen.newEnhancer) + int idx = type.getName().indexOf( "$$" ); + if ( idx >= 0 ) + { + Class base = type.getSuperclass(); + if ( base != null && idx == base.getName().length() && type.getName().startsWith( base.getName() ) ) + { + type = base; + } + } + return type; + } + + static String[] getConfigKeys( Class type ) + { + List keys = new ArrayList(); + keys.add( ConfigurationProperties.PREFIX_PRIORITY + type.getName() ); + String sn = type.getSimpleName(); + keys.add( ConfigurationProperties.PREFIX_PRIORITY + sn ); + if ( sn.endsWith( FACTORY_SUFFIX ) ) + { + keys.add( ConfigurationProperties.PREFIX_PRIORITY + sn.substring( 0, sn.length() - FACTORY_SUFFIX.length() ) ); + } + return keys.toArray( new String[keys.size()] ); + } + + public boolean isEmpty() + { + return components.isEmpty(); + } + + public List> getAll() + { + return components; + } + + public List> getEnabled() + { + return components.subList( 0, firstDisabled ); + } + + public void list( StringBuilder buffer ) + { + for ( int i = 0; i < components.size(); i++ ) + { + if ( i > 0 ) + { + buffer.append( ", " ); + } + PrioritizedComponent component = components.get( i ); + buffer.append( component.getType().getSimpleName() ); + if ( component.isDisabled() ) + { + buffer.append( " (disabled)" ); + } + } + } + + @Override + public String toString() + { + return components.toString(); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/SafeTransferListener.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/SafeTransferListener.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/SafeTransferListener.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/SafeTransferListener.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.transfer.AbstractTransferListener; +import org.eclipse.aether.transfer.TransferCancelledException; +import org.eclipse.aether.transfer.TransferEvent; +import org.eclipse.aether.transfer.TransferListener; + +class SafeTransferListener + extends AbstractTransferListener +{ + + private final Logger logger; + + private final TransferListener listener; + + public static TransferListener wrap( RepositorySystemSession session, Logger logger ) + { + TransferListener listener = session.getTransferListener(); + if ( listener == null ) + { + return null; + } + return new SafeTransferListener( listener, logger ); + } + + protected SafeTransferListener( RepositorySystemSession session, Logger logger ) + { + this( session.getTransferListener(), logger ); + } + + private SafeTransferListener( TransferListener listener, Logger logger ) + { + this.listener = listener; + this.logger = logger; + } + + private void logError( TransferEvent event, Throwable e ) + { + String msg = "Failed to dispatch transfer event '" + event + "' to " + listener.getClass().getCanonicalName(); + logger.debug( msg, e ); + } + + @Override + public void transferInitiated( TransferEvent event ) + throws TransferCancelledException + { + if ( listener != null ) + { + try + { + listener.transferInitiated( event ); + } + catch ( RuntimeException e ) + { + logError( event, e ); + } + catch ( LinkageError e ) + { + logError( event, e ); + } + } + } + + @Override + public void transferStarted( TransferEvent event ) + throws TransferCancelledException + { + if ( listener != null ) + { + try + { + listener.transferStarted( event ); + } + catch ( RuntimeException e ) + { + logError( event, e ); + } + catch ( LinkageError e ) + { + logError( event, e ); + } + } + } + + @Override + public void transferProgressed( TransferEvent event ) + throws TransferCancelledException + { + if ( listener != null ) + { + try + { + listener.transferProgressed( event ); + } + catch ( RuntimeException e ) + { + logError( event, e ); + } + catch ( LinkageError e ) + { + logError( event, e ); + } + } + } + + @Override + public void transferCorrupted( TransferEvent event ) + throws TransferCancelledException + { + if ( listener != null ) + { + try + { + listener.transferCorrupted( event ); + } + catch ( RuntimeException e ) + { + logError( event, e ); + } + catch ( LinkageError e ) + { + logError( event, e ); + } + } + } + + @Override + public void transferSucceeded( TransferEvent event ) + { + if ( listener != null ) + { + try + { + listener.transferSucceeded( event ); + } + catch ( RuntimeException e ) + { + logError( event, e ); + } + catch ( LinkageError e ) + { + logError( event, e ); + } + } + } + + @Override + public void transferFailed( TransferEvent event ) + { + if ( listener != null ) + { + try + { + listener.transferFailed( event ); + } + catch ( RuntimeException e ) + { + logError( event, e ); + } + catch ( LinkageError e ) + { + logError( event, e ); + } + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/SimpleDigest.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/SimpleDigest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/SimpleDigest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/SimpleDigest.java 2015-01-14 12:56:17.000000000 +0000 @@ -74,9 +74,9 @@ StringBuilder buffer = new StringBuilder( 64 ); byte[] bytes = digest.digest(); - for ( int i = 0; i < bytes.length; i++ ) + for ( byte aByte : bytes ) { - int b = bytes[i] & 0xFF; + int b = aByte & 0xFF; if ( b < 0x10 ) { diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/SimpleLocalRepositoryManagerFactory.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/SimpleLocalRepositoryManagerFactory.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/SimpleLocalRepositoryManagerFactory.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/SimpleLocalRepositoryManagerFactory.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,10 +10,9 @@ *******************************************************************************/ package org.eclipse.aether.internal.impl; +import javax.inject.Inject; import javax.inject.Named; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.LocalRepositoryManager; @@ -29,14 +28,25 @@ * Creates local repository managers for repository type {@code "simple"}. */ @Named( "simple" ) -@Component( role = LocalRepositoryManagerFactory.class, hint = "simple" ) public class SimpleLocalRepositoryManagerFactory implements LocalRepositoryManagerFactory, Service { - @Requirement( role = LoggerFactory.class ) private Logger logger = NullLoggerFactory.LOGGER; + private float priority; + + public SimpleLocalRepositoryManagerFactory() + { + // enable no-arg constructor + } + + @Inject + SimpleLocalRepositoryManagerFactory( LoggerFactory loggerFactory ) + { + setLoggerFactory( loggerFactory ); + } + public LocalRepositoryManager newInstance( RepositorySystemSession session, LocalRepository repository ) throws NoLocalRepositoryManagerException { @@ -61,15 +71,21 @@ return this; } - void setLogger( LoggerFactory loggerFactory ) + public float getPriority() { - // plexus support - setLoggerFactory( loggerFactory ); + return priority; } - public float getPriority() + /** + * Sets the priority of this component. + * + * @param priority The priority. + * @return This component for chaining, never {@code null}. + */ + public SimpleLocalRepositoryManagerFactory setPriority( float priority ) { - return 0; + this.priority = priority; + return this; } } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/slf4j/package-info.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/slf4j/package-info.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/slf4j/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/slf4j/package-info.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * The integration with the logging framework SLF4J. + */ +package org.eclipse.aether.internal.impl.slf4j; + diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/slf4j/Slf4jLoggerFactory.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/slf4j/Slf4jLoggerFactory.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/slf4j/Slf4jLoggerFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/slf4j/Slf4jLoggerFactory.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,192 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl.slf4j; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.aether.spi.locator.Service; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.sisu.Nullable; +import org.slf4j.ILoggerFactory; +import org.slf4j.spi.LocationAwareLogger; + +/** + * A logger factory that delegates to SLF4J logging. + */ +@Named( "slf4j" ) +public class Slf4jLoggerFactory + implements LoggerFactory, Service +{ + + private static final boolean AVAILABLE; + + static + { + boolean available; + try + { + Slf4jLoggerFactory.class.getClassLoader().loadClass( "org.slf4j.ILoggerFactory" ); + available = true; + } + catch ( Exception e ) + { + available = false; + } + catch ( LinkageError e ) + { + available = false; + } + AVAILABLE = available; + } + + public static boolean isSlf4jAvailable() + { + return AVAILABLE; + } + + private ILoggerFactory factory; + + /** + * Creates an instance of this logger factory. + */ + public Slf4jLoggerFactory() + { + // enables no-arg constructor + } + + @Inject + Slf4jLoggerFactory( @Nullable ILoggerFactory factory ) + { + setLoggerFactory( factory ); + } + + public void initService( ServiceLocator locator ) + { + setLoggerFactory( locator.getService( ILoggerFactory.class ) ); + } + + public Slf4jLoggerFactory setLoggerFactory( ILoggerFactory factory ) + { + this.factory = factory; + return this; + } + + public Logger getLogger( String name ) + { + org.slf4j.Logger logger = getFactory().getLogger( name ); + if ( logger instanceof LocationAwareLogger ) + { + return new Slf4jLoggerEx( (LocationAwareLogger) logger ); + } + return new Slf4jLogger( logger ); + } + + private ILoggerFactory getFactory() + { + if ( factory == null ) + { + factory = org.slf4j.LoggerFactory.getILoggerFactory(); + } + return factory; + } + + private static final class Slf4jLogger + implements Logger + { + + private final org.slf4j.Logger logger; + + public Slf4jLogger( org.slf4j.Logger logger ) + { + this.logger = logger; + } + + public boolean isDebugEnabled() + { + return logger.isDebugEnabled(); + } + + public void debug( String msg ) + { + logger.debug( msg ); + } + + public void debug( String msg, Throwable error ) + { + logger.debug( msg, error ); + } + + public boolean isWarnEnabled() + { + return logger.isWarnEnabled(); + } + + public void warn( String msg ) + { + logger.warn( msg ); + } + + public void warn( String msg, Throwable error ) + { + logger.warn( msg, error ); + } + + } + + private static final class Slf4jLoggerEx + implements Logger + { + + private static final String FQCN = Slf4jLoggerEx.class.getName(); + + private final LocationAwareLogger logger; + + public Slf4jLoggerEx( LocationAwareLogger logger ) + { + this.logger = logger; + } + + public boolean isDebugEnabled() + { + return logger.isDebugEnabled(); + } + + public void debug( String msg ) + { + logger.log( null, FQCN, LocationAwareLogger.DEBUG_INT, msg, null, null ); + } + + public void debug( String msg, Throwable error ) + { + logger.log( null, FQCN, LocationAwareLogger.DEBUG_INT, msg, null, error ); + } + + public boolean isWarnEnabled() + { + return logger.isWarnEnabled(); + } + + public void warn( String msg ) + { + logger.log( null, FQCN, LocationAwareLogger.WARN_INT, msg, null, null ); + } + + public void warn( String msg, Throwable error ) + { + logger.log( null, FQCN, LocationAwareLogger.WARN_INT, msg, null, error ); + } + + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/Slf4jLoggerFactory.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/Slf4jLoggerFactory.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/Slf4jLoggerFactory.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/Slf4jLoggerFactory.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,188 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.internal.impl; - -import javax.inject.Inject; -import javax.inject.Named; - -import org.eclipse.aether.spi.locator.Service; -import org.eclipse.aether.spi.locator.ServiceLocator; -import org.eclipse.aether.spi.log.Logger; -import org.eclipse.aether.spi.log.LoggerFactory; -import org.slf4j.ILoggerFactory; -import org.slf4j.spi.LocationAwareLogger; - -/** - * A logger factory that delegates to Slf4J logging. - */ -@Named -public class Slf4jLoggerFactory - implements LoggerFactory, Service -{ - - private static final boolean AVAILABLE; - - static - { - boolean available; - try - { - Slf4jLoggerFactory.class.getClassLoader().loadClass( "org.slf4j.ILoggerFactory" ); - available = true; - } - catch ( Exception e ) - { - available = false; - } - catch ( LinkageError e ) - { - available = false; - } - AVAILABLE = available; - } - - public static boolean isSlf4jAvailable() - { - return AVAILABLE; - } - - private ILoggerFactory factory; - - public Slf4jLoggerFactory() - { - // enables no-arg constructor - } - - @Inject - Slf4jLoggerFactory( ILoggerFactory factory ) - { - setLoggerFactory( factory ); - } - - public void initService( ServiceLocator locator ) - { - setLoggerFactory( locator.getService( ILoggerFactory.class ) ); - } - - public Slf4jLoggerFactory setLoggerFactory( ILoggerFactory factory ) - { - this.factory = factory; - return this; - } - - public Logger getLogger( String name ) - { - org.slf4j.Logger logger = getFactory().getLogger( name ); - if ( logger instanceof LocationAwareLogger ) - { - return new Slf4jLoggerEx( (LocationAwareLogger) logger ); - } - return new Slf4jLogger( logger ); - } - - private ILoggerFactory getFactory() - { - if ( factory == null ) - { - factory = org.slf4j.LoggerFactory.getILoggerFactory(); - } - return factory; - } - - private static final class Slf4jLogger - implements Logger - { - - private final org.slf4j.Logger logger; - - public Slf4jLogger( org.slf4j.Logger logger ) - { - this.logger = logger; - } - - public boolean isDebugEnabled() - { - return logger.isDebugEnabled(); - } - - public void debug( String msg ) - { - logger.debug( msg ); - } - - public void debug( String msg, Throwable error ) - { - logger.debug( msg, error ); - } - - public boolean isWarnEnabled() - { - return logger.isWarnEnabled(); - } - - public void warn( String msg ) - { - logger.warn( msg ); - } - - public void warn( String msg, Throwable error ) - { - logger.warn( msg, error ); - } - - } - - private static final class Slf4jLoggerEx - implements Logger - { - - private static final String FQCN = Slf4jLoggerEx.class.getName(); - - private final LocationAwareLogger logger; - - public Slf4jLoggerEx( LocationAwareLogger logger ) - { - this.logger = logger; - } - - public boolean isDebugEnabled() - { - return logger.isDebugEnabled(); - } - - public void debug( String msg ) - { - logger.log( null, FQCN, LocationAwareLogger.DEBUG_INT, msg, null, null ); - } - - public void debug( String msg, Throwable error ) - { - logger.log( null, FQCN, LocationAwareLogger.DEBUG_INT, msg, null, error ); - } - - public boolean isWarnEnabled() - { - return logger.isWarnEnabled(); - } - - public void warn( String msg ) - { - logger.log( null, FQCN, LocationAwareLogger.WARN_INT, msg, null, null ); - } - - public void warn( String msg, Throwable error ) - { - logger.log( null, FQCN, LocationAwareLogger.WARN_INT, msg, null, error ); - } - - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/Utils.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/Utils.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/Utils.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/Utils.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2012 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -12,42 +12,39 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; import java.util.List; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.impl.MetadataGenerator; import org.eclipse.aether.impl.MetadataGeneratorFactory; +import org.eclipse.aether.impl.OfflineController; import org.eclipse.aether.metadata.Metadata; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ResolutionErrorPolicy; import org.eclipse.aether.resolution.ResolutionErrorPolicyRequest; +import org.eclipse.aether.transfer.RepositoryOfflineException; /** + * Internal utility methods. */ final class Utils { - private static final Comparator COMPARATOR = new Comparator() + public static PrioritizedComponents sortMetadataGeneratorFactories( RepositorySystemSession session, + Collection factories ) { - - public int compare( MetadataGeneratorFactory o1, MetadataGeneratorFactory o2 ) + PrioritizedComponents result = + new PrioritizedComponents( session ); + for ( MetadataGeneratorFactory factory : factories ) { - return Float.compare( o2.getPriority(), o1.getPriority() ); + result.add( factory, factory.getPriority() ); } - - }; - - public static List sortMetadataGeneratorFactories( Collection factories ) - { - List result = new ArrayList( factories ); - Collections.sort( result, COMPARATOR ); return result; } - public static List prepareMetadata( List generators, List artifacts ) + public static List prepareMetadata( List generators, + List artifacts ) { List metadatas = new ArrayList(); @@ -59,7 +56,8 @@ return metadatas; } - public static List finishMetadata( List generators, List artifacts ) + public static List finishMetadata( List generators, + List artifacts ) { List metadatas = new ArrayList(); @@ -99,4 +97,23 @@ return rep.getMetadataPolicy( session, new ResolutionErrorPolicyRequest( metadata, repository ) ); } + public static void appendClassLoader( StringBuilder buffer, Object component ) + { + ClassLoader loader = component.getClass().getClassLoader(); + if ( loader != null && !loader.equals( Utils.class.getClassLoader() ) ) + { + buffer.append( " from " ).append( loader ); + } + } + + public static void checkOffline( RepositorySystemSession session, OfflineController offlineController, + RemoteRepository repository ) + throws RepositoryOfflineException + { + if ( session.isOffline() ) + { + offlineController.checkOffline( session, repository ); + } + } + } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/WarnChecksumPolicy.java eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/WarnChecksumPolicy.java --- eclipse-aether-0.9.0.M2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/WarnChecksumPolicy.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/main/java/org/eclipse/aether/internal/impl/WarnChecksumPolicy.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.transfer.ChecksumFailureException; +import org.eclipse.aether.transfer.TransferResource; + +/** + * Implements {@link org.eclipse.aether.repository.RepositoryPolicy#CHECKSUM_POLICY_WARN}. + */ +final class WarnChecksumPolicy + extends AbstractChecksumPolicy +{ + + public WarnChecksumPolicy( LoggerFactory loggerFactory, TransferResource resource ) + { + super( loggerFactory, resource ); + } + + public boolean onTransferChecksumFailure( ChecksumFailureException exception ) + { + String msg = + "Could not validate integrity of download from " + resource.getRepositoryUrl() + resource.getResourceName(); + if ( logger.isDebugEnabled() ) + { + logger.warn( msg, exception ); + } + else + { + logger.warn( msg + ": " + exception.getMessage() ); + } + return true; + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/impl/AetherModuleTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/impl/AetherModuleTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/impl/AetherModuleTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/impl/AetherModuleTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.impl; - -import static org.junit.Assert.*; - -import java.util.Collections; -import java.util.Set; - -import org.eclipse.aether.RepositorySystem; -import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; -import org.junit.Test; - -import com.google.inject.AbstractModule; -import com.google.inject.Guice; -import com.google.inject.Provides; - -public class AetherModuleTest -{ - - @Test - public void testModuleCompleteness() - { - assertNotNull( Guice.createInjector( new SystemModule() ).getInstance( RepositorySystem.class ) ); - } - - static class SystemModule - extends AbstractModule - { - - @Override - protected void configure() - { - install( new AetherModule() ); - bind( ArtifactDescriptorReader.class ).to( StubArtifactDescriptorReader.class ); - bind( VersionRangeResolver.class ).to( StubVersionRangeResolver.class ); - bind( VersionResolver.class ).to( StubVersionResolver.class ); - } - - @Provides - public Set metadataGeneratorFactories() - { - return Collections.emptySet(); - } - - @Provides - public Set repositoryConnectorFactories() - { - return Collections.emptySet(); - } - - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/impl/guice/AetherModuleTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/impl/guice/AetherModuleTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/impl/guice/AetherModuleTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/impl/guice/AetherModuleTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2012, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.impl.guice; + +import static org.junit.Assert.*; + +import java.util.Collections; +import java.util.Set; + +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.impl.ArtifactDescriptorReader; +import org.eclipse.aether.impl.MetadataGeneratorFactory; +import org.eclipse.aether.impl.StubArtifactDescriptorReader; +import org.eclipse.aether.impl.StubVersionRangeResolver; +import org.eclipse.aether.impl.StubVersionResolver; +import org.eclipse.aether.impl.VersionRangeResolver; +import org.eclipse.aether.impl.VersionResolver; +import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.junit.Test; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Provides; + +public class AetherModuleTest +{ + + @Test + public void testModuleCompleteness() + { + assertNotNull( Guice.createInjector( new SystemModule() ).getInstance( RepositorySystem.class ) ); + } + + static class SystemModule + extends AbstractModule + { + + @Override + protected void configure() + { + install( new AetherModule() ); + bind( ArtifactDescriptorReader.class ).to( StubArtifactDescriptorReader.class ); + bind( VersionRangeResolver.class ).to( StubVersionRangeResolver.class ); + bind( VersionResolver.class ).to( StubVersionResolver.class ); + } + + @Provides + public Set metadataGeneratorFactories() + { + return Collections.emptySet(); + } + + @Provides + public Set repositoryConnectorFactories() + { + return Collections.emptySet(); + } + + @Provides + public Set transporterFactories() + { + return Collections.emptySet(); + } + + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/impl/PlexusSupportTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/impl/PlexusSupportTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/impl/PlexusSupportTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/impl/PlexusSupportTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Sonatype, Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.aether.impl; - -import java.util.List; - -import org.codehaus.plexus.ContainerConfiguration; -import org.codehaus.plexus.PlexusTestCase; -import org.eclipse.aether.RepositorySystem; -import org.eclipse.aether.impl.ArtifactDescriptorReader; -import org.eclipse.aether.impl.VersionRangeResolver; -import org.eclipse.aether.impl.VersionResolver; -import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory; - -/** - */ -public class PlexusSupportTest - extends PlexusTestCase -{ - - @Override - protected void customizeContainerConfiguration( ContainerConfiguration containerConfiguration ) - { - containerConfiguration.setClassPathScanning( "cache" ); - } - - public void testExistenceOfPlexusComponentMetadata() - throws Exception - { - getContainer().addComponent( new StubVersionRangeResolver(), VersionRangeResolver.class, null ); - getContainer().addComponent( new StubVersionResolver(), VersionResolver.class, null ); - getContainer().addComponent( new StubArtifactDescriptorReader(), ArtifactDescriptorReader.class, null ); - - RepositorySystem repoSystem = lookup( RepositorySystem.class ); - assertNotNull( repoSystem ); - assertSame( repoSystem, lookup( RepositorySystem.class ) ); - - List lrmfs = getContainer().lookupList( LocalRepositoryManagerFactory.class ); - assertNotNull( lrmfs ); - assertEquals( 2, lrmfs.size() ); - } - -} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -21,7 +21,9 @@ import java.util.Map; import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositoryEvent; import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RepositoryEvent.EventType; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.ArtifactProperties; import org.eclipse.aether.artifact.DefaultArtifact; @@ -29,13 +31,10 @@ import org.eclipse.aether.impl.VersionResolver; import org.eclipse.aether.internal.impl.DefaultArtifactResolver; import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager; -import org.eclipse.aether.internal.test.util.RecordingRepositoryListener; import org.eclipse.aether.internal.test.util.TestFileProcessor; import org.eclipse.aether.internal.test.util.TestFileUtils; import org.eclipse.aether.internal.test.util.TestLocalRepositoryManager; import org.eclipse.aether.internal.test.util.TestUtils; -import org.eclipse.aether.internal.test.util.RecordingRepositoryListener.EventWrapper; -import org.eclipse.aether.internal.test.util.RecordingRepositoryListener.Type; import org.eclipse.aether.metadata.Metadata; import org.eclipse.aether.repository.LocalArtifactRegistration; import org.eclipse.aether.repository.LocalArtifactRequest; @@ -111,7 +110,7 @@ { if ( session.getLocalRepository() != null ) { - TestFileUtils.delete( session.getLocalRepository().getBasedir() ); + TestFileUtils.deleteFile( session.getLocalRepository().getBasedir() ); } } @@ -290,8 +289,8 @@ connector.assertSeenExpected(); } - TestFileUtils.write( "artifact", - new File( lrm.getRepository().getBasedir(), lrm.getPathForLocalArtifact( artifact2 ) ) ); + TestFileUtils.writeString( new File( lrm.getRepository().getBasedir(), lrm.getPathForLocalArtifact( artifact2 ) ), + "artifact" ); lrm.setArtifactAvailability( artifact2, false ); DefaultUpdateCheckManagerTest.resetSessionData( session ); @@ -355,8 +354,7 @@ Artifact resolved = result.getArtifact(); assertNotNull( resolved.getFile() ); - byte[] expected = resolved.toString().getBytes( "UTF-8" ); - TestFileUtils.assertContent( expected, resolved.getFile() ); + assertEquals( resolved.toString(), TestFileUtils.readString( resolved.getFile() ) ); resolved = resolved.setFile( null ); assertEquals( artifact, resolved ); @@ -422,17 +420,17 @@ ArtifactRequest request = new ArtifactRequest( artifact, null, "" ); resolver.resolveArtifact( session, request ); - List events = listener.getEvents(); + List events = listener.getEvents(); assertEquals( 2, events.size() ); - EventWrapper event = events.get( 0 ); - assertEquals( RecordingRepositoryListener.Type.ARTIFACT_RESOLVING, event.getType() ); - assertNull( event.getEvent().getException() ); - assertEquals( artifact, event.getEvent().getArtifact() ); + RepositoryEvent event = events.get( 0 ); + assertEquals( EventType.ARTIFACT_RESOLVING, event.getType() ); + assertNull( event.getException() ); + assertEquals( artifact, event.getArtifact() ); event = events.get( 1 ); - assertEquals( RecordingRepositoryListener.Type.ARTIFACT_RESOLVED, event.getType() ); - assertNull( event.getEvent().getException() ); - assertEquals( artifact, event.getEvent().getArtifact().setFile( null ) ); + assertEquals( EventType.ARTIFACT_RESOLVED, event.getType() ); + assertNull( event.getException() ); + assertEquals( artifact, event.getArtifact().setFile( null ) ); } @Test @@ -456,18 +454,18 @@ { } - List events = listener.getEvents(); + List events = listener.getEvents(); assertEquals( 2, events.size() ); - EventWrapper event = events.get( 0 ); - assertEquals( artifact, event.getEvent().getArtifact() ); - assertEquals( Type.ARTIFACT_RESOLVING, event.getType() ); + RepositoryEvent event = events.get( 0 ); + assertEquals( artifact, event.getArtifact() ); + assertEquals( EventType.ARTIFACT_RESOLVING, event.getType() ); event = events.get( 1 ); - assertEquals( artifact, event.getEvent().getArtifact() ); - assertEquals( Type.ARTIFACT_RESOLVED, event.getType() ); - assertNotNull( event.getEvent().getException() ); - assertEquals( 1, event.getEvent().getExceptions().size() ); + assertEquals( artifact, event.getArtifact() ); + assertEquals( EventType.ARTIFACT_RESOLVED, event.getType() ); + assertNotNull( event.getException() ); + assertEquals( 1, event.getExceptions().size() ); } @@ -483,17 +481,27 @@ resolver.resolveArtifact( session, request ); - List events = listener.getEvents(); - assertEquals( 2, events.size() ); - EventWrapper event = events.get( 0 ); - assertEquals( RecordingRepositoryListener.Type.ARTIFACT_RESOLVING, event.getType() ); - assertNull( event.getEvent().getException() ); - assertEquals( artifact, event.getEvent().getArtifact() ); + List events = listener.getEvents(); + assertEquals( events.toString(), 4, events.size() ); + RepositoryEvent event = events.get( 0 ); + assertEquals( EventType.ARTIFACT_RESOLVING, event.getType() ); + assertNull( event.getException() ); + assertEquals( artifact, event.getArtifact() ); event = events.get( 1 ); - assertEquals( RecordingRepositoryListener.Type.ARTIFACT_RESOLVED, event.getType() ); - assertNull( event.getEvent().getException() ); - assertEquals( artifact, event.getEvent().getArtifact().setFile( null ) ); + assertEquals( EventType.ARTIFACT_DOWNLOADING, event.getType() ); + assertNull( event.getException() ); + assertEquals( artifact, event.getArtifact().setFile( null ) ); + + event = events.get( 2 ); + assertEquals( EventType.ARTIFACT_DOWNLOADED, event.getType() ); + assertNull( event.getException() ); + assertEquals( artifact, event.getArtifact().setFile( null ) ); + + event = events.get( 3 ); + assertEquals( EventType.ARTIFACT_RESOLVED, event.getType() ); + assertNull( event.getException() ); + assertEquals( artifact, event.getArtifact().setFile( null ) ); } @Test @@ -532,18 +540,28 @@ { } - List events = listener.getEvents(); - assertEquals( 2, events.size() ); + List events = listener.getEvents(); + assertEquals( events.toString(), 4, events.size() ); - EventWrapper event = events.get( 0 ); - assertEquals( artifact, event.getEvent().getArtifact() ); - assertEquals( Type.ARTIFACT_RESOLVING, event.getType() ); + RepositoryEvent event = events.get( 0 ); + assertEquals( artifact, event.getArtifact() ); + assertEquals( EventType.ARTIFACT_RESOLVING, event.getType() ); event = events.get( 1 ); - assertEquals( artifact, event.getEvent().getArtifact() ); - assertEquals( Type.ARTIFACT_RESOLVED, event.getType() ); - assertNotNull( event.getEvent().getException() ); - assertEquals( 1, event.getEvent().getExceptions().size() ); + assertEquals( artifact, event.getArtifact() ); + assertEquals( EventType.ARTIFACT_DOWNLOADING, event.getType() ); + + event = events.get( 2 ); + assertEquals( artifact, event.getArtifact() ); + assertEquals( EventType.ARTIFACT_DOWNLOADED, event.getType() ); + assertNotNull( event.getException() ); + assertEquals( 1, event.getExceptions().size() ); + + event = events.get( 3 ); + assertEquals( artifact, event.getArtifact() ); + assertEquals( EventType.ARTIFACT_RESOLVED, event.getType() ); + assertNotNull( event.getException() ); + assertEquals( 1, event.getExceptions().size() ); } @Test @@ -609,18 +627,18 @@ { } - List events = listener.getEvents(); + List events = listener.getEvents(); assertEquals( 2, events.size() ); - EventWrapper event = events.get( 0 ); - assertEquals( artifact, event.getEvent().getArtifact() ); - assertEquals( Type.ARTIFACT_RESOLVING, event.getType() ); + RepositoryEvent event = events.get( 0 ); + assertEquals( artifact, event.getArtifact() ); + assertEquals( EventType.ARTIFACT_RESOLVING, event.getType() ); event = events.get( 1 ); - assertEquals( artifact, event.getEvent().getArtifact() ); - assertEquals( Type.ARTIFACT_RESOLVED, event.getType() ); - assertNotNull( event.getEvent().getException() ); - assertEquals( 1, event.getEvent().getExceptions().size() ); + assertEquals( artifact, event.getArtifact() ); + assertEquals( EventType.ARTIFACT_RESOLVED, event.getType() ); + assertNotNull( event.getException() ); + assertEquals( 1, event.getExceptions().size() ); } @Test diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultChecksumPolicyProviderTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultChecksumPolicyProviderTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultChecksumPolicyProviderTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultChecksumPolicyProviderTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import static org.junit.Assert.*; + +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.internal.test.util.TestUtils; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.repository.RepositoryPolicy; +import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy; +import org.eclipse.aether.transfer.TransferResource; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class DefaultChecksumPolicyProviderTest +{ + + private static final String CHECKSUM_POLICY_UNKNOWN = "unknown"; + + private DefaultRepositorySystemSession session; + + private DefaultChecksumPolicyProvider provider; + + private RemoteRepository repository; + + private TransferResource resource; + + @Before + public void setup() + throws Exception + { + session = TestUtils.newSession(); + provider = new DefaultChecksumPolicyProvider(); + repository = new RemoteRepository.Builder( "test", "default", "file:/void" ).build(); + resource = new TransferResource( repository.getUrl(), "file.txt", null, null ); + } + + @After + public void teardown() + throws Exception + { + provider = null; + session = null; + repository = null; + resource = null; + } + + @Test + public void testNewChecksumPolicy_Fail() + { + ChecksumPolicy policy = + provider.newChecksumPolicy( session, repository, resource, RepositoryPolicy.CHECKSUM_POLICY_FAIL ); + assertNotNull( policy ); + assertEquals( FailChecksumPolicy.class, policy.getClass() ); + } + + @Test + public void testNewChecksumPolicy_Warn() + { + ChecksumPolicy policy = + provider.newChecksumPolicy( session, repository, resource, RepositoryPolicy.CHECKSUM_POLICY_WARN ); + assertNotNull( policy ); + assertEquals( WarnChecksumPolicy.class, policy.getClass() ); + } + + @Test + public void testNewChecksumPolicy_Ignore() + { + ChecksumPolicy policy = + provider.newChecksumPolicy( session, repository, resource, RepositoryPolicy.CHECKSUM_POLICY_IGNORE ); + assertNull( policy ); + } + + @Test + public void testNewChecksumPolicy_Unknown() + { + ChecksumPolicy policy = provider.newChecksumPolicy( session, repository, resource, CHECKSUM_POLICY_UNKNOWN ); + assertNotNull( policy ); + assertEquals( WarnChecksumPolicy.class, policy.getClass() ); + } + + @Test + public void testGetEffectiveChecksumPolicy_EqualPolicies() + { + String[] policies = + { RepositoryPolicy.CHECKSUM_POLICY_FAIL, RepositoryPolicy.CHECKSUM_POLICY_WARN, + RepositoryPolicy.CHECKSUM_POLICY_IGNORE, CHECKSUM_POLICY_UNKNOWN }; + for ( String policy : policies ) + { + assertEquals( policy, policy, provider.getEffectiveChecksumPolicy( session, policy, policy ) ); + } + } + + @Test + public void testGetEffectiveChecksumPolicy_DifferentPolicies() + { + String[][] testCases = + { { RepositoryPolicy.CHECKSUM_POLICY_WARN, RepositoryPolicy.CHECKSUM_POLICY_FAIL }, + { RepositoryPolicy.CHECKSUM_POLICY_IGNORE, RepositoryPolicy.CHECKSUM_POLICY_FAIL }, + { RepositoryPolicy.CHECKSUM_POLICY_IGNORE, RepositoryPolicy.CHECKSUM_POLICY_WARN } }; + for ( String[] testCase : testCases ) + { + assertEquals( testCase[0] + " vs " + testCase[1], testCase[0], + provider.getEffectiveChecksumPolicy( session, testCase[0], testCase[1] ) ); + assertEquals( testCase[0] + " vs " + testCase[1], testCase[0], + provider.getEffectiveChecksumPolicy( session, testCase[1], testCase[0] ) ); + } + } + + @Test + public void testGetEffectiveChecksumPolicy_UnknownPolicies() + { + String[][] testCases = + { { RepositoryPolicy.CHECKSUM_POLICY_WARN, RepositoryPolicy.CHECKSUM_POLICY_FAIL }, + { RepositoryPolicy.CHECKSUM_POLICY_WARN, RepositoryPolicy.CHECKSUM_POLICY_WARN }, + { RepositoryPolicy.CHECKSUM_POLICY_IGNORE, RepositoryPolicy.CHECKSUM_POLICY_IGNORE } }; + for ( String[] testCase : testCases ) + { + assertEquals( "unknown vs " + testCase[1], testCase[0], + provider.getEffectiveChecksumPolicy( session, CHECKSUM_POLICY_UNKNOWN, testCase[1] ) ); + assertEquals( "unknown vs " + testCase[1], testCase[0], + provider.getEffectiveChecksumPolicy( session, testCase[1], CHECKSUM_POLICY_UNKNOWN ) ); + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDependencyCollectorTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDependencyCollectorTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDependencyCollectorTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDependencyCollectorTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -35,10 +35,10 @@ import org.eclipse.aether.collection.DependencyManagement; import org.eclipse.aether.collection.DependencyManager; import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.graph.DependencyCycle; import org.eclipse.aether.graph.DependencyNode; import org.eclipse.aether.graph.Exclusion; import org.eclipse.aether.impl.ArtifactDescriptorReader; -import org.eclipse.aether.internal.impl.DefaultDependencyCollector; import org.eclipse.aether.internal.test.util.DependencyGraphParser; import org.eclipse.aether.internal.test.util.TestLoggerFactory; import org.eclipse.aether.internal.test.util.TestUtils; @@ -49,6 +49,7 @@ import org.eclipse.aether.util.artifact.ArtifactIdUtils; import org.eclipse.aether.util.graph.manager.ClassicDependencyManager; import org.eclipse.aether.util.graph.manager.DependencyManagerUtils; +import org.eclipse.aether.util.graph.version.HighestVersionFilter; import org.junit.Before; import org.junit.Test; @@ -145,9 +146,9 @@ try { DependencyNode node = root; - for ( int i = 0; i < coords.length; i++ ) + for ( int coord : coords ) { - node = node.getChildren().get( coords[i] ); + node = node.getChildren().get( coord ); } return node; @@ -276,13 +277,43 @@ CollectRequest request = new CollectRequest( newDep( "test:a:2" ), Arrays.asList( repository ) ); collector.setArtifactDescriptorReader( newReader( "versionless-cycle/" ) ); CollectResult result = collector.collectDependencies( session, request ); - DependencyNode a1 = path( result.getRoot(), 0, 0 ); + DependencyNode root = result.getRoot(); + DependencyNode a1 = path( root, 0, 0 ); assertEquals( "a", a1.getArtifact().getArtifactId() ); assertEquals( "1", a1.getArtifact().getVersion() ); for ( DependencyNode child : a1.getChildren() ) { assertFalse( "1".equals( child.getArtifact().getVersion() ) ); } + + assertEquals( 1, result.getCycles().size() ); + DependencyCycle cycle = result.getCycles().get( 0 ); + assertEquals( Arrays.asList(), cycle.getPrecedingDependencies() ); + assertEquals( Arrays.asList( root.getDependency(), path( root, 0 ).getDependency(), a1.getDependency() ), + cycle.getCyclicDependencies() ); + } + + @Test + public void testCyclicProjects_ConsiderLabelOfRootlessGraph() + throws Exception + { + Dependency dep = newDep( "gid:aid:ver", "compile" ); + CollectRequest request = + new CollectRequest().addDependency( dep ).addRepository( repository ).setRootArtifact( dep.getArtifact() ); + CollectResult result = collector.collectDependencies( session, request ); + DependencyNode root = result.getRoot(); + DependencyNode a1 = root.getChildren().get( 0 ); + assertEquals( "aid", a1.getArtifact().getArtifactId() ); + assertEquals( "ver", a1.getArtifact().getVersion() ); + DependencyNode a2 = a1.getChildren().get( 0 ); + assertEquals( "aid2", a2.getArtifact().getArtifactId() ); + assertEquals( "ver", a2.getArtifact().getVersion() ); + + assertEquals( 1, result.getCycles().size() ); + DependencyCycle cycle = result.getCycles().get( 0 ); + assertEquals( Arrays.asList(), cycle.getPrecedingDependencies() ); + assertEquals( Arrays.asList( new Dependency( dep.getArtifact(), null ), a1.getDependency() ), + cycle.getCyclicDependencies() ); } @Test @@ -441,6 +472,16 @@ assertEquals( Boolean.FALSE, DependencyManagerUtils.getPremanagedOptional( node ) ); } + @Test + public void testVersionFilter() + throws Exception + { + session.setVersionFilter( new HighestVersionFilter() ); + CollectRequest request = new CollectRequest().setRoot( newDep( "gid:aid:1" ) ); + CollectResult result = collector.collectDependencies( session, request ); + assertEquals( 1, result.getRoot().getChildren().size() ); + } + static class TestDependencyManager implements DependencyManager { diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDeployerTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDeployerTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDeployerTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDeployerTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,7 +10,6 @@ *******************************************************************************/ package org.eclipse.aether.internal.impl; -import static org.eclipse.aether.internal.test.util.RecordingRepositoryListener.Type.*; import static org.junit.Assert.*; import java.io.File; @@ -23,17 +22,16 @@ import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.RepositoryEvent.EventType; import org.eclipse.aether.RepositoryException; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.deployment.DeployRequest; import org.eclipse.aether.deployment.DeploymentException; import org.eclipse.aether.internal.impl.DefaultDeployer; -import org.eclipse.aether.internal.test.util.RecordingRepositoryListener; import org.eclipse.aether.internal.test.util.TestFileProcessor; import org.eclipse.aether.internal.test.util.TestFileUtils; import org.eclipse.aether.internal.test.util.TestUtils; -import org.eclipse.aether.internal.test.util.RecordingRepositoryListener.EventWrapper; import org.eclipse.aether.metadata.DefaultMetadata; import org.eclipse.aether.metadata.MergeableMetadata; import org.eclipse.aether.metadata.Metadata; @@ -44,10 +42,7 @@ import org.eclipse.aether.spi.connector.MetadataDownload; import org.eclipse.aether.spi.connector.MetadataUpload; import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.aether.spi.connector.Transfer.State; -import org.eclipse.aether.transfer.ArtifactTransferException; import org.eclipse.aether.transfer.MetadataNotFoundException; -import org.eclipse.aether.transfer.MetadataTransferException; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -95,7 +90,7 @@ request = new DeployRequest(); request.setRepository( new RemoteRepository.Builder( "id", "default", "file:///" ).build() ); - connector = new RecordingRepositoryConnector(); + connector = new RecordingRepositoryConnector( session ); connectorProvider.setConnector( connector ); listener = new RecordingRepositoryListener(); @@ -108,7 +103,7 @@ { if ( session.getLocalRepository() != null ) { - TestFileUtils.delete( session.getLocalRepository().getBasedir() ); + TestFileUtils.deleteFile( session.getLocalRepository().getBasedir() ); } session = null; listener = null; @@ -157,20 +152,16 @@ deployer.deploy( session, request ); - List events = listener.getEvents(); + List events = listener.getEvents(); assertEquals( 2, events.size() ); - EventWrapper wrapper = events.get( 0 ); - assertEquals( ARTIFACT_DEPLOYING, wrapper.getType() ); - - RepositoryEvent event = wrapper.getEvent(); + RepositoryEvent event = events.get( 0 ); + assertEquals( EventType.ARTIFACT_DEPLOYING, event.getType() ); assertEquals( artifact, event.getArtifact() ); assertNull( event.getException() ); - wrapper = events.get( 1 ); - assertEquals( ARTIFACT_DEPLOYED, wrapper.getType() ); - - event = wrapper.getEvent(); + event = events.get( 1 ); + assertEquals( EventType.ARTIFACT_DEPLOYED, event.getType() ); assertEquals( artifact, event.getArtifact() ); assertNull( event.getException() ); } @@ -178,54 +169,7 @@ @Test public void testFailingArtifactEvents() { - connector = new RecordingRepositoryConnector() - { - - @Override - public void get( Collection artifactDownloads, - Collection metadataDownloads ) - { - metadataDownloads = - metadataDownloads == null ? Collections. emptyList() : metadataDownloads; - artifactDownloads = - artifactDownloads == null ? Collections. emptyList() : artifactDownloads; - for ( MetadataDownload d : metadataDownloads ) - { - d.setState( State.ACTIVE ); - d.setException( new MetadataTransferException( d.getMetadata(), null, "failed" ) ); - d.setState( State.DONE ); - } - for ( ArtifactDownload d : artifactDownloads ) - { - d.setState( State.ACTIVE ); - d.setException( new ArtifactTransferException( d.getArtifact(), null, "failed" ) ); - d.setState( State.DONE ); - } - } - - @Override - public void put( Collection artifactUploads, - Collection metadataUploads ) - { - metadataUploads = metadataUploads == null ? Collections. emptyList() : metadataUploads; - artifactUploads = artifactUploads == null ? Collections. emptyList() : artifactUploads; - for ( MetadataUpload d : metadataUploads ) - { - d.setState( State.ACTIVE ); - d.setException( new MetadataTransferException( d.getMetadata(), null, "failed" ) ); - d.setState( State.DONE ); - } - for ( ArtifactUpload d : artifactUploads ) - { - d.setState( State.ACTIVE ); - d.setException( new ArtifactTransferException( d.getArtifact(), null, "failed" ) ); - d.setState( State.DONE ); - } - } - - }; - - connectorProvider.setConnector( connector ); + connector.fail = true; request.addArtifact( artifact ); @@ -236,20 +180,16 @@ } catch ( DeploymentException e ) { - List events = listener.getEvents(); + List events = listener.getEvents(); assertEquals( 2, events.size() ); - EventWrapper wrapper = events.get( 0 ); - assertEquals( ARTIFACT_DEPLOYING, wrapper.getType() ); - - RepositoryEvent event = wrapper.getEvent(); + RepositoryEvent event = events.get( 0 ); + assertEquals( EventType.ARTIFACT_DEPLOYING, event.getType() ); assertEquals( artifact, event.getArtifact() ); assertNull( event.getException() ); - wrapper = events.get( 1 ); - assertEquals( ARTIFACT_DEPLOYED, wrapper.getType() ); - - event = wrapper.getEvent(); + event = events.get( 1 ); + assertEquals( EventType.ARTIFACT_DEPLOYED, event.getType() ); assertEquals( artifact, event.getArtifact() ); assertNotNull( event.getException() ); } @@ -263,20 +203,16 @@ deployer.deploy( session, request ); - List events = listener.getEvents(); + List events = listener.getEvents(); assertEquals( 2, events.size() ); - EventWrapper wrapper = events.get( 0 ); - assertEquals( METADATA_DEPLOYING, wrapper.getType() ); - - RepositoryEvent event = wrapper.getEvent(); + RepositoryEvent event = events.get( 0 ); + assertEquals( EventType.METADATA_DEPLOYING, event.getType() ); assertEquals( metadata, event.getMetadata() ); assertNull( event.getException() ); - wrapper = events.get( 1 ); - assertEquals( METADATA_DEPLOYED, wrapper.getType() ); - - event = wrapper.getEvent(); + event = events.get( 1 ); + assertEquals( EventType.METADATA_DEPLOYED, event.getType() ); assertEquals( metadata, event.getMetadata() ); assertNull( event.getException() ); } @@ -284,54 +220,7 @@ @Test public void testFailingMetdataEvents() { - connector = new RecordingRepositoryConnector() - { - - @Override - public void get( Collection artifactDownloads, - Collection metadataDownloads ) - { - metadataDownloads = - metadataDownloads == null ? Collections. emptyList() : metadataDownloads; - artifactDownloads = - artifactDownloads == null ? Collections. emptyList() : artifactDownloads; - for ( MetadataDownload d : metadataDownloads ) - { - d.setState( State.ACTIVE ); - d.setException( new MetadataTransferException( d.getMetadata(), null, "failed" ) ); - d.setState( State.DONE ); - } - for ( ArtifactDownload d : artifactDownloads ) - { - d.setState( State.ACTIVE ); - d.setException( new ArtifactTransferException( d.getArtifact(), null, "failed" ) ); - d.setState( State.DONE ); - } - } - - @Override - public void put( Collection artifactUploads, - Collection metadataUploads ) - { - metadataUploads = metadataUploads == null ? Collections. emptyList() : metadataUploads; - artifactUploads = artifactUploads == null ? Collections. emptyList() : artifactUploads; - for ( MetadataUpload d : metadataUploads ) - { - d.setState( State.ACTIVE ); - d.setException( new MetadataTransferException( d.getMetadata(), null, "failed" ) ); - d.setState( State.DONE ); - } - for ( ArtifactUpload d : artifactUploads ) - { - d.setState( State.ACTIVE ); - d.setException( new ArtifactTransferException( d.getArtifact(), null, "failed" ) ); - d.setState( State.DONE ); - } - } - - }; - - connectorProvider.setConnector( connector ); + connector.fail = true; request.addMetadata( metadata ); @@ -342,20 +231,16 @@ } catch ( DeploymentException e ) { - List events = listener.getEvents(); + List events = listener.getEvents(); assertEquals( 2, events.size() ); - EventWrapper wrapper = events.get( 0 ); - assertEquals( METADATA_DEPLOYING, wrapper.getType() ); - - RepositoryEvent event = wrapper.getEvent(); + RepositoryEvent event = events.get( 0 ); + assertEquals( EventType.METADATA_DEPLOYING, event.getType() ); assertEquals( metadata, event.getMetadata() ); assertNull( event.getException() ); - wrapper = events.get( 1 ); - assertEquals( METADATA_DEPLOYED, wrapper.getType() ); - - event = wrapper.getEvent(); + event = events.get( 1 ); + assertEquals( EventType.METADATA_DEPLOYED, event.getType() ); assertEquals( metadata, event.getMetadata() ); assertNotNull( event.getException() ); } @@ -427,12 +312,12 @@ { if ( current.isFile() ) { - TestFileUtils.read( props, current ); + TestFileUtils.readProps( current, props ); } props.setProperty( "new", "value" ); - TestFileUtils.write( props, result ); + TestFileUtils.writeProps( result, props ); } catch ( IOException e ) { @@ -479,12 +364,12 @@ "" ) ); Properties props = new Properties(); props.setProperty( "old", "value" ); - TestFileUtils.write( props, metadataFile ); + TestFileUtils.writeProps( metadataFile, props ); deployer.deploy( session, request ); props = new Properties(); - TestFileUtils.read( props, metadataFile ); + TestFileUtils.readProps( metadataFile, props ); assertNull( props.toString(), props.get( "old" ) ); } diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultFileProcessorTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultFileProcessorTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultFileProcessorTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultFileProcessorTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. + * Copyright (c) 2010, 2013 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -45,7 +45,7 @@ public void teardown() throws Exception { - TestFileUtils.delete( targetDir ); + TestFileUtils.deleteFile( targetDir ); fileProcessor = null; } @@ -53,12 +53,13 @@ public void testCopy() throws IOException { - File file = TestFileUtils.createTempFile( "testCopy\nasdf" ); + String data = "testCopy\nasdf"; + File file = TestFileUtils.createTempFile( data ); File target = new File( targetDir, "testCopy.txt" ); fileProcessor.copy( file, target ); - TestFileUtils.assertContent( "testCopy\nasdf".getBytes( "UTF-8" ), file ); + assertEquals( data, TestFileUtils.readString( file ) ); file.delete(); } @@ -67,13 +68,14 @@ public void testOverwrite() throws IOException { - File file = TestFileUtils.createTempFile( "testCopy\nasdf" ); + String data = "testCopy\nasdf"; + File file = TestFileUtils.createTempFile( data ); for ( int i = 0; i < 5; i++ ) { File target = new File( targetDir, "testCopy.txt" ); fileProcessor.copy( file, target ); - TestFileUtils.assertContent( "testCopy\nasdf".getBytes( "UTF-8" ), file ); + assertEquals( data, TestFileUtils.readString( file ) ); } file.delete(); diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultInstallerTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultInstallerTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultInstallerTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultInstallerTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,7 +10,6 @@ *******************************************************************************/ package org.eclipse.aether.internal.impl; -import static org.eclipse.aether.internal.test.util.RecordingRepositoryListener.Type.*; import static org.junit.Assert.*; import java.io.File; @@ -20,6 +19,7 @@ import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.RepositoryEvent.EventType; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.installation.InstallRequest; @@ -27,12 +27,10 @@ import org.eclipse.aether.installation.InstallationException; import org.eclipse.aether.internal.impl.DefaultFileProcessor; import org.eclipse.aether.internal.impl.DefaultInstaller; -import org.eclipse.aether.internal.test.util.RecordingRepositoryListener; import org.eclipse.aether.internal.test.util.TestFileProcessor; import org.eclipse.aether.internal.test.util.TestFileUtils; import org.eclipse.aether.internal.test.util.TestLocalRepositoryManager; import org.eclipse.aether.internal.test.util.TestUtils; -import org.eclipse.aether.internal.test.util.RecordingRepositoryListener.EventWrapper; import org.eclipse.aether.metadata.DefaultMetadata; import org.eclipse.aether.metadata.Metadata; import org.eclipse.aether.metadata.Metadata.Nature; @@ -45,7 +43,7 @@ private Artifact artifact; - private DefaultMetadata metadata; + private Metadata metadata; private DefaultRepositorySystemSession session; @@ -89,14 +87,14 @@ lrm = (TestLocalRepositoryManager) session.getLocalRepositoryManager(); - TestFileUtils.delete( session.getLocalRepository().getBasedir() ); + TestFileUtils.deleteFile( session.getLocalRepository().getBasedir() ); } @After public void teardown() throws Exception { - TestFileUtils.delete( session.getLocalRepository().getBasedir() ); + TestFileUtils.deleteFile( session.getLocalRepository().getBasedir() ); } @Test @@ -117,10 +115,10 @@ InstallResult result = installer.install( session, request ); assertTrue( artifactFile.exists() ); - TestFileUtils.assertContent( "artifact".getBytes( "UTF-8" ), artifactFile ); + assertEquals( "artifact", TestFileUtils.readString( artifactFile ) ); assertTrue( metadataFile.exists() ); - TestFileUtils.assertContent( "metadata".getBytes( "UTF-8" ), metadataFile ); + assertEquals( "metadata", TestFileUtils.readString( metadataFile ) ); assertEquals( result.getRequest(), request ); @@ -203,6 +201,32 @@ installer.install( session, request ); } + @Test( expected = InstallationException.class ) + public void testArtifactDestinationEqualsSource() + throws Exception + { + String path = session.getLocalRepositoryManager().getPathForLocalArtifact( artifact ); + File file = new File( session.getLocalRepository().getBasedir(), path ); + artifact = artifact.setFile( file ); + TestFileUtils.writeString( file, "test" ); + + request.addArtifact( artifact ); + installer.install( session, request ); + } + + @Test( expected = InstallationException.class ) + public void testMetadataDestinationEqualsSource() + throws Exception + { + String path = session.getLocalRepositoryManager().getPathForLocalMetadata( metadata ); + File file = new File( session.getLocalRepository().getBasedir(), path ); + metadata = metadata.setFile( file ); + TestFileUtils.writeString( file, "test" ); + + request.addMetadata( metadata ); + installer.install( session, request ); + } + @Test public void testSuccessfulArtifactEvents() throws InstallationException @@ -274,18 +298,15 @@ private void checkEvents( String msg, Metadata metadata, boolean failed ) { - List events = listener.getEvents(); + List events = listener.getEvents(); assertEquals( msg, 2, events.size() ); - EventWrapper wrapper = events.get( 0 ); - assertEquals( msg, METADATA_INSTALLING, wrapper.getType() ); - - RepositoryEvent event = wrapper.getEvent(); + RepositoryEvent event = events.get( 0 ); + assertEquals( msg, EventType.METADATA_INSTALLING, event.getType() ); assertEquals( msg, metadata, event.getMetadata() ); assertNull( msg, event.getException() ); - wrapper = events.get( 1 ); - assertEquals( msg, METADATA_INSTALLED, wrapper.getType() ); - event = wrapper.getEvent(); + event = events.get( 1 ); + assertEquals( msg, EventType.METADATA_INSTALLED, event.getType() ); assertEquals( msg, metadata, event.getMetadata() ); if ( failed ) { @@ -315,18 +336,15 @@ private void checkEvents( String msg, Artifact artifact, boolean failed ) { - List events = listener.getEvents(); + List events = listener.getEvents(); assertEquals( msg, 2, events.size() ); - EventWrapper wrapper = events.get( 0 ); - assertEquals( msg, ARTIFACT_INSTALLING, wrapper.getType() ); - - RepositoryEvent event = wrapper.getEvent(); + RepositoryEvent event = events.get( 0 ); + assertEquals( msg, EventType.ARTIFACT_INSTALLING, event.getType() ); assertEquals( msg, artifact, event.getArtifact() ); assertNull( msg, event.getException() ); - wrapper = events.get( 1 ); - assertEquals( msg, ARTIFACT_INSTALLED, wrapper.getType() ); - event = wrapper.getEvent(); + event = events.get( 1 ); + assertEquals( msg, EventType.ARTIFACT_INSTALLED, event.getType() ); assertEquals( msg, artifact, event.getArtifact() ); if ( failed ) { diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultMetadataResolverTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultMetadataResolverTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultMetadataResolverTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultMetadataResolverTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -83,8 +83,8 @@ public void teardown() throws Exception { - TestFileUtils.delete( new File( new URI( repository.getUrl() ) ) ); - TestFileUtils.delete( session.getLocalRepository().getBasedir() ); + TestFileUtils.deleteFile( new File( new URI( repository.getUrl() ) ) ); + TestFileUtils.deleteFile( session.getLocalRepository().getBasedir() ); } @Test @@ -115,7 +115,7 @@ new File( session.getLocalRepository().getBasedir(), session.getLocalRepositoryManager().getPathForRemoteMetadata( metadata, repository, "" ) ); - TestFileUtils.write( file.getAbsolutePath(), file ); + TestFileUtils.writeString( file, file.getAbsolutePath() ); MetadataRequest request = new MetadataRequest( metadata, repository, "" ); List results = resolver.resolveMetadata( session, Arrays.asList( request ) ); @@ -162,7 +162,7 @@ File file = new File( session.getLocalRepository().getBasedir(), session.getLocalRepositoryManager().getPathForRemoteMetadata( metadata, repository, "" ) ); - TestFileUtils.write( file.getAbsolutePath(), file ); + TestFileUtils.writeString( file, file.getAbsolutePath() ); metadata.setFile( file ); MetadataRequest request = new MetadataRequest( metadata, repository, "" ); @@ -201,7 +201,7 @@ String path = session.getLocalRepositoryManager().getPathForRemoteMetadata( metadata, repository, "" ); File file = new File( session.getLocalRepository().getBasedir(), path ); - TestFileUtils.write( file.getAbsolutePath(), file ); + TestFileUtils.writeString( file, file.getAbsolutePath() ); // set file to use in TestLRM find() metadata = metadata.setFile( file ); @@ -229,7 +229,7 @@ lrm.add( session, new LocalMetadataRegistration( metadata ) ); String path = session.getLocalRepositoryManager().getPathForLocalMetadata( metadata ); File file = new File( session.getLocalRepository().getBasedir(), path ); - TestFileUtils.write( file.getAbsolutePath(), file ); + TestFileUtils.writeString( file, file.getAbsolutePath() ); MetadataRequest request = new MetadataRequest( metadata, repository, "" ); request.setFavorLocalRepository( true ); diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultOfflineControllerTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultOfflineControllerTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultOfflineControllerTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultOfflineControllerTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012 Sonatype, Inc. + * Copyright (c) 2012, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -26,8 +26,8 @@ { DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(); session.setOffline( offline ); - session.setConfigProperty( "aether.offline.protocols", protocols ); - session.setConfigProperty( "aether.offline.hosts", hosts ); + session.setConfigProperty( DefaultOfflineController.CONFIG_PROP_OFFLINE_PROTOCOLS, protocols ); + session.setConfigProperty( DefaultOfflineController.CONFIG_PROP_OFFLINE_HOSTS, hosts ); return session; } @@ -42,7 +42,7 @@ controller = new DefaultOfflineController(); } - @Test + @Test( expected = RepositoryOfflineException.class ) public void testCheckOffline_Online() throws Exception { diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManagerTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManagerTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManagerTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManagerTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -28,6 +28,7 @@ import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.repository.RepositoryPolicy; import org.eclipse.aether.util.repository.AuthenticationBuilder; +import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -50,9 +51,11 @@ session.setUpdatePolicy( null ); manager = new DefaultRemoteRepositoryManager(); manager.setUpdatePolicyAnalyzer( new StubUpdatePolicyAnalyzer() ); + manager.setChecksumPolicyProvider( new DefaultChecksumPolicyProvider() ); manager.setLoggerFactory( new TestLoggerFactory() ); } + @After public void teardown() throws Exception { @@ -117,6 +120,25 @@ } @Test + public void testAggregateSimpleRepos_MustKeepDisabledRecessiveRepo() + { + RemoteRepository dominant = newRepo( "a", "file://", true, "", "" ).build(); + + RemoteRepository recessive1 = newRepo( "b", "http://", false, "", "" ).build(); + + List result = + manager.aggregateRepositories( session, Arrays.asList( dominant ), Arrays.asList( recessive1 ), false ); + + RemoteRepository recessive2 = newRepo( recessive1.getId(), "http://", true, "", "" ).build(); + + result = manager.aggregateRepositories( session, result, Arrays.asList( recessive2 ), false ); + + assertEquals( 2, result.size() ); + assertEqual( dominant, result.get( 0 ) ); + assertEqual( recessive1, result.get( 1 ) ); + } + + @Test public void testAggregateMirrorRepos_DominantMirrorComplete() { RemoteRepository dominant1 = newRepo( "a", "http://", false, "", "" ).build(); @@ -163,9 +185,9 @@ @Test public void testMirrorAuthentication() { - final RemoteRepository repo = newRepo( "a", "http://", false, "", "" ).build(); + final RemoteRepository repo = newRepo( "a", "http://", true, "", "" ).build(); final RemoteRepository mirror = - newRepo( "a", "http://", false, "", "" ).setAuthentication( new AuthenticationBuilder().addUsername( "test" ).build() ).build(); + newRepo( "a", "http://", true, "", "" ).setAuthentication( new AuthenticationBuilder().addUsername( "test" ).build() ).build(); session.setMirrorSelector( new MirrorSelector() { public RemoteRepository getMirror( RemoteRepository repository ) @@ -185,9 +207,9 @@ @Test public void testMirrorProxy() { - final RemoteRepository repo = newRepo( "a", "http://", false, "", "" ).build(); + final RemoteRepository repo = newRepo( "a", "http://", true, "", "" ).build(); final RemoteRepository mirror = - newRepo( "a", "http://", false, "", "" ).setProxy( new Proxy( "http", "host", 2011, null ) ).build(); + newRepo( "a", "http://", true, "", "" ).setProxy( new Proxy( "http", "host", 2011, null ) ).build(); session.setMirrorSelector( new MirrorSelector() { public RemoteRepository getMirror( RemoteRepository repository ) @@ -209,7 +231,7 @@ @Test public void testProxySelector() { - final RemoteRepository repo = newRepo( "a", "http://", false, "", "" ).build(); + final RemoteRepository repo = newRepo( "a", "http://", true, "", "" ).build(); final Proxy proxy = new Proxy( "http", "host", 2011, null ); session.setProxySelector( new ProxySelector() { diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import static org.junit.Assert.*; + +import java.util.Arrays; +import java.util.List; + +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.internal.test.util.TestUtils; +import org.eclipse.aether.repository.Authentication; +import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.util.repository.AuthenticationBuilder; +import org.eclipse.aether.util.repository.DefaultAuthenticationSelector; +import org.eclipse.aether.util.repository.DefaultMirrorSelector; +import org.eclipse.aether.util.repository.DefaultProxySelector; +import org.junit.Before; +import org.junit.Test; + +public class DefaultRepositorySystemTest +{ + + private DefaultRepositorySystem system; + + private DefaultRepositorySystemSession session; + + @Before + public void init() + { + DefaultRemoteRepositoryManager remoteRepoManager = new DefaultRemoteRepositoryManager(); + system = new DefaultRepositorySystem(); + system.setRemoteRepositoryManager( remoteRepoManager ); + session = TestUtils.newSession(); + } + + @Test + public void testNewResolutionRepositories() + { + Proxy proxy = new Proxy( "http", "localhost", 8080 ); + DefaultProxySelector proxySelector = new DefaultProxySelector(); + proxySelector.add( proxy, null ); + session.setProxySelector( proxySelector ); + + Authentication auth = new AuthenticationBuilder().addUsername( "user" ).build(); + DefaultAuthenticationSelector authSelector = new DefaultAuthenticationSelector(); + authSelector.add( "mirror", auth ); + authSelector.add( "test-2", auth ); + session.setAuthenticationSelector( authSelector ); + + DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector(); + mirrorSelector.add( "mirror", "http:void", "default", false, "test-1", null ); + session.setMirrorSelector( mirrorSelector ); + + RemoteRepository rawRepo1 = new RemoteRepository.Builder( "test-1", "default", "http://void" ).build(); + RemoteRepository rawRepo2 = new RemoteRepository.Builder( "test-2", "default", "http://null" ).build(); + List resolveRepos = + system.newResolutionRepositories( session, Arrays.asList( rawRepo1, rawRepo2 ) ); + assertNotNull( resolveRepos ); + assertEquals( 2, resolveRepos.size() ); + RemoteRepository resolveRepo = resolveRepos.get( 0 ); + assertNotNull( resolveRepo ); + assertEquals( "mirror", resolveRepo.getId() ); + assertSame( proxy, resolveRepo.getProxy() ); + assertSame( auth, resolveRepo.getAuthentication() ); + resolveRepo = resolveRepos.get( 1 ); + assertNotNull( resolveRepo ); + assertEquals( "test-2", resolveRepo.getId() ); + assertSame( proxy, resolveRepo.getProxy() ); + assertSame( auth, resolveRepo.getAuthentication() ); + } + + @Test + public void testNewDeploymentRepository() + { + Proxy proxy = new Proxy( "http", "localhost", 8080 ); + DefaultProxySelector proxySelector = new DefaultProxySelector(); + proxySelector.add( proxy, null ); + session.setProxySelector( proxySelector ); + + Authentication auth = new AuthenticationBuilder().addUsername( "user" ).build(); + DefaultAuthenticationSelector authSelector = new DefaultAuthenticationSelector(); + authSelector.add( "test", auth ); + session.setAuthenticationSelector( authSelector ); + + DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector(); + mirrorSelector.add( "mirror", "file:void", "default", false, "*", null ); + session.setMirrorSelector( mirrorSelector ); + + RemoteRepository rawRepo = new RemoteRepository.Builder( "test", "default", "http://void" ).build(); + RemoteRepository deployRepo = system.newDeploymentRepository( session, rawRepo ); + assertNotNull( deployRepo ); + assertSame( proxy, deployRepo.getProxy() ); + assertSame( auth, deployRepo.getAuthentication() ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultUpdateCheckManagerTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultUpdateCheckManagerTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultUpdateCheckManagerTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultUpdateCheckManagerTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -61,15 +61,16 @@ throws Exception { File dir = TestFileUtils.createTempFile( "" ); - TestFileUtils.delete( dir ); + TestFileUtils.deleteFile( dir ); File metadataFile = new File( dir, "metadata.txt" ); - TestFileUtils.write( "metadata", metadataFile ); + TestFileUtils.writeString( metadataFile, "metadata" ); File artifactFile = new File( dir, "artifact.txt" ); - TestFileUtils.write( "artifact", artifactFile ); + TestFileUtils.writeString( artifactFile, "artifact" ); session = TestUtils.newSession(); - repository = new RemoteRepository.Builder( "id", "default", TestFileUtils.createTempDir().toURI().toURL().toString() ).build(); + repository = + new RemoteRepository.Builder( "id", "default", TestFileUtils.createTempDir().toURI().toURL().toString() ).build(); manager = new DefaultUpdateCheckManager().setUpdatePolicyAnalyzer( new DefaultUpdatePolicyAnalyzer() ); metadata = new DefaultMetadata( "gid", "aid", "ver", "maven-metadata.xml", Metadata.Nature.RELEASE_OR_SNAPSHOT, @@ -85,7 +86,7 @@ new File( artifact.getFile().getPath() + ".lastUpdated" ).delete(); metadata.getFile().delete(); artifact.getFile().delete(); - TestFileUtils.delete( new File( new URI( repository.getUrl() ) ) ); + TestFileUtils.deleteFile( new File( new URI( repository.getUrl() ) ) ); } static void resetSessionData( RepositorySystemSession session ) @@ -238,7 +239,8 @@ check = newMetadataCheck().setPolicy( RepositoryPolicy.UPDATE_POLICY_DAILY ); manager.checkMetadata( session, check ); assertEquals( false, check.isRequired() ); - assertNotNull( check.getException() ); + assertTrue( check.getException() instanceof MetadataNotFoundException ); + assertTrue( check.getException().isFromCache() ); } @Test @@ -262,7 +264,7 @@ } @Test - public void testCheckMetadataErrorFromRepo() + public void testCheckMetadataErrorFromRepoCachingEnabled() throws Exception { metadata.getFile().delete(); @@ -281,10 +283,11 @@ assertEquals( false, check.isRequired() ); assertTrue( check.getException() instanceof MetadataTransferException ); assertTrue( String.valueOf( check.getException() ), check.getException().getMessage().contains( "some error" ) ); + assertTrue( check.getException().isFromCache() ); } @Test - public void testCheckMetadataErrorFromRepoNoCaching() + public void testCheckMetadataErrorFromRepoCachingDisabled() throws Exception { metadata.getFile().delete(); @@ -323,6 +326,78 @@ } @Test + public void testCheckMetadataSessionStateModes() + throws Exception + { + UpdateCheck check = newMetadataCheck(); + check.setPolicy( RepositoryPolicy.UPDATE_POLICY_ALWAYS ); + manager.touchMetadata( session, check ); + + session.setConfigProperty( DefaultUpdateCheckManager.CONFIG_PROP_SESSION_STATE, "bypass" ); + manager.checkMetadata( session, check ); + assertEquals( true, check.isRequired() ); + + resetSessionData( session ); + manager.touchMetadata( session, check ); + + session.setConfigProperty( DefaultUpdateCheckManager.CONFIG_PROP_SESSION_STATE, "true" ); + manager.checkMetadata( session, check ); + assertEquals( false, check.isRequired() ); + + session.setConfigProperty( DefaultUpdateCheckManager.CONFIG_PROP_SESSION_STATE, "false" ); + manager.checkMetadata( session, check ); + assertEquals( true, check.isRequired() ); + } + + @Test + public void testCheckMetadataAtMostOnceDuringSessionEvenIfUpdatePolicyAlways_InvalidFile() + throws Exception + { + UpdateCheck check = newMetadataCheck(); + check.setPolicy( RepositoryPolicy.UPDATE_POLICY_ALWAYS ); + check.setFileValid( false ); + + // first check + manager.checkMetadata( session, check ); + assertEquals( true, check.isRequired() ); + + // first touch, without exception + manager.touchMetadata( session, check ); + + // another check in same session + manager.checkMetadata( session, check ); + assertEquals( true, check.isRequired() ); + + // another touch, with exception + check.setException( new MetadataNotFoundException( check.getItem(), check.getRepository() ) ); + manager.touchMetadata( session, check ); + + // another check in same session + manager.checkMetadata( session, check ); + assertEquals( false, check.isRequired() ); + } + + @Test + public void testCheckMetadataAtMostOnceDuringSessionEvenIfUpdatePolicyAlways_DifferentRepoIdSameUrl() + throws Exception + { + UpdateCheck check = newMetadataCheck(); + check.setPolicy( RepositoryPolicy.UPDATE_POLICY_ALWAYS ); + check.setFileValid( false ); + + // first check + manager.checkMetadata( session, check ); + assertEquals( true, check.isRequired() ); + + manager.touchMetadata( session, check ); + + // second check in same session but for repo with different id + check.setRepository( new RemoteRepository.Builder( check.getRepository() ).setId( "check" ).build() ); + manager.checkMetadata( session, check ); + assertEquals( true, check.isRequired() ); + } + + @Test public void testCheckMetadataWhenLocallyMissingEvenIfUpdatePolicyIsNever() throws Exception { @@ -516,6 +591,7 @@ manager.checkArtifact( session, check ); assertEquals( false, check.isRequired() ); assertTrue( check.getException() instanceof ArtifactNotFoundException ); + assertTrue( check.getException().isFromCache() ); } @Test @@ -555,6 +631,7 @@ manager.checkArtifact( session, check ); assertEquals( false, check.isRequired() ); assertTrue( check.getException() instanceof ArtifactTransferException ); + assertTrue( check.getException().isFromCache() ); } @Test @@ -596,6 +673,77 @@ } @Test + public void testCheckArtifactSessionStateModes() + throws Exception + { + UpdateCheck check = newArtifactCheck(); + check.setPolicy( RepositoryPolicy.UPDATE_POLICY_ALWAYS ); + manager.touchArtifact( session, check ); + + session.setConfigProperty( DefaultUpdateCheckManager.CONFIG_PROP_SESSION_STATE, "bypass" ); + manager.checkArtifact( session, check ); + assertEquals( true, check.isRequired() ); + + resetSessionData( session ); + manager.touchArtifact( session, check ); + + session.setConfigProperty( DefaultUpdateCheckManager.CONFIG_PROP_SESSION_STATE, "true" ); + manager.checkArtifact( session, check ); + assertEquals( false, check.isRequired() ); + + session.setConfigProperty( DefaultUpdateCheckManager.CONFIG_PROP_SESSION_STATE, "false" ); + manager.checkArtifact( session, check ); + assertEquals( true, check.isRequired() ); + } + + @Test + public void testCheckArtifactAtMostOnceDuringSessionEvenIfUpdatePolicyAlways_InvalidFile() + throws Exception + { + UpdateCheck check = newArtifactCheck(); + check.setPolicy( RepositoryPolicy.UPDATE_POLICY_ALWAYS ); + check.setFileValid( false ); + + // first check + manager.checkArtifact( session, check ); + assertEquals( true, check.isRequired() ); + + // first touch, without exception + manager.touchArtifact( session, check ); + + // another check in same session + manager.checkArtifact( session, check ); + assertEquals( true, check.isRequired() ); + + // another touch, with exception + check.setException( new ArtifactNotFoundException( check.getItem(), check.getRepository() ) ); + manager.touchArtifact( session, check ); + + // another check in same session + manager.checkArtifact( session, check ); + assertEquals( false, check.isRequired() ); + } + + @Test + public void testCheckArtifactAtMostOnceDuringSessionEvenIfUpdatePolicyAlways_DifferentRepoIdSameUrl() + throws Exception + { + UpdateCheck check = newArtifactCheck(); + check.setPolicy( RepositoryPolicy.UPDATE_POLICY_ALWAYS ); + + // first check + manager.checkArtifact( session, check ); + assertEquals( true, check.isRequired() ); + + manager.touchArtifact( session, check ); + + // second check in same session but for repo with different id + check.setRepository( new RemoteRepository.Builder( check.getRepository() ).setId( "check" ).build() ); + manager.checkArtifact( session, check ); + assertEquals( true, check.isRequired() ); + } + + @Test public void testCheckArtifactWhenLocallyMissingEvenIfUpdatePolicyIsNever() throws Exception { diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -96,8 +96,8 @@ public void tearDown() throws Exception { - TestFileUtils.delete( basedir ); - TestFileUtils.delete( new File( new URI( repository.getUrl() ) ) ); + TestFileUtils.deleteFile( basedir ); + TestFileUtils.deleteFile( new File( new URI( repository.getUrl() ) ) ); session = null; manager = null; @@ -130,7 +130,7 @@ { return -1; } - return TestFileUtils.copy( metadata.getFile(), new File( basedir, path ) ); + return TestFileUtils.copyFile( metadata.getFile(), new File( basedir, path ) ); } private long copy( Artifact artifact, String path ) @@ -141,7 +141,7 @@ return -1; } File artifactFile = new File( basedir, path ); - return TestFileUtils.copy( artifact.getFile(), artifactFile ); + return TestFileUtils.copyFile( artifact.getFile(), artifactFile ); } @Test @@ -320,7 +320,7 @@ { Artifact artifact = new DefaultArtifact( "g.i.d:a.i.d:1.0-SNAPSHOT" ); File file = new File( basedir, manager.getPathForLocalArtifact( artifact ) ); - TestFileUtils.write( "test", file ); + TestFileUtils.writeString( file, "test" ); addLocalArtifact( artifact ); artifact = artifact.setVersion( "1.0-20110329.221805-4" ); diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/FailChecksumPolicyTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/FailChecksumPolicyTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/FailChecksumPolicyTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/FailChecksumPolicyTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import static org.junit.Assert.*; + +import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy; +import org.eclipse.aether.transfer.ChecksumFailureException; +import org.eclipse.aether.transfer.TransferResource; +import org.junit.Before; +import org.junit.Test; + +public class FailChecksumPolicyTest +{ + + private FailChecksumPolicy policy; + + private ChecksumFailureException exception; + + @Before + public void setup() + { + policy = new FailChecksumPolicy( null, new TransferResource( "file:/dev/null", "file.txt", null, null ) ); + exception = new ChecksumFailureException( "test" ); + } + + @Test + public void testOnTransferChecksumFailure() + { + assertFalse( policy.onTransferChecksumFailure( exception ) ); + } + + @Test + public void testOnChecksumMatch() + { + assertTrue( policy.onChecksumMatch( "SHA-1", 0 ) ); + assertTrue( policy.onChecksumMatch( "SHA-1", ChecksumPolicy.KIND_UNOFFICIAL ) ); + } + + @Test + public void testOnChecksumMismatch() + throws Exception + { + try + { + policy.onChecksumMismatch( "SHA-1", 0, exception ); + fail( "No exception" ); + } + catch ( ChecksumFailureException e ) + { + assertSame( exception, e ); + } + policy.onChecksumMismatch( "SHA-1", ChecksumPolicy.KIND_UNOFFICIAL, exception ); + } + + @Test + public void testOnChecksumError() + throws Exception + { + policy.onChecksumError( "SHA-1", 0, exception ); + } + + @Test + public void testOnNoMoreChecksums() + { + try + { + policy.onNoMoreChecksums(); + fail( "No exception" ); + } + catch ( ChecksumFailureException e ) + { + assertTrue( e.getMessage().contains( "no checksums available" ) ); + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactoryTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactoryTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactoryTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactoryTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,232 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import static org.junit.Assert.*; + +import java.net.URI; +import java.util.List; +import java.util.Locale; + +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.internal.test.util.TestUtils; +import org.eclipse.aether.metadata.DefaultMetadata; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.layout.RepositoryLayout; +import org.eclipse.aether.spi.connector.layout.RepositoryLayout.Checksum; +import org.eclipse.aether.transfer.NoRepositoryLayoutException; +import org.junit.Before; +import org.junit.Test; + +public class Maven2RepositoryLayoutFactoryTest +{ + + private DefaultRepositorySystemSession session; + + private Maven2RepositoryLayoutFactory factory; + + private RepositoryLayout layout; + + private RemoteRepository newRepo( String type ) + { + return new RemoteRepository.Builder( "test", type, "classpath:/nil" ).build(); + } + + private void assertChecksum( Checksum actual, String expectedUri, String expectedAlgo ) + { + assertEquals( expectedUri, actual.getLocation().toString() ); + assertEquals( expectedAlgo, actual.getAlgorithm() ); + } + + private void assertChecksums( List actual, String baseUri, String... algos ) + { + assertEquals( algos.length, actual.size() ); + for ( int i = 0; i < algos.length; i++ ) + { + String uri = baseUri + '.' + algos[i].replace( "-", "" ).toLowerCase( Locale.ENGLISH ); + assertChecksum( actual.get( i ), uri, algos[i] ); + } + } + + @Before + public void setUp() + throws Exception + { + session = TestUtils.newSession(); + factory = new Maven2RepositoryLayoutFactory(); + layout = factory.newInstance( session, newRepo( "default" ) ); + } + + @Test( expected = NoRepositoryLayoutException.class ) + public void testBadLayout() + throws Exception + { + factory.newInstance( session, newRepo( "DEFAULT" ) ); + } + + @Test + public void testArtifactLocation_Release() + { + DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "ext", "1.0" ); + URI uri = layout.getLocation( artifact, false ); + assertEquals( "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext", uri.toString() ); + uri = layout.getLocation( artifact, true ); + assertEquals( "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext", uri.toString() ); + } + + @Test + public void testArtifactLocation_Snapshot() + { + DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "ext", "1.0-20110329.221805-4" ); + URI uri = layout.getLocation( artifact, false ); + assertEquals( "g/i/d/a-i.d/1.0-SNAPSHOT/a-i.d-1.0-20110329.221805-4-cls.ext", uri.toString() ); + uri = layout.getLocation( artifact, true ); + assertEquals( "g/i/d/a-i.d/1.0-SNAPSHOT/a-i.d-1.0-20110329.221805-4-cls.ext", uri.toString() ); + } + + @Test + public void testMetadataLocation_RootLevel() + { + DefaultMetadata metadata = new DefaultMetadata( "archetype-catalog.xml", Metadata.Nature.RELEASE_OR_SNAPSHOT ); + URI uri = layout.getLocation( metadata, false ); + assertEquals( "archetype-catalog.xml", uri.toString() ); + uri = layout.getLocation( metadata, true ); + assertEquals( "archetype-catalog.xml", uri.toString() ); + } + + @Test + public void testMetadataLocation_GroupLevel() + { + DefaultMetadata metadata = + new DefaultMetadata( "org.apache.maven.plugins", "maven-metadata.xml", Metadata.Nature.RELEASE_OR_SNAPSHOT ); + URI uri = layout.getLocation( metadata, false ); + assertEquals( "org/apache/maven/plugins/maven-metadata.xml", uri.toString() ); + uri = layout.getLocation( metadata, true ); + assertEquals( "org/apache/maven/plugins/maven-metadata.xml", uri.toString() ); + } + + @Test + public void testMetadataLocation_ArtifactLevel() + { + DefaultMetadata metadata = + new DefaultMetadata( "org.apache.maven.plugins", "maven-jar-plugin", "maven-metadata.xml", + Metadata.Nature.RELEASE_OR_SNAPSHOT ); + URI uri = layout.getLocation( metadata, false ); + assertEquals( "org/apache/maven/plugins/maven-jar-plugin/maven-metadata.xml", uri.toString() ); + uri = layout.getLocation( metadata, true ); + assertEquals( "org/apache/maven/plugins/maven-jar-plugin/maven-metadata.xml", uri.toString() ); + } + + @Test + public void testMetadataLocation_VersionLevel() + { + DefaultMetadata metadata = + new DefaultMetadata( "org.apache.maven.plugins", "maven-jar-plugin", "1.0-SNAPSHOT", "maven-metadata.xml", + Metadata.Nature.RELEASE_OR_SNAPSHOT ); + URI uri = layout.getLocation( metadata, false ); + assertEquals( "org/apache/maven/plugins/maven-jar-plugin/1.0-SNAPSHOT/maven-metadata.xml", uri.toString() ); + uri = layout.getLocation( metadata, true ); + assertEquals( "org/apache/maven/plugins/maven-jar-plugin/1.0-SNAPSHOT/maven-metadata.xml", uri.toString() ); + } + + @Test + public void testArtifactChecksums_Download() + { + DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "ext", "1.0" ); + URI uri = layout.getLocation( artifact, false ); + List checksums = layout.getChecksums( artifact, false, uri ); + assertEquals( 2, checksums.size() ); + assertChecksum( checksums.get( 0 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.sha1", "SHA-1" ); + assertChecksum( checksums.get( 1 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.md5", "MD5" ); + } + + @Test + public void testArtifactChecksums_Upload() + { + DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "ext", "1.0" ); + URI uri = layout.getLocation( artifact, true ); + List checksums = layout.getChecksums( artifact, true, uri ); + assertEquals( 2, checksums.size() ); + assertChecksum( checksums.get( 0 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.sha1", "SHA-1" ); + assertChecksum( checksums.get( 1 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.md5", "MD5" ); + } + + @Test + public void testMetadataChecksums_Download() + { + DefaultMetadata metadata = + new DefaultMetadata( "org.apache.maven.plugins", "maven-jar-plugin", "maven-metadata.xml", + Metadata.Nature.RELEASE_OR_SNAPSHOT ); + URI uri = layout.getLocation( metadata, false ); + List checksums = layout.getChecksums( metadata, false, uri ); + assertEquals( 2, checksums.size() ); + assertChecksum( checksums.get( 0 ), "org/apache/maven/plugins/maven-jar-plugin/maven-metadata.xml.sha1", + "SHA-1" ); + assertChecksum( checksums.get( 1 ), "org/apache/maven/plugins/maven-jar-plugin/maven-metadata.xml.md5", "MD5" ); + } + + @Test + public void testMetadataChecksums_Upload() + { + DefaultMetadata metadata = + new DefaultMetadata( "org.apache.maven.plugins", "maven-jar-plugin", "maven-metadata.xml", + Metadata.Nature.RELEASE_OR_SNAPSHOT ); + URI uri = layout.getLocation( metadata, true ); + List checksums = layout.getChecksums( metadata, true, uri ); + assertEquals( 2, checksums.size() ); + assertChecksum( checksums.get( 0 ), "org/apache/maven/plugins/maven-jar-plugin/maven-metadata.xml.sha1", + "SHA-1" ); + assertChecksum( checksums.get( 1 ), "org/apache/maven/plugins/maven-jar-plugin/maven-metadata.xml.md5", "MD5" ); + } + + @Test + public void testSignatureChecksums_Download() + { + DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "asc", "1.0" ); + URI uri = layout.getLocation( artifact, false ); + List checksums = layout.getChecksums( artifact, false, uri ); + assertChecksums( checksums, "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.asc", "SHA-1", "MD5" ); + + artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "jar.asc", "1.0" ); + uri = layout.getLocation( artifact, false ); + checksums = layout.getChecksums( artifact, false, uri ); + assertEquals( 0, checksums.size() ); + } + + @Test + public void testSignatureChecksums_Upload() + { + DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "asc", "1.0" ); + URI uri = layout.getLocation( artifact, true ); + List checksums = layout.getChecksums( artifact, true, uri ); + assertChecksums( checksums, "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.asc", "SHA-1", "MD5" ); + + artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "jar.asc", "1.0" ); + uri = layout.getLocation( artifact, true ); + checksums = layout.getChecksums( artifact, true, uri ); + assertEquals( 0, checksums.size() ); + } + + @Test + public void testSignatureChecksums_Force() + throws Exception + { + session.setConfigProperty( Maven2RepositoryLayoutFactory.CONFIG_PROP_SIGNATURE_CHECKSUMS, "true" ); + layout = factory.newInstance( session, newRepo( "default" ) ); + DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "jar.asc", "1.0" ); + URI uri = layout.getLocation( artifact, true ); + List checksums = layout.getChecksums( artifact, true, uri ); + assertChecksums( checksums, "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.jar.asc", "SHA-1", "MD5" ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/PrioritizedComponentsTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/PrioritizedComponentsTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/PrioritizedComponentsTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/PrioritizedComponentsTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ThreadFactory; + +import org.eclipse.aether.ConfigurationProperties; +import org.junit.Test; + +public class PrioritizedComponentsTest +{ + + @Test + public void testGetConfigKeys() + { + String[] keys = + { ConfigurationProperties.PREFIX_PRIORITY + "java.lang.String", + ConfigurationProperties.PREFIX_PRIORITY + "String" }; + assertArrayEquals( keys, PrioritizedComponents.getConfigKeys( String.class ) ); + + keys = + new String[] { ConfigurationProperties.PREFIX_PRIORITY + "java.util.concurrent.ThreadFactory", + ConfigurationProperties.PREFIX_PRIORITY + "ThreadFactory", + ConfigurationProperties.PREFIX_PRIORITY + "Thread" }; + assertArrayEquals( keys, PrioritizedComponents.getConfigKeys( ThreadFactory.class ) ); + } + + @Test + public void testAdd_PriorityOverride() + { + Exception comp1 = new IllegalArgumentException(); + Exception comp2 = new NullPointerException(); + Map config = new HashMap(); + config.put( ConfigurationProperties.PREFIX_PRIORITY + comp1.getClass().getName(), 6 ); + config.put( ConfigurationProperties.PREFIX_PRIORITY + comp2.getClass().getName(), 7 ); + PrioritizedComponents components = new PrioritizedComponents( config ); + components.add( comp1, 1 ); + components.add( comp2, 0 ); + List> sorted = components.getEnabled(); + assertEquals( 2, sorted.size() ); + assertSame( comp2, sorted.get( 0 ).getComponent() ); + assertEquals( 7, sorted.get( 0 ).getPriority(), 0.1f ); + assertSame( comp1, sorted.get( 1 ).getComponent() ); + assertEquals( 6, sorted.get( 1 ).getPriority(), 0.1f ); + } + + @Test + public void testAdd_ImplicitPriority() + { + Exception comp1 = new IllegalArgumentException(); + Exception comp2 = new NullPointerException(); + Map config = new HashMap(); + config.put( ConfigurationProperties.IMPLICIT_PRIORITIES, true ); + PrioritizedComponents components = new PrioritizedComponents( config ); + components.add( comp1, 1 ); + components.add( comp2, 2 ); + List> sorted = components.getEnabled(); + assertEquals( 2, sorted.size() ); + assertSame( comp1, sorted.get( 0 ).getComponent() ); + assertSame( comp2, sorted.get( 1 ).getComponent() ); + } + + @Test + public void testAdd_Disabled() + { + Exception comp1 = new IllegalArgumentException(); + Exception comp2 = new NullPointerException(); + Map config = new HashMap(); + PrioritizedComponents components = new PrioritizedComponents( config ); + + components.add( new UnsupportedOperationException(), Float.NaN ); + List> sorted = components.getEnabled(); + assertEquals( 0, sorted.size() ); + + components.add( comp1, 1 ); + sorted = components.getEnabled(); + assertEquals( 1, sorted.size() ); + assertSame( comp1, sorted.get( 0 ).getComponent() ); + + components.add( new Exception(), Float.NaN ); + sorted = components.getEnabled(); + assertEquals( 1, sorted.size() ); + assertSame( comp1, sorted.get( 0 ).getComponent() ); + + components.add( comp2, 0 ); + sorted = components.getEnabled(); + assertEquals( 2, sorted.size() ); + assertSame( comp1, sorted.get( 0 ).getComponent() ); + assertSame( comp2, sorted.get( 1 ).getComponent() ); + } +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/PrioritizedComponentTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/PrioritizedComponentTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/PrioritizedComponentTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/PrioritizedComponentTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class PrioritizedComponentTest +{ + + @Test + public void testIsDisabled() + { + assertTrue( new PrioritizedComponent( "", String.class, Float.NaN, 0 ).isDisabled() ); + assertFalse( new PrioritizedComponent( "", String.class, 0, 0 ).isDisabled() ); + assertFalse( new PrioritizedComponent( "", String.class, 1, 0 ).isDisabled() ); + assertFalse( new PrioritizedComponent( "", String.class, -1, 0 ).isDisabled() ); + } + + @Test + public void testCompareTo() + { + assertCompare( 0, Float.NaN, Float.NaN ); + assertCompare( 0, 0, 0 ); + + assertCompare( 1, 0, 1 ); + assertCompare( 1, 2, Float.POSITIVE_INFINITY ); + assertCompare( 1, Float.NEGATIVE_INFINITY, -3 ); + + assertCompare( 1, Float.NaN, 0 ); + assertCompare( 1, Float.NaN, -1 ); + assertCompare( 1, Float.NaN, Float.NEGATIVE_INFINITY ); + assertCompare( 1, Float.NaN, Float.POSITIVE_INFINITY ); + + assertCompare( -1, Float.NaN, 0, 1 ); + assertCompare( -1, 10, 0, 1 ); + } + + private void assertCompare( int expected, float priority1, float priority2 ) + { + PrioritizedComponent one = new PrioritizedComponent( "", String.class, priority1, 0 ); + PrioritizedComponent two = new PrioritizedComponent( "", String.class, priority2, 0 ); + assertEquals( expected, one.compareTo( two ) ); + assertEquals( -expected, two.compareTo( one ) ); + } + + private void assertCompare( int expected, float priority, int index1, int index2 ) + { + PrioritizedComponent one = new PrioritizedComponent( "", String.class, priority, index1 ); + PrioritizedComponent two = new PrioritizedComponent( "", String.class, priority, index2 ); + assertEquals( expected, one.compareTo( two ) ); + assertEquals( -expected, two.compareTo( one ) ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/RecordingRepositoryConnector.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/RecordingRepositoryConnector.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/RecordingRepositoryConnector.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/RecordingRepositoryConnector.java 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2011 Sonatype, Inc. + * Copyright (c) 2010, 2014 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,13 +10,13 @@ *******************************************************************************/ package org.eclipse.aether.internal.impl; -import static junit.framework.Assert.*; +import static org.junit.Assert.*; -import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.internal.test.util.TestFileUtils; import org.eclipse.aether.metadata.Metadata; @@ -25,9 +25,12 @@ import org.eclipse.aether.spi.connector.MetadataDownload; import org.eclipse.aether.spi.connector.MetadataUpload; import org.eclipse.aether.spi.connector.RepositoryConnector; -import org.eclipse.aether.spi.connector.Transfer.State; +import org.eclipse.aether.spi.connector.Transfer; import org.eclipse.aether.transfer.ArtifactTransferException; import org.eclipse.aether.transfer.MetadataTransferException; +import org.eclipse.aether.transfer.TransferEvent; +import org.eclipse.aether.transfer.TransferListener; +import org.eclipse.aether.transfer.TransferResource; /** * A repository connector recording all get/put-requests and faking the results. @@ -35,6 +38,11 @@ class RecordingRepositoryConnector implements RepositoryConnector { + + RepositorySystemSession session; + + boolean fail; + private Artifact[] expectGet; private Artifact[] expectPut; @@ -51,15 +59,21 @@ private List actualPutMD = new ArrayList(); - public RecordingRepositoryConnector( Artifact[] expectGet, Artifact[] expectPut, Metadata[] expectGetMD, - Metadata[] expectPutMD ) + public RecordingRepositoryConnector( RepositorySystemSession session, Artifact[] expectGet, Artifact[] expectPut, + Metadata[] expectGetMD, Metadata[] expectPutMD ) { + this.session = session; this.expectGet = expectGet; this.expectPut = expectPut; this.expectGetMD = expectGetMD; this.expectPutMD = expectPutMD; } + public RecordingRepositoryConnector( RepositorySystemSession session ) + { + this.session = session; + } + public RecordingRepositoryConnector() { } @@ -71,68 +85,130 @@ { if ( artifactDownloads != null ) { - for ( ArtifactDownload artifactDownload : artifactDownloads ) + for ( ArtifactDownload download : artifactDownloads ) { - artifactDownload.setState( State.ACTIVE ); - Artifact artifact = artifactDownload.getArtifact(); + fireInitiated( download ); + Artifact artifact = download.getArtifact(); this.actualGet.add( artifact ); - TestFileUtils.write( artifact.toString(), artifactDownload.getFile() ); - artifactDownload.setState( State.DONE ); + if ( fail ) + { + download.setException( new ArtifactTransferException( artifact, null, "forced failure" ) ); + } + else + { + TestFileUtils.writeString( download.getFile(), artifact.toString() ); + } + fireDone( download ); } } if ( metadataDownloads != null ) { - for ( MetadataDownload metadataDownload : metadataDownloads ) + for ( MetadataDownload download : metadataDownloads ) { - metadataDownload.setState( State.ACTIVE ); - Metadata metadata = metadataDownload.getMetadata(); + fireInitiated( download ); + Metadata metadata = download.getMetadata(); this.actualGetMD.add( metadata ); - TestFileUtils.write( metadata.toString(), metadataDownload.getFile() ); - metadataDownload.setState( State.DONE ); + if ( fail ) + { + download.setException( new MetadataTransferException( metadata, null, "forced failure" ) ); + } + else + { + TestFileUtils.writeString( download.getFile(), metadata.toString() ); + } + fireDone( download ); } } } - catch ( IOException e ) + catch ( Exception e ) { - throw new IllegalStateException( "Cannot create temporary file", e ); + throw new IllegalStateException( e ); } - } public void put( Collection artifactUploads, Collection metadataUploads ) { - if ( artifactUploads != null ) + try { - for ( ArtifactUpload artifactUpload : artifactUploads ) + if ( artifactUploads != null ) { - // mimic "real" connector - artifactUpload.setState( State.ACTIVE ); - if ( artifactUpload.getFile() == null ) + for ( ArtifactUpload upload : artifactUploads ) { - artifactUpload.setException( new ArtifactTransferException( artifactUpload.getArtifact(), null, - "no file" ) ); + // mimic "real" connector + fireInitiated( upload ); + if ( upload.getFile() == null ) + { + upload.setException( new ArtifactTransferException( upload.getArtifact(), null, "no file" ) ); + } + else if ( fail ) + { + upload.setException( new ArtifactTransferException( upload.getArtifact(), null, + "forced failure" ) ); + } + this.actualPut.add( upload.getArtifact() ); + fireDone( upload ); } - this.actualPut.add( artifactUpload.getArtifact() ); - artifactUpload.setState( State.DONE ); } - } - if ( metadataUploads != null ) - { - for ( MetadataUpload metadataUpload : metadataUploads ) + if ( metadataUploads != null ) { - // mimic "real" connector - metadataUpload.setState( State.ACTIVE ); - if ( metadataUpload.getFile() == null ) + for ( MetadataUpload upload : metadataUploads ) { - metadataUpload.setException( new MetadataTransferException( metadataUpload.getMetadata(), null, - "no file" ) ); + // mimic "real" connector + fireInitiated( upload ); + if ( upload.getFile() == null ) + { + upload.setException( new MetadataTransferException( upload.getMetadata(), null, "no file" ) ); + } + else if ( fail ) + { + upload.setException( new MetadataTransferException( upload.getMetadata(), null, + "forced failure" ) ); + } + this.actualPutMD.add( upload.getMetadata() ); + fireDone( upload ); } - this.actualPutMD.add( metadataUpload.getMetadata() ); - metadataUpload.setState( State.DONE ); } } + catch ( Exception e ) + { + throw new IllegalStateException( e ); + } + } + private void fireInitiated( Transfer transfer ) + throws Exception + { + TransferListener listener = transfer.getListener(); + if ( listener == null ) + { + return; + } + TransferEvent.Builder event = + new TransferEvent.Builder( session, new TransferResource( null, null, null, transfer.getTrace() ) ); + event.setType( TransferEvent.EventType.INITIATED ); + listener.transferInitiated( event.build() ); + } + + private void fireDone( Transfer transfer ) + throws Exception + { + TransferListener listener = transfer.getListener(); + if ( listener == null ) + { + return; + } + TransferEvent.Builder event = + new TransferEvent.Builder( session, new TransferResource( null, null, null, transfer.getTrace() ) ); + event.setException( transfer.getException() ); + if ( transfer.getException() != null ) + { + listener.transferFailed( event.setType( TransferEvent.EventType.FAILED ).build() ); + } + else + { + listener.transferSucceeded( event.setType( TransferEvent.EventType.SUCCEEDED ).build() ); + } } public void close() diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/RecordingRepositoryListener.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/RecordingRepositoryListener.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/RecordingRepositoryListener.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/RecordingRepositoryListener.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.RepositoryListener; + +/** + * Collects observed repository events for later inspection. + */ +class RecordingRepositoryListener + implements RepositoryListener +{ + + private List events = Collections.synchronizedList( new ArrayList() ); + + public List getEvents() + { + return events; + } + + public void clear() + { + events.clear(); + } + + public void artifactDescriptorInvalid( RepositoryEvent event ) + { + events.add( event ); + } + + public void artifactDescriptorMissing( RepositoryEvent event ) + { + events.add( event ); + } + + public void metadataInvalid( RepositoryEvent event ) + { + events.add( event ); + } + + public void artifactResolving( RepositoryEvent event ) + { + events.add( event ); + } + + public void artifactResolved( RepositoryEvent event ) + { + events.add( event ); + } + + public void artifactDownloading( RepositoryEvent event ) + { + events.add( event ); + } + + public void artifactDownloaded( RepositoryEvent event ) + { + events.add( event ); + } + + public void metadataDownloaded( RepositoryEvent event ) + { + events.add( event ); + } + + public void metadataDownloading( RepositoryEvent event ) + { + events.add( event ); + } + + public void metadataResolving( RepositoryEvent event ) + { + events.add( event ); + } + + public void metadataResolved( RepositoryEvent event ) + { + events.add( event ); + } + + public void artifactInstalling( RepositoryEvent event ) + { + events.add( event ); + } + + public void artifactInstalled( RepositoryEvent event ) + { + events.add( event ); + } + + public void metadataInstalling( RepositoryEvent event ) + { + events.add( event ); + } + + public void metadataInstalled( RepositoryEvent event ) + { + events.add( event ); + } + + public void artifactDeploying( RepositoryEvent event ) + { + events.add( event ); + } + + public void artifactDeployed( RepositoryEvent event ) + { + events.add( event ); + } + + public void metadataDeploying( RepositoryEvent event ) + { + events.add( event ); + } + + public void metadataDeployed( RepositoryEvent event ) + { + events.add( event ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/SafeTransferListenerTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/SafeTransferListenerTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/SafeTransferListenerTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/SafeTransferListenerTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import static org.junit.Assert.*; + +import java.lang.reflect.Method; + +import org.eclipse.aether.transfer.TransferListener; +import org.junit.Test; + +/** + */ +public class SafeTransferListenerTest +{ + + @Test + public void testAllEventTypesHandled() + throws Exception + { + Class type = SafeTransferListener.class; + for ( Method method : TransferListener.class.getMethods() ) + { + assertNotNull( type.getDeclaredMethod( method.getName(), method.getParameterTypes() ) ); + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/SimpleLocalRepositoryManagerTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/SimpleLocalRepositoryManagerTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/SimpleLocalRepositoryManagerTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/SimpleLocalRepositoryManagerTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -52,7 +52,7 @@ public void tearDown() throws Exception { - TestFileUtils.delete( basedir ); + TestFileUtils.deleteFile( basedir ); manager = null; session = null; } @@ -96,7 +96,7 @@ { Artifact artifact = new DefaultArtifact( "g.i.d:a.i.d:1.0-SNAPSHOT" ); File file = new File( basedir, manager.getPathForLocalArtifact( artifact ) ); - TestFileUtils.write( "test", file ); + TestFileUtils.writeString( file, "test" ); artifact = artifact.setVersion( "1.0-20110329.221805-4" ); LocalArtifactRequest request = new LocalArtifactRequest(); diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/StubVersionRangeResolver.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/StubVersionRangeResolver.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/StubVersionRangeResolver.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/StubVersionRangeResolver.java 2015-01-14 12:56:17.000000000 +0000 @@ -10,8 +10,6 @@ *******************************************************************************/ package org.eclipse.aether.internal.impl; -import java.util.Arrays; - import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.impl.VersionRangeResolver; import org.eclipse.aether.resolution.VersionRangeRequest; @@ -20,6 +18,7 @@ import org.eclipse.aether.util.version.GenericVersionScheme; import org.eclipse.aether.version.InvalidVersionSpecificationException; import org.eclipse.aether.version.Version; +import org.eclipse.aether.version.VersionConstraint; import org.eclipse.aether.version.VersionScheme; /** @@ -33,24 +32,29 @@ public VersionRangeResult resolveVersionRange( RepositorySystemSession session, VersionRangeRequest request ) throws VersionRangeResolutionException { - String version = request.getArtifact().getVersion(); - boolean range = false; - - if ( version.matches( "\\[[^,]+,.*" ) ) - { - version = version.substring( 1, version.indexOf( ',', 1 ) ); - range = true; - } - VersionRangeResult result = new VersionRangeResult( request ); try { - Version ver = versionScheme.parseVersion( version ); - result.setVersionConstraint( versionScheme.parseVersionConstraint( request.getArtifact().getVersion() ) ); - result.setVersions( Arrays.asList( (Version) ver ) ); - if ( range && !request.getRepositories().isEmpty() ) + VersionConstraint constraint = versionScheme.parseVersionConstraint( request.getArtifact().getVersion() ); + result.setVersionConstraint( constraint ); + if ( constraint.getRange() == null ) + { + result.addVersion( constraint.getVersion() ); + } + else { - result.setRepository( ver, request.getRepositories().get( 0 ) ); + for ( int i = 1; i < 10; i++ ) + { + Version ver = versionScheme.parseVersion( Integer.toString( i ) ); + if ( constraint.containsVersion( ver ) ) + { + result.addVersion( ver ); + if ( !request.getRepositories().isEmpty() ) + { + result.setRepository( ver, request.getRepositories().get( 0 ) ); + } + } + } } } catch ( InvalidVersionSpecificationException e ) diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/TrackingFileManagerTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/TrackingFileManagerTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/TrackingFileManagerTest.java 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/TrackingFileManagerTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -143,14 +143,14 @@ }; } - for ( int i = 0; i < threads.length; i++ ) + for ( Thread thread1 : threads ) { - threads[i].start(); + thread1.start(); } - for ( int i = 0; i < threads.length; i++ ) + for ( Thread thread : threads ) { - threads[i].join(); + thread.join(); } assertEquals( Collections.emptyList(), errors ); diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/WarnChecksumPolicyTest.java eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/WarnChecksumPolicyTest.java --- eclipse-aether-0.9.0.M2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/WarnChecksumPolicyTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/java/org/eclipse/aether/internal/impl/WarnChecksumPolicyTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.impl; + +import static org.junit.Assert.*; + +import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy; +import org.eclipse.aether.transfer.ChecksumFailureException; +import org.eclipse.aether.transfer.TransferResource; +import org.junit.Before; +import org.junit.Test; + +public class WarnChecksumPolicyTest +{ + + private WarnChecksumPolicy policy; + + private ChecksumFailureException exception; + + @Before + public void setup() + { + policy = new WarnChecksumPolicy( null, new TransferResource( "file:/dev/null", "file.txt", null, null ) ); + exception = new ChecksumFailureException( "test" ); + } + + @Test + public void testOnTransferChecksumFailure() + { + assertTrue( policy.onTransferChecksumFailure( exception ) ); + } + + @Test + public void testOnChecksumMatch() + { + assertTrue( policy.onChecksumMatch( "SHA-1", 0 ) ); + assertTrue( policy.onChecksumMatch( "SHA-1", ChecksumPolicy.KIND_UNOFFICIAL ) ); + } + + @Test + public void testOnChecksumMismatch() + throws Exception + { + try + { + policy.onChecksumMismatch( "SHA-1", 0, exception ); + fail( "No exception" ); + } + catch ( ChecksumFailureException e ) + { + assertSame( exception, e ); + } + policy.onChecksumMismatch( "SHA-1", ChecksumPolicy.KIND_UNOFFICIAL, exception ); + } + + @Test + public void testOnChecksumError() + throws Exception + { + policy.onChecksumError( "SHA-1", 0, exception ); + } + + @Test + public void testOnNoMoreChecksums() + { + try + { + policy.onNoMoreChecksums(); + fail( "No exception" ); + } + catch ( ChecksumFailureException e ) + { + assertTrue( e.getMessage().contains( "no checksums available" ) ); + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/resources/artifact-descriptions/expectedPartialSubtreeOnError.txt eclipse-aether-1.0.2/aether-impl/src/test/resources/artifact-descriptions/expectedPartialSubtreeOnError.txt --- eclipse-aether-0.9.0.M2/aether-impl/src/test/resources/artifact-descriptions/expectedPartialSubtreeOnError.txt 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/resources/artifact-descriptions/expectedPartialSubtreeOnError.txt 2015-01-14 12:56:17.000000000 +0000 @@ -1,5 +1,6 @@ subtree:comparison:ext:error +- duplicate:transitive:ext:dependency compile - +- gid:aid:ext:ver compile - | \- gid:aid2:ext:ver compile - \- gid:aid2:ext:ver compile +| +- gid:aid:ext:ver compile +| | \- gid:aid2:ext:ver compile +| \- gid:aid2:ext:ver compile +\- git:aid:ext:ver compile diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/resources/artifact-descriptions/gid_aid_1.ini eclipse-aether-1.0.2/aether-impl/src/test/resources/artifact-descriptions/gid_aid_1.ini --- eclipse-aether-0.9.0.M2/aether-impl/src/test/resources/artifact-descriptions/gid_aid_1.ini 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/resources/artifact-descriptions/gid_aid_1.ini 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,2 @@ +[dependencies] +gid:aid2:ext:[1,9] diff -Nru eclipse-aether-0.9.0.M2/aether-impl/src/test/resources/artifact-descriptions/gid_aid2_9.ini eclipse-aether-1.0.2/aether-impl/src/test/resources/artifact-descriptions/gid_aid2_9.ini --- eclipse-aether-0.9.0.M2/aether-impl/src/test/resources/artifact-descriptions/gid_aid2_9.ini 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-impl/src/test/resources/artifact-descriptions/gid_aid2_9.ini 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1 @@ +[dependencies] diff -Nru eclipse-aether-0.9.0.M2/aether-spi/pom.xml eclipse-aether-1.0.2/aether-spi/pom.xml --- eclipse-aether-0.9.0.M2/aether-spi/pom.xml 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-spi/pom.xml 2015-01-14 12:56:17.000000000 +0000 @@ -1,7 +1,7 @@ + + + 4.0.0 + + + org.eclipse.aether + aether + 1.0.2.v20150114 + + + aether-transport-classpath + + Aether Transport Classpath + + A transport implementation for repositories using classpath:// URLs. + + + + org.eclipse.aether.transport.classpath + + + + + org.eclipse.aether + aether-api + + + org.eclipse.aether + aether-spi + + + org.eclipse.aether + aether-util + + + javax.inject + javax.inject + provided + true + + + org.sonatype.sisu + sisu-guice + no_aop + test + + + junit + junit + test + + + org.hamcrest + hamcrest-library + test + + + org.eclipse.aether + aether-test-util + test + + + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + + + org.eclipse.sisu + sisu-maven-plugin + + + org.apache.felix + maven-bundle-plugin + + + + diff -Nru eclipse-aether-0.9.0.M2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/ClasspathTransporterFactory.java eclipse-aether-1.0.2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/ClasspathTransporterFactory.java --- eclipse-aether-0.9.0.M2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/ClasspathTransporterFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/ClasspathTransporterFactory.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.classpath; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.spi.locator.Service; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.spi.log.NullLoggerFactory; +import org.eclipse.aether.transfer.NoTransporterException; + +/** + * A transporter factory for repositories using the {@code classpath:} protocol. As example, getting an item named + * {@code some/file.txt} from a repository with the URL {@code classpath:/base/dir} results in retrieving the resource + * {@code base/dir/some/file.txt} from the classpath. The classpath to load the resources from is given via a + * {@link ClassLoader} that can be configured via the configuration property {@link #CONFIG_PROP_CLASS_LOADER}. + *

+ * Note: Such repositories are read-only and uploads to them are generally not supported. + */ +@Named( "classpath" ) +public final class ClasspathTransporterFactory + implements TransporterFactory, Service +{ + + /** + * The key in the repository session's {@link RepositorySystemSession#getConfigProperties() configuration + * properties} used to store a {@link ClassLoader} from which resources should be retrieved. If unspecified, the + * {@link Thread#getContextClassLoader() context class loader} of the current thread will be used. + */ + public static final String CONFIG_PROP_CLASS_LOADER = "aether.connector.classpath.loader"; + + private Logger logger = NullLoggerFactory.LOGGER; + + private float priority; + + /** + * Creates an (uninitialized) instance of this transporter factory. Note: In case of manual instantiation + * by clients, the new factory needs to be configured via its various mutators before first use or runtime errors + * will occur. + */ + public ClasspathTransporterFactory() + { + // enables default constructor + } + + @Inject + ClasspathTransporterFactory( LoggerFactory loggerFactory ) + { + setLoggerFactory( loggerFactory ); + } + + public void initService( ServiceLocator locator ) + { + setLoggerFactory( locator.getService( LoggerFactory.class ) ); + } + + /** + * Sets the logger factory to use for this component. + * + * @param loggerFactory The logger factory to use, may be {@code null} to disable logging. + * @return This component for chaining, never {@code null}. + */ + public ClasspathTransporterFactory setLoggerFactory( LoggerFactory loggerFactory ) + { + this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, ClasspathTransporter.class ); + return this; + } + + public float getPriority() + { + return priority; + } + + /** + * Sets the priority of this component. + * + * @param priority The priority. + * @return This component for chaining, never {@code null}. + */ + public ClasspathTransporterFactory setPriority( float priority ) + { + this.priority = priority; + return this; + } + + public Transporter newInstance( RepositorySystemSession session, RemoteRepository repository ) + throws NoTransporterException + { + return new ClasspathTransporter( session, repository, logger ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/ClasspathTransporter.java eclipse-aether-1.0.2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/ClasspathTransporter.java --- eclipse-aether-0.9.0.M2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/ClasspathTransporter.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/ClasspathTransporter.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.classpath; + +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.transport.AbstractTransporter; +import org.eclipse.aether.spi.connector.transport.GetTask; +import org.eclipse.aether.spi.connector.transport.PeekTask; +import org.eclipse.aether.spi.connector.transport.PutTask; +import org.eclipse.aether.spi.connector.transport.TransportTask; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.transfer.NoTransporterException; +import org.eclipse.aether.util.ConfigUtils; + +/** + * A transporter reading from the classpath. + */ +final class ClasspathTransporter + extends AbstractTransporter +{ + + private final String resourceBase; + + private final ClassLoader classLoader; + + public ClasspathTransporter( RepositorySystemSession session, RemoteRepository repository, Logger logger ) + throws NoTransporterException + { + if ( !"classpath".equalsIgnoreCase( repository.getProtocol() ) ) + { + throw new NoTransporterException( repository ); + } + + String base; + try + { + URI uri = new URI( repository.getUrl() ); + String ssp = uri.getSchemeSpecificPart(); + if ( ssp.startsWith( "/" ) ) + { + base = uri.getPath(); + if ( base == null ) + { + base = ""; + } + else if ( base.startsWith( "/" ) ) + { + base = base.substring( 1 ); + } + } + else + { + base = ssp; + } + if ( base.length() > 0 && !base.endsWith( "/" ) ) + { + base += '/'; + } + } + catch ( URISyntaxException e ) + { + throw new NoTransporterException( repository, e ); + } + resourceBase = base; + + Object cl = ConfigUtils.getObject( session, null, ClasspathTransporterFactory.CONFIG_PROP_CLASS_LOADER ); + if ( cl instanceof ClassLoader ) + { + classLoader = (ClassLoader) cl; + } + else + { + classLoader = Thread.currentThread().getContextClassLoader(); + } + } + + private URL getResource( TransportTask task ) + throws Exception + { + String resource = resourceBase + task.getLocation().getPath(); + URL url = classLoader.getResource( resource ); + if ( url == null ) + { + throw new ResourceNotFoundException( "Could not locate " + resource ); + } + return url; + } + + public int classify( Throwable error ) + { + if ( error instanceof ResourceNotFoundException ) + { + return ERROR_NOT_FOUND; + } + return ERROR_OTHER; + } + + @Override + protected void implPeek( PeekTask task ) + throws Exception + { + getResource( task ); + } + + @Override + protected void implGet( GetTask task ) + throws Exception + { + URL url = getResource( task ); + URLConnection conn = url.openConnection(); + utilGet( task, conn.getInputStream(), true, conn.getContentLength(), false ); + } + + @Override + protected void implPut( PutTask task ) + throws Exception + { + throw new UnsupportedOperationException( "Uploading to a classpath: repository is not supported" ); + } + + @Override + protected void implClose() + { + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/package-info.java eclipse-aether-1.0.2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/package-info.java --- eclipse-aether-0.9.0.M2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/package-info.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * Support for downloads that utilize the classpath as "remote" storage. + */ +package org.eclipse.aether.transport.classpath; + diff -Nru eclipse-aether-0.9.0.M2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/ResourceNotFoundException.java eclipse-aether-1.0.2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/ResourceNotFoundException.java --- eclipse-aether-0.9.0.M2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/ResourceNotFoundException.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-classpath/src/main/java/org/eclipse/aether/transport/classpath/ResourceNotFoundException.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.classpath; + +import java.io.IOException; + +/** + * Special exception type used instead of {@code FileNotFoundException} to avoid misinterpretation of errors unrelated + * to the remote resource. + */ +class ResourceNotFoundException + extends IOException +{ + + public ResourceNotFoundException( String message ) + { + super( message ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-classpath/src/main/resources/about.html eclipse-aether-1.0.2/aether-transport-classpath/src/main/resources/about.html --- eclipse-aether-0.9.0.M2/aether-transport-classpath/src/main/resources/about.html 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-classpath/src/main/resources/about.html 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,28 @@ + + + + +About + + +

About This Content

+ +

September 23, 2011

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + + diff -Nru eclipse-aether-0.9.0.M2/aether-transport-classpath/src/test/java/org/eclipse/aether/transport/classpath/ClasspathTransporterTest.java eclipse-aether-1.0.2/aether-transport-classpath/src/test/java/org/eclipse/aether/transport/classpath/ClasspathTransporterTest.java --- eclipse-aether-0.9.0.M2/aether-transport-classpath/src/test/java/org/eclipse/aether/transport/classpath/ClasspathTransporterTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-classpath/src/test/java/org/eclipse/aether/transport/classpath/ClasspathTransporterTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,402 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.classpath; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.FileNotFoundException; +import java.net.URI; + +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.internal.test.util.TestFileUtils; +import org.eclipse.aether.internal.test.util.TestLoggerFactory; +import org.eclipse.aether.internal.test.util.TestUtils; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.transport.GetTask; +import org.eclipse.aether.spi.connector.transport.PeekTask; +import org.eclipse.aether.spi.connector.transport.PutTask; +import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.transfer.NoTransporterException; +import org.eclipse.aether.transfer.TransferCancelledException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + */ +public class ClasspathTransporterTest +{ + + private DefaultRepositorySystemSession session; + + private TransporterFactory factory; + + private Transporter transporter; + + private RemoteRepository newRepo( String url ) + { + return new RemoteRepository.Builder( "test", "default", url ).build(); + } + + private void newTransporter( String url ) + throws Exception + { + if ( transporter != null ) + { + transporter.close(); + transporter = null; + } + transporter = factory.newInstance( session, newRepo( url ) ); + } + + @Before + public void setUp() + throws Exception + { + session = TestUtils.newSession(); + factory = new ClasspathTransporterFactory( new TestLoggerFactory() ); + newTransporter( "classpath:/repository" ); + } + + @After + public void tearDown() + { + if ( transporter != null ) + { + transporter.close(); + transporter = null; + } + factory = null; + session = null; + } + + @Test + public void testClassify() + throws Exception + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( new FileNotFoundException() ) ); + assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( new ResourceNotFoundException( "test" ) ) ); + } + + @Test + public void testPeek() + throws Exception + { + transporter.peek( new PeekTask( URI.create( "file.txt" ) ) ); + } + + @Test + public void testPeek_NotFound() + throws Exception + { + try + { + transporter.peek( new PeekTask( URI.create( "missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( ResourceNotFoundException e ) + { + assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( e ) ); + } + } + + @Test + public void testPeek_Closed() + throws Exception + { + transporter.close(); + try + { + transporter.peek( new PeekTask( URI.create( "missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( IllegalStateException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testGet_ToMemory() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( task.getDataString(), listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_ToFile() + throws Exception + { + File file = TestFileUtils.createTempFile( "failure" ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "file.txt" ) ).setDataFile( file ).setListener( listener ); + transporter.get( task ); + assertEquals( "test", TestFileUtils.readString( file ) ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "test", listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_EmptyResource() + throws Exception + { + File file = TestFileUtils.createTempFile( "failure" ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "empty.txt" ) ).setDataFile( file ).setListener( listener ); + transporter.get( task ); + assertEquals( "", TestFileUtils.readString( file ) ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 0, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + assertEquals( "", listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_EncodedResourcePath() + throws Exception + { + GetTask task = new GetTask( URI.create( "some%20space.txt" ) ); + transporter.get( task ); + assertEquals( "space", task.getDataString() ); + } + + @Test + public void testGet_Fragment() + throws Exception + { + GetTask task = new GetTask( URI.create( "file.txt#ignored" ) ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + } + + @Test + public void testGet_Query() + throws Exception + { + GetTask task = new GetTask( URI.create( "file.txt?ignored" ) ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + } + + @Test + public void testGet_FileHandleLeak() + throws Exception + { + for ( int i = 0; i < 100; i++ ) + { + File file = TestFileUtils.createTempFile( "failure" ); + transporter.get( new GetTask( URI.create( "file.txt" ) ).setDataFile( file ) ); + assertTrue( i + ", " + file.getAbsolutePath(), file.delete() ); + } + } + + @Test + public void testGet_NotFound() + throws Exception + { + try + { + transporter.get( new GetTask( URI.create( "missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( ResourceNotFoundException e ) + { + assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( e ) ); + } + } + + @Test + public void testGet_Closed() + throws Exception + { + transporter.close(); + try + { + transporter.get( new GetTask( URI.create( "file.txt" ) ) ); + fail( "Expected error" ); + } + catch ( IllegalStateException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testGet_StartCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelStart = true; + GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener ); + try + { + transporter.get( task ); + fail( "Expected error" ); + } + catch ( TransferCancelledException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + } + + @Test + public void testGet_ProgressCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelProgress = true; + GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener ); + try + { + transporter.get( task ); + fail( "Expected error" ); + } + catch ( TransferCancelledException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 1, listener.progressedCount ); + } + + @Test + public void testPut() + throws Exception + { + try + { + transporter.put( new PutTask( URI.create( "missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( UnsupportedOperationException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testPut_Closed() + throws Exception + { + transporter.close(); + try + { + transporter.put( new PutTask( URI.create( "missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( IllegalStateException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test( expected = NoTransporterException.class ) + public void testInit_BadProtocol() + throws Exception + { + newTransporter( "bad:/void" ); + } + + @Test + public void testInit_CaseInsensitiveProtocol() + throws Exception + { + newTransporter( "classpath:/void" ); + newTransporter( "CLASSPATH:/void" ); + newTransporter( "ClassPath:/void" ); + } + + @Test + public void testInit_OpaqueUrl() + throws Exception + { + testInit( "classpath:repository" ); + } + + @Test + public void testInit_OpaqueUrlTrailingSlash() + throws Exception + { + testInit( "classpath:repository/" ); + } + + @Test + public void testInit_OpaqueUrlSpaces() + throws Exception + { + testInit( "classpath:repo%20space" ); + } + + @Test + public void testInit_HierarchicalUrl() + throws Exception + { + testInit( "classpath:/repository" ); + } + + @Test + public void testInit_HierarchicalUrlTrailingSlash() + throws Exception + { + testInit( "classpath:/repository/" ); + } + + @Test + public void testInit_HierarchicalUrlSpaces() + throws Exception + { + testInit( "classpath:/repo%20space" ); + } + + @Test + public void testInit_HierarchicalUrlRoot() + throws Exception + { + testInit( "classpath:/" ); + } + + @Test + public void testInit_HierarchicalUrlNoPath() + throws Exception + { + testInit( "classpath://reserved" ); + } + + private void testInit( String base ) + throws Exception + { + newTransporter( base ); + GetTask task = new GetTask( URI.create( "file.txt" ) ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-classpath/src/test/java/org/eclipse/aether/transport/classpath/RecordingTransportListener.java eclipse-aether-1.0.2/aether-transport-classpath/src/test/java/org/eclipse/aether/transport/classpath/RecordingTransportListener.java --- eclipse-aether-0.9.0.M2/aether-transport-classpath/src/test/java/org/eclipse/aether/transport/classpath/RecordingTransportListener.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-classpath/src/test/java/org/eclipse/aether/transport/classpath/RecordingTransportListener.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.classpath; + +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; + +import org.eclipse.aether.spi.connector.transport.TransportListener; +import org.eclipse.aether.transfer.TransferCancelledException; + +class RecordingTransportListener + extends TransportListener +{ + + public final ByteArrayOutputStream baos = new ByteArrayOutputStream( 1024 ); + + public long dataOffset; + + public long dataLength; + + public int startedCount; + + public int progressedCount; + + public boolean cancelStart; + + public boolean cancelProgress; + + @Override + public void transportStarted( long dataOffset, long dataLength ) + throws TransferCancelledException + { + startedCount++; + progressedCount = 0; + this.dataLength = dataLength; + this.dataOffset = dataOffset; + baos.reset(); + if ( cancelStart ) + { + throw new TransferCancelledException(); + } + } + + @Override + public void transportProgressed( ByteBuffer data ) + throws TransferCancelledException + { + progressedCount++; + baos.write( data.array(), data.arrayOffset() + data.position(), data.remaining() ); + if ( cancelProgress ) + { + throw new TransferCancelledException(); + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-classpath/src/test/resources/file.txt eclipse-aether-1.0.2/aether-transport-classpath/src/test/resources/file.txt --- eclipse-aether-0.9.0.M2/aether-transport-classpath/src/test/resources/file.txt 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-classpath/src/test/resources/file.txt 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1 @@ +test \ No newline at end of file diff -Nru eclipse-aether-0.9.0.M2/aether-transport-classpath/src/test/resources/repository/file.txt eclipse-aether-1.0.2/aether-transport-classpath/src/test/resources/repository/file.txt --- eclipse-aether-0.9.0.M2/aether-transport-classpath/src/test/resources/repository/file.txt 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-classpath/src/test/resources/repository/file.txt 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1 @@ +test \ No newline at end of file diff -Nru eclipse-aether-0.9.0.M2/aether-transport-classpath/src/test/resources/repository/some space.txt eclipse-aether-1.0.2/aether-transport-classpath/src/test/resources/repository/some space.txt --- eclipse-aether-0.9.0.M2/aether-transport-classpath/src/test/resources/repository/some space.txt 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-classpath/src/test/resources/repository/some space.txt 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1 @@ +space \ No newline at end of file diff -Nru eclipse-aether-0.9.0.M2/aether-transport-classpath/src/test/resources/repo space/file.txt eclipse-aether-1.0.2/aether-transport-classpath/src/test/resources/repo space/file.txt --- eclipse-aether-0.9.0.M2/aether-transport-classpath/src/test/resources/repo space/file.txt 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-classpath/src/test/resources/repo space/file.txt 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1 @@ +test \ No newline at end of file diff -Nru eclipse-aether-0.9.0.M2/aether-transport-file/pom.xml eclipse-aether-1.0.2/aether-transport-file/pom.xml --- eclipse-aether-0.9.0.M2/aether-transport-file/pom.xml 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-file/pom.xml 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,92 @@ + + + + + + 4.0.0 + + + org.eclipse.aether + aether + 1.0.2.v20150114 + + + aether-transport-file + + Aether Transport File + + A transport implementation for repositories using file:// URLs. + + + + org.eclipse.aether.transport.file + + + + + org.eclipse.aether + aether-api + + + org.eclipse.aether + aether-spi + + + org.eclipse.aether + aether-util + + + javax.inject + javax.inject + provided + true + + + org.sonatype.sisu + sisu-guice + no_aop + test + + + junit + junit + test + + + org.hamcrest + hamcrest-library + test + + + org.eclipse.aether + aether-test-util + test + + + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + + + org.eclipse.sisu + sisu-maven-plugin + + + org.apache.felix + maven-bundle-plugin + + + + diff -Nru eclipse-aether-0.9.0.M2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/FileTransporterFactory.java eclipse-aether-1.0.2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/FileTransporterFactory.java --- eclipse-aether-0.9.0.M2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/FileTransporterFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/FileTransporterFactory.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.file; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.spi.locator.Service; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.spi.log.NullLoggerFactory; +import org.eclipse.aether.transfer.NoTransporterException; + +/** + * A transporter factory for repositories using the {@code file:} protocol. + */ +@Named( "file" ) +public final class FileTransporterFactory + implements TransporterFactory, Service +{ + + private Logger logger = NullLoggerFactory.LOGGER; + + private float priority; + + /** + * Creates an (uninitialized) instance of this transporter factory. Note: In case of manual instantiation + * by clients, the new factory needs to be configured via its various mutators before first use or runtime errors + * will occur. + */ + public FileTransporterFactory() + { + // enables default constructor + } + + @Inject + FileTransporterFactory( LoggerFactory loggerFactory ) + { + setLoggerFactory( loggerFactory ); + } + + public void initService( ServiceLocator locator ) + { + setLoggerFactory( locator.getService( LoggerFactory.class ) ); + } + + /** + * Sets the logger factory to use for this component. + * + * @param loggerFactory The logger factory to use, may be {@code null} to disable logging. + * @return This component for chaining, never {@code null}. + */ + public FileTransporterFactory setLoggerFactory( LoggerFactory loggerFactory ) + { + this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, FileTransporter.class ); + return this; + } + + public float getPriority() + { + return priority; + } + + /** + * Sets the priority of this component. + * + * @param priority The priority. + * @return This component for chaining, never {@code null}. + */ + public FileTransporterFactory setPriority( float priority ) + { + this.priority = priority; + return this; + } + + public Transporter newInstance( RepositorySystemSession session, RemoteRepository repository ) + throws NoTransporterException + { + return new FileTransporter( repository, logger ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/FileTransporter.java eclipse-aether-1.0.2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/FileTransporter.java --- eclipse-aether-0.9.0.M2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/FileTransporter.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/FileTransporter.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.file; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; + +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.transport.AbstractTransporter; +import org.eclipse.aether.spi.connector.transport.GetTask; +import org.eclipse.aether.spi.connector.transport.PeekTask; +import org.eclipse.aether.spi.connector.transport.PutTask; +import org.eclipse.aether.spi.connector.transport.TransportTask; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.transfer.NoTransporterException; + +/** + * A transporter using {@link java.io.File}. + */ +final class FileTransporter + extends AbstractTransporter +{ + + private final Logger logger; + + private final File basedir; + + public FileTransporter( RemoteRepository repository, Logger logger ) + throws NoTransporterException + { + if ( !"file".equalsIgnoreCase( repository.getProtocol() ) ) + { + throw new NoTransporterException( repository ); + } + this.logger = logger; + basedir = new File( PathUtils.basedir( repository.getUrl() ) ).getAbsoluteFile(); + } + + File getBasedir() + { + return basedir; + } + + public int classify( Throwable error ) + { + if ( error instanceof ResourceNotFoundException ) + { + return ERROR_NOT_FOUND; + } + return ERROR_OTHER; + } + + @Override + protected void implPeek( PeekTask task ) + throws Exception + { + getFile( task, true ); + } + + @Override + protected void implGet( GetTask task ) + throws Exception + { + File file = getFile( task, true ); + utilGet( task, new FileInputStream( file ), true, file.length(), false ); + } + + @Override + protected void implPut( PutTask task ) + throws Exception + { + File file = getFile( task, false ); + file.getParentFile().mkdirs(); + try + { + utilPut( task, new FileOutputStream( file ), true ); + } + catch ( Exception e ) + { + if ( !file.delete() && file.exists() ) + { + logger.debug( "Could not delete partial file " + file ); + } + throw e; + } + } + + private File getFile( TransportTask task, boolean required ) + throws Exception + { + String path = task.getLocation().getPath(); + if ( path.contains( "../" ) ) + { + throw new IllegalArgumentException( "Illegal resource path: " + path ); + } + File file = new File( basedir, path ); + if ( required && !file.exists() ) + { + throw new ResourceNotFoundException( "Could not locate " + file ); + } + return file; + } + + @Override + protected void implClose() + { + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/package-info.java eclipse-aether-1.0.2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/package-info.java --- eclipse-aether-0.9.0.M2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/package-info.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * Support for downloads/uploads using the local filesystem as "remote" storage. + */ +package org.eclipse.aether.transport.file; + diff -Nru eclipse-aether-0.9.0.M2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/PathUtils.java eclipse-aether-1.0.2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/PathUtils.java --- eclipse-aether-0.9.0.M2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/PathUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/PathUtils.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.file; + +/** + * URL handling for file URLs. Based on org.apache.maven.wagon.PathUtils. + */ +final class PathUtils +{ + + private PathUtils() + { + } + + /** + * Return the protocol name.
+ * E.g: for input http://www.codehause.org this method will return http + * + * @param url the url + * @return the host name + */ + public static String protocol( final String url ) + { + final int pos = url.indexOf( ":" ); + + if ( pos == -1 ) + { + return ""; + } + return url.substring( 0, pos ).trim(); + } + + /** + * Derive the path portion of the given URL. + * + * @param url the file-repository URL + * @return the basedir of the repository + */ + public static String basedir( String url ) + { + String protocol = PathUtils.protocol( url ); + + String retValue = null; + + if ( protocol.length() > 0 ) + { + retValue = url.substring( protocol.length() + 1 ); + } + else + { + retValue = url; + } + retValue = decode( retValue ); + // special case: if omitted // on protocol, keep path as is + if ( retValue.startsWith( "//" ) ) + { + retValue = retValue.substring( 2 ); + + if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) ) + { + // special case: if there is a windows drive letter, then keep the original return value + retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 ); + } + else + { + // Now we expect the host + int index = retValue.indexOf( "/" ); + if ( index >= 0 ) + { + retValue = retValue.substring( index + 1 ); + } + + // special case: if there is a windows drive letter, then keep the original return value + if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) ) + { + retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 ); + } + else if ( index >= 0 ) + { + // leading / was previously stripped + retValue = "/" + retValue; + } + } + } + + // special case: if there is a windows drive letter using |, switch to : + if ( retValue.length() >= 2 && retValue.charAt( 1 ) == '|' ) + { + retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 ); + } + + return retValue.trim(); + } + + /** + * Decodes the specified (portion of a) URL. Note: This decoder assumes that ISO-8859-1 is used to + * convert URL-encoded octets to characters. + * + * @param url The URL to decode, may be null. + * @return The decoded URL or null if the input was null. + */ + static String decode( String url ) + { + String decoded = url; + if ( url != null ) + { + int pos = -1; + while ( ( pos = decoded.indexOf( '%', pos + 1 ) ) >= 0 ) + { + if ( pos + 2 < decoded.length() ) + { + String hexStr = decoded.substring( pos + 1, pos + 3 ); + char ch = (char) Integer.parseInt( hexStr, 16 ); + decoded = decoded.substring( 0, pos ) + ch + decoded.substring( pos + 3 ); + } + } + } + return decoded; + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/ResourceNotFoundException.java eclipse-aether-1.0.2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/ResourceNotFoundException.java --- eclipse-aether-0.9.0.M2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/ResourceNotFoundException.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-file/src/main/java/org/eclipse/aether/transport/file/ResourceNotFoundException.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.file; + +import java.io.IOException; + +/** + * Special exception type used instead of {@code FileNotFoundException} to avoid misinterpretation of errors unrelated + * to the remote resource. + */ +class ResourceNotFoundException + extends IOException +{ + + public ResourceNotFoundException( String message ) + { + super( message ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-file/src/main/resources/about.html eclipse-aether-1.0.2/aether-transport-file/src/main/resources/about.html --- eclipse-aether-0.9.0.M2/aether-transport-file/src/main/resources/about.html 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-file/src/main/resources/about.html 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,28 @@ + + + + +About + + +

About This Content

+ +

September 23, 2011

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + + diff -Nru eclipse-aether-0.9.0.M2/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/FileTransporterTest.java eclipse-aether-1.0.2/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/FileTransporterTest.java --- eclipse-aether-0.9.0.M2/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/FileTransporterTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/FileTransporterTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,545 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.file; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.FileNotFoundException; +import java.net.URI; + +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.internal.test.util.TestFileUtils; +import org.eclipse.aether.internal.test.util.TestLoggerFactory; +import org.eclipse.aether.internal.test.util.TestUtils; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.transport.GetTask; +import org.eclipse.aether.spi.connector.transport.PeekTask; +import org.eclipse.aether.spi.connector.transport.PutTask; +import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.transfer.NoTransporterException; +import org.eclipse.aether.transfer.TransferCancelledException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + */ +public class FileTransporterTest +{ + + private DefaultRepositorySystemSession session; + + private TransporterFactory factory; + + private Transporter transporter; + + private File repoDir; + + private RemoteRepository newRepo( String url ) + { + return new RemoteRepository.Builder( "test", "default", url ).build(); + } + + private void newTransporter( String url ) + throws Exception + { + if ( transporter != null ) + { + transporter.close(); + transporter = null; + } + transporter = factory.newInstance( session, newRepo( url ) ); + } + + @Before + public void setUp() + throws Exception + { + session = TestUtils.newSession(); + factory = new FileTransporterFactory( new TestLoggerFactory() ); + repoDir = TestFileUtils.createTempDir(); + TestFileUtils.writeString( new File( repoDir, "file.txt" ), "test" ); + TestFileUtils.writeString( new File( repoDir, "empty.txt" ), "" ); + TestFileUtils.writeString( new File( repoDir, "some space.txt" ), "space" ); + newTransporter( repoDir.toURI().toString() ); + } + + @After + public void tearDown() + { + if ( transporter != null ) + { + transporter.close(); + transporter = null; + } + factory = null; + session = null; + } + + @Test + public void testClassify() + throws Exception + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( new FileNotFoundException() ) ); + assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( new ResourceNotFoundException( "test" ) ) ); + } + + @Test + public void testPeek() + throws Exception + { + transporter.peek( new PeekTask( URI.create( "file.txt" ) ) ); + } + + @Test + public void testPeek_NotFound() + throws Exception + { + try + { + transporter.peek( new PeekTask( URI.create( "missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( ResourceNotFoundException e ) + { + assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( e ) ); + } + } + + @Test + public void testPeek_Closed() + throws Exception + { + transporter.close(); + try + { + transporter.peek( new PeekTask( URI.create( "missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( IllegalStateException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testGet_ToMemory() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( task.getDataString(), listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_ToFile() + throws Exception + { + File file = TestFileUtils.createTempFile( "failure" ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "file.txt" ) ).setDataFile( file ).setListener( listener ); + transporter.get( task ); + assertEquals( "test", TestFileUtils.readString( file ) ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "test", listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_EmptyResource() + throws Exception + { + File file = TestFileUtils.createTempFile( "failure" ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "empty.txt" ) ).setDataFile( file ).setListener( listener ); + transporter.get( task ); + assertEquals( "", TestFileUtils.readString( file ) ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 0, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + assertEquals( "", listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_EncodedResourcePath() + throws Exception + { + GetTask task = new GetTask( URI.create( "some%20space.txt" ) ); + transporter.get( task ); + assertEquals( "space", task.getDataString() ); + } + + @Test + public void testGet_Fragment() + throws Exception + { + GetTask task = new GetTask( URI.create( "file.txt#ignored" ) ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + } + + @Test + public void testGet_Query() + throws Exception + { + GetTask task = new GetTask( URI.create( "file.txt?ignored" ) ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + } + + @Test + public void testGet_FileHandleLeak() + throws Exception + { + for ( int i = 0; i < 100; i++ ) + { + File file = TestFileUtils.createTempFile( "failure" ); + transporter.get( new GetTask( URI.create( "file.txt" ) ).setDataFile( file ) ); + assertTrue( i + ", " + file.getAbsolutePath(), file.delete() ); + } + } + + @Test + public void testGet_NotFound() + throws Exception + { + try + { + transporter.get( new GetTask( URI.create( "missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( ResourceNotFoundException e ) + { + assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( e ) ); + } + } + + @Test + public void testGet_Closed() + throws Exception + { + transporter.close(); + try + { + transporter.get( new GetTask( URI.create( "file.txt" ) ) ); + fail( "Expected error" ); + } + catch ( IllegalStateException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testGet_StartCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelStart = true; + GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener ); + try + { + transporter.get( task ); + fail( "Expected error" ); + } + catch ( TransferCancelledException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + } + + @Test + public void testGet_ProgressCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelProgress = true; + GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener ); + try + { + transporter.get( task ); + fail( "Expected error" ); + } + catch ( TransferCancelledException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 1, listener.progressedCount ); + } + + @Test + public void testPut_FromMemory() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); + } + + @Test + public void testPut_FromFile() + throws Exception + { + File file = TestFileUtils.createTempFile( "upload" ); + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataFile( file ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); + } + + @Test + public void testPut_EmptyResource() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 0, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + assertEquals( "", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); + } + + @Test + public void testPut_NonExistentParentDir() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = + new PutTask( URI.create( "dir/sub/dir/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "dir/sub/dir/file.txt" ) ) ); + } + + @Test + public void testPut_EncodedResourcePath() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "some%20space.txt" ) ).setListener( listener ).setDataString( "OK" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 2, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "OK", TestFileUtils.readString( new File( repoDir, "some space.txt" ) ) ); + } + + @Test + public void testPut_FileHandleLeak() + throws Exception + { + for ( int i = 0; i < 100; i++ ) + { + File src = TestFileUtils.createTempFile( "upload" ); + File dst = new File( repoDir, "file.txt" ); + transporter.put( new PutTask( URI.create( "file.txt" ) ).setDataFile( src ) ); + assertTrue( i + ", " + src.getAbsolutePath(), src.delete() ); + assertTrue( i + ", " + dst.getAbsolutePath(), dst.delete() ); + } + } + + @Test + public void testPut_Closed() + throws Exception + { + transporter.close(); + try + { + transporter.put( new PutTask( URI.create( "missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( IllegalStateException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testPut_StartCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelStart = true; + PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataString( "upload" ); + try + { + transporter.put( task ); + fail( "Expected error" ); + } + catch ( TransferCancelledException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + assertFalse( new File( repoDir, "file.txt" ).exists() ); + } + + @Test + public void testPut_ProgressCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelProgress = true; + PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataString( "upload" ); + try + { + transporter.put( task ); + fail( "Expected error" ); + } + catch ( TransferCancelledException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 1, listener.progressedCount ); + assertFalse( new File( repoDir, "file.txt" ).exists() ); + } + + @Test( expected = NoTransporterException.class ) + public void testInit_BadProtocol() + throws Exception + { + newTransporter( "bad:/void" ); + } + + @Test + public void testInit_CaseInsensitiveProtocol() + throws Exception + { + newTransporter( "file:/void" ); + newTransporter( "FILE:/void" ); + newTransporter( "File:/void" ); + } + + @Test + public void testInit_OpaqueUrl() + throws Exception + { + testInit( "file:repository", "repository" ); + } + + @Test + public void testInit_OpaqueUrlTrailingSlash() + throws Exception + { + testInit( "file:repository/", "repository" ); + } + + @Test + public void testInit_OpaqueUrlSpaces() + throws Exception + { + testInit( "file:repo%20space", "repo space" ); + } + + @Test + public void testInit_OpaqueUrlSpacesDecoded() + throws Exception + { + testInit( "file:repo space", "repo space" ); + } + + @Test + public void testInit_HierarchicalUrl() + throws Exception + { + testInit( "file:/repository", "/repository" ); + } + + @Test + public void testInit_HierarchicalUrlTrailingSlash() + throws Exception + { + testInit( "file:/repository/", "/repository" ); + } + + @Test + public void testInit_HierarchicalUrlSpaces() + throws Exception + { + testInit( "file:/repo%20space", "/repo space" ); + } + + @Test + public void testInit_HierarchicalUrlSpacesDecoded() + throws Exception + { + testInit( "file:/repo space", "/repo space" ); + } + + @Test + public void testInit_HierarchicalUrlRoot() + throws Exception + { + testInit( "file:/", "/" ); + } + + @Test + public void testInit_HierarchicalUrlHostNoPath() + throws Exception + { + testInit( "file://host/", "/" ); + } + + @Test + public void testInit_HierarchicalUrlHostPath() + throws Exception + { + testInit( "file://host/dir", "/dir" ); + } + + private void testInit( String base, String expected ) + throws Exception + { + newTransporter( base ); + File exp = new File( expected ).getAbsoluteFile(); + assertEquals( exp, ( (FileTransporter) transporter ).getBasedir() ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/RecordingTransportListener.java eclipse-aether-1.0.2/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/RecordingTransportListener.java --- eclipse-aether-0.9.0.M2/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/RecordingTransportListener.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/RecordingTransportListener.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.file; + +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; + +import org.eclipse.aether.spi.connector.transport.TransportListener; +import org.eclipse.aether.transfer.TransferCancelledException; + +class RecordingTransportListener + extends TransportListener +{ + + public final ByteArrayOutputStream baos = new ByteArrayOutputStream( 1024 ); + + public long dataOffset; + + public long dataLength; + + public int startedCount; + + public int progressedCount; + + public boolean cancelStart; + + public boolean cancelProgress; + + @Override + public void transportStarted( long dataOffset, long dataLength ) + throws TransferCancelledException + { + startedCount++; + progressedCount = 0; + this.dataLength = dataLength; + this.dataOffset = dataOffset; + baos.reset(); + if ( cancelStart ) + { + throw new TransferCancelledException(); + } + } + + @Override + public void transportProgressed( ByteBuffer data ) + throws TransferCancelledException + { + progressedCount++; + baos.write( data.array(), data.arrayOffset() + data.position(), data.remaining() ); + if ( cancelProgress ) + { + throw new TransferCancelledException(); + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/pom.xml eclipse-aether-1.0.2/aether-transport-http/pom.xml --- eclipse-aether-0.9.0.M2/aether-transport-http/pom.xml 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/pom.xml 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,126 @@ + + + + + + 4.0.0 + + + org.eclipse.aether + aether + 1.0.2.v20150114 + + + aether-transport-http + + Aether Transport HTTP + + A transport implementation for repositories using http:// and https:// URLs. + + + + org.eclipse.aether.transport.http + + + + + org.eclipse.aether + aether-api + + + org.eclipse.aether + aether-spi + + + org.eclipse.aether + aether-util + + + org.apache.httpcomponents + httpclient + 4.2.6 + + + + commons-logging + commons-logging + + + + + org.slf4j + jcl-over-slf4j + 1.6.2 + + + javax.inject + javax.inject + provided + true + + + org.sonatype.sisu + sisu-guice + no_aop + test + + + junit + junit + test + + + org.hamcrest + hamcrest-library + test + + + org.eclipse.aether + aether-test-util + test + + + org.eclipse.jetty + jetty-server + 7.6.14.v20131031 + test + + + ch.qos.logback + logback-classic + 1.0.7 + test + + + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + + + org.eclipse.sisu + sisu-maven-plugin + + + org.apache.felix + maven-bundle-plugin + + + org.apache.http.*;version="[4.2.1,4.4)",* + + + + + + diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/AuthSchemePool.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/AuthSchemePool.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/AuthSchemePool.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/AuthSchemePool.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.util.LinkedList; + +import org.apache.http.auth.AuthScheme; +import org.apache.http.client.params.AuthPolicy; +import org.apache.http.impl.auth.BasicScheme; + +/** + * Pool of (equivalent) auth schemes for a single host. + */ +final class AuthSchemePool +{ + + private final LinkedList authSchemes; + + private String schemeName; + + public AuthSchemePool() + { + authSchemes = new LinkedList(); + } + + public synchronized AuthScheme get() + { + AuthScheme authScheme = null; + if ( !authSchemes.isEmpty() ) + { + authScheme = authSchemes.removeLast(); + } + else if ( AuthPolicy.BASIC.equalsIgnoreCase( schemeName ) ) + { + authScheme = new BasicScheme(); + } + return authScheme; + } + + public synchronized void put( AuthScheme authScheme ) + { + if ( authScheme == null ) + { + return; + } + if ( !authScheme.getSchemeName().equals( schemeName ) ) + { + schemeName = authScheme.getSchemeName(); + authSchemes.clear(); + } + authSchemes.add( authScheme ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DeferredCredentialsProvider.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DeferredCredentialsProvider.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DeferredCredentialsProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DeferredCredentialsProvider.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,185 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.NTCredentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.eclipse.aether.repository.AuthenticationContext; + +/** + * Credentials provider that defers calls into the auth context until authentication is actually requested. + */ +final class DeferredCredentialsProvider + implements CredentialsProvider +{ + + private final CredentialsProvider delegate; + + private final Map factories; + + public DeferredCredentialsProvider() + { + delegate = new BasicCredentialsProvider(); + factories = new HashMap(); + } + + public void setCredentials( AuthScope authScope, Factory factory ) + { + factories.put( authScope, factory ); + } + + public void setCredentials( AuthScope authScope, Credentials credentials ) + { + delegate.setCredentials( authScope, credentials ); + } + + public Credentials getCredentials( AuthScope authScope ) + { + synchronized ( factories ) + { + for ( Iterator> it = factories.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry entry = it.next(); + if ( authScope.match( entry.getKey() ) >= 0 ) + { + it.remove(); + delegate.setCredentials( entry.getKey(), entry.getValue().newCredentials() ); + } + } + } + return delegate.getCredentials( authScope ); + } + + public void clear() + { + delegate.clear(); + } + + interface Factory + { + + Credentials newCredentials(); + + } + + static class BasicFactory + implements Factory + { + + private final AuthenticationContext authContext; + + public BasicFactory( AuthenticationContext authContext ) + { + this.authContext = authContext; + } + + public Credentials newCredentials() + { + String username = authContext.get( AuthenticationContext.USERNAME ); + if ( username == null ) + { + return null; + } + String password = authContext.get( AuthenticationContext.PASSWORD ); + return new UsernamePasswordCredentials( username, password ); + } + + } + + static class NtlmFactory + implements Factory + { + + private final AuthenticationContext authContext; + + public NtlmFactory( AuthenticationContext authContext ) + { + this.authContext = authContext; + } + + public Credentials newCredentials() + { + String username = authContext.get( AuthenticationContext.USERNAME ); + if ( username == null ) + { + return null; + } + String password = authContext.get( AuthenticationContext.PASSWORD ); + String domain = authContext.get( AuthenticationContext.NTLM_DOMAIN ); + String workstation = authContext.get( AuthenticationContext.NTLM_WORKSTATION ); + + if ( domain == null ) + { + int backslash = username.indexOf( '\\' ); + if ( backslash < 0 ) + { + domain = guessDomain(); + } + else + { + domain = username.substring( 0, backslash ); + username = username.substring( backslash + 1 ); + } + } + if ( workstation == null ) + { + workstation = guessWorkstation(); + } + + return new NTCredentials( username, password, workstation, domain ); + } + + private static String guessDomain() + { + return safeNtlmString( System.getProperty( "http.auth.ntlm.domain" ), System.getenv( "USERDOMAIN" ) ); + } + + private static String guessWorkstation() + { + String localHost = null; + try + { + localHost = InetAddress.getLocalHost().getHostName(); + } + catch ( UnknownHostException e ) + { + // well, we have other options to try + } + return safeNtlmString( System.getProperty( "http.auth.ntlm.host" ), System.getenv( "COMPUTERNAME" ), + localHost ); + } + + private static String safeNtlmString( String... strings ) + { + for ( String string : strings ) + { + if ( string != null ) + { + return string; + } + } + // avoid NPE from httpclient and trigger proper auth failure instead + return ""; + } + + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DemuxCredentialsProvider.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DemuxCredentialsProvider.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DemuxCredentialsProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DemuxCredentialsProvider.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.client.CredentialsProvider; + +/** + * Credentials provider that helps to isolate server from proxy credentials. Apache HttpClient uses a single provider + * for both server and proxy auth, using the auth scope (host, port, etc.) to select the proper credentials. With regard + * to redirects, we use an auth scope for server credentials that's not specific enough to not be mistaken for proxy + * auth. This provider helps to maintain the proper isolation. + */ +final class DemuxCredentialsProvider + implements CredentialsProvider +{ + + private final CredentialsProvider serverCredentialsProvider; + + private final CredentialsProvider proxyCredentialsProvider; + + private final HttpHost proxy; + + public DemuxCredentialsProvider( CredentialsProvider serverCredentialsProvider, + CredentialsProvider proxyCredentialsProvider, HttpHost proxy ) + { + this.serverCredentialsProvider = serverCredentialsProvider; + this.proxyCredentialsProvider = proxyCredentialsProvider; + this.proxy = proxy; + } + + private CredentialsProvider getDelegate( AuthScope authScope ) + { + if ( proxy.getPort() == authScope.getPort() && proxy.getHostName().equalsIgnoreCase( authScope.getHost() ) ) + { + return proxyCredentialsProvider; + } + return serverCredentialsProvider; + } + + public Credentials getCredentials( AuthScope authScope ) + { + return getDelegate( authScope ).getCredentials( authScope ); + } + + public void setCredentials( AuthScope authScope, Credentials credentials ) + { + getDelegate( authScope ).setCredentials( authScope, credentials ); + } + + public void clear() + { + serverCredentialsProvider.clear(); + proxyCredentialsProvider.clear(); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.io.Closeable; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.apache.http.HttpHost; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.impl.conn.PoolingClientConnectionManager; +import org.eclipse.aether.RepositoryCache; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.util.ConfigUtils; + +/** + * Container for HTTP-related state that can be shared across incarnations of the transporter to optimize the + * communication with servers. + */ +final class GlobalState + implements Closeable +{ + + static class CompoundKey + { + + private final Object[] keys; + + public CompoundKey( Object... keys ) + { + this.keys = keys; + } + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + { + return true; + } + if ( obj == null || !getClass().equals( obj.getClass() ) ) + { + return false; + } + CompoundKey that = (CompoundKey) obj; + return Arrays.equals( keys, that.keys ); + } + + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + Arrays.hashCode( keys ); + return hash; + } + + @Override + public String toString() + { + return Arrays.toString( keys ); + } + } + + private static final String KEY = GlobalState.class.getName(); + + private static final String CONFIG_PROP_CACHE_STATE = "aether.connector.http.cacheState"; + + private final ConcurrentMap connectionManagers; + + private final ConcurrentMap userTokens; + + private final ConcurrentMap authSchemePools; + + private final ConcurrentMap expectContinues; + + public static GlobalState get( RepositorySystemSession session ) + { + GlobalState cache; + RepositoryCache repoCache = session.getCache(); + if ( repoCache == null || !ConfigUtils.getBoolean( session, true, CONFIG_PROP_CACHE_STATE ) ) + { + cache = null; + } + else + { + Object tmp = repoCache.get( session, KEY ); + if ( tmp instanceof GlobalState ) + { + cache = (GlobalState) tmp; + } + else + { + synchronized ( GlobalState.class ) + { + tmp = repoCache.get( session, KEY ); + if ( tmp instanceof GlobalState ) + { + cache = (GlobalState) tmp; + } + else + { + cache = new GlobalState(); + repoCache.put( session, KEY, cache ); + } + } + } + } + return cache; + } + + private GlobalState() + { + connectionManagers = new ConcurrentHashMap(); + userTokens = new ConcurrentHashMap(); + authSchemePools = new ConcurrentHashMap(); + expectContinues = new ConcurrentHashMap(); + } + + public void close() + { + for ( Iterator> it = connectionManagers.entrySet().iterator(); it.hasNext(); ) + { + ClientConnectionManager connMgr = it.next().getValue(); + it.remove(); + connMgr.shutdown(); + } + } + + public ClientConnectionManager getConnectionManager( SslConfig config ) + { + ClientConnectionManager manager = connectionManagers.get( config ); + if ( manager == null ) + { + ClientConnectionManager connMgr = newConnectionManager( config ); + manager = connectionManagers.putIfAbsent( config, connMgr ); + if ( manager != null ) + { + connMgr.shutdown(); + } + else + { + manager = connMgr; + } + } + return manager; + } + + public static ClientConnectionManager newConnectionManager( SslConfig sslConfig ) + { + SchemeRegistry schemeReg = new SchemeRegistry(); + schemeReg.register( new Scheme( "http", 80, new PlainSocketFactory() ) ); + schemeReg.register( new Scheme( "https", 443, new SslSocketFactory( sslConfig ) ) ); + + PoolingClientConnectionManager connMgr = new PoolingClientConnectionManager( schemeReg ); + connMgr.setMaxTotal( 100 ); + connMgr.setDefaultMaxPerRoute( 50 ); + return connMgr; + } + + public Object getUserToken( CompoundKey key ) + { + return userTokens.get( key ); + } + + public void setUserToken( CompoundKey key, Object userToken ) + { + if ( userToken != null ) + { + userTokens.put( key, userToken ); + } + else + { + userTokens.remove( key ); + } + } + + public ConcurrentMap getAuthSchemePools() + { + return authSchemePools; + } + + public Boolean getExpectContinue( CompoundKey key ) + { + return expectContinues.get( key ); + } + + public void setExpectContinue( CompoundKey key, boolean enabled ) + { + expectContinues.put( key, enabled ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpMkCol.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpMkCol.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpMkCol.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpMkCol.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.net.URI; + +import org.apache.http.client.methods.HttpRequestBase; + +/** + * WebDAV MKCOL request to create parent directories. + */ +final class HttpMkCol + extends HttpRequestBase +{ + + public HttpMkCol( URI uri ) + { + setURI( uri ); + } + + @Override + public String getMethod() + { + return "MKCOL"; + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporterFactory.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporterFactory.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporterFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporterFactory.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.spi.locator.Service; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.spi.log.NullLoggerFactory; +import org.eclipse.aether.transfer.NoTransporterException; + +/** + * A transporter factory for repositories using the {@code http:} or {@code https:} protocol. The provided transporters + * support uploads to WebDAV servers and resumable downloads. + */ +@Named( "http" ) +public final class HttpTransporterFactory + implements TransporterFactory, Service +{ + + private Logger logger = NullLoggerFactory.LOGGER; + + private float priority = 5; + + /** + * Creates an (uninitialized) instance of this transporter factory. Note: In case of manual instantiation + * by clients, the new factory needs to be configured via its various mutators before first use or runtime errors + * will occur. + */ + public HttpTransporterFactory() + { + // enables default constructor + } + + @Inject + HttpTransporterFactory( LoggerFactory loggerFactory ) + { + setLoggerFactory( loggerFactory ); + } + + public void initService( ServiceLocator locator ) + { + setLoggerFactory( locator.getService( LoggerFactory.class ) ); + } + + /** + * Sets the logger factory to use for this component. + * + * @param loggerFactory The logger factory to use, may be {@code null} to disable logging. + * @return This component for chaining, never {@code null}. + */ + public HttpTransporterFactory setLoggerFactory( LoggerFactory loggerFactory ) + { + this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, HttpTransporter.class ); + return this; + } + + public float getPriority() + { + return priority; + } + + /** + * Sets the priority of this component. + * + * @param priority The priority. + * @return This component for chaining, never {@code null}. + */ + public HttpTransporterFactory setPriority( float priority ) + { + this.priority = priority; + return this; + } + + public Transporter newInstance( RepositorySystemSession session, RemoteRepository repository ) + throws NoTransporterException + { + return new HttpTransporter( repository, session, logger ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,589 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.params.AuthParams; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.HttpClient; +import org.apache.http.client.HttpResponseException; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpHead; +import org.apache.http.client.methods.HttpOptions; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.utils.URIUtils; +import org.apache.http.conn.params.ConnRouteParams; +import org.apache.http.entity.AbstractHttpEntity; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.impl.client.DecompressingHttpClient; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.cookie.DateUtils; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; +import org.apache.http.params.HttpProtocolParams; +import org.apache.http.util.EntityUtils; +import org.eclipse.aether.ConfigurationProperties; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.AuthenticationContext; +import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.transport.AbstractTransporter; +import org.eclipse.aether.spi.connector.transport.GetTask; +import org.eclipse.aether.spi.connector.transport.PeekTask; +import org.eclipse.aether.spi.connector.transport.PutTask; +import org.eclipse.aether.spi.connector.transport.TransportTask; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.transfer.NoTransporterException; +import org.eclipse.aether.transfer.TransferCancelledException; +import org.eclipse.aether.util.ConfigUtils; + +/** + * A transporter for HTTP/HTTPS. + */ +final class HttpTransporter + extends AbstractTransporter +{ + + private static final Pattern CONTENT_RANGE_PATTERN = + Pattern.compile( "\\s*bytes\\s+([0-9]+)\\s*-\\s*([0-9]+)\\s*/.*" ); + + private final Logger logger; + + private final AuthenticationContext repoAuthContext; + + private final AuthenticationContext proxyAuthContext; + + private final URI baseUri; + + private final HttpHost server; + + private final HttpHost proxy; + + private final HttpClient client; + + private final Map headers; + + private final LocalState state; + + public HttpTransporter( RemoteRepository repository, RepositorySystemSession session, Logger logger ) + throws NoTransporterException + { + if ( !"http".equalsIgnoreCase( repository.getProtocol() ) + && !"https".equalsIgnoreCase( repository.getProtocol() ) ) + { + throw new NoTransporterException( repository ); + } + this.logger = logger; + try + { + baseUri = new URI( repository.getUrl() ).parseServerAuthority(); + if ( baseUri.isOpaque() ) + { + throw new URISyntaxException( repository.getUrl(), "URL must not be opaque" ); + } + server = URIUtils.extractHost( baseUri ); + if ( server == null ) + { + throw new URISyntaxException( repository.getUrl(), "URL lacks host name" ); + } + } + catch ( URISyntaxException e ) + { + throw new NoTransporterException( repository, e.getMessage(), e ); + } + proxy = toHost( repository.getProxy() ); + + repoAuthContext = AuthenticationContext.forRepository( session, repository ); + proxyAuthContext = AuthenticationContext.forProxy( session, repository ); + + state = new LocalState( session, repository, new SslConfig( session, repoAuthContext ) ); + + headers = + ConfigUtils.getMap( session, Collections.emptyMap(), ConfigurationProperties.HTTP_HEADERS + "." + + repository.getId(), ConfigurationProperties.HTTP_HEADERS ); + + DefaultHttpClient client = new DefaultHttpClient( state.getConnectionManager() ); + + configureClient( client.getParams(), session, repository, proxy ); + + client.setCredentialsProvider( toCredentialsProvider( server, repoAuthContext, proxy, proxyAuthContext ) ); + + this.client = new DecompressingHttpClient( client ); + } + + private static HttpHost toHost( Proxy proxy ) + { + HttpHost host = null; + if ( proxy != null ) + { + host = new HttpHost( proxy.getHost(), proxy.getPort() ); + } + return host; + } + + private static void configureClient( HttpParams params, RepositorySystemSession session, + RemoteRepository repository, HttpHost proxy ) + { + AuthParams.setCredentialCharset( params, + ConfigUtils.getString( session, + ConfigurationProperties.DEFAULT_HTTP_CREDENTIAL_ENCODING, + ConfigurationProperties.HTTP_CREDENTIAL_ENCODING + "." + + repository.getId(), + ConfigurationProperties.HTTP_CREDENTIAL_ENCODING ) ); + ConnRouteParams.setDefaultProxy( params, proxy ); + HttpConnectionParams.setConnectionTimeout( params, + ConfigUtils.getInteger( session, + ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT, + ConfigurationProperties.CONNECT_TIMEOUT + + "." + repository.getId(), + ConfigurationProperties.CONNECT_TIMEOUT ) ); + HttpConnectionParams.setSoTimeout( params, + ConfigUtils.getInteger( session, + ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT, + ConfigurationProperties.REQUEST_TIMEOUT + "." + + repository.getId(), + ConfigurationProperties.REQUEST_TIMEOUT ) ); + HttpProtocolParams.setUserAgent( params, ConfigUtils.getString( session, + ConfigurationProperties.DEFAULT_USER_AGENT, + ConfigurationProperties.USER_AGENT ) ); + } + + private static CredentialsProvider toCredentialsProvider( HttpHost server, AuthenticationContext serverAuthCtx, + HttpHost proxy, AuthenticationContext proxyAuthCtx ) + { + CredentialsProvider provider = toCredentialsProvider( server.getHostName(), AuthScope.ANY_PORT, serverAuthCtx ); + if ( proxy != null ) + { + CredentialsProvider p = toCredentialsProvider( proxy.getHostName(), proxy.getPort(), proxyAuthCtx ); + provider = new DemuxCredentialsProvider( provider, p, proxy ); + } + return provider; + } + + private static CredentialsProvider toCredentialsProvider( String host, int port, AuthenticationContext ctx ) + { + DeferredCredentialsProvider provider = new DeferredCredentialsProvider(); + if ( ctx != null ) + { + AuthScope basicScope = new AuthScope( host, port ); + provider.setCredentials( basicScope, new DeferredCredentialsProvider.BasicFactory( ctx ) ); + + AuthScope ntlmScope = new AuthScope( host, port, AuthScope.ANY_REALM, "ntlm" ); + provider.setCredentials( ntlmScope, new DeferredCredentialsProvider.NtlmFactory( ctx ) ); + } + return provider; + } + + LocalState getState() + { + return state; + } + + private URI resolve( TransportTask task ) + { + return UriUtils.resolve( baseUri, task.getLocation() ); + } + + public int classify( Throwable error ) + { + if ( error instanceof HttpResponseException + && ( (HttpResponseException) error ).getStatusCode() == HttpStatus.SC_NOT_FOUND ) + { + return ERROR_NOT_FOUND; + } + return ERROR_OTHER; + } + + @Override + protected void implPeek( PeekTask task ) + throws Exception + { + HttpHead request = commonHeaders( new HttpHead( resolve( task ) ) ); + execute( request, null ); + } + + @Override + protected void implGet( GetTask task ) + throws Exception + { + EntityGetter getter = new EntityGetter( task ); + HttpGet request = commonHeaders( new HttpGet( resolve( task ) ) ); + resume( request, task ); + try + { + execute( request, getter ); + } + catch ( HttpResponseException e ) + { + if ( e.getStatusCode() == HttpStatus.SC_PRECONDITION_FAILED && request.containsHeader( HttpHeaders.RANGE ) ) + { + request = commonHeaders( new HttpGet( request.getURI() ) ); + execute( request, getter ); + return; + } + throw e; + } + } + + @Override + protected void implPut( PutTask task ) + throws Exception + { + PutTaskEntity entity = new PutTaskEntity( task ); + HttpPut request = commonHeaders( entity( new HttpPut( resolve( task ) ), entity ) ); + try + { + execute( request, null ); + } + catch ( HttpResponseException e ) + { + if ( e.getStatusCode() == HttpStatus.SC_EXPECTATION_FAILED && request.containsHeader( HttpHeaders.EXPECT ) ) + { + state.setExpectContinue( false ); + request = commonHeaders( entity( new HttpPut( request.getURI() ), entity ) ); + execute( request, null ); + return; + } + throw e; + } + } + + private void execute( HttpUriRequest request, EntityGetter getter ) + throws Exception + { + try + { + SharingHttpContext context = new SharingHttpContext( state ); + prepare( request, context ); + HttpResponse response = client.execute( server, request, context ); + try + { + context.close(); + handleStatus( response ); + if ( getter != null ) + { + getter.handle( response ); + } + } + finally + { + EntityUtils.consumeQuietly( response.getEntity() ); + } + } + catch ( IOException e ) + { + if ( e.getCause() instanceof TransferCancelledException ) + { + throw (Exception) e.getCause(); + } + throw e; + } + } + + private void prepare( HttpUriRequest request, SharingHttpContext context ) + { + boolean put = HttpPut.METHOD_NAME.equalsIgnoreCase( request.getMethod() ); + if ( state.getWebDav() == null && ( put || isPayloadPresent( request ) ) ) + { + try + { + HttpOptions req = commonHeaders( new HttpOptions( request.getURI() ) ); + HttpResponse response = client.execute( server, req, context ); + state.setWebDav( isWebDav( response ) ); + EntityUtils.consumeQuietly( response.getEntity() ); + } + catch ( IOException e ) + { + logger.debug( "Failed to prepare HTTP context", e ); + } + } + if ( put && Boolean.TRUE.equals( state.getWebDav() ) ) + { + mkdirs( request.getURI(), context ); + } + } + + private boolean isWebDav( HttpResponse response ) + { + return response.containsHeader( HttpHeaders.DAV ); + } + + private void mkdirs( URI uri, SharingHttpContext context ) + { + List dirs = UriUtils.getDirectories( baseUri, uri ); + int index = 0; + for ( ; index < dirs.size(); index++ ) + { + try + { + HttpResponse response = + client.execute( server, commonHeaders( new HttpMkCol( dirs.get( index ) ) ), context ); + try + { + int status = response.getStatusLine().getStatusCode(); + if ( status < 300 || status == HttpStatus.SC_METHOD_NOT_ALLOWED ) + { + break; + } + else if ( status == HttpStatus.SC_CONFLICT ) + { + continue; + } + handleStatus( response ); + } + finally + { + EntityUtils.consumeQuietly( response.getEntity() ); + } + } + catch ( IOException e ) + { + logger.debug( "Failed to create parent directory " + dirs.get( index ), e ); + return; + } + } + for ( index--; index >= 0; index-- ) + { + try + { + HttpResponse response = + client.execute( server, commonHeaders( new HttpMkCol( dirs.get( index ) ) ), context ); + try + { + handleStatus( response ); + } + finally + { + EntityUtils.consumeQuietly( response.getEntity() ); + } + } + catch ( IOException e ) + { + logger.debug( "Failed to create parent directory " + dirs.get( index ), e ); + return; + } + } + } + + private T entity( T request, HttpEntity entity ) + { + request.setEntity( entity ); + return request; + } + + private boolean isPayloadPresent( HttpUriRequest request ) + { + if ( request instanceof HttpEntityEnclosingRequest ) + { + HttpEntity entity = ( (HttpEntityEnclosingRequest) request ).getEntity(); + return entity != null && entity.getContentLength() != 0; + } + return false; + } + + private T commonHeaders( T request ) + { + request.setHeader( HttpHeaders.CACHE_CONTROL, "no-cache, no-store" ); + request.setHeader( HttpHeaders.PRAGMA, "no-cache" ); + + if ( state.isExpectContinue() && isPayloadPresent( request ) ) + { + request.setHeader( HttpHeaders.EXPECT, "100-continue" ); + } + + for ( Map.Entry entry : headers.entrySet() ) + { + if ( !( entry.getKey() instanceof String ) ) + { + continue; + } + if ( entry.getValue() instanceof String ) + { + request.setHeader( entry.getKey().toString(), entry.getValue().toString() ); + } + else + { + request.removeHeaders( entry.getKey().toString() ); + } + } + + if ( !state.isExpectContinue() ) + { + request.removeHeaders( HttpHeaders.EXPECT ); + } + + return request; + } + + private T resume( T request, GetTask task ) + { + long resumeOffset = task.getResumeOffset(); + if ( resumeOffset > 0 && task.getDataFile() != null ) + { + request.setHeader( HttpHeaders.RANGE, "bytes=" + Long.toString( resumeOffset ) + '-' ); + request.setHeader( HttpHeaders.IF_UNMODIFIED_SINCE, + DateUtils.formatDate( new Date( task.getDataFile().lastModified() - 60 * 1000 ) ) ); + request.setHeader( HttpHeaders.ACCEPT_ENCODING, "identity" ); + } + return request; + } + + private void handleStatus( HttpResponse response ) + throws HttpResponseException + { + int status = response.getStatusLine().getStatusCode(); + if ( status >= 300 ) + { + throw new HttpResponseException( status, response.getStatusLine().getReasonPhrase() + " (" + status + ")" ); + } + } + + @Override + protected void implClose() + { + AuthenticationContext.close( repoAuthContext ); + AuthenticationContext.close( proxyAuthContext ); + state.close(); + } + + private class EntityGetter + { + + private final GetTask task; + + public EntityGetter( GetTask task ) + { + this.task = task; + } + + public void handle( HttpResponse response ) + throws IOException, TransferCancelledException + { + HttpEntity entity = response.getEntity(); + if ( entity == null ) + { + entity = new ByteArrayEntity( new byte[0] ); + } + + long offset = 0, length = entity.getContentLength(); + String range = getHeader( response, HttpHeaders.CONTENT_RANGE ); + if ( range != null ) + { + Matcher m = CONTENT_RANGE_PATTERN.matcher( range ); + if ( !m.matches() ) + { + throw new IOException( "Invalid Content-Range header for partial download: " + range ); + } + offset = Long.parseLong( m.group( 1 ) ); + length = Long.parseLong( m.group( 2 ) ) + 1; + if ( offset < 0 || offset >= length || ( offset > 0 && offset != task.getResumeOffset() ) ) + { + throw new IOException( "Invalid Content-Range header for partial download from offset " + + task.getResumeOffset() + ": " + range ); + } + } + + InputStream is = entity.getContent(); + utilGet( task, is, true, length, offset > 0 ); + extractChecksums( response ); + } + + private void extractChecksums( HttpResponse response ) + { + // Nexus-style, ETag: "{SHA1{d40d68ba1f88d8e9b0040f175a6ff41928abd5e7}}" + String etag = getHeader( response, HttpHeaders.ETAG ); + if ( etag != null ) + { + int start = etag.indexOf( "SHA1{" ), end = etag.indexOf( "}", start + 5 ); + if ( start >= 0 && end > start ) + { + task.setChecksum( "SHA-1", etag.substring( start + 5, end ) ); + } + } + } + + private String getHeader( HttpResponse response, String name ) + { + Header header = response.getFirstHeader( name ); + return ( header != null ) ? header.getValue() : null; + } + + } + + private class PutTaskEntity + extends AbstractHttpEntity + { + + private final PutTask task; + + public PutTaskEntity( PutTask task ) + { + this.task = task; + } + + public boolean isRepeatable() + { + return true; + } + + public boolean isStreaming() + { + return false; + } + + public long getContentLength() + { + return task.getDataLength(); + } + + public InputStream getContent() + throws IOException + { + return task.newInputStream(); + } + + public void writeTo( OutputStream os ) + throws IOException + { + try + { + utilPut( task, os, false ); + } + catch ( TransferCancelledException e ) + { + throw (IOException) new InterruptedIOException().initCause( e ); + } + } + + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/LocalState.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/LocalState.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/LocalState.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/LocalState.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,153 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.io.Closeable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScheme; +import org.apache.http.conn.ClientConnectionManager; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.transport.http.GlobalState.CompoundKey; + +/** + * Container for HTTP-related state that can be shared across invocations of the transporter to optimize the + * communication with server. + */ +final class LocalState + implements Closeable +{ + + private final GlobalState global; + + private final ClientConnectionManager connMgr; + + private final CompoundKey userTokenKey; + + private volatile Object userToken; + + private final CompoundKey expectContinueKey; + + private volatile Boolean expectContinue; + + private volatile Boolean webDav; + + private final ConcurrentMap authSchemePools; + + public LocalState( RepositorySystemSession session, RemoteRepository repo, SslConfig sslConfig ) + { + global = GlobalState.get( session ); + userToken = this; + if ( global == null ) + { + connMgr = GlobalState.newConnectionManager( sslConfig ); + userTokenKey = null; + expectContinueKey = null; + authSchemePools = new ConcurrentHashMap(); + } + else + { + connMgr = global.getConnectionManager( sslConfig ); + userTokenKey = new CompoundKey( repo.getId(), repo.getUrl(), repo.getAuthentication(), repo.getProxy() ); + expectContinueKey = new CompoundKey( repo.getUrl(), repo.getProxy() ); + authSchemePools = global.getAuthSchemePools(); + } + } + + public ClientConnectionManager getConnectionManager() + { + return connMgr; + } + + public Object getUserToken() + { + if ( userToken == this ) + { + userToken = ( global != null ) ? global.getUserToken( userTokenKey ) : null; + } + return userToken; + } + + public void setUserToken( Object userToken ) + { + this.userToken = userToken; + if ( global != null ) + { + global.setUserToken( userTokenKey, userToken ); + } + } + + public boolean isExpectContinue() + { + if ( expectContinue == null ) + { + expectContinue = + !Boolean.FALSE.equals( ( global != null ) ? global.getExpectContinue( expectContinueKey ) : null ); + } + return expectContinue; + } + + public void setExpectContinue( boolean enabled ) + { + expectContinue = enabled; + if ( global != null ) + { + global.setExpectContinue( expectContinueKey, enabled ); + } + } + + public Boolean getWebDav() + { + return webDav; + } + + public void setWebDav( boolean webDav ) + { + this.webDav = webDav; + } + + public AuthScheme getAuthScheme( HttpHost host ) + { + AuthSchemePool pool = authSchemePools.get( host ); + if ( pool != null ) + { + return pool.get(); + } + return null; + } + + public void setAuthScheme( HttpHost host, AuthScheme authScheme ) + { + AuthSchemePool pool = authSchemePools.get( host ); + if ( pool == null ) + { + AuthSchemePool p = new AuthSchemePool(); + pool = authSchemePools.putIfAbsent( host, p ); + if ( pool == null ) + { + pool = p; + } + } + pool.put( authScheme ); + } + + public void close() + { + if ( global == null ) + { + connMgr.shutdown(); + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/package-info.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/package-info.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/package-info.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * Support for downloads/uploads via the HTTP and HTTPS protocols. The current implementation is backed by + * Apache HttpClient. + */ +package org.eclipse.aether.transport.http; + diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingAuthCache.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingAuthCache.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingAuthCache.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingAuthCache.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScheme; +import org.apache.http.client.AuthCache; + +/** + * Auth scheme cache that upon clearing releases all cached schemes into a pool for future reuse by other requests, + * thereby reducing challenge-response roundtrips. + */ +final class SharingAuthCache + implements AuthCache +{ + + private final LocalState state; + + private final Map authSchemes; + + public SharingAuthCache( LocalState state ) + { + this.state = state; + authSchemes = new HashMap(); + } + + private static HttpHost toKey( HttpHost host ) + { + if ( host.getPort() <= 0 ) + { + int port = host.getSchemeName().equalsIgnoreCase( "https" ) ? 443 : 80; + return new HttpHost( host.getHostName(), port, host.getSchemeName() ); + } + return host; + } + + public AuthScheme get( HttpHost host ) + { + host = toKey( host ); + AuthScheme authScheme = authSchemes.get( host ); + if ( authScheme == null ) + { + authScheme = state.getAuthScheme( host ); + authSchemes.put( host, authScheme ); + } + return authScheme; + } + + public void put( HttpHost host, AuthScheme authScheme ) + { + if ( authScheme != null ) + { + authSchemes.put( toKey( host ), authScheme ); + } + else + { + remove( host ); + } + } + + public void remove( HttpHost host ) + { + authSchemes.remove( toKey( host ) ); + } + + public void clear() + { + share(); + authSchemes.clear(); + } + + private void share() + { + for ( Map.Entry entry : authSchemes.entrySet() ) + { + state.setAuthScheme( entry.getKey(), entry.getValue() ); + } + } + + @Override + public String toString() + { + return authSchemes.toString(); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingHttpContext.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingHttpContext.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingHttpContext.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingHttpContext.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.io.Closeable; + +import org.apache.http.client.protocol.ClientContext; +import org.apache.http.protocol.BasicHttpContext; + +/** + * HTTP context that shares certain attributes among requests to optimize the communication with the server. + * + * @see Stateful HTTP + * connections + */ +final class SharingHttpContext + extends BasicHttpContext + implements Closeable +{ + + private final LocalState state; + + private final SharingAuthCache authCache; + + public SharingHttpContext( LocalState state ) + { + this.state = state; + authCache = new SharingAuthCache( state ); + super.setAttribute( ClientContext.AUTH_CACHE, authCache ); + } + + @Override + public Object getAttribute( String id ) + { + if ( ClientContext.USER_TOKEN.equals( id ) ) + { + return state.getUserToken(); + } + return super.getAttribute( id ); + } + + @Override + public void setAttribute( String id, Object obj ) + { + if ( ClientContext.USER_TOKEN.equals( id ) ) + { + state.setUserToken( obj ); + } + else + { + super.setAttribute( id, obj ); + } + } + + @Override + public Object removeAttribute( String id ) + { + if ( ClientContext.USER_TOKEN.equals( id ) ) + { + state.setUserToken( null ); + return null; + } + return super.removeAttribute( id ); + } + + public void close() + { + authCache.clear(); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SslConfig.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SslConfig.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SslConfig.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SslConfig.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.util.Arrays; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.AuthenticationContext; +import org.eclipse.aether.util.ConfigUtils; + +/** + * SSL-related configuration and cache key for connection pools (whose scheme registries are derived from this config). + */ +final class SslConfig +{ + + private static final String CIPHER_SUITES = "https.cipherSuites"; + + private static final String PROTOCOLS = "https.protocols"; + + final SSLContext context; + + final HostnameVerifier verifier; + + final String[] cipherSuites; + + final String[] protocols; + + public SslConfig( RepositorySystemSession session, AuthenticationContext authContext ) + { + context = + ( authContext != null ) ? authContext.get( AuthenticationContext.SSL_CONTEXT, SSLContext.class ) : null; + verifier = + ( authContext != null ) ? authContext.get( AuthenticationContext.SSL_HOSTNAME_VERIFIER, + HostnameVerifier.class ) : null; + + cipherSuites = split( get( session, CIPHER_SUITES ) ); + protocols = split( get( session, PROTOCOLS ) ); + } + + private static String get( RepositorySystemSession session, String key ) + { + String value = ConfigUtils.getString( session, null, "aether.connector." + key, key ); + if ( value == null ) + { + value = System.getProperty( key ); + } + return value; + } + + private static String[] split( String value ) + { + if ( value == null || value.length() <= 0 ) + { + return null; + } + return value.split( ",+" ); + } + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + { + return true; + } + if ( obj == null || !getClass().equals( obj.getClass() ) ) + { + return false; + } + SslConfig that = (SslConfig) obj; + return eq( context, that.context ) && eq( verifier, that.verifier ) + && Arrays.equals( cipherSuites, that.cipherSuites ) && Arrays.equals( protocols, that.protocols ); + } + + private static boolean eq( T s1, T s2 ) + { + return s1 != null ? s1.equals( s2 ) : s2 == null; + } + + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + hash( context ); + hash = hash * 31 + hash( verifier ); + hash = hash * 31 + Arrays.hashCode( cipherSuites ); + hash = hash * 31 + Arrays.hashCode( protocols ); + return hash; + } + + private static int hash( Object obj ) + { + return obj != null ? obj.hashCode() : 0; + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SslSocketFactory.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SslSocketFactory.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SslSocketFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SslSocketFactory.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.io.IOException; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +import org.apache.http.conn.ssl.X509HostnameVerifier; + +/** + * Specialized SSL socket factory to more closely resemble the JRE's HttpsClient and respect well-known SSL-related + * configuration properties. + * + * @see JSSE + * Reference Guide, Customization + */ +final class SslSocketFactory + extends org.apache.http.conn.ssl.SSLSocketFactory +{ + + private final String[] cipherSuites; + + private final String[] protocols; + + public SslSocketFactory( SslConfig config ) + { + this( getSocketFactory( config.context ), getHostnameVerifier( config.verifier ), config.cipherSuites, + config.protocols ); + } + + private static SSLSocketFactory getSocketFactory( SSLContext context ) + { + return ( context != null ) ? context.getSocketFactory() : (SSLSocketFactory) SSLSocketFactory.getDefault(); + } + + private static X509HostnameVerifier getHostnameVerifier( HostnameVerifier verifier ) + { + return ( verifier != null ) ? X509HostnameVerifierAdapter.adapt( verifier ) + : org.apache.http.conn.ssl.SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER; + } + + private SslSocketFactory( SSLSocketFactory socketfactory, X509HostnameVerifier hostnameVerifier, + String[] cipherSuites, String[] protocols ) + { + super( socketfactory, hostnameVerifier ); + + this.cipherSuites = cipherSuites; + this.protocols = protocols; + } + + @Override + protected void prepareSocket( SSLSocket socket ) + throws IOException + { + super.prepareSocket( socket ); + if ( cipherSuites != null ) + { + socket.setEnabledCipherSuites( cipherSuites ); + } + if ( protocols != null ) + { + socket.setEnabledProtocols( protocols ); + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/UriUtils.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/UriUtils.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/UriUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/UriUtils.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.http.client.utils.URIUtils; + +/** + * Helps to deal with URIs. + */ +final class UriUtils +{ + + public static URI resolve( URI base, URI ref ) + { + String path = ref.getRawPath(); + if ( path != null && path.length() > 0 ) + { + path = base.getRawPath(); + if ( path == null || !path.endsWith( "/" ) ) + { + try + { + base = new URI( base.getScheme(), base.getAuthority(), base.getPath() + '/', null, null ); + } + catch ( URISyntaxException e ) + { + throw new IllegalStateException( e ); + } + } + } + return URIUtils.resolve( base, ref ); + } + + public static List getDirectories( URI base, URI uri ) + { + List dirs = new ArrayList(); + for ( URI dir = uri.resolve( "." ); !isBase( base, dir ); dir = dir.resolve( ".." ) ) + { + dirs.add( dir ); + } + return dirs; + } + + private static boolean isBase( URI base, URI uri ) + { + String path = uri.getRawPath(); + if ( path == null || "/".equals( path ) ) + { + return true; + } + if ( base != null ) + { + URI rel = base.relativize( uri ); + if ( rel.getRawPath() == null || rel.getRawPath().length() <= 0 || rel.equals( uri ) ) + { + return true; + } + } + return false; + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/X509HostnameVerifierAdapter.java eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/X509HostnameVerifierAdapter.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/X509HostnameVerifierAdapter.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/X509HostnameVerifierAdapter.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.io.IOException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; + +import org.apache.http.conn.ssl.X509HostnameVerifier; + +/** + * Makes a standard hostname verifier compatible with Apache HttpClient's API. + */ +final class X509HostnameVerifierAdapter + implements X509HostnameVerifier +{ + + private final HostnameVerifier verifier; + + public static X509HostnameVerifier adapt( HostnameVerifier verifier ) + { + if ( verifier instanceof X509HostnameVerifier ) + { + return (X509HostnameVerifier) verifier; + } + return new X509HostnameVerifierAdapter( verifier ); + } + + private X509HostnameVerifierAdapter( HostnameVerifier verifier ) + { + this.verifier = verifier; + } + + public boolean verify( String hostname, SSLSession session ) + { + return verifier.verify( hostname, session ); + } + + public void verify( String host, SSLSocket socket ) + throws IOException + { + if ( !verify( host, socket.getSession() ) ) + { + throw new SSLException( "<" + host + "> does not pass hostname verification" ); + } + } + + public void verify( String host, X509Certificate cert ) + throws SSLException + { + throw new UnsupportedOperationException(); + } + + public void verify( String host, String[] cns, String[] subjectAlts ) + throws SSLException + { + throw new UnsupportedOperationException(); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/main/resources/about.html eclipse-aether-1.0.2/aether-transport-http/src/main/resources/about.html --- eclipse-aether-0.9.0.M2/aether-transport-http/src/main/resources/about.html 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/main/resources/about.html 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,28 @@ + + + + +About + + +

About This Content

+ +

September 23, 2011

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + + diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpServer.java eclipse-aether-1.0.2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpServer.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpServer.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpServer.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,562 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.aether.util.ChecksumUtils; +import org.eclipse.jetty.http.HttpHeaders; +import org.eclipse.jetty.http.HttpMethods; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.HandlerList; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; +import org.eclipse.jetty.util.B64Code; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.URIUtil; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HttpServer +{ + + public static class LogEntry + { + + public final String method; + + public final String path; + + public final Map headers; + + public LogEntry( String method, String path, Map headers ) + { + this.method = method; + this.path = path; + this.headers = headers; + } + + @Override + public String toString() + { + return method + " " + path; + } + + } + + public enum ExpectContinue + { + FAIL, PROPER, BROKEN + } + + public enum ChecksumHeader + { + NEXUS + } + + private static final Logger log = LoggerFactory.getLogger( HttpServer.class ); + + private File repoDir; + + private boolean rangeSupport = true; + + private boolean webDav; + + private ExpectContinue expectContinue = ExpectContinue.PROPER; + + private ChecksumHeader checksumHeader; + + private Server server; + + private Connector httpConnector; + + private Connector httpsConnector; + + private String username; + + private String password; + + private String proxyUsername; + + private String proxyPassword; + + private List logEntries = Collections.synchronizedList( new ArrayList() ); + + public String getHost() + { + return "localhost"; + } + + public int getHttpPort() + { + return httpConnector != null ? httpConnector.getLocalPort() : -1; + } + + public int getHttpsPort() + { + return httpsConnector != null ? httpsConnector.getLocalPort() : -1; + } + + public String getHttpUrl() + { + return "http://" + getHost() + ":" + getHttpPort(); + } + + public String getHttpsUrl() + { + return "https://" + getHost() + ":" + getHttpsPort(); + } + + public HttpServer addSslConnector() + { + if ( httpsConnector == null ) + { + SslContextFactory ssl = new SslContextFactory(); + ssl.setKeyStorePath( new File( "src/test/resources/ssl/server-store" ).getAbsolutePath() ); + ssl.setKeyStorePassword( "server-pwd" ); + ssl.setTrustStore( new File( "src/test/resources/ssl/client-store" ).getAbsolutePath() ); + ssl.setTrustStorePassword( "client-pwd" ); + ssl.setNeedClientAuth( true ); + httpsConnector = new SslSelectChannelConnector( ssl ); + server.addConnector( httpsConnector ); + try + { + httpsConnector.start(); + } + catch ( Exception e ) + { + throw new IllegalStateException( e ); + } + } + return this; + } + + public List getLogEntries() + { + return logEntries; + } + + public HttpServer setRepoDir( File repoDir ) + { + this.repoDir = repoDir; + return this; + } + + public HttpServer setRangeSupport( boolean rangeSupport ) + { + this.rangeSupport = rangeSupport; + return this; + } + + public HttpServer setWebDav( boolean webDav ) + { + this.webDav = webDav; + return this; + } + + public HttpServer setExpectSupport( ExpectContinue expectContinue ) + { + this.expectContinue = expectContinue; + return this; + } + + public HttpServer setChecksumHeader( ChecksumHeader checksumHeader ) + { + this.checksumHeader = checksumHeader; + return this; + } + + public HttpServer setAuthentication( String username, String password ) + { + this.username = username; + this.password = password; + return this; + } + + public HttpServer setProxyAuthentication( String username, String password ) + { + proxyUsername = username; + proxyPassword = password; + return this; + } + + public HttpServer start() + throws Exception + { + if ( server != null ) + { + return this; + } + + httpConnector = new SelectChannelConnector(); + + HandlerList handlers = new HandlerList(); + handlers.addHandler( new LogHandler() ); + handlers.addHandler( new ProxyAuthHandler() ); + handlers.addHandler( new AuthHandler() ); + handlers.addHandler( new RedirectHandler() ); + handlers.addHandler( new RepoHandler() ); + + server = new Server(); + server.addConnector( httpConnector ); + server.setHandler( handlers ); + server.start(); + + return this; + } + + public void stop() + throws Exception + { + if ( server != null ) + { + server.stop(); + server = null; + httpConnector = null; + httpsConnector = null; + } + } + + private class LogHandler + extends AbstractHandler + { + + @SuppressWarnings( "unchecked" ) + public void handle( String target, Request req, HttpServletRequest request, HttpServletResponse response ) + throws IOException + { + log.info( "{} {}{}", new Object[] { req.getMethod(), req.getRequestURL(), + req.getQueryString() != null ? "?" + req.getQueryString() : "" } ); + + Map headers = new TreeMap( String.CASE_INSENSITIVE_ORDER ); + for ( Enumeration en = req.getHeaderNames(); en.hasMoreElements(); ) + { + String name = en.nextElement(); + StringBuilder buffer = new StringBuilder( 128 ); + for ( Enumeration ien = req.getHeaders( name ); ien.hasMoreElements(); ) + { + if ( buffer.length() > 0 ) + { + buffer.append( ", " ); + } + buffer.append( ien.nextElement() ); + } + headers.put( name, buffer.toString() ); + } + logEntries.add( new LogEntry( req.getMethod(), req.getPathInfo(), Collections.unmodifiableMap( headers ) ) ); + } + + } + + private class RepoHandler + extends AbstractHandler + { + + private final Pattern SIMPLE_RANGE = Pattern.compile( "bytes=([0-9])+-" ); + + public void handle( String target, Request req, HttpServletRequest request, HttpServletResponse response ) + throws IOException + { + String path = req.getPathInfo().substring( 1 ); + + if ( !path.startsWith( "repo/" ) ) + { + return; + } + req.setHandled( true ); + + if ( ExpectContinue.FAIL.equals( expectContinue ) && request.getHeader( HttpHeaders.EXPECT ) != null ) + { + response.setStatus( HttpServletResponse.SC_EXPECTATION_FAILED ); + return; + } + + File file = new File( repoDir, path.substring( 5 ) ); + if ( HttpMethods.GET.equals( req.getMethod() ) || HttpMethods.HEAD.equals( req.getMethod() ) ) + { + if ( !file.isFile() || path.endsWith( URIUtil.SLASH ) ) + { + response.setStatus( HttpServletResponse.SC_NOT_FOUND ); + return; + } + long ifUnmodifiedSince = request.getDateHeader( HttpHeaders.IF_UNMODIFIED_SINCE ); + if ( ifUnmodifiedSince != -1 && file.lastModified() > ifUnmodifiedSince ) + { + response.setStatus( HttpServletResponse.SC_PRECONDITION_FAILED ); + return; + } + long offset = 0; + String range = request.getHeader( HttpHeaders.RANGE ); + if ( range != null && rangeSupport ) + { + Matcher m = SIMPLE_RANGE.matcher( range ); + if ( m.matches() ) + { + offset = Long.parseLong( m.group( 1 ) ); + if ( offset >= file.length() ) + { + response.setStatus( HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE ); + return; + } + } + String encoding = request.getHeader( HttpHeaders.ACCEPT_ENCODING ); + if ( ( encoding != null && !"identity".equals( encoding ) ) || ifUnmodifiedSince == -1 ) + { + response.setStatus( HttpServletResponse.SC_BAD_REQUEST ); + return; + } + } + response.setStatus( ( offset > 0 ) ? HttpServletResponse.SC_PARTIAL_CONTENT : HttpServletResponse.SC_OK ); + response.setDateHeader( HttpHeaders.LAST_MODIFIED, file.lastModified() ); + response.setHeader( HttpHeaders.CONTENT_LENGTH, Long.toString( file.length() - offset ) ); + if ( offset > 0 ) + { + response.setHeader( HttpHeaders.CONTENT_RANGE, "bytes " + offset + "-" + ( file.length() - 1 ) + + "/" + file.length() ); + } + if ( checksumHeader != null ) + { + Map checksums = ChecksumUtils.calc( file, Collections.singleton( "SHA-1" ) ); + switch ( checksumHeader ) + { + case NEXUS: + response.setHeader( HttpHeaders.ETAG, "{SHA1{" + checksums.get( "SHA-1" ) + "}}" ); + break; + } + } + if ( HttpMethods.HEAD.equals( req.getMethod() ) ) + { + return; + } + FileInputStream is = new FileInputStream( file ); + try + { + if ( offset > 0 ) + { + long skipped = is.skip( offset ); + while ( skipped < offset && is.read() >= 0 ) + { + skipped++; + } + } + IO.copy( is, response.getOutputStream() ); + } + finally + { + IO.close( is ); + } + } + else if ( HttpMethods.PUT.equals( req.getMethod() ) ) + { + if ( !webDav ) + { + file.getParentFile().mkdirs(); + } + if ( file.getParentFile().exists() ) + { + try + { + FileOutputStream os = new FileOutputStream( file ); + try + { + IO.copy( request.getInputStream(), os ); + } + finally + { + os.close(); + } + } + catch ( IOException e ) + { + file.delete(); + throw e; + } + response.setStatus( HttpServletResponse.SC_NO_CONTENT ); + } + else + { + response.setStatus( HttpServletResponse.SC_FORBIDDEN ); + } + } + else if ( HttpMethods.OPTIONS.equals( req.getMethod() ) ) + { + if ( webDav ) + { + response.setHeader( "DAV", "1,2" ); + } + response.setHeader( HttpHeaders.ALLOW, "GET, PUT, HEAD, OPTIONS" ); + response.setStatus( HttpServletResponse.SC_OK ); + } + else if ( webDav && "MKCOL".equals( req.getMethod() ) ) + { + if ( file.exists() ) + { + response.setStatus( HttpServletResponse.SC_METHOD_NOT_ALLOWED ); + } + else if ( file.mkdir() ) + { + response.setStatus( HttpServletResponse.SC_CREATED ); + } + else + { + response.setStatus( HttpServletResponse.SC_CONFLICT ); + } + } + else + { + response.setStatus( HttpServletResponse.SC_METHOD_NOT_ALLOWED ); + } + } + + } + + private class RedirectHandler + extends AbstractHandler + { + + public void handle( String target, Request req, HttpServletRequest request, HttpServletResponse response ) + throws IOException + { + String path = req.getPathInfo(); + if ( !path.startsWith( "/redirect/" ) ) + { + return; + } + req.setHandled( true ); + StringBuilder location = new StringBuilder( 128 ); + String scheme = req.getParameter( "scheme" ); + location.append( scheme != null ? scheme : req.getScheme() ); + location.append( "://" ); + location.append( req.getServerName() ); + location.append( ":" ); + if ( "http".equalsIgnoreCase( scheme ) ) + { + location.append( getHttpPort() ); + } + else if ( "https".equalsIgnoreCase( scheme ) ) + { + location.append( getHttpsPort() ); + } + else + { + location.append( req.getServerPort() ); + } + location.append( "/repo" ).append( path.substring( 9 ) ); + response.setStatus( HttpServletResponse.SC_MOVED_PERMANENTLY ); + response.setHeader( HttpHeaders.LOCATION, location.toString() ); + } + + } + + private class AuthHandler + extends AbstractHandler + { + + public void handle( String target, Request req, HttpServletRequest request, HttpServletResponse response ) + throws IOException + { + if ( ExpectContinue.BROKEN.equals( expectContinue ) + && "100-continue".equalsIgnoreCase( request.getHeader( HttpHeaders.EXPECT ) ) ) + { + request.getInputStream(); + } + + if ( username != null && password != null ) + { + if ( checkBasicAuth( request.getHeader( HttpHeaders.AUTHORIZATION ), username, password ) ) + { + return; + } + req.setHandled( true ); + response.setHeader( HttpHeaders.WWW_AUTHENTICATE, "basic realm=\"Test-Realm\"" ); + response.setStatus( HttpServletResponse.SC_UNAUTHORIZED ); + } + } + + } + + private class ProxyAuthHandler + extends AbstractHandler + { + + public void handle( String target, Request req, HttpServletRequest request, HttpServletResponse response ) + throws IOException + { + if ( proxyUsername != null && proxyPassword != null ) + { + if ( checkBasicAuth( request.getHeader( HttpHeaders.PROXY_AUTHORIZATION ), proxyUsername, proxyPassword ) ) + { + return; + } + req.setHandled( true ); + response.setHeader( HttpHeaders.PROXY_AUTHENTICATE, "basic realm=\"Test-Realm\"" ); + response.setStatus( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED ); + } + } + + } + + static boolean checkBasicAuth( String credentials, String username, String password ) + { + if ( credentials != null ) + { + int space = credentials.indexOf( ' ' ); + if ( space > 0 ) + { + String method = credentials.substring( 0, space ); + if ( "basic".equalsIgnoreCase( method ) ) + { + credentials = credentials.substring( space + 1 ); + try + { + credentials = B64Code.decode( credentials, StringUtil.__ISO_8859_1 ); + } + catch ( UnsupportedEncodingException e ) + { + throw new IllegalStateException( e ); + } + int i = credentials.indexOf( ':' ); + if ( i > 0 ) + { + String user = credentials.substring( 0, i ); + String pass = credentials.substring( i + 1 ); + if ( username.equals( user ) && password.equals( pass ) ) + { + return true; + } + } + } + } + } + return false; + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpTransporterTest.java eclipse-aether-1.0.2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpTransporterTest.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpTransporterTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpTransporterTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,1153 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.FileNotFoundException; +import java.net.ConnectException; +import java.net.ServerSocket; +import java.net.SocketTimeoutException; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.http.client.HttpResponseException; +import org.apache.http.conn.ConnectTimeoutException; +import org.apache.http.pool.ConnPoolControl; +import org.apache.http.pool.PoolStats; +import org.eclipse.aether.ConfigurationProperties; +import org.eclipse.aether.DefaultRepositoryCache; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.internal.test.util.TestFileUtils; +import org.eclipse.aether.internal.test.util.TestLoggerFactory; +import org.eclipse.aether.internal.test.util.TestUtils; +import org.eclipse.aether.repository.Authentication; +import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.transport.GetTask; +import org.eclipse.aether.spi.connector.transport.PeekTask; +import org.eclipse.aether.spi.connector.transport.PutTask; +import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.transfer.NoTransporterException; +import org.eclipse.aether.transfer.TransferCancelledException; +import org.eclipse.aether.util.repository.AuthenticationBuilder; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +/** + */ +public class HttpTransporterTest +{ + + static + { + System.setProperty( "javax.net.ssl.trustStore", + new File( "src/test/resources/ssl/server-store" ).getAbsolutePath() ); + System.setProperty( "javax.net.ssl.trustStorePassword", "server-pwd" ); + System.setProperty( "javax.net.ssl.keyStore", + new File( "src/test/resources/ssl/client-store" ).getAbsolutePath() ); + System.setProperty( "javax.net.ssl.keyStorePassword", "client-pwd" ); + } + + @Rule + public TestName testName = new TestName(); + + private DefaultRepositorySystemSession session; + + private TransporterFactory factory; + + private Transporter transporter; + + private File repoDir; + + private HttpServer httpServer; + + private Authentication auth; + + private Proxy proxy; + + private RemoteRepository newRepo( String url ) + { + return new RemoteRepository.Builder( "test", "default", url ).setAuthentication( auth ).setProxy( proxy ).build(); + } + + private void newTransporter( String url ) + throws Exception + { + if ( transporter != null ) + { + transporter.close(); + transporter = null; + } + transporter = factory.newInstance( session, newRepo( url ) ); + } + + @Before + public void setUp() + throws Exception + { + System.out.println( "=== " + testName.getMethodName() + " ===" ); + session = TestUtils.newSession(); + factory = new HttpTransporterFactory( new TestLoggerFactory() ); + repoDir = TestFileUtils.createTempDir(); + TestFileUtils.writeString( new File( repoDir, "file.txt" ), "test" ); + TestFileUtils.writeString( new File( repoDir, "dir/file.txt" ), "test" ); + TestFileUtils.writeString( new File( repoDir, "empty.txt" ), "" ); + TestFileUtils.writeString( new File( repoDir, "some space.txt" ), "space" ); + File resumable = new File( repoDir, "resume.txt" ); + TestFileUtils.writeString( resumable, "resumable" ); + resumable.setLastModified( System.currentTimeMillis() - 90 * 1000 ); + httpServer = new HttpServer().setRepoDir( repoDir ).start(); + newTransporter( httpServer.getHttpUrl() ); + } + + @After + public void tearDown() + throws Exception + { + if ( transporter != null ) + { + transporter.close(); + transporter = null; + } + if ( httpServer != null ) + { + httpServer.stop(); + httpServer = null; + } + factory = null; + session = null; + } + + @Test + public void testClassify() + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( new FileNotFoundException() ) ); + assertEquals( Transporter.ERROR_OTHER, transporter.classify( new HttpResponseException( 403, "Forbidden" ) ) ); + assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( new HttpResponseException( 404, "Not Found" ) ) ); + } + + @Test + public void testPeek() + throws Exception + { + transporter.peek( new PeekTask( URI.create( "repo/file.txt" ) ) ); + } + + @Test + public void testPeek_NotFound() + throws Exception + { + try + { + transporter.peek( new PeekTask( URI.create( "repo/missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( HttpResponseException e ) + { + assertEquals( 404, e.getStatusCode() ); + assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( e ) ); + } + } + + @Test + public void testPeek_Closed() + throws Exception + { + transporter.close(); + try + { + transporter.peek( new PeekTask( URI.create( "repo/missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( IllegalStateException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testPeek_Authenticated() + throws Exception + { + httpServer.setAuthentication( "testuser", "testpass" ); + auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + newTransporter( httpServer.getHttpUrl() ); + transporter.peek( new PeekTask( URI.create( "repo/file.txt" ) ) ); + } + + @Test + public void testPeek_Unauthenticated() + throws Exception + { + httpServer.setAuthentication( "testuser", "testpass" ); + try + { + transporter.peek( new PeekTask( URI.create( "repo/file.txt" ) ) ); + fail( "Expected error" ); + } + catch ( HttpResponseException e ) + { + assertEquals( 401, e.getStatusCode() ); + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testPeek_ProxyAuthenticated() + throws Exception + { + httpServer.setProxyAuthentication( "testuser", "testpass" ); + auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + proxy = new Proxy( Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth ); + newTransporter( "http://bad.localhost:1/" ); + transporter.peek( new PeekTask( URI.create( "repo/file.txt" ) ) ); + } + + @Test + public void testPeek_ProxyUnauthenticated() + throws Exception + { + httpServer.setProxyAuthentication( "testuser", "testpass" ); + proxy = new Proxy( Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort() ); + newTransporter( "http://bad.localhost:1/" ); + try + { + transporter.peek( new PeekTask( URI.create( "repo/file.txt" ) ) ); + fail( "Expected error" ); + } + catch ( HttpResponseException e ) + { + assertEquals( 407, e.getStatusCode() ); + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testPeek_SSL() + throws Exception + { + httpServer.addSslConnector(); + newTransporter( httpServer.getHttpsUrl() ); + transporter.peek( new PeekTask( URI.create( "repo/file.txt" ) ) ); + } + + @Test + public void testPeek_Redirect() + throws Exception + { + httpServer.addSslConnector(); + transporter.peek( new PeekTask( URI.create( "redirect/file.txt" ) ) ); + transporter.peek( new PeekTask( URI.create( "redirect/file.txt?scheme=https" ) ) ); + } + + @Test + public void testGet_ToMemory() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "repo/file.txt" ) ).setListener( listener ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( task.getDataString(), listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_ToFile() + throws Exception + { + File file = TestFileUtils.createTempFile( "failure" ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "repo/file.txt" ) ).setDataFile( file ).setListener( listener ); + transporter.get( task ); + assertEquals( "test", TestFileUtils.readString( file ) ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "test", listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_EmptyResource() + throws Exception + { + File file = TestFileUtils.createTempFile( "failure" ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "repo/empty.txt" ) ).setDataFile( file ).setListener( listener ); + transporter.get( task ); + assertEquals( "", TestFileUtils.readString( file ) ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 0, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + assertEquals( "", listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_EncodedResourcePath() + throws Exception + { + GetTask task = new GetTask( URI.create( "repo/some%20space.txt" ) ); + transporter.get( task ); + assertEquals( "space", task.getDataString() ); + } + + @Test + public void testGet_Authenticated() + throws Exception + { + httpServer.setAuthentication( "testuser", "testpass" ); + auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + newTransporter( httpServer.getHttpUrl() ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "repo/file.txt" ) ).setListener( listener ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( task.getDataString(), listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_Unauthenticated() + throws Exception + { + httpServer.setAuthentication( "testuser", "testpass" ); + try + { + transporter.get( new GetTask( URI.create( "repo/file.txt" ) ) ); + fail( "Expected error" ); + } + catch ( HttpResponseException e ) + { + assertEquals( 401, e.getStatusCode() ); + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testGet_ProxyAuthenticated() + throws Exception + { + httpServer.setProxyAuthentication( "testuser", "testpass" ); + Authentication auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + proxy = new Proxy( Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth ); + newTransporter( "http://bad.localhost:1/" ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "repo/file.txt" ) ).setListener( listener ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( task.getDataString(), listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_ProxyUnauthenticated() + throws Exception + { + httpServer.setProxyAuthentication( "testuser", "testpass" ); + proxy = new Proxy( Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort() ); + newTransporter( "http://bad.localhost:1/" ); + try + { + transporter.get( new GetTask( URI.create( "repo/file.txt" ) ) ); + fail( "Expected error" ); + } + catch ( HttpResponseException e ) + { + assertEquals( 407, e.getStatusCode() ); + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testGet_SSL() + throws Exception + { + httpServer.addSslConnector(); + newTransporter( httpServer.getHttpsUrl() ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "repo/file.txt" ) ).setListener( listener ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( task.getDataString(), listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_WebDav() + throws Exception + { + httpServer.setWebDav( true ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "repo/dir/file.txt" ) ).setListener( listener ); + ( (HttpTransporter) transporter ).getState().setWebDav( true ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( task.getDataString(), listener.baos.toString( "UTF-8" ) ); + assertEquals( httpServer.getLogEntries().toString(), 1, httpServer.getLogEntries().size() ); + } + + @Test + public void testGet_Redirect() + throws Exception + { + httpServer.addSslConnector(); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "redirect/file.txt?scheme=https" ) ).setListener( listener ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( task.getDataString(), listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_Resume() + throws Exception + { + File file = TestFileUtils.createTempFile( "re" ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "repo/resume.txt" ) ).setDataFile( file, true ).setListener( listener ); + transporter.get( task ); + assertEquals( "resumable", TestFileUtils.readString( file ) ); + assertEquals( 1, listener.startedCount ); + assertEquals( 2, listener.dataOffset ); + assertEquals( 9, listener.dataLength ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "sumable", listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_ResumeLocalContentsOutdated() + throws Exception + { + File file = TestFileUtils.createTempFile( "re" ); + file.setLastModified( System.currentTimeMillis() - 5 * 60 * 1000 ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "repo/resume.txt" ) ).setDataFile( file, true ).setListener( listener ); + transporter.get( task ); + assertEquals( "resumable", TestFileUtils.readString( file ) ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 9, listener.dataLength ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "resumable", listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_ResumeRangesNotSupportedByServer() + throws Exception + { + httpServer.setRangeSupport( false ); + File file = TestFileUtils.createTempFile( "re" ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "repo/resume.txt" ) ).setDataFile( file, true ).setListener( listener ); + transporter.get( task ); + assertEquals( "resumable", TestFileUtils.readString( file ) ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 9, listener.dataLength ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "resumable", listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_Checksums_Nexus() + throws Exception + { + httpServer.setChecksumHeader( HttpServer.ChecksumHeader.NEXUS ); + GetTask task = new GetTask( URI.create( "repo/file.txt" ) ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + assertEquals( "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", task.getChecksums().get( "SHA-1" ) ); + } + + @Test + public void testGet_FileHandleLeak() + throws Exception + { + for ( int i = 0; i < 100; i++ ) + { + File file = TestFileUtils.createTempFile( "failure" ); + transporter.get( new GetTask( URI.create( "repo/file.txt" ) ).setDataFile( file ) ); + assertTrue( i + ", " + file.getAbsolutePath(), file.delete() ); + } + } + + @Test + public void testGet_NotFound() + throws Exception + { + try + { + transporter.get( new GetTask( URI.create( "repo/missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( HttpResponseException e ) + { + assertEquals( 404, e.getStatusCode() ); + assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( e ) ); + } + } + + @Test + public void testGet_Closed() + throws Exception + { + transporter.close(); + try + { + transporter.get( new GetTask( URI.create( "repo/file.txt" ) ) ); + fail( "Expected error" ); + } + catch ( IllegalStateException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testGet_StartCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelStart = true; + GetTask task = new GetTask( URI.create( "repo/file.txt" ) ).setListener( listener ); + try + { + transporter.get( task ); + fail( "Expected error" ); + } + catch ( TransferCancelledException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + } + + @Test + public void testGet_ProgressCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelProgress = true; + GetTask task = new GetTask( URI.create( "repo/file.txt" ) ).setListener( listener ); + try + { + transporter.get( task ); + fail( "Expected error" ); + } + catch ( TransferCancelledException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 1, listener.progressedCount ); + } + + @Test + public void testPut_FromMemory() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); + } + + @Test + public void testPut_FromFile() + throws Exception + { + File file = TestFileUtils.createTempFile( "upload" ); + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ).setDataFile( file ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); + } + + @Test + public void testPut_EmptyResource() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 0, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + assertEquals( "", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); + } + + @Test + public void testPut_EncodedResourcePath() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = + new PutTask( URI.create( "repo/some%20space.txt" ) ).setListener( listener ).setDataString( "OK" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 2, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "OK", TestFileUtils.readString( new File( repoDir, "some space.txt" ) ) ); + } + + @Test + public void testPut_Authenticated_ExpectContinue() + throws Exception + { + httpServer.setAuthentication( "testuser", "testpass" ); + auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + newTransporter( httpServer.getHttpUrl() ); + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); + } + + @Test + public void testPut_Authenticated_ExpectContinueBroken() + throws Exception + { + httpServer.setAuthentication( "testuser", "testpass" ); + httpServer.setExpectSupport( HttpServer.ExpectContinue.BROKEN ); + auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + newTransporter( httpServer.getHttpUrl() ); + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); + } + + @Test + public void testPut_Authenticated_ExpectContinueRejected() + throws Exception + { + httpServer.setAuthentication( "testuser", "testpass" ); + httpServer.setExpectSupport( HttpServer.ExpectContinue.FAIL ); + auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + newTransporter( httpServer.getHttpUrl() ); + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); + } + + @Test + public void testPut_Authenticated_ExpectContinueRejected_ExplicitlyConfiguredHeader() + throws Exception + { + Map headers = new HashMap(); + headers.put( "Expect", "100-continue" ); + session.setConfigProperty( ConfigurationProperties.HTTP_HEADERS + ".test", headers ); + httpServer.setAuthentication( "testuser", "testpass" ); + httpServer.setExpectSupport( HttpServer.ExpectContinue.FAIL ); + auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + newTransporter( httpServer.getHttpUrl() ); + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); + } + + @Test + public void testPut_Unauthenticated() + throws Exception + { + httpServer.setAuthentication( "testuser", "testpass" ); + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + try + { + transporter.put( task ); + fail( "Expected error" ); + } + catch ( HttpResponseException e ) + { + assertEquals( 401, e.getStatusCode() ); + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + } + + @Test + public void testPut_ProxyAuthenticated() + throws Exception + { + httpServer.setProxyAuthentication( "testuser", "testpass" ); + Authentication auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + proxy = new Proxy( Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth ); + newTransporter( "http://bad.localhost:1/" ); + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); + } + + @Test + public void testPut_ProxyUnauthenticated() + throws Exception + { + httpServer.setProxyAuthentication( "testuser", "testpass" ); + proxy = new Proxy( Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort() ); + newTransporter( "http://bad.localhost:1/" ); + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + try + { + transporter.put( task ); + fail( "Expected error" ); + } + catch ( HttpResponseException e ) + { + assertEquals( 407, e.getStatusCode() ); + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + } + + @Test + public void testPut_SSL() + throws Exception + { + httpServer.addSslConnector(); + httpServer.setAuthentication( "testuser", "testpass" ); + auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + newTransporter( httpServer.getHttpsUrl() ); + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); + } + + @Test + public void testPut_WebDav() + throws Exception + { + httpServer.setWebDav( true ); + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = + new PutTask( URI.create( "repo/dir1/dir2/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "dir1/dir2/file.txt" ) ) ); + + assertEquals( 5, httpServer.getLogEntries().size() ); + assertEquals( "OPTIONS", httpServer.getLogEntries().get( 0 ).method ); + assertEquals( "MKCOL", httpServer.getLogEntries().get( 1 ).method ); + assertEquals( "/repo/dir1/dir2/", httpServer.getLogEntries().get( 1 ).path ); + assertEquals( "MKCOL", httpServer.getLogEntries().get( 2 ).method ); + assertEquals( "/repo/dir1/", httpServer.getLogEntries().get( 2 ).path ); + assertEquals( "MKCOL", httpServer.getLogEntries().get( 3 ).method ); + assertEquals( "/repo/dir1/dir2/", httpServer.getLogEntries().get( 3 ).path ); + assertEquals( "PUT", httpServer.getLogEntries().get( 4 ).method ); + } + + @Test + public void testPut_FileHandleLeak() + throws Exception + { + for ( int i = 0; i < 100; i++ ) + { + File src = TestFileUtils.createTempFile( "upload" ); + File dst = new File( repoDir, "file.txt" ); + transporter.put( new PutTask( URI.create( "repo/file.txt" ) ).setDataFile( src ) ); + assertTrue( i + ", " + src.getAbsolutePath(), src.delete() ); + assertTrue( i + ", " + dst.getAbsolutePath(), dst.delete() ); + } + } + + @Test + public void testPut_Closed() + throws Exception + { + transporter.close(); + try + { + transporter.put( new PutTask( URI.create( "repo/missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( IllegalStateException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testPut_StartCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelStart = true; + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + try + { + transporter.put( task ); + fail( "Expected error" ); + } + catch ( TransferCancelledException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + } + + @Test + public void testPut_ProgressCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelProgress = true; + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + try + { + transporter.put( task ); + fail( "Expected error" ); + } + catch ( TransferCancelledException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 1, listener.progressedCount ); + } + + @Test + public void testGetPut_AuthCache() + throws Exception + { + httpServer.setAuthentication( "testuser", "testpass" ); + auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + newTransporter( httpServer.getHttpUrl() ); + GetTask get = new GetTask( URI.create( "repo/file.txt" ) ); + transporter.get( get ); + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "repo/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 1, listener.startedCount ); + } + + @Test( timeout = 10000 ) + public void testConcurrency() + throws Exception + { + httpServer.setAuthentication( "testuser", "testpass" ); + auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + newTransporter( httpServer.getHttpUrl() ); + final AtomicReference error = new AtomicReference(); + Thread threads[] = new Thread[20]; + for ( int i = 0; i < threads.length; i++ ) + { + final String path = "repo/file.txt?i=" + i; + threads[i] = new Thread() + { + @Override + public void run() + { + try + { + for ( int j = 0; j < 100; j++ ) + { + GetTask task = new GetTask( URI.create( path ) ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + } + } + catch ( Throwable t ) + { + error.compareAndSet( null, t ); + System.err.println( path ); + t.printStackTrace(); + } + } + }; + threads[i].setName( "Task-" + i ); + } + for ( Thread thread : threads ) + { + thread.start(); + } + for ( Thread thread : threads ) + { + thread.join(); + } + assertNull( String.valueOf( error.get() ), error.get() ); + } + + @Test( timeout = 1000 ) + public void testConnectTimeout() + throws Exception + { + session.setConfigProperty( ConfigurationProperties.CONNECT_TIMEOUT, 100 ); + int port = 1; + newTransporter( "http://localhost:" + port ); + try + { + transporter.get( new GetTask( URI.create( "repo/file.txt" ) ) ); + fail( "Expected error" ); + } + catch ( ConnectTimeoutException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + catch ( ConnectException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test( timeout = 1000 ) + public void testRequestTimeout() + throws Exception + { + session.setConfigProperty( ConfigurationProperties.REQUEST_TIMEOUT, 100 ); + ServerSocket server = new ServerSocket( 0 ); + newTransporter( "http://localhost:" + server.getLocalPort() ); + try + { + try + { + transporter.get( new GetTask( URI.create( "repo/file.txt" ) ) ); + fail( "Expected error" ); + } + catch ( SocketTimeoutException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + finally + { + server.close(); + } + } + + @Test + public void testUserAgent() + throws Exception + { + session.setConfigProperty( ConfigurationProperties.USER_AGENT, "SomeTest/1.0" ); + newTransporter( httpServer.getHttpUrl() ); + transporter.get( new GetTask( URI.create( "repo/file.txt" ) ) ); + assertEquals( 1, httpServer.getLogEntries().size() ); + for ( HttpServer.LogEntry log : httpServer.getLogEntries() ) + { + assertEquals( "SomeTest/1.0", log.headers.get( "User-Agent" ) ); + } + } + + @Test + public void testCustomHeaders() + throws Exception + { + Map headers = new HashMap(); + headers.put( "User-Agent", "Custom/1.0" ); + headers.put( "X-CustomHeader", "Custom-Value" ); + session.setConfigProperty( ConfigurationProperties.USER_AGENT, "SomeTest/1.0" ); + session.setConfigProperty( ConfigurationProperties.HTTP_HEADERS + ".test", headers ); + newTransporter( httpServer.getHttpUrl() ); + transporter.get( new GetTask( URI.create( "repo/file.txt" ) ) ); + assertEquals( 1, httpServer.getLogEntries().size() ); + for ( HttpServer.LogEntry log : httpServer.getLogEntries() ) + { + for ( Map.Entry entry : headers.entrySet() ) + { + assertEquals( entry.getKey(), entry.getValue(), log.headers.get( entry.getKey() ) ); + } + } + } + + @Test + public void testServerAuthScope_NotUsedForProxy() + throws Exception + { + String username = "testuser", password = "testpass"; + httpServer.setProxyAuthentication( username, password ); + auth = new AuthenticationBuilder().addUsername( username ).addPassword( password ).build(); + proxy = new Proxy( Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort() ); + newTransporter( "http://" + httpServer.getHost() + ":12/" ); + try + { + transporter.get( new GetTask( URI.create( "repo/file.txt" ) ) ); + fail( "Server auth must not be used as proxy auth" ); + } + catch ( HttpResponseException e ) + { + assertEquals( 407, e.getStatusCode() ); + } + } + + @Test + public void testProxyAuthScope_NotUsedForServer() + throws Exception + { + String username = "testuser", password = "testpass"; + httpServer.setAuthentication( username, password ); + Authentication auth = new AuthenticationBuilder().addUsername( username ).addPassword( password ).build(); + proxy = new Proxy( Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth ); + newTransporter( "http://" + httpServer.getHost() + ":12/" ); + try + { + transporter.get( new GetTask( URI.create( "repo/file.txt" ) ) ); + fail( "Proxy auth must not be used as server auth" ); + } + catch ( HttpResponseException e ) + { + assertEquals( 401, e.getStatusCode() ); + } + } + + @Test + public void testAuthSchemeReuse() + throws Exception + { + httpServer.setAuthentication( "testuser", "testpass" ); + httpServer.setProxyAuthentication( "proxyuser", "proxypass" ); + session.setCache( new DefaultRepositoryCache() ); + auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + Authentication auth = new AuthenticationBuilder().addUsername( "proxyuser" ).addPassword( "proxypass" ).build(); + proxy = new Proxy( Proxy.TYPE_HTTP, httpServer.getHost(), httpServer.getHttpPort(), auth ); + newTransporter( "http://bad.localhost:1/" ); + GetTask task = new GetTask( URI.create( "repo/file.txt" ) ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + assertEquals( 3, httpServer.getLogEntries().size() ); + httpServer.getLogEntries().clear(); + newTransporter( "http://bad.localhost:1/" ); + task = new GetTask( URI.create( "repo/file.txt" ) ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + assertEquals( 1, httpServer.getLogEntries().size() ); + assertNotNull( httpServer.getLogEntries().get( 0 ).headers.get( "Authorization" ) ); + assertNotNull( httpServer.getLogEntries().get( 0 ).headers.get( "Proxy-Authorization" ) ); + } + + @Test + public void testConnectionReuse() + throws Exception + { + httpServer.addSslConnector(); + session.setCache( new DefaultRepositoryCache() ); + for ( int i = 0; i < 3; i++ ) + { + newTransporter( httpServer.getHttpsUrl() ); + GetTask task = new GetTask( URI.create( "repo/file.txt" ) ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + } + PoolStats stats = + ( (ConnPoolControl) ( (HttpTransporter) transporter ).getState().getConnectionManager() ).getTotalStats(); + assertEquals( stats.toString(), 1, stats.getAvailable() ); + } + + @Test( expected = NoTransporterException.class ) + public void testInit_BadProtocol() + throws Exception + { + newTransporter( "bad:/void" ); + } + + @Test( expected = NoTransporterException.class ) + public void testInit_BadUrl() + throws Exception + { + newTransporter( "http://localhost:NaN" ); + } + + @Test + public void testInit_CaseInsensitiveProtocol() + throws Exception + { + newTransporter( "http://localhost" ); + newTransporter( "HTTP://localhost" ); + newTransporter( "Http://localhost" ); + newTransporter( "https://localhost" ); + newTransporter( "HTTPS://localhost" ); + newTransporter( "HttpS://localhost" ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/RecordingTransportListener.java eclipse-aether-1.0.2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/RecordingTransportListener.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/RecordingTransportListener.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/RecordingTransportListener.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; + +import org.eclipse.aether.spi.connector.transport.TransportListener; +import org.eclipse.aether.transfer.TransferCancelledException; + +class RecordingTransportListener + extends TransportListener +{ + + public final ByteArrayOutputStream baos = new ByteArrayOutputStream( 1024 ); + + public long dataOffset; + + public long dataLength; + + public int startedCount; + + public int progressedCount; + + public boolean cancelStart; + + public boolean cancelProgress; + + @Override + public void transportStarted( long dataOffset, long dataLength ) + throws TransferCancelledException + { + startedCount++; + progressedCount = 0; + this.dataLength = dataLength; + this.dataOffset = dataOffset; + baos.reset(); + if ( cancelStart ) + { + throw new TransferCancelledException(); + } + } + + @Override + public void transportProgressed( ByteBuffer data ) + throws TransferCancelledException + { + progressedCount++; + baos.write( data.array(), data.arrayOffset() + data.position(), data.remaining() ); + if ( cancelProgress ) + { + throw new TransferCancelledException(); + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/UriUtilsTest.java eclipse-aether-1.0.2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/UriUtilsTest.java --- eclipse-aether-0.9.0.M2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/UriUtilsTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/test/java/org/eclipse/aether/transport/http/UriUtilsTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.http; + +import static org.junit.Assert.*; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; + +public class UriUtilsTest +{ + + private String resolve( URI base, String ref ) + { + return UriUtils.resolve( base, URI.create( ref ) ).toString(); + } + + @Test + public void testResolve_BaseEmptyPath() + { + URI base = URI.create( "http://host" ); + assertEquals( "http://host/file.jar", resolve( base, "file.jar" ) ); + assertEquals( "http://host/dir/file.jar", resolve( base, "dir/file.jar" ) ); + assertEquals( "http://host?arg=val", resolve( base, "?arg=val" ) ); + assertEquals( "http://host/file?arg=val", resolve( base, "file?arg=val" ) ); + assertEquals( "http://host/dir/file?arg=val", resolve( base, "dir/file?arg=val" ) ); + } + + @Test + public void testResolve_BaseRootPath() + { + URI base = URI.create( "http://host/" ); + assertEquals( "http://host/file.jar", resolve( base, "file.jar" ) ); + assertEquals( "http://host/dir/file.jar", resolve( base, "dir/file.jar" ) ); + assertEquals( "http://host/?arg=val", resolve( base, "?arg=val" ) ); + assertEquals( "http://host/file?arg=val", resolve( base, "file?arg=val" ) ); + assertEquals( "http://host/dir/file?arg=val", resolve( base, "dir/file?arg=val" ) ); + } + + @Test + public void testResolve_BasePathTrailingSlash() + { + URI base = URI.create( "http://host/sub/dir/" ); + assertEquals( "http://host/sub/dir/file.jar", resolve( base, "file.jar" ) ); + assertEquals( "http://host/sub/dir/dir/file.jar", resolve( base, "dir/file.jar" ) ); + assertEquals( "http://host/sub/dir/?arg=val", resolve( base, "?arg=val" ) ); + assertEquals( "http://host/sub/dir/file?arg=val", resolve( base, "file?arg=val" ) ); + assertEquals( "http://host/sub/dir/dir/file?arg=val", resolve( base, "dir/file?arg=val" ) ); + } + + @Test + public void testResolve_BasePathNoTrailingSlash() + { + URI base = URI.create( "http://host/sub/d%20r" ); + assertEquals( "http://host/sub/d%20r/file.jar", resolve( base, "file.jar" ) ); + assertEquals( "http://host/sub/d%20r/dir/file.jar", resolve( base, "dir/file.jar" ) ); + assertEquals( "http://host/sub/d%20r?arg=val", resolve( base, "?arg=val" ) ); + assertEquals( "http://host/sub/d%20r/file?arg=val", resolve( base, "file?arg=val" ) ); + assertEquals( "http://host/sub/d%20r/dir/file?arg=val", resolve( base, "dir/file?arg=val" ) ); + } + + private List getDirs( String base, String uri ) + { + return UriUtils.getDirectories( ( base != null ) ? URI.create( base ) : null, URI.create( uri ) ); + } + + private void assertUris( List actual, String... expected ) + { + List uris = new ArrayList( actual.size() ); + for ( URI uri : actual ) + { + uris.add( uri.toString() ); + } + assertEquals( Arrays.asList( expected ), uris ); + } + + @Test + public void testGetDirectories_NoBase() + { + List parents = getDirs( null, "http://host/repo/sub/dir/file.jar" ); + assertUris( parents, "http://host/repo/sub/dir/", "http://host/repo/sub/", "http://host/repo/" ); + + parents = getDirs( null, "http://host/repo/sub/dir/?file.jar" ); + assertUris( parents, "http://host/repo/sub/dir/", "http://host/repo/sub/", "http://host/repo/" ); + + parents = getDirs( null, "http://host/" ); + assertUris( parents ); + } + + @Test + public void testGetDirectories_ExplicitBaseTrailingSlash() + { + List parents = getDirs( "http://host/repo/", "http://host/repo/sub/dir/file.jar" ); + assertUris( parents, "http://host/repo/sub/dir/", "http://host/repo/sub/" ); + + parents = getDirs( "http://host/repo/", "http://host/repo/sub/dir/?file.jar" ); + assertUris( parents, "http://host/repo/sub/dir/", "http://host/repo/sub/" ); + + parents = getDirs( "http://host/repo/", "http://host/" ); + assertUris( parents ); + } + + @Test + public void testGetDirectories_ExplicitBaseNoTrailingSlash() + { + List parents = getDirs( "http://host/repo", "http://host/repo/sub/dir/file.jar" ); + assertUris( parents, "http://host/repo/sub/dir/", "http://host/repo/sub/" ); + + parents = getDirs( "http://host/repo", "http://host/repo/sub/dir/?file.jar" ); + assertUris( parents, "http://host/repo/sub/dir/", "http://host/repo/sub/" ); + + parents = getDirs( "http://host/repo", "http://host/" ); + assertUris( parents ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/test/resources/logback.xml eclipse-aether-1.0.2/aether-transport-http/src/test/resources/logback.xml --- eclipse-aether-0.9.0.M2/aether-transport-http/src/test/resources/logback.xml 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/test/resources/logback.xml 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,27 @@ + + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + Binary files /tmp/tgnHCPYjrp/eclipse-aether-0.9.0.M2/aether-transport-http/src/test/resources/ssl/client-store and /tmp/V9kaLqCWm7/eclipse-aether-1.0.2/aether-transport-http/src/test/resources/ssl/client-store differ diff -Nru eclipse-aether-0.9.0.M2/aether-transport-http/src/test/resources/ssl/README.txt eclipse-aether-1.0.2/aether-transport-http/src/test/resources/ssl/README.txt --- eclipse-aether-0.9.0.M2/aether-transport-http/src/test/resources/ssl/README.txt 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-http/src/test/resources/ssl/README.txt 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,5 @@ +client-store generated via +> keytool -genkey -alias localhost -keypass client-pwd -keystore client-store -storepass client-pwd -validity 4096 -dname "cn=localhost, ou=None, L=Seattle, ST=Washington, o=ExampleOrg, c=US" -keyalg RSA + +server-store generated via +> keytool -genkey -alias localhost -keypass server-pwd -keystore server-store -storepass server-pwd -validity 4096 -dname "cn=localhost, ou=None, L=Seattle, ST=Washington, o=ExampleOrg, c=US" -keyalg RSA Binary files /tmp/tgnHCPYjrp/eclipse-aether-0.9.0.M2/aether-transport-http/src/test/resources/ssl/server-store and /tmp/V9kaLqCWm7/eclipse-aether-1.0.2/aether-transport-http/src/test/resources/ssl/server-store differ diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/pom.xml eclipse-aether-1.0.2/aether-transport-wagon/pom.xml --- eclipse-aether-0.9.0.M2/aether-transport-wagon/pom.xml 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/pom.xml 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,125 @@ + + + + + + 4.0.0 + + + org.eclipse.aether + aether + 1.0.2.v20150114 + + + aether-transport-wagon + + Aether Transport Wagon + + A transport implementation based on Maven Wagon. + + + + 1.0 + org.eclipse.aether.transport.wagon + + + + + org.eclipse.aether + aether-api + + + org.eclipse.aether + aether-spi + + + org.eclipse.aether + aether-util + + + org.apache.maven.wagon + wagon-provider-api + ${wagonVersion} + + + javax.inject + javax.inject + provided + true + + + org.codehaus.plexus + plexus-component-annotations + provided + true + + + org.codehaus.plexus + plexus-classworlds + 2.4 + true + + + org.codehaus.plexus + plexus-utils + 2.1 + true + + + org.eclipse.sisu + org.eclipse.sisu.plexus + true + + + org.sonatype.sisu + sisu-guice + no_aop + test + + + junit + junit + test + + + org.hamcrest + hamcrest-library + test + + + org.eclipse.aether + aether-test-util + test + + + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + + + org.codehaus.plexus + plexus-component-metadata + + + org.eclipse.sisu + sisu-maven-plugin + + + org.apache.felix + maven-bundle-plugin + + + + diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/internal/transport/wagon/package-info.java eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/internal/transport/wagon/package-info.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/internal/transport/wagon/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/internal/transport/wagon/package-info.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * Integration with the Plexus IoC container which is the native runtime environment expected by many wagon + * implementations. + */ +package org.eclipse.aether.internal.transport.wagon; + diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/internal/transport/wagon/PlexusWagonConfigurator.java eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/internal/transport/wagon/PlexusWagonConfigurator.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/internal/transport/wagon/PlexusWagonConfigurator.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/internal/transport/wagon/PlexusWagonConfigurator.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.transport.wagon; + +import org.apache.maven.wagon.Wagon; +import org.codehaus.plexus.PlexusContainer; +import org.codehaus.plexus.classworlds.realm.ClassRealm; +import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.component.annotations.Requirement; +import org.codehaus.plexus.component.configurator.AbstractComponentConfigurator; +import org.codehaus.plexus.component.configurator.ComponentConfigurationException; +import org.codehaus.plexus.component.configurator.ConfigurationListener; +import org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; +import org.codehaus.plexus.configuration.PlexusConfiguration; +import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.eclipse.aether.transport.wagon.WagonConfigurator; + +/** + * A wagon configurator based on the Plexus component configuration framework. + */ +@Component( role = WagonConfigurator.class, hint = "plexus" ) +public class PlexusWagonConfigurator + implements WagonConfigurator +{ + + @Requirement + private PlexusContainer container; + + /** + * Creates an uninitialized wagon configurator. + * + * @noreference This constructor only supports the Plexus IoC container and should not be called directly by + * clients. + */ + public PlexusWagonConfigurator() + { + // enables no-arg constructor + } + + /** + * Creates a wagon configurator using the specified Plexus container. + * + * @param container The Plexus container instance to use, must not be {@code null}. + */ + public PlexusWagonConfigurator( PlexusContainer container ) + { + if ( container == null ) + { + throw new IllegalArgumentException( "plexus container has not been specified" ); + } + this.container = container; + } + + public void configure( Wagon wagon, Object configuration ) + throws Exception + { + PlexusConfiguration config = null; + if ( configuration instanceof PlexusConfiguration ) + { + config = (PlexusConfiguration) configuration; + } + else if ( configuration instanceof Xpp3Dom ) + { + config = new XmlPlexusConfiguration( (Xpp3Dom) configuration ); + } + else if ( configuration == null ) + { + return; + } + else + { + throw new IllegalArgumentException( "Unexpected configuration type: " + configuration.getClass().getName() ); + } + + WagonComponentConfigurator configurator = new WagonComponentConfigurator(); + + configurator.configureComponent( wagon, config, container.getContainerRealm() ); + } + + static class WagonComponentConfigurator + extends AbstractComponentConfigurator + { + + @Override + public void configureComponent( Object component, PlexusConfiguration configuration, + ExpressionEvaluator expressionEvaluator, ClassRealm containerRealm, + ConfigurationListener listener ) + throws ComponentConfigurationException + { + ObjectWithFieldsConverter converter = new ObjectWithFieldsConverter(); + + converter.processConfiguration( converterLookup, component, containerRealm, configuration, + expressionEvaluator, listener ); + } + + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/internal/transport/wagon/PlexusWagonProvider.java eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/internal/transport/wagon/PlexusWagonProvider.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/internal/transport/wagon/PlexusWagonProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/internal/transport/wagon/PlexusWagonProvider.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.internal.transport.wagon; + +import org.apache.maven.wagon.Wagon; +import org.codehaus.plexus.PlexusContainer; +import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.component.annotations.Requirement; +import org.eclipse.aether.transport.wagon.WagonProvider; + +/** + * A wagon provider backed by a Plexus container and the wagons registered with this container. + */ +@Component( role = WagonProvider.class, hint = "plexus" ) +public class PlexusWagonProvider + implements WagonProvider +{ + + @Requirement + private PlexusContainer container; + + /** + * Creates an uninitialized wagon provider. + * + * @noreference This constructor only supports the Plexus IoC container and should not be called directly by + * clients. + */ + public PlexusWagonProvider() + { + // enables no-arg constructor + } + + /** + * Creates a wagon provider using the specified Plexus container. + * + * @param container The Plexus container instance to use, must not be {@code null}. + */ + public PlexusWagonProvider( PlexusContainer container ) + { + if ( container == null ) + { + throw new IllegalArgumentException( "plexus container has not been specified" ); + } + this.container = container; + } + + public Wagon lookup( String roleHint ) + throws Exception + { + return container.lookup( Wagon.class, roleHint ); + } + + public void release( Wagon wagon ) + { + try + { + if ( wagon != null ) + { + container.release( wagon ); + } + } + catch ( Exception e ) + { + // too bad + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/package-info.java eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/package-info.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/package-info.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +/** + * Support for downloads/uploads using Apache Maven Wagon. + */ +package org.eclipse.aether.transport.wagon; + diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonCancelledException.java eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonCancelledException.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonCancelledException.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonCancelledException.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import org.eclipse.aether.transfer.TransferCancelledException; + +/** + * Unchecked exception to allow the checked {@link TransferCancelledException} to bubble up from a wagon. + */ +class WagonCancelledException + extends RuntimeException +{ + + public WagonCancelledException( TransferCancelledException cause ) + { + super( cause ); + } + + public static Exception unwrap( Exception e ) + { + if ( e instanceof WagonCancelledException ) + { + e = (Exception) e.getCause(); + } + return e; + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonConfigurator.java eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonConfigurator.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonConfigurator.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonConfigurator.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import org.apache.maven.wagon.Wagon; + +/** + * A component to configure wagon instances with provider-specific parameters. + */ +public interface WagonConfigurator +{ + + /** + * Configures the specified wagon instance with the given configuration. + * + * @param wagon The wagon instance to configure, must not be {@code null}. + * @param configuration The configuration to apply to the wagon instance, must not be {@code null}. + * @throws Exception If the configuration could not be applied to the wagon. + */ + void configure( Wagon wagon, Object configuration ) + throws Exception; + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonProvider.java eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonProvider.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonProvider.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import org.apache.maven.wagon.Wagon; + +/** + * A component to acquire and release wagon instances for uploads/downloads. + */ +public interface WagonProvider +{ + + /** + * Acquires a wagon instance that matches the specified role hint. The role hint is derived from the URI scheme, + * e.g. "http" or "file". + * + * @param roleHint The role hint to get a wagon for, must not be {@code null}. + * @return The requested wagon instance, never {@code null}. + * @throws Exception If no wagon could be retrieved for the specified role hint. + */ + Wagon lookup( String roleHint ) + throws Exception; + + /** + * Releases the specified wagon. A wagon provider may either free any resources allocated for the wagon instance or + * return the instance back to a pool for future use. + * + * @param wagon The wagon to release, may be {@code null}. + */ + void release( Wagon wagon ); + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransferListener.java eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransferListener.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransferListener.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransferListener.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import java.nio.ByteBuffer; + +import org.apache.maven.wagon.events.TransferEvent; +import org.apache.maven.wagon.observers.AbstractTransferListener; +import org.eclipse.aether.spi.connector.transport.TransportListener; +import org.eclipse.aether.transfer.TransferCancelledException; + +/** + * A wagon transfer listener that forwards events to a transport listener. + */ +final class WagonTransferListener + extends AbstractTransferListener +{ + + private final TransportListener listener; + + public WagonTransferListener( TransportListener listener ) + { + this.listener = listener; + } + + @Override + public void transferStarted( TransferEvent event ) + { + try + { + listener.transportStarted( 0, event.getResource().getContentLength() ); + } + catch ( TransferCancelledException e ) + { + /* + * NOTE: Wagon transfers are not freely abortable. In particular, aborting from + * AbstractWagon.fire(Get|Put)Started() would result in unclosed streams so we avoid this case. + */ + } + } + + @Override + public void transferProgress( TransferEvent event, byte[] buffer, int length ) + { + try + { + listener.transportProgressed( ByteBuffer.wrap( buffer, 0, length ) ); + } + catch ( TransferCancelledException e ) + { + throw new WagonCancelledException( e ); + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporterFactory.java eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporterFactory.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporterFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporterFactory.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.spi.locator.Service; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.spi.log.NullLoggerFactory; +import org.eclipse.aether.transfer.NoTransporterException; + +/** + * A transporter factory using Apache Maven Wagon. Note + * that this factory merely serves as an adapter to the Wagon API and by itself does not provide any transport services + * unless one or more wagon implementations are registered with the {@link WagonProvider}. + */ +@Named( "wagon" ) +public final class WagonTransporterFactory + implements TransporterFactory, Service +{ + + private Logger logger = NullLoggerFactory.LOGGER; + + private WagonProvider wagonProvider; + + private WagonConfigurator wagonConfigurator; + + private float priority = -1; + + /** + * Creates an (uninitialized) instance of this transporter factory. Note: In case of manual instantiation + * by clients, the new factory needs to be configured via its various mutators before first use or runtime errors + * will occur. + */ + public WagonTransporterFactory() + { + // enables default constructor + } + + @Inject + WagonTransporterFactory( WagonProvider wagonProvider, WagonConfigurator wagonConfigurator, + LoggerFactory loggerFactory ) + { + setWagonProvider( wagonProvider ); + setWagonConfigurator( wagonConfigurator ); + setLoggerFactory( loggerFactory ); + } + + public void initService( ServiceLocator locator ) + { + setLoggerFactory( locator.getService( LoggerFactory.class ) ); + setWagonProvider( locator.getService( WagonProvider.class ) ); + setWagonConfigurator( locator.getService( WagonConfigurator.class ) ); + } + + /** + * Sets the logger factory to use for this component. + * + * @param loggerFactory The logger factory to use, may be {@code null} to disable logging. + * @return This component for chaining, never {@code null}. + */ + public WagonTransporterFactory setLoggerFactory( LoggerFactory loggerFactory ) + { + this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, WagonTransporter.class ); + return this; + } + + /** + * Sets the wagon provider to use to acquire and release wagon instances. + * + * @param wagonProvider The wagon provider to use, may be {@code null}. + * @return This factory for chaining, never {@code null}. + */ + public WagonTransporterFactory setWagonProvider( WagonProvider wagonProvider ) + { + this.wagonProvider = wagonProvider; + return this; + } + + /** + * Sets the wagon configurator to use to apply provider-specific configuration to wagon instances. + * + * @param wagonConfigurator The wagon configurator to use, may be {@code null}. + * @return This factory for chaining, never {@code null}. + */ + public WagonTransporterFactory setWagonConfigurator( WagonConfigurator wagonConfigurator ) + { + this.wagonConfigurator = wagonConfigurator; + return this; + } + + public float getPriority() + { + return priority; + } + + /** + * Sets the priority of this component. + * + * @param priority The priority. + * @return This component for chaining, never {@code null}. + */ + public WagonTransporterFactory setPriority( float priority ) + { + this.priority = priority; + return this; + } + + public Transporter newInstance( RepositorySystemSession session, RemoteRepository repository ) + throws NoTransporterException + { + return new WagonTransporter( wagonProvider, wagonConfigurator, repository, session, logger ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,691 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import java.io.Closeable; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Method; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.Queue; +import java.util.UUID; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.maven.wagon.ResourceDoesNotExistException; +import org.apache.maven.wagon.StreamingWagon; +import org.apache.maven.wagon.Wagon; +import org.apache.maven.wagon.authentication.AuthenticationInfo; +import org.apache.maven.wagon.proxy.ProxyInfo; +import org.apache.maven.wagon.proxy.ProxyInfoProvider; +import org.apache.maven.wagon.repository.Repository; +import org.apache.maven.wagon.repository.RepositoryPermissions; +import org.eclipse.aether.ConfigurationProperties; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.AuthenticationContext; +import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.transport.GetTask; +import org.eclipse.aether.spi.connector.transport.PeekTask; +import org.eclipse.aether.spi.connector.transport.PutTask; +import org.eclipse.aether.spi.connector.transport.TransportTask; +import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.transfer.NoTransporterException; +import org.eclipse.aether.util.ConfigUtils; + +/** + * A transporter using Maven Wagon. + */ +final class WagonTransporter + implements Transporter +{ + + private static final String CONFIG_PROP_CONFIG = "aether.connector.wagon.config"; + + private static final String CONFIG_PROP_FILE_MODE = "aether.connector.perms.fileMode"; + + private static final String CONFIG_PROP_DIR_MODE = "aether.connector.perms.dirMode"; + + private static final String CONFIG_PROP_GROUP = "aether.connector.perms.group"; + + private final Logger logger; + + private final RemoteRepository repository; + + private final RepositorySystemSession session; + + private final AuthenticationContext repoAuthContext; + + private final AuthenticationContext proxyAuthContext; + + private final WagonProvider wagonProvider; + + private final WagonConfigurator wagonConfigurator; + + private final String wagonHint; + + private final Repository wagonRepo; + + private final AuthenticationInfo wagonAuth; + + private final ProxyInfoProvider wagonProxy; + + private final Properties headers; + + private final Queue wagons = new ConcurrentLinkedQueue(); + + private final AtomicBoolean closed = new AtomicBoolean(); + + public WagonTransporter( WagonProvider wagonProvider, WagonConfigurator wagonConfigurator, + RemoteRepository repository, RepositorySystemSession session, Logger logger ) + throws NoTransporterException + { + this.logger = logger; + this.wagonProvider = wagonProvider; + this.wagonConfigurator = wagonConfigurator; + this.repository = repository; + this.session = session; + + wagonRepo = new Repository( repository.getId(), repository.getUrl() ); + wagonRepo.setPermissions( getPermissions( repository.getId(), session ) ); + + wagonHint = wagonRepo.getProtocol().toLowerCase( Locale.ENGLISH ); + if ( wagonHint == null || wagonHint.length() <= 0 ) + { + throw new NoTransporterException( repository ); + } + + try + { + wagons.add( lookupWagon() ); + } + catch ( Exception e ) + { + logger.debug( e.getMessage(), e ); + throw new NoTransporterException( repository, e.getMessage(), e ); + } + + repoAuthContext = AuthenticationContext.forRepository( session, repository ); + proxyAuthContext = AuthenticationContext.forProxy( session, repository ); + + wagonAuth = getAuthenticationInfo( repository, repoAuthContext ); + wagonProxy = getProxy( repository, proxyAuthContext ); + + headers = new Properties(); + headers.put( "User-Agent", ConfigUtils.getString( session, ConfigurationProperties.DEFAULT_USER_AGENT, + ConfigurationProperties.USER_AGENT ) ); + Map headers = + ConfigUtils.getMap( session, null, ConfigurationProperties.HTTP_HEADERS + "." + repository.getId(), + ConfigurationProperties.HTTP_HEADERS ); + if ( headers != null ) + { + this.headers.putAll( headers ); + } + } + + private static RepositoryPermissions getPermissions( String repoId, RepositorySystemSession session ) + { + RepositoryPermissions result = null; + + RepositoryPermissions perms = new RepositoryPermissions(); + + String suffix = '.' + repoId; + + String fileMode = ConfigUtils.getString( session, (String) null, CONFIG_PROP_FILE_MODE + suffix ); + if ( fileMode != null ) + { + perms.setFileMode( fileMode ); + result = perms; + } + + String dirMode = ConfigUtils.getString( session, (String) null, CONFIG_PROP_DIR_MODE + suffix ); + if ( dirMode != null ) + { + perms.setDirectoryMode( dirMode ); + result = perms; + } + + String group = ConfigUtils.getString( session, (String) null, CONFIG_PROP_GROUP + suffix ); + if ( group != null ) + { + perms.setGroup( group ); + result = perms; + } + + return result; + } + + private AuthenticationInfo getAuthenticationInfo( RemoteRepository repository, + final AuthenticationContext authContext ) + { + AuthenticationInfo auth = null; + + if ( authContext != null ) + { + auth = new AuthenticationInfo() + { + @Override + public String getUserName() + { + return authContext.get( AuthenticationContext.USERNAME ); + } + + @Override + public String getPassword() + { + return authContext.get( AuthenticationContext.PASSWORD ); + } + + @Override + public String getPrivateKey() + { + return authContext.get( AuthenticationContext.PRIVATE_KEY_PATH ); + } + + @Override + public String getPassphrase() + { + return authContext.get( AuthenticationContext.PRIVATE_KEY_PASSPHRASE ); + } + }; + } + + return auth; + } + + private ProxyInfoProvider getProxy( RemoteRepository repository, final AuthenticationContext authContext ) + { + ProxyInfoProvider proxy = null; + + Proxy p = repository.getProxy(); + if ( p != null ) + { + final ProxyInfo prox; + if ( authContext != null ) + { + prox = new ProxyInfo() + { + @Override + public String getUserName() + { + return authContext.get( AuthenticationContext.USERNAME ); + } + + @Override + public String getPassword() + { + return authContext.get( AuthenticationContext.PASSWORD ); + } + + @Override + public String getNtlmDomain() + { + return authContext.get( AuthenticationContext.NTLM_DOMAIN ); + } + + @Override + public String getNtlmHost() + { + return authContext.get( AuthenticationContext.NTLM_WORKSTATION ); + } + }; + } + else + { + prox = new ProxyInfo(); + } + prox.setType( p.getType() ); + prox.setHost( p.getHost() ); + prox.setPort( p.getPort() ); + + proxy = new ProxyInfoProvider() + { + public ProxyInfo getProxyInfo( String protocol ) + { + return prox; + } + }; + } + + return proxy; + } + + private Wagon lookupWagon() + throws Exception + { + return wagonProvider.lookup( wagonHint ); + } + + private void releaseWagon( Wagon wagon ) + { + wagonProvider.release( wagon ); + } + + private void connectWagon( Wagon wagon ) + throws Exception + { + if ( !headers.isEmpty() ) + { + try + { + Method setHttpHeaders = wagon.getClass().getMethod( "setHttpHeaders", Properties.class ); + setHttpHeaders.invoke( wagon, headers ); + } + catch ( NoSuchMethodException e ) + { + // normal for non-http wagons + } + catch ( Exception e ) + { + logger.debug( "Could not set user agent for wagon " + wagon.getClass().getName() + ": " + e ); + } + } + + int connectTimeout = + ConfigUtils.getInteger( session, ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT, + ConfigurationProperties.CONNECT_TIMEOUT ); + int requestTimeout = + ConfigUtils.getInteger( session, ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT, + ConfigurationProperties.REQUEST_TIMEOUT ); + + wagon.setTimeout( Math.max( Math.max( connectTimeout, requestTimeout ), 0 ) ); + + wagon.setInteractive( ConfigUtils.getBoolean( session, ConfigurationProperties.DEFAULT_INTERACTIVE, + ConfigurationProperties.INTERACTIVE ) ); + + Object configuration = ConfigUtils.getObject( session, null, CONFIG_PROP_CONFIG + "." + repository.getId() ); + if ( configuration != null && wagonConfigurator != null ) + { + try + { + wagonConfigurator.configure( wagon, configuration ); + } + catch ( Exception e ) + { + String msg = + "Could not apply configuration for " + repository.getId() + " to wagon " + + wagon.getClass().getName() + ":" + e.getMessage(); + if ( logger.isDebugEnabled() ) + { + logger.warn( msg, e ); + } + else + { + logger.warn( msg ); + } + } + } + + wagon.connect( wagonRepo, wagonAuth, wagonProxy ); + } + + private void disconnectWagon( Wagon wagon ) + { + try + { + if ( wagon != null ) + { + wagon.disconnect(); + } + } + catch ( Exception e ) + { + logger.debug( "Could not disconnect wagon " + wagon, e ); + } + } + + private Wagon pollWagon() + throws Exception + { + Wagon wagon = wagons.poll(); + + if ( wagon == null ) + { + try + { + wagon = lookupWagon(); + connectWagon( wagon ); + } + catch ( Exception e ) + { + releaseWagon( wagon ); + throw e; + } + } + else if ( wagon.getRepository() == null ) + { + try + { + connectWagon( wagon ); + } + catch ( Exception e ) + { + wagons.add( wagon ); + throw e; + } + } + + return wagon; + } + + public int classify( Throwable error ) + { + if ( error instanceof ResourceDoesNotExistException ) + { + return ERROR_NOT_FOUND; + } + return ERROR_OTHER; + } + + public void peek( PeekTask task ) + throws Exception + { + execute( task, new PeekTaskRunner( task ) ); + } + + public void get( GetTask task ) + throws Exception + { + execute( task, new GetTaskRunner( task ) ); + } + + public void put( PutTask task ) + throws Exception + { + execute( task, new PutTaskRunner( task ) ); + } + + private void execute( TransportTask task, TaskRunner runner ) + throws Exception + { + if ( closed.get() ) + { + throw new IllegalStateException( "transporter closed, cannot execute task " + task ); + } + try + { + WagonTransferListener listener = new WagonTransferListener( task.getListener() ); + Wagon wagon = pollWagon(); + try + { + wagon.addTransferListener( listener ); + runner.run( wagon ); + } + finally + { + wagon.removeTransferListener( listener ); + wagons.add( wagon ); + } + } + catch ( Exception e ) + { + throw WagonCancelledException.unwrap( e ); + } + } + + private static File newTempFile() + throws IOException + { + return File.createTempFile( "wagon-" + UUID.randomUUID().toString().replace( "-", "" ), ".tmp" ); + } + + private void delTempFile( File path ) + { + if ( path != null && !path.delete() && path.exists() ) + { + logger.debug( "Could not delete temorary file " + path ); + } + } + + private static void copy( OutputStream os, InputStream is ) + throws IOException + { + byte[] buffer = new byte[1024 * 32]; + for ( int read = is.read( buffer ); read >= 0; read = is.read( buffer ) ) + { + os.write( buffer, 0, read ); + } + } + + private static void close( Closeable file ) + { + if ( file != null ) + { + try + { + file.close(); + } + catch ( IOException e ) + { + // too bad + } + } + } + + public void close() + { + if ( closed.compareAndSet( false, true ) ) + { + AuthenticationContext.close( repoAuthContext ); + AuthenticationContext.close( proxyAuthContext ); + + for ( Wagon wagon = wagons.poll(); wagon != null; wagon = wagons.poll() ) + { + disconnectWagon( wagon ); + releaseWagon( wagon ); + } + } + } + + private interface TaskRunner + { + + public void run( Wagon wagon ) + throws Exception; + + } + + private static class PeekTaskRunner + implements TaskRunner + { + + private final PeekTask task; + + public PeekTaskRunner( PeekTask task ) + { + this.task = task; + } + + public void run( Wagon wagon ) + throws Exception + { + String src = task.getLocation().toString(); + if ( !wagon.resourceExists( src ) ) + { + throw new ResourceDoesNotExistException( "Could not find " + src + " in " + + wagon.getRepository().getUrl() ); + } + } + + } + + private class GetTaskRunner + implements TaskRunner + { + + private final GetTask task; + + public GetTaskRunner( GetTask task ) + { + this.task = task; + } + + public void run( Wagon wagon ) + throws Exception + { + String src = task.getLocation().toString(); + File file = task.getDataFile(); + if ( file == null && wagon instanceof StreamingWagon ) + { + OutputStream dst = task.newOutputStream(); + try + { + ( (StreamingWagon) wagon ).getToStream( src, dst ); + } + finally + { + dst.close(); + } + } + else + { + File dst = ( file != null ) ? file : newTempFile(); + try + { + wagon.get( src, dst ); + if ( !dst.exists() ) + { + /* + * NOTE: Wagon (1.0-beta-6) doesn't create the destination file when transferring a 0-byte + * resource. So if the resource we asked for didn't cause any exception but doesn't show up in + * the dst file either, Wagon tells us in its weird way the file is empty. + */ + new FileOutputStream( dst ).close(); + } + if ( file == null ) + { + readTempFile( dst ); + } + } + finally + { + if ( file == null ) + { + delTempFile( dst ); + } + } + } + } + + private void readTempFile( File dst ) + throws IOException + { + FileInputStream fis = new FileInputStream( dst ); + try + { + OutputStream os = task.newOutputStream(); + try + { + copy( os, fis ); + os.close(); + } + finally + { + close( os ); + } + } + finally + { + close( fis ); + } + } + + } + + private class PutTaskRunner + implements TaskRunner + { + + private final PutTask task; + + public PutTaskRunner( PutTask task ) + { + this.task = task; + } + + public void run( Wagon wagon ) + throws Exception + { + String dst = task.getLocation().toString(); + File file = task.getDataFile(); + if ( file == null && wagon instanceof StreamingWagon ) + { + InputStream src = task.newInputStream(); + try + { + // StreamingWagon uses an internal buffer on src input stream. + ( (StreamingWagon) wagon ).putFromStream( src, dst, task.getDataLength(), -1 ); + } + finally + { + close( src ); + } + } + else + { + File src = ( file != null ) ? file : createTempFile(); + try + { + wagon.put( src, dst ); + } + finally + { + if ( file == null ) + { + delTempFile( src ); + } + } + } + } + + private File createTempFile() + throws IOException + { + File tmp = newTempFile(); + try + { + FileOutputStream fos = new FileOutputStream( tmp ); + try + { + InputStream is = task.newInputStream(); + try + { + copy( fos, is ); + fos.close(); + } + finally + { + close( is ); + } + } + finally + { + close( fos ); + } + } + catch ( IOException e ) + { + delTempFile( tmp ); + throw e; + } + return tmp; + } + + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/resources/about.html eclipse-aether-1.0.2/aether-transport-wagon/src/main/resources/about.html --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/main/resources/about.html 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/main/resources/about.html 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,28 @@ + + + + +About + + +

About This Content

+ +

September 23, 2011

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + + diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/AbstractWagonTransporterTest.java eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/AbstractWagonTransporterTest.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/AbstractWagonTransporterTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/AbstractWagonTransporterTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,525 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.net.URI; +import java.util.Map; +import java.util.UUID; + +import org.apache.maven.wagon.ResourceDoesNotExistException; +import org.apache.maven.wagon.TransferFailedException; +import org.apache.maven.wagon.Wagon; +import org.eclipse.aether.ConfigurationProperties; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.internal.test.util.TestFileUtils; +import org.eclipse.aether.internal.test.util.TestLoggerFactory; +import org.eclipse.aether.internal.test.util.TestUtils; +import org.eclipse.aether.repository.Authentication; +import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.transport.GetTask; +import org.eclipse.aether.spi.connector.transport.PeekTask; +import org.eclipse.aether.spi.connector.transport.PutTask; +import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.transfer.NoTransporterException; +import org.eclipse.aether.transfer.TransferCancelledException; +import org.eclipse.aether.util.repository.AuthenticationBuilder; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + */ +public abstract class AbstractWagonTransporterTest +{ + + private DefaultRepositorySystemSession session; + + private TransporterFactory factory; + + private Transporter transporter; + + private String id; + + private Map fs; + + protected abstract Wagon newWagon(); + + private RemoteRepository newRepo( String url ) + { + return new RemoteRepository.Builder( "test", "default", url ).build(); + } + + private void newTransporter( String url ) + throws Exception + { + newTransporter( newRepo( url ) ); + } + + private void newTransporter( RemoteRepository repo ) + throws Exception + { + if ( transporter != null ) + { + transporter.close(); + transporter = null; + } + transporter = factory.newInstance( session, repo ); + } + + @Before + public void setUp() + throws Exception + { + session = TestUtils.newSession(); + factory = new WagonTransporterFactory( new WagonProvider() + { + public Wagon lookup( String roleHint ) + throws Exception + { + if ( "mem".equalsIgnoreCase( roleHint ) ) + { + return newWagon(); + } + throw new IllegalArgumentException( "Unknown wagon role: " + roleHint ); + } + + public void release( Wagon wagon ) + { + } + }, new WagonConfigurator() + { + public void configure( Wagon wagon, Object configuration ) + throws Exception + { + ( (Configurable) wagon ).setConfiguration( configuration ); + } + }, new TestLoggerFactory() ); + id = UUID.randomUUID().toString().replace( "-", "" ); + fs = MemWagonUtils.getFilesystem( id ); + fs.put( "file.txt", "test" ); + fs.put( "empty.txt", "" ); + fs.put( "some space.txt", "space" ); + newTransporter( "mem://" + id ); + } + + @After + public void tearDown() + { + if ( transporter != null ) + { + transporter.close(); + transporter = null; + } + factory = null; + session = null; + } + + @Test + public void testClassify() + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( new TransferFailedException( "test" ) ) ); + assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( new ResourceDoesNotExistException( "test" ) ) ); + } + + @Test + public void testPeek() + throws Exception + { + transporter.peek( new PeekTask( URI.create( "file.txt" ) ) ); + } + + @Test + public void testPeek_NotFound() + throws Exception + { + try + { + transporter.peek( new PeekTask( URI.create( "missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( ResourceDoesNotExistException e ) + { + assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( e ) ); + } + } + + @Test + public void testPeek_Closed() + throws Exception + { + transporter.close(); + try + { + transporter.peek( new PeekTask( URI.create( "missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( IllegalStateException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testGet_ToMemory() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener ); + transporter.get( task ); + assertEquals( "test", task.getDataString() ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( task.getDataString(), listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_ToFile() + throws Exception + { + File file = TestFileUtils.createTempFile( "failure" ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "file.txt" ) ).setDataFile( file ).setListener( listener ); + transporter.get( task ); + assertEquals( "test", TestFileUtils.readString( file ) ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "test", listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_EmptyResource() + throws Exception + { + File file = TestFileUtils.createTempFile( "failure" ); + assertTrue( file.delete() && !file.exists() ); + RecordingTransportListener listener = new RecordingTransportListener(); + GetTask task = new GetTask( URI.create( "empty.txt" ) ).setDataFile( file ).setListener( listener ); + transporter.get( task ); + assertEquals( "", TestFileUtils.readString( file ) ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 0, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + assertEquals( "", listener.baos.toString( "UTF-8" ) ); + } + + @Test + public void testGet_EncodedResourcePath() + throws Exception + { + GetTask task = new GetTask( URI.create( "some%20space.txt" ) ); + transporter.get( task ); + assertEquals( "space", task.getDataString() ); + } + + @Test + public void testGet_FileHandleLeak() + throws Exception + { + for ( int i = 0; i < 100; i++ ) + { + File file = TestFileUtils.createTempFile( "failure" ); + transporter.get( new GetTask( URI.create( "file.txt" ) ).setDataFile( file ) ); + assertTrue( i + ", " + file.getAbsolutePath(), file.delete() ); + } + } + + @Test + public void testGet_NotFound() + throws Exception + { + try + { + transporter.get( new GetTask( URI.create( "missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( ResourceDoesNotExistException e ) + { + assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( e ) ); + } + } + + @Test + public void testGet_Closed() + throws Exception + { + transporter.close(); + try + { + transporter.get( new GetTask( URI.create( "file.txt" ) ) ); + fail( "Expected error" ); + } + catch ( IllegalStateException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testGet_StartCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelStart = true; + GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener ); + transporter.get( task ); + assertEquals( 1, listener.startedCount ); + } + + @Test + public void testGet_ProgressCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelProgress = true; + GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener ); + try + { + transporter.get( task ); + fail( "Expected error" ); + } + catch ( TransferCancelledException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.dataOffset ); + assertEquals( 4, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 1, listener.progressedCount ); + } + + @Test + public void testPut_FromMemory() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", fs.get( "file.txt" ) ); + } + + @Test + public void testPut_FromFile() + throws Exception + { + File file = TestFileUtils.createTempFile( "upload" ); + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataFile( file ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", fs.get( "file.txt" ) ); + } + + @Test + public void testPut_EmptyResource() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 0, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 0, listener.progressedCount ); + assertEquals( "", fs.get( "file.txt" ) ); + } + + @Test + public void testPut_NonExistentParentDir() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = + new PutTask( URI.create( "dir/sub/dir/file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "upload", fs.get( "dir/sub/dir/file.txt" ) ); + } + + @Test + public void testPut_EncodedResourcePath() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + PutTask task = new PutTask( URI.create( "some%20space.txt" ) ).setListener( listener ).setDataString( "OK" ); + transporter.put( task ); + assertEquals( 0, listener.dataOffset ); + assertEquals( 2, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); + assertEquals( "OK", fs.get( "some space.txt" ) ); + } + + @Test + public void testPut_FileHandleLeak() + throws Exception + { + for ( int i = 0; i < 100; i++ ) + { + File src = TestFileUtils.createTempFile( "upload" ); + transporter.put( new PutTask( URI.create( "file.txt" ) ).setDataFile( src ) ); + assertTrue( i + ", " + src.getAbsolutePath(), src.delete() ); + } + } + + @Test + public void testPut_Closed() + throws Exception + { + transporter.close(); + try + { + transporter.put( new PutTask( URI.create( "missing.txt" ) ) ); + fail( "Expected error" ); + } + catch ( IllegalStateException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + } + + @Test + public void testPut_StartCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelStart = true; + PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataString( "upload" ); + transporter.put( task ); + assertEquals( 1, listener.startedCount ); + } + + @Test + public void testPut_ProgressCancelled() + throws Exception + { + RecordingTransportListener listener = new RecordingTransportListener(); + listener.cancelProgress = true; + PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataString( "upload" ); + try + { + transporter.put( task ); + fail( "Expected error" ); + } + catch ( TransferCancelledException e ) + { + assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); + } + assertEquals( 0, listener.dataOffset ); + assertEquals( 6, listener.dataLength ); + assertEquals( 1, listener.startedCount ); + assertEquals( 1, listener.progressedCount ); + } + + @Test( expected = NoTransporterException.class ) + public void testInit_BadProtocol() + throws Exception + { + newTransporter( "bad:/void" ); + } + + @Test + public void testInit_CaseInsensitiveProtocol() + throws Exception + { + newTransporter( "mem:/void" ); + newTransporter( "MEM:/void" ); + newTransporter( "mEm:/void" ); + } + + @Test + public void testInit_Configuration() + throws Exception + { + session.setConfigProperty( "aether.connector.wagon.config.test", "passed" ); + newTransporter( "mem://" + id + "?config=passed" ); + transporter.peek( new PeekTask( URI.create( "file.txt" ) ) ); + } + + @Test + public void testInit_UserAgent() + throws Exception + { + session.setConfigProperty( ConfigurationProperties.USER_AGENT, "Test/1.0" ); + newTransporter( "mem://" + id + "?userAgent=Test/1.0" ); + transporter.peek( new PeekTask( URI.create( "file.txt" ) ) ); + } + + @Test + public void testInit_Timeout() + throws Exception + { + session.setConfigProperty( ConfigurationProperties.REQUEST_TIMEOUT, "12345678" ); + newTransporter( "mem://" + id + "?requestTimeout=12345678" ); + transporter.peek( new PeekTask( URI.create( "file.txt" ) ) ); + } + + @Test + public void testInit_ServerAuth() + throws Exception + { + String url = + "mem://" + id + "?serverUsername=testuser&serverPassword=testpass" + + "&serverPrivateKey=testkey&serverPassphrase=testphrase"; + Authentication auth = + new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).addPrivateKey( "testkey", + "testphrase" ).build(); + RemoteRepository repo = + new RemoteRepository.Builder( "test", "default", url ).setAuthentication( auth ).build(); + newTransporter( repo ); + transporter.peek( new PeekTask( URI.create( "file.txt" ) ) ); + } + + @Test + public void testInit_Proxy() + throws Exception + { + String url = "mem://" + id + "?proxyHost=testhost&proxyPort=8888"; + RemoteRepository repo = + new RemoteRepository.Builder( "test", "default", url ).setProxy( new Proxy( "http", "testhost", 8888 ) ).build(); + newTransporter( repo ); + transporter.peek( new PeekTask( URI.create( "file.txt" ) ) ); + } + + @Test + public void testInit_ProxyAuth() + throws Exception + { + String url = "mem://" + id + "?proxyUsername=testuser&proxyPassword=testpass"; + Authentication auth = new AuthenticationBuilder().addUsername( "testuser" ).addPassword( "testpass" ).build(); + RemoteRepository repo = + new RemoteRepository.Builder( "test", "default", url ).setProxy( new Proxy( "http", "testhost", 8888, auth ) ).build(); + newTransporter( repo ); + transporter.peek( new PeekTask( URI.create( "file.txt" ) ) ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/Configurable.java eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/Configurable.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/Configurable.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/Configurable.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +/** + */ +public interface Configurable +{ + + Object getConfiguration(); + + void setConfiguration( Object config ); + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/MemStreamWagon.java eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/MemStreamWagon.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/MemStreamWagon.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/MemStreamWagon.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.Map; +import java.util.Properties; + +import org.apache.maven.wagon.ConnectionException; +import org.apache.maven.wagon.InputData; +import org.apache.maven.wagon.OutputData; +import org.apache.maven.wagon.ResourceDoesNotExistException; +import org.apache.maven.wagon.StreamWagon; +import org.apache.maven.wagon.TransferFailedException; +import org.apache.maven.wagon.authentication.AuthenticationException; +import org.apache.maven.wagon.authorization.AuthorizationException; +import org.apache.maven.wagon.resource.Resource; + +/** + */ +public class MemStreamWagon + extends StreamWagon + implements Configurable +{ + + private Map fs; + + private Properties headers; + + private Object config; + + public void setConfiguration( Object config ) + { + this.config = config; + } + + public Object getConfiguration() + { + return config; + } + + public void setHttpHeaders( Properties httpHeaders ) + { + headers = httpHeaders; + } + + @Override + protected void openConnectionInternal() + throws ConnectionException, AuthenticationException + { + fs = + MemWagonUtils.openConnection( this, getAuthenticationInfo(), + getProxyInfo( "mem", getRepository().getHost() ), headers ); + } + + @Override + public void closeConnection() + throws ConnectionException + { + fs = null; + } + + private String getData( String resource ) + { + return fs.get( URI.create( resource ).getSchemeSpecificPart() ); + } + + @Override + public boolean resourceExists( String resourceName ) + throws TransferFailedException, AuthorizationException + { + String data = getData( resourceName ); + return data != null; + } + + @Override + public void fillInputData( InputData inputData ) + throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException + { + String data = getData( inputData.getResource().getName() ); + if ( data == null ) + { + throw new ResourceDoesNotExistException( "Missing resource: " + inputData.getResource().getName() ); + } + byte[] bytes; + try + { + bytes = data.getBytes( "UTF-8" ); + } + catch ( UnsupportedEncodingException e ) + { + throw new TransferFailedException( e.getMessage(), e ); + } + inputData.getResource().setContentLength( bytes.length ); + inputData.setInputStream( new ByteArrayInputStream( bytes ) ); + } + + @Override + public void fillOutputData( OutputData outputData ) + throws TransferFailedException + { + outputData.setOutputStream( new ByteArrayOutputStream() ); + } + + @Override + protected void finishPutTransfer( Resource resource, InputStream input, OutputStream output ) + throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException + { + String data; + try + { + data = ( (ByteArrayOutputStream) output ).toString( "UTF-8" ); + } + catch ( UnsupportedEncodingException e ) + { + throw new TransferFailedException( e.getMessage(), e ); + } + fs.put( URI.create( resource.getName() ).getSchemeSpecificPart(), data ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/MemWagon.java eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/MemWagon.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/MemWagon.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/MemWagon.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.Map; +import java.util.Properties; + +import org.apache.maven.wagon.AbstractWagon; +import org.apache.maven.wagon.ConnectionException; +import org.apache.maven.wagon.InputData; +import org.apache.maven.wagon.OutputData; +import org.apache.maven.wagon.ResourceDoesNotExistException; +import org.apache.maven.wagon.TransferFailedException; +import org.apache.maven.wagon.authentication.AuthenticationException; +import org.apache.maven.wagon.authorization.AuthorizationException; +import org.apache.maven.wagon.events.TransferEvent; +import org.apache.maven.wagon.resource.Resource; + +/** + */ +public class MemWagon + extends AbstractWagon + implements Configurable +{ + + private Map fs; + + private Properties headers; + + private Object config; + + public void setConfiguration( Object config ) + { + this.config = config; + } + + public Object getConfiguration() + { + return config; + } + + public void setHttpHeaders( Properties httpHeaders ) + { + headers = httpHeaders; + } + + @Override + protected void openConnectionInternal() + throws ConnectionException, AuthenticationException + { + fs = + MemWagonUtils.openConnection( this, getAuthenticationInfo(), + getProxyInfo( "mem", getRepository().getHost() ), headers ); + } + + @Override + protected void closeConnection() + throws ConnectionException + { + fs = null; + } + + private String getData( String resource ) + { + return fs.get( URI.create( resource ).getSchemeSpecificPart() ); + } + + @Override + public boolean resourceExists( String resourceName ) + throws TransferFailedException, AuthorizationException + { + String data = getData( resourceName ); + return data != null; + } + + public void get( String resourceName, File destination ) + throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException + { + getIfNewer( resourceName, destination, 0 ); + } + + public boolean getIfNewer( String resourceName, File destination, long timestamp ) + throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException + { + Resource resource = new Resource( resourceName ); + fireGetInitiated( resource, destination ); + resource.setLastModified( timestamp ); + getTransfer( resource, destination, getInputStream( resource ) ); + return true; + } + + protected InputStream getInputStream( Resource resource ) + throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException + { + InputData inputData = new InputData(); + inputData.setResource( resource ); + try + { + fillInputData( inputData ); + } + catch ( TransferFailedException e ) + { + fireTransferError( resource, e, TransferEvent.REQUEST_GET ); + cleanupGetTransfer( resource ); + throw e; + } + catch ( ResourceDoesNotExistException e ) + { + fireTransferError( resource, e, TransferEvent.REQUEST_GET ); + cleanupGetTransfer( resource ); + throw e; + } + catch ( AuthorizationException e ) + { + fireTransferError( resource, e, TransferEvent.REQUEST_GET ); + cleanupGetTransfer( resource ); + throw e; + } + finally + { + if ( inputData.getInputStream() == null ) + { + cleanupGetTransfer( resource ); + } + } + return inputData.getInputStream(); + } + + protected void fillInputData( InputData inputData ) + throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException + { + String data = getData( inputData.getResource().getName() ); + if ( data == null ) + { + throw new ResourceDoesNotExistException( "Missing resource: " + inputData.getResource().getName() ); + } + byte[] bytes; + try + { + bytes = data.getBytes( "UTF-8" ); + } + catch ( UnsupportedEncodingException e ) + { + throw new TransferFailedException( e.getMessage(), e ); + } + inputData.getResource().setContentLength( bytes.length ); + inputData.setInputStream( new ByteArrayInputStream( bytes ) ); + } + + public void put( File source, String resourceName ) + throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException + { + Resource resource = new Resource( resourceName ); + firePutInitiated( resource, source ); + resource.setContentLength( source.length() ); + resource.setLastModified( source.lastModified() ); + OutputStream os = getOutputStream( resource ); + putTransfer( resource, source, os, true ); + } + + protected OutputStream getOutputStream( Resource resource ) + throws TransferFailedException + { + OutputData outputData = new OutputData(); + outputData.setResource( resource ); + try + { + fillOutputData( outputData ); + } + catch ( TransferFailedException e ) + { + fireTransferError( resource, e, TransferEvent.REQUEST_PUT ); + throw e; + } + finally + { + if ( outputData.getOutputStream() == null ) + { + cleanupPutTransfer( resource ); + } + } + + return outputData.getOutputStream(); + } + + protected void fillOutputData( OutputData outputData ) + throws TransferFailedException + { + outputData.setOutputStream( new ByteArrayOutputStream() ); + } + + @Override + protected void finishPutTransfer( Resource resource, InputStream input, OutputStream output ) + throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException + { + String data; + try + { + data = ( (ByteArrayOutputStream) output ).toString( "UTF-8" ); + } + catch ( UnsupportedEncodingException e ) + { + throw new TransferFailedException( e.getMessage(), e ); + } + fs.put( URI.create( resource.getName() ).getSchemeSpecificPart(), data ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/MemWagonUtils.java eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/MemWagonUtils.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/MemWagonUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/MemWagonUtils.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import java.net.URI; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.apache.maven.wagon.ConnectionException; +import org.apache.maven.wagon.Wagon; +import org.apache.maven.wagon.authentication.AuthenticationException; +import org.apache.maven.wagon.authentication.AuthenticationInfo; +import org.apache.maven.wagon.proxy.ProxyInfo; + +/** + */ +class MemWagonUtils +{ + + private static final ConcurrentMap> mounts = + new ConcurrentHashMap>(); + + public static Map getFilesystem( String id ) + { + Map fs = mounts.get( id ); + if ( fs == null ) + { + fs = new ConcurrentHashMap(); + Map prev = mounts.putIfAbsent( id, fs ); + if ( prev != null ) + { + fs = prev; + } + } + return fs; + } + + public static Map openConnection( Wagon wagon, AuthenticationInfo auth, ProxyInfo proxy, + Properties headers ) + throws ConnectionException, AuthenticationException + { + URI uri = URI.create( wagon.getRepository().getUrl() ); + + String query = uri.getQuery(); + if ( query != null ) + { + verify( query, "config", String.valueOf( ( (Configurable) wagon ).getConfiguration() ) ); + + verify( query, "userAgent", ( headers != null ) ? headers.getProperty( "User-Agent" ) : null ); + verify( query, "requestTimeout", Integer.toString( wagon.getTimeout() ) ); + + verify( query, "serverUsername", ( auth != null ) ? auth.getUserName() : null ); + verify( query, "serverPassword", ( auth != null ) ? auth.getPassword() : null ); + verify( query, "serverPrivateKey", ( auth != null ) ? auth.getPrivateKey() : null ); + verify( query, "serverPassphrase", ( auth != null ) ? auth.getPassphrase() : null ); + + verify( query, "proxyHost", ( proxy != null ) ? proxy.getHost() : null ); + verify( query, "proxyPort", ( proxy != null ) ? Integer.toString( proxy.getPort() ) : null ); + verify( query, "proxyUsername", ( proxy != null ) ? proxy.getUserName() : null ); + verify( query, "proxyPassword", ( proxy != null ) ? proxy.getPassword() : null ); + } + + return getFilesystem( uri.getHost() ); + } + + private static void verify( String query, String key, String value ) + throws ConnectionException + { + int index = query.indexOf( key + "=" ); + if ( index < 0 ) + { + return; + } + String expected = query.substring( index + key.length() + 1 ); + index = expected.indexOf( "&" ); + if ( index >= 0 ) + { + expected = expected.substring( 0, index ); + } + + if ( expected.length() == 0 ) + { + if ( value != null ) + { + throw new ConnectionException( "Bad " + key + ": " + value ); + } + } + else if ( !expected.equals( value ) ) + { + throw new ConnectionException( "Bad " + key + ": " + value ); + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/PlexusSupportTest.java eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/PlexusSupportTest.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/PlexusSupportTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/PlexusSupportTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import org.codehaus.plexus.ContainerConfiguration; +import org.codehaus.plexus.PlexusTestCase; +import org.eclipse.aether.internal.test.util.TestLoggerFactory; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.spi.log.LoggerFactory; + +/** + */ +public class PlexusSupportTest + extends PlexusTestCase +{ + + @Override + protected void customizeContainerConfiguration( ContainerConfiguration containerConfiguration ) + { + containerConfiguration.setClassPathScanning( "cache" ); + } + + public void testExistenceOfPlexusComponentMetadata() + throws Exception + { + getContainer().addComponent( new TestLoggerFactory(), LoggerFactory.class, null ); + + TransporterFactory factory = lookup( TransporterFactory.class, "wagon" ); + assertNotNull( factory ); + assertEquals( WagonTransporterFactory.class, factory.getClass() ); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/RecordingTransportListener.java eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/RecordingTransportListener.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/RecordingTransportListener.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/RecordingTransportListener.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; + +import org.eclipse.aether.spi.connector.transport.TransportListener; +import org.eclipse.aether.transfer.TransferCancelledException; + +class RecordingTransportListener + extends TransportListener +{ + + public final ByteArrayOutputStream baos = new ByteArrayOutputStream( 1024 ); + + public long dataOffset; + + public long dataLength; + + public int startedCount; + + public int progressedCount; + + public boolean cancelStart; + + public boolean cancelProgress; + + @Override + public void transportStarted( long dataOffset, long dataLength ) + throws TransferCancelledException + { + startedCount++; + progressedCount = 0; + this.dataLength = dataLength; + this.dataOffset = dataOffset; + baos.reset(); + if ( cancelStart ) + { + throw new TransferCancelledException(); + } + } + + @Override + public void transportProgressed( ByteBuffer data ) + throws TransferCancelledException + { + progressedCount++; + baos.write( data.array(), data.arrayOffset() + data.position(), data.remaining() ); + if ( cancelProgress ) + { + throw new TransferCancelledException(); + } + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/StreamWagonTransporterTest.java eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/StreamWagonTransporterTest.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/StreamWagonTransporterTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/StreamWagonTransporterTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import org.apache.maven.wagon.Wagon; + +/** + */ +public class StreamWagonTransporterTest + extends AbstractWagonTransporterTest +{ + + @Override + protected Wagon newWagon() + { + return new MemStreamWagon(); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/WagonTransporterTest.java eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/WagonTransporterTest.java --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/WagonTransporterTest.java 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/WagonTransporterTest.java 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2013 Sonatype, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sonatype, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.aether.transport.wagon; + +import org.apache.maven.wagon.Wagon; + +/** + */ +public class WagonTransporterTest + extends AbstractWagonTransporterTest +{ + + @Override + protected Wagon newWagon() + { + return new MemWagon(); + } + +} diff -Nru eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/resources/logback-test.xml eclipse-aether-1.0.2/aether-transport-wagon/src/test/resources/logback-test.xml --- eclipse-aether-0.9.0.M2/aether-transport-wagon/src/test/resources/logback-test.xml 1970-01-01 00:00:00.000000000 +0000 +++ eclipse-aether-1.0.2/aether-transport-wagon/src/test/resources/logback-test.xml 2015-01-14 12:56:17.000000000 +0000 @@ -0,0 +1,28 @@ + + + + + + + + %d{HH:mm:ss.SSS} [%-18thread] %c{1} [%p] %m%n + + + + + + + + + + + diff -Nru eclipse-aether-0.9.0.M2/aether-util/pom.xml eclipse-aether-1.0.2/aether-util/pom.xml --- eclipse-aether-0.9.0.M2/aether-util/pom.xml 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/aether-util/pom.xml 2015-01-14 12:56:17.000000000 +0000 @@ -1,7 +1,7 @@ - - + - + -
+ -

Eclipse Public License - v 1.0 -

+

Eclipse Public License - v 1.0

-

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER -THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, -REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE -OF THIS AGREEMENT.

- -

1. DEFINITIONS

- -

"Contribution" means:

- -

a) -in the case of the initial Contributor, the initial code and documentation -distributed under this Agreement, and
-b) in the case of each subsequent Contributor:

- -

i) -changes to the Program, and

- -

ii) -additions to the Program;

- -

where -such changes and/or additions to the Program originate from and are distributed -by that particular Contributor. A Contribution 'originates' from a Contributor -if it was added to the Program by such Contributor itself or anyone acting on -such Contributor's behalf. Contributions do not include additions to the -Program which: (i) are separate modules of software distributed in conjunction -with the Program under their own license agreement, and (ii) are not derivative -works of the Program.

- -

"Contributor" means any person or -entity that distributes the Program.

- -

"Licensed Patents " mean patent -claims licensable by a Contributor which are necessarily infringed by the use -or sale of its Contribution alone or when combined with the Program.

- -

"Program" means the Contributions -distributed in accordance with this Agreement.

- -

"Recipient" means anyone who -receives the Program under this Agreement, including all Contributors.

- -

2. GRANT OF RIGHTS

- -

a) -Subject to the terms of this Agreement, each Contributor hereby grants Recipient -a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly -display, publicly perform, distribute and sublicense the Contribution of such -Contributor, if any, and such derivative works, in source code and object code -form.

- -

b) -Subject to the terms of this Agreement, each Contributor hereby grants -Recipient a non-exclusive, worldwide, royalty-free -patent license under Licensed Patents to make, use, sell, offer to sell, import -and otherwise transfer the Contribution of such Contributor, if any, in source -code and object code form. This patent license shall apply to the combination -of the Contribution and the Program if, at the time the Contribution is added -by the Contributor, such addition of the Contribution causes such combination -to be covered by the Licensed Patents. The patent license shall not apply to -any other combinations which include the Contribution. No hardware per se is -licensed hereunder.

- -

c) -Recipient understands that although each Contributor grants the licenses to its -Contributions set forth herein, no assurances are provided by any Contributor -that the Program does not infringe the patent or other intellectual property -rights of any other entity. Each Contributor disclaims any liability to Recipient -for claims brought by any other entity based on infringement of intellectual -property rights or otherwise. As a condition to exercising the rights and -licenses granted hereunder, each Recipient hereby assumes sole responsibility -to secure any other intellectual property rights needed, if any. For example, -if a third party patent license is required to allow Recipient to distribute -the Program, it is Recipient's responsibility to acquire that license before -distributing the Program.

- -

d) -Each Contributor represents that to its knowledge it has sufficient copyright -rights in its Contribution, if any, to grant the copyright license set forth in -this Agreement.

- -

3. REQUIREMENTS

- -

A Contributor may choose to distribute the -Program in object code form under its own license agreement, provided that: -

- -

a) -it complies with the terms and conditions of this Agreement; and

- -

b) -its license agreement:

- -

i) -effectively disclaims on behalf of all Contributors all warranties and -conditions, express and implied, including warranties or conditions of title -and non-infringement, and implied warranties or conditions of merchantability -and fitness for a particular purpose;

- -

ii) -effectively excludes on behalf of all Contributors all liability for damages, -including direct, indirect, special, incidental and consequential damages, such -as lost profits;

- -

iii) -states that any provisions which differ from this Agreement are offered by that -Contributor alone and not by any other party; and

- -

iv) -states that source code for the Program is available from such Contributor, and -informs licensees how to obtain it in a reasonable manner on or through a -medium customarily used for software exchange.

- -

When the Program is made available in source -code form:

- -

a) -it must be made available under this Agreement; and

- -

b) a -copy of this Agreement must be included with each copy of the Program.

- -

Contributors may not remove or alter any -copyright notices contained within the Program.

- -

Each Contributor must identify itself as the -originator of its Contribution, if any, in a manner that reasonably allows -subsequent Recipients to identify the originator of the Contribution.

- -

4. COMMERCIAL DISTRIBUTION

- -

Commercial distributors of software may -accept certain responsibilities with respect to end users, business partners -and the like. While this license is intended to facilitate the commercial use -of the Program, the Contributor who includes the Program in a commercial -product offering should do so in a manner which does not create potential -liability for other Contributors. Therefore, if a Contributor includes the -Program in a commercial product offering, such Contributor ("Commercial -Contributor") hereby agrees to defend and indemnify every other -Contributor ("Indemnified Contributor") against any losses, damages and -costs (collectively "Losses") arising from claims, lawsuits and other -legal actions brought by a third party against the Indemnified Contributor to -the extent caused by the acts or omissions of such Commercial Contributor in -connection with its distribution of the Program in a commercial product -offering. The obligations in this section do not apply to any claims or Losses -relating to any actual or alleged intellectual property infringement. In order -to qualify, an Indemnified Contributor must: a) promptly notify the Commercial -Contributor in writing of such claim, and b) allow the Commercial Contributor -to control, and cooperate with the Commercial Contributor in, the defense and -any related settlement negotiations. The Indemnified Contributor may participate -in any such claim at its own expense.

- -

For example, a Contributor might include the -Program in a commercial product offering, Product X. That Contributor is then a -Commercial Contributor. If that Commercial Contributor then makes performance -claims, or offers warranties related to Product X, those performance claims and -warranties are such Commercial Contributor's responsibility alone. Under this -section, the Commercial Contributor would have to defend claims against the -other Contributors related to those performance claims and warranties, and if a -court requires any other Contributor to pay any damages as a result, the -Commercial Contributor must pay those damages.

- -

5. NO WARRANTY

- -

EXCEPT AS EXPRESSLY SET FORTH IN THIS -AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT -WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, -WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely -responsible for determining the appropriateness of using and distributing the -Program and assumes all risks associated with its exercise of rights under this -Agreement , including but not limited to the risks and costs of program errors, -compliance with applicable laws, damage to or loss of data, programs or -equipment, and unavailability or interruption of operations.

- -

6. DISCLAIMER OF LIABILITY

- -

EXCEPT AS EXPRESSLY SET FORTH IN THIS -AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY -OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF -THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGES.

- -

7. GENERAL

- -

If any provision of this Agreement is invalid -or unenforceable under applicable law, it shall not affect the validity or -enforceability of the remainder of the terms of this Agreement, and without -further action by the parties hereto, such provision shall be reformed to the -minimum extent necessary to make such provision valid and enforceable.

- -

If Recipient institutes patent litigation -against any entity (including a cross-claim or counterclaim in a lawsuit) -alleging that the Program itself (excluding combinations of the Program with -other software or hardware) infringes such Recipient's patent(s), then such -Recipient's rights granted under Section 2(b) shall terminate as of the date -such litigation is filed.

- -

All Recipient's rights under this Agreement -shall terminate if it fails to comply with any of the material terms or -conditions of this Agreement and does not cure such failure in a reasonable -period of time after becoming aware of such noncompliance. If all Recipient's -rights under this Agreement terminate, Recipient agrees to cease use and +

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE +PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR +DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS +AGREEMENT.

+ +

1. DEFINITIONS

+ +

"Contribution" means:

+ +

a) in the case of the initial Contributor, the initial +code and documentation distributed under this Agreement, and

+

b) in the case of each subsequent Contributor:

+

i) changes to the Program, and

+

ii) additions to the Program;

+

where such changes and/or additions to the Program +originate from and are distributed by that particular Contributor. A +Contribution 'originates' from a Contributor if it was added to the +Program by such Contributor itself or anyone acting on such +Contributor's behalf. Contributions do not include additions to the +Program which: (i) are separate modules of software distributed in +conjunction with the Program under their own license agreement, and (ii) +are not derivative works of the Program.

+ +

"Contributor" means any person or entity that distributes +the Program.

+ +

"Licensed Patents" mean patent claims licensable by a +Contributor which are necessarily infringed by the use or sale of its +Contribution alone or when combined with the Program.

+ +

"Program" means the Contributions distributed in accordance +with this Agreement.

+ +

"Recipient" means anyone who receives the Program under +this Agreement, including all Contributors.

+ +

2. GRANT OF RIGHTS

+ +

a) Subject to the terms of this Agreement, each +Contributor hereby grants Recipient a non-exclusive, worldwide, +royalty-free copyright license to reproduce, prepare derivative works +of, publicly display, publicly perform, distribute and sublicense the +Contribution of such Contributor, if any, and such derivative works, in +source code and object code form.

+ +

b) Subject to the terms of this Agreement, each +Contributor hereby grants Recipient a non-exclusive, worldwide, +royalty-free patent license under Licensed Patents to make, use, sell, +offer to sell, import and otherwise transfer the Contribution of such +Contributor, if any, in source code and object code form. This patent +license shall apply to the combination of the Contribution and the +Program if, at the time the Contribution is added by the Contributor, +such addition of the Contribution causes such combination to be covered +by the Licensed Patents. The patent license shall not apply to any other +combinations which include the Contribution. No hardware per se is +licensed hereunder.

+ +

c) Recipient understands that although each Contributor +grants the licenses to its Contributions set forth herein, no assurances +are provided by any Contributor that the Program does not infringe the +patent or other intellectual property rights of any other entity. Each +Contributor disclaims any liability to Recipient for claims brought by +any other entity based on infringement of intellectual property rights +or otherwise. As a condition to exercising the rights and licenses +granted hereunder, each Recipient hereby assumes sole responsibility to +secure any other intellectual property rights needed, if any. For +example, if a third party patent license is required to allow Recipient +to distribute the Program, it is Recipient's responsibility to acquire +that license before distributing the Program.

+ +

d) Each Contributor represents that to its knowledge it +has sufficient copyright rights in its Contribution, if any, to grant +the copyright license set forth in this Agreement.

+ +

3. REQUIREMENTS

+ +

A Contributor may choose to distribute the Program in object code +form under its own license agreement, provided that:

+ +

a) it complies with the terms and conditions of this +Agreement; and

+ +

b) its license agreement:

+ +

i) effectively disclaims on behalf of all Contributors +all warranties and conditions, express and implied, including warranties +or conditions of title and non-infringement, and implied warranties or +conditions of merchantability and fitness for a particular purpose;

+ +

ii) effectively excludes on behalf of all Contributors +all liability for damages, including direct, indirect, special, +incidental and consequential damages, such as lost profits;

+ +

iii) states that any provisions which differ from this +Agreement are offered by that Contributor alone and not by any other +party; and

+ +

iv) states that source code for the Program is available +from such Contributor, and informs licensees how to obtain it in a +reasonable manner on or through a medium customarily used for software +exchange.

+ +

When the Program is made available in source code form:

+ +

a) it must be made available under this Agreement; and

+ +

b) a copy of this Agreement must be included with each +copy of the Program.

+ +

Contributors may not remove or alter any copyright notices contained +within the Program.

+ +

Each Contributor must identify itself as the originator of its +Contribution, if any, in a manner that reasonably allows subsequent +Recipients to identify the originator of the Contribution.

+ +

4. COMMERCIAL DISTRIBUTION

+ +

Commercial distributors of software may accept certain +responsibilities with respect to end users, business partners and the +like. While this license is intended to facilitate the commercial use of +the Program, the Contributor who includes the Program in a commercial +product offering should do so in a manner which does not create +potential liability for other Contributors. Therefore, if a Contributor +includes the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and +indemnify every other Contributor ("Indemnified Contributor") +against any losses, damages and costs (collectively "Losses") +arising from claims, lawsuits and other legal actions brought by a third +party against the Indemnified Contributor to the extent caused by the +acts or omissions of such Commercial Contributor in connection with its +distribution of the Program in a commercial product offering. The +obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In +order to qualify, an Indemnified Contributor must: a) promptly notify +the Commercial Contributor in writing of such claim, and b) allow the +Commercial Contributor to control, and cooperate with the Commercial +Contributor in, the defense and any related settlement negotiations. The +Indemnified Contributor may participate in any such claim at its own +expense.

+ +

For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those +performance claims and warranties, and if a court requires any other +Contributor to pay any damages as a result, the Commercial Contributor +must pay those damages.

+ +

5. NO WARRANTY

+ +

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS +PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, +ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY +OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely +responsible for determining the appropriateness of using and +distributing the Program and assumes all risks associated with its +exercise of rights under this Agreement , including but not limited to +the risks and costs of program errors, compliance with applicable laws, +damage to or loss of data, programs or equipment, and unavailability or +interruption of operations.

+ +

6. DISCLAIMER OF LIABILITY

+ +

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT +NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING +WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR +DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED +HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

+ +

7. GENERAL

+ +

If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further action +by the parties hereto, such provision shall be reformed to the minimum +extent necessary to make such provision valid and enforceable.

+ +

If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other +software or hardware) infringes such Recipient's patent(s), then such +Recipient's rights granted under Section 2(b) shall terminate as of the +date such litigation is filed.

+ +

All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of time +after becoming aware of such noncompliance. If all Recipient's rights +under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by -Recipient relating to the Program shall continue and survive.

- -

Everyone is permitted to copy and distribute -copies of this Agreement, but in order to avoid inconsistency the Agreement is -copyrighted and may only be modified in the following manner. The Agreement -Steward reserves the right to publish new versions (including revisions) of -this Agreement from time to time. No one other than the Agreement Steward has -the right to modify this Agreement. The Eclipse Foundation is the initial -Agreement Steward. The Eclipse Foundation may assign the responsibility to -serve as the Agreement Steward to a suitable separate entity. Each new version -of the Agreement will be given a distinguishing version number. The Program -(including Contributions) may always be distributed subject to the version of -the Agreement under which it was received. In addition, after a new version of -the Agreement is published, Contributor may elect to distribute the Program -(including its Contributions) under the new version. Except as expressly stated -in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to -the intellectual property of any Contributor under this Agreement, whether -expressly, by implication, estoppel or otherwise. All rights in the Program not -expressly granted under this Agreement are reserved.

- -

This Agreement is governed by the laws of the -State of New York and the intellectual property laws of the United States of -America. No party to this Agreement will bring a legal action under this -Agreement more than one year after the cause of action arose. Each party waives -its rights to a jury trial in any resulting litigation.

- -

 

+Recipient relating to the Program shall continue and survive.

-
+

Everyone is permitted to copy and distribute copies of this +Agreement, but in order to avoid inconsistency the Agreement is +copyrighted and may only be modified in the following manner. The +Agreement Steward reserves the right to publish new versions (including +revisions) of this Agreement from time to time. No one other than the +Agreement Steward has the right to modify this Agreement. The Eclipse +Foundation is the initial Agreement Steward. The Eclipse Foundation may +assign the responsibility to serve as the Agreement Steward to a +suitable separate entity. Each new version of the Agreement will be +given a distinguishing version number. The Program (including +Contributions) may always be distributed subject to the version of the +Agreement under which it was received. In addition, after a new version +of the Agreement is published, Contributor may elect to distribute the +Program (including its Contributions) under the new version. Except as +expressly stated in Sections 2(a) and 2(b) above, Recipient receives no +rights or licenses to the intellectual property of any Contributor under +this Agreement, whether expressly, by implication, estoppel or +otherwise. All rights in the Program not expressly granted under this +Agreement are reserved.

+ +

This Agreement is governed by the laws of the State of New York and +the intellectual property laws of the United States of America. No party +to this Agreement will bring a legal action under this Agreement more +than one year after the cause of action arose. Each party waives its +rights to a jury trial in any resulting litigation.

- \ No newline at end of file + diff -Nru eclipse-aether-0.9.0.M2/notice.html eclipse-aether-1.0.2/notice.html --- eclipse-aether-0.9.0.M2/notice.html 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/notice.html 2015-01-14 12:56:17.000000000 +0000 @@ -1,18 +1,19 @@ - - - - - - + + + + + Eclipse Foundation Software User Agreement - + + +

Eclipse Foundation Software User Agreement

-

February 1, 2011

+

April 9, 2014

Usage Of Content

THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS - (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND + (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND @@ -20,69 +21,40 @@

Applicable Licenses

-

Unless otherwise indicated, all Content made available by the Eclipse - Foundation is provided to you under the terms and conditions of the -Eclipse Public License Version 1.0 - ("EPL"). A copy of the EPL is provided with this Content and is also - available at http://www.eclipse.org/legal/epl-v10.html. - For purposes of the EPL, "Program" will mean the Content.

- -

Content includes, but is not limited to, source code, object code, -documentation and other files maintained in the Eclipse Foundation -source code - repository ("Repository") in software modules ("Modules") and made -available as downloadable archives ("Downloads").

+

Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0 + ("EPL"). A copy of the EPL is provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html. + For purposes of the EPL, "Program" will mean the Content.

+ +

Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code + repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").

    -
  • Content may be structured and packaged into modules to -facilitate delivering, extending, and upgrading the Content. Typical -modules may include plug-ins ("Plug-ins"), plug-in fragments -("Fragments"), and features ("Features").
  • -
  • Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".
  • -
  • A Feature is a bundle of one or more Plug-ins and/or -Fragments and associated material. Each Feature may be packaged as a -sub-directory in a directory named "features". Within a Feature, files -named "feature.xml" may contain a list of the names and version numbers -of the Plug-ins +
  • Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").
  • +
  • Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".
  • +
  • A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named "features". Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins and/or Fragments associated with that Feature.
  • -
  • Features may also include other Features ("Included -Features"). Within a Feature, files named "feature.xml" may contain a -list of the names and version numbers of Included Features.
  • +
  • Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.
-

The terms and conditions governing Plug-ins and Fragments should be -contained in files named "about.html" ("Abouts"). The terms and -conditions governing Features and -Included Features should be contained in files named "license.html" -("Feature Licenses"). Abouts and Feature Licenses may be located in any - directory of a Download or Module +

The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and +Included Features should be contained in files named "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module including, but not limited to the following locations:

  • The top-level (root) directory
  • Plug-in and Fragment directories
  • Inside Plug-ins and Fragments packaged as JARs
  • -
  • Sub-directories of the directory named "src" of certain Plug-ins
  • +
  • Sub-directories of the directory named "src" of certain Plug-ins
  • Feature directories
-

Note: if a Feature made available by the Eclipse Foundation is -installed using the Provisioning Technology (as defined below), you must - agree to a license ("Feature Update License") during the -installation process. If the Feature contains Included Features, the -Feature Update License should either provide you with the terms and -conditions governing the Included Features or -inform you where you can locate them. Feature Update Licenses may be -found in the "license" property of files named "feature.properties" -found within a Feature. -Such Abouts, Feature Licenses, and Feature Update Licenses contain the -terms and conditions (or references to such terms and conditions) that -govern your use of the associated Content in +

Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the +installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or +inform you where you can locate them. Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature. +Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in that directory.

-

THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER -TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. - SOME OF THESE +

THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):

-

IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND -CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, -or Feature Update License is provided, please -contact the Eclipse Foundation to determine what terms and conditions -govern that particular Content.

+

IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please +contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.

Use of Provisioning Technology

-

The Eclipse Foundation makes available provisioning software, -examples of which include, but are not limited to, p2 and the Eclipse - Update Manager ("Provisioning Technology") for the purpose of -allowing users to install software, documentation, information and/or - other materials (collectively "Installable Software"). This -capability is provided with the intent of allowing such users to - install, extend and update Eclipse-based products. Information about -packaging Installable Software is available at http://eclipse.org/equinox/p2/repository_packaging.html - ("Specification").

- -

You may use Provisioning Technology to allow other parties to install - Installable Software. You shall be responsible for enabling the - applicable license agreements relating to the Installable Software to - be presented to, and accepted by, the users of the Provisioning -Technology - in accordance with the Specification. By using Provisioning -Technology in such a manner and making it available in accordance with -the - Specification, you further acknowledge your agreement to, and the -acquisition of all necessary rights to permit the following:

+

The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse + Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or + other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to + install, extend and update Eclipse-based products. Information about packaging Installable Software is available at http://eclipse.org/equinox/p2/repository_packaging.html + ("Specification").

+ +

You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the + applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology + in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the + Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:

    -
  1. A series of actions may occur ("Provisioning Process") in -which a user may execute the Provisioning Technology - on a machine ("Target Machine") with the intent of installing, -extending or updating the functionality of an Eclipse-based +
  2. A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology + on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based product.
  3. -
  4. During the Provisioning Process, the Provisioning Technology -may cause third party Installable Software or a portion thereof to be +
  5. During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be accessed and copied to the Target Machine.
  6. -
  7. Pursuant to the Specification, you will provide to the user -the terms and conditions that govern the use of the Installable - Software ("Installable Software Agreement") and such Installable -Software Agreement shall be accessed from the Target - Machine in accordance with the Specification. Such Installable -Software Agreement must inform the user of the terms and conditions that - govern - the Installable Software and must solicit acceptance by the end -user in the manner prescribed in such Installable Software Agreement. -Upon such - indication of agreement by the user, the provisioning Technology -will complete installation of the Installable Software.
  8. +
  9. Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable + Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target + Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern + the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such + indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.

Cryptography

-

Content may contain encryption software. The country in which you are - currently may have restrictions on the import, possession, and use, -and/or re-export to - another country, of encryption software. BEFORE using any encryption -software, please check the country's laws, regulations and policies -concerning the import, - possession, or use, and re-export of encryption software, to see if -this is permitted.

+

Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to + another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import, + possession, or use, and re-export of encryption software, to see if this is permitted.

Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.

- \ No newline at end of file + + diff -Nru eclipse-aether-0.9.0.M2/pom.xml eclipse-aether-1.0.2/pom.xml --- eclipse-aether-0.9.0.M2/pom.xml 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/pom.xml 2015-01-14 12:56:17.000000000 +0000 @@ -1,7 +1,7 @@ aether-api aether-spi aether-util aether-impl aether-test-util - aether-connector-file - aether-connector-wagon - aether-connector-asynchttpclient + aether-connector-basic + aether-transport-classpath + aether-transport-file + aether-transport-http + aether-transport-wagon + J2SE-1.5 + Eclipse Aether UTF-8 UTF-8 true @@ -155,17 +160,7 @@ org.eclipse.aether - aether-connector-file - ${project.version} - - - org.eclipse.aether - aether-connector-wagon - ${project.version} - - - org.eclipse.aether - aether-connector-asynchttpclient + aether-connector-basic ${project.version} @@ -178,7 +173,19 @@ junit junit - 4.8.2 + 4.11 + test + + + org.hamcrest + hamcrest-core + 1.3 + test + + + org.hamcrest + hamcrest-library + 1.3 test @@ -196,9 +203,36 @@ + org.eclipse.sisu + org.eclipse.sisu.inject + 0.1.1 + + + org.eclipse.sisu + org.eclipse.sisu.plexus + 0.1.1 + + + javax.enterprise + cdi-api + + + + org.sonatype.sisu - sisu-inject-plexus - 2.3.0 + sisu-guice + 3.1.6 + no_aop + + + aopalliance + aopalliance + + + com.google.code.findbugs + jsr305 + + @@ -215,13 +249,16 @@ org.apache.felix maven-bundle-plugin - 2.3.7 + 2.4.0 ${project.url} - ${project.name} (Incubation) + ${project.name} + ${bundle.env} ${bundle.symbolicName} + ${bundle.vendor} ${bundle.osgiVersion} + org.eclipse.aether.internal.*;x-internal:=true,org.eclipse.aether.* @@ -319,6 +356,11 @@ a Restriction: + + provisional + a + Provisional: + @@ -338,6 +380,10 @@ org.eclipse.aether.connector* + Transporters + org.eclipse.aether.transport* + + Implementation org.eclipse.aether.impl* @@ -378,10 +424,11 @@ 2 - ${project.name} Sources (Incubation) + ${project.name} Sources http://www.eclipse.org/legal/epl-v10.html + ${bundle.env} ${bundle.symbolicName}.source - ${project.organization.name} + ${bundle.vendor} ${bundle.osgiVersion} ${bundle.symbolicName};version="${bundle.osgiVersion}";roots:="." @@ -441,9 +488,9 @@ - org.sonatype.plugins + org.eclipse.sisu sisu-maven-plugin - 1.1 + 0.0.0.M2 generate-index @@ -483,39 +530,40 @@ org.eclipse.aether + org.eclipse.sisu + org.eclipse.jetty:*:*:*:test - org.slf4j:slf4j-api:1.6.2 - - junit:junit:4.8.2 + org.slf4j:slf4j-api:[1.6.2] - org.codehaus.plexus:plexus-component-annotations:1.5.5 + org.codehaus.plexus:plexus-component-annotations:[1.5.5] - org.codehaus.plexus:plexus-utils:2.1 + org.codehaus.plexus:plexus-utils:[2.1] - org.codehaus.plexus:plexus-classworlds:2.4 + org.codehaus.plexus:plexus-classworlds:[2.4] - org.apache.maven.wagon:wagon-provider-api:1.0 - - com.ning:async-http-client:1.7.6 - - io.netty:netty:3.4.4.Final - - org.sonatype.sisu:sisu-inject-plexus:2.3.0 + org.apache.maven.wagon:wagon-provider-api:[1.0] - org.sonatype.sisu:sisu-guice:3.1.0 - - org.sonatype.sisu:sisu-guava:0.9.9 + org.sonatype.sisu:sisu-guice:[3.1.6] + + com.google.guava:guava:[11.0.2] - javax.inject:javax.inject:1 - - org.sonatype.sisu:sisu-inject-bean:2.3.0 - - ch.qos.logback:*:*:*:test - org.apache.maven.wagon:wagon-http-lightweight:*:*:test - org.eclipse.jetty:*:*:*:test - org.mortbay.jetty:*:*:*:test - org.sonatype.http-testing-harness:*:*:*:test - javax.servlet:*:*:*:test + javax.inject:javax.inject:[1] + + org.apache.httpcomponents:httpclient:[4.2.6] + + org.apache.httpcomponents:httpcore:[4.2.5] + + commons-codec:commons-codec:[1.6] + + org.slf4j:jcl-over-slf4j:[1.6.2] + + junit:junit:[4.11]:*:test + org.hamcrest:hamcrest-core:[1.3]:*:test + org.hamcrest:hamcrest-library:[1.3]:*:test + com.googlecode.jmockit:jmockit:[1.3]:*:test + ch.qos.logback:logback-core:[1.0.7]:*:test + ch.qos.logback:logback-classic:[1.0.7]:*:test + org.eclipse.jetty.orbit:javax.servlet:[2.5.0.v201103041518]:*:test @@ -707,9 +755,9 @@ - org.sonatype.plugins + org.eclipse.sisu sisu-maven-plugin - [1.1,) + [0.0.0.M2,) test-index main-index @@ -730,15 +778,22 @@ - - true - + + + org.apache.felix + maven-bundle-plugin + + + $(replace;${project.version};-SNAPSHOT;.qualifier) + + + diff -Nru eclipse-aether-0.9.0.M2/README.md eclipse-aether-1.0.2/README.md --- eclipse-aether-0.9.0.M2/README.md 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/README.md 2015-01-14 12:56:17.000000000 +0000 @@ -2,17 +2,6 @@ ======== -Contribution -============ -As required by the Eclipse IP process, all contributions need to be submitted in form of patches attached to a -[Bugzilla entry](https://bugs.eclipse.org/bugs/enter_bug.cgi?product=Aether), thereby being subject to the -[Eclipse Terms of Use](http://www.eclipse.org/legal/termsofuse.php). For clarity, patches should be provided as -standalone files attached to the issue, not as text embedded in the issue description or a comment. - -When submitting patches, please follow the existing code style. The corresponding formatter settings for some IDEs can -be taken from the [Maven Code Style](http://maven.apache.org/developers/committer-environment.html#Maven_Code_Style) -page. - License ======= - [Eclipse Public License, v1.0](http://www.eclipse.org/legal/epl-v10.html) diff -Nru eclipse-aether-0.9.0.M2/src/main/assembly/bin.xml eclipse-aether-1.0.2/src/main/assembly/bin.xml --- eclipse-aether-0.9.0.M2/src/main/assembly/bin.xml 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/src/main/assembly/bin.xml 2015-01-14 12:56:17.000000000 +0000 @@ -1,7 +1,7 @@ - - - - - -
- -

Eclipse Public License - v 1.0 -

- -

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER -THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, -REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE -OF THIS AGREEMENT.

- -

1. DEFINITIONS

- -

"Contribution" means:

- -

a) -in the case of the initial Contributor, the initial code and documentation -distributed under this Agreement, and
-b) in the case of each subsequent Contributor:

- -

i) -changes to the Program, and

- -

ii) -additions to the Program;

- -

where -such changes and/or additions to the Program originate from and are distributed -by that particular Contributor. A Contribution 'originates' from a Contributor -if it was added to the Program by such Contributor itself or anyone acting on -such Contributor's behalf. Contributions do not include additions to the -Program which: (i) are separate modules of software distributed in conjunction -with the Program under their own license agreement, and (ii) are not derivative -works of the Program.

- -

"Contributor" means any person or -entity that distributes the Program.

- -

"Licensed Patents " mean patent -claims licensable by a Contributor which are necessarily infringed by the use -or sale of its Contribution alone or when combined with the Program.

- -

"Program" means the Contributions -distributed in accordance with this Agreement.

- -

"Recipient" means anyone who -receives the Program under this Agreement, including all Contributors.

- -

2. GRANT OF RIGHTS

- -

a) -Subject to the terms of this Agreement, each Contributor hereby grants Recipient -a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly -display, publicly perform, distribute and sublicense the Contribution of such -Contributor, if any, and such derivative works, in source code and object code -form.

- -

b) -Subject to the terms of this Agreement, each Contributor hereby grants -Recipient a non-exclusive, worldwide, royalty-free -patent license under Licensed Patents to make, use, sell, offer to sell, import -and otherwise transfer the Contribution of such Contributor, if any, in source -code and object code form. This patent license shall apply to the combination -of the Contribution and the Program if, at the time the Contribution is added -by the Contributor, such addition of the Contribution causes such combination -to be covered by the Licensed Patents. The patent license shall not apply to -any other combinations which include the Contribution. No hardware per se is -licensed hereunder.

- -

c) -Recipient understands that although each Contributor grants the licenses to its -Contributions set forth herein, no assurances are provided by any Contributor -that the Program does not infringe the patent or other intellectual property -rights of any other entity. Each Contributor disclaims any liability to Recipient -for claims brought by any other entity based on infringement of intellectual -property rights or otherwise. As a condition to exercising the rights and -licenses granted hereunder, each Recipient hereby assumes sole responsibility -to secure any other intellectual property rights needed, if any. For example, -if a third party patent license is required to allow Recipient to distribute -the Program, it is Recipient's responsibility to acquire that license before -distributing the Program.

- -

d) -Each Contributor represents that to its knowledge it has sufficient copyright -rights in its Contribution, if any, to grant the copyright license set forth in -this Agreement.

- -

3. REQUIREMENTS

- -

A Contributor may choose to distribute the -Program in object code form under its own license agreement, provided that: -

- -

a) -it complies with the terms and conditions of this Agreement; and

- -

b) -its license agreement:

- -

i) -effectively disclaims on behalf of all Contributors all warranties and -conditions, express and implied, including warranties or conditions of title -and non-infringement, and implied warranties or conditions of merchantability -and fitness for a particular purpose;

- -

ii) -effectively excludes on behalf of all Contributors all liability for damages, -including direct, indirect, special, incidental and consequential damages, such -as lost profits;

- -

iii) -states that any provisions which differ from this Agreement are offered by that -Contributor alone and not by any other party; and

- -

iv) -states that source code for the Program is available from such Contributor, and -informs licensees how to obtain it in a reasonable manner on or through a -medium customarily used for software exchange.

- -

When the Program is made available in source -code form:

- -

a) -it must be made available under this Agreement; and

- -

b) a -copy of this Agreement must be included with each copy of the Program.

- -

Contributors may not remove or alter any -copyright notices contained within the Program.

- -

Each Contributor must identify itself as the -originator of its Contribution, if any, in a manner that reasonably allows -subsequent Recipients to identify the originator of the Contribution.

- -

4. COMMERCIAL DISTRIBUTION

- -

Commercial distributors of software may -accept certain responsibilities with respect to end users, business partners -and the like. While this license is intended to facilitate the commercial use -of the Program, the Contributor who includes the Program in a commercial -product offering should do so in a manner which does not create potential -liability for other Contributors. Therefore, if a Contributor includes the -Program in a commercial product offering, such Contributor ("Commercial -Contributor") hereby agrees to defend and indemnify every other -Contributor ("Indemnified Contributor") against any losses, damages and -costs (collectively "Losses") arising from claims, lawsuits and other -legal actions brought by a third party against the Indemnified Contributor to -the extent caused by the acts or omissions of such Commercial Contributor in -connection with its distribution of the Program in a commercial product -offering. The obligations in this section do not apply to any claims or Losses -relating to any actual or alleged intellectual property infringement. In order -to qualify, an Indemnified Contributor must: a) promptly notify the Commercial -Contributor in writing of such claim, and b) allow the Commercial Contributor -to control, and cooperate with the Commercial Contributor in, the defense and -any related settlement negotiations. The Indemnified Contributor may participate -in any such claim at its own expense.

- -

For example, a Contributor might include the -Program in a commercial product offering, Product X. That Contributor is then a -Commercial Contributor. If that Commercial Contributor then makes performance -claims, or offers warranties related to Product X, those performance claims and -warranties are such Commercial Contributor's responsibility alone. Under this -section, the Commercial Contributor would have to defend claims against the -other Contributors related to those performance claims and warranties, and if a -court requires any other Contributor to pay any damages as a result, the -Commercial Contributor must pay those damages.

- -

5. NO WARRANTY

- -

EXCEPT AS EXPRESSLY SET FORTH IN THIS -AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT -WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, -WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely -responsible for determining the appropriateness of using and distributing the -Program and assumes all risks associated with its exercise of rights under this -Agreement , including but not limited to the risks and costs of program errors, -compliance with applicable laws, damage to or loss of data, programs or -equipment, and unavailability or interruption of operations.

- -

6. DISCLAIMER OF LIABILITY

- -

EXCEPT AS EXPRESSLY SET FORTH IN THIS -AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY -OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF -THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGES.

- -

7. GENERAL

- -

If any provision of this Agreement is invalid -or unenforceable under applicable law, it shall not affect the validity or -enforceability of the remainder of the terms of this Agreement, and without -further action by the parties hereto, such provision shall be reformed to the -minimum extent necessary to make such provision valid and enforceable.

- -

If Recipient institutes patent litigation -against any entity (including a cross-claim or counterclaim in a lawsuit) -alleging that the Program itself (excluding combinations of the Program with -other software or hardware) infringes such Recipient's patent(s), then such -Recipient's rights granted under Section 2(b) shall terminate as of the date -such litigation is filed.

- -

All Recipient's rights under this Agreement -shall terminate if it fails to comply with any of the material terms or -conditions of this Agreement and does not cure such failure in a reasonable -period of time after becoming aware of such noncompliance. If all Recipient's -rights under this Agreement terminate, Recipient agrees to cease use and -distribution of the Program as soon as reasonably practicable. However, -Recipient's obligations under this Agreement and any licenses granted by -Recipient relating to the Program shall continue and survive.

- -

Everyone is permitted to copy and distribute -copies of this Agreement, but in order to avoid inconsistency the Agreement is -copyrighted and may only be modified in the following manner. The Agreement -Steward reserves the right to publish new versions (including revisions) of -this Agreement from time to time. No one other than the Agreement Steward has -the right to modify this Agreement. The Eclipse Foundation is the initial -Agreement Steward. The Eclipse Foundation may assign the responsibility to -serve as the Agreement Steward to a suitable separate entity. Each new version -of the Agreement will be given a distinguishing version number. The Program -(including Contributions) may always be distributed subject to the version of -the Agreement under which it was received. In addition, after a new version of -the Agreement is published, Contributor may elect to distribute the Program -(including its Contributions) under the new version. Except as expressly stated -in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to -the intellectual property of any Contributor under this Agreement, whether -expressly, by implication, estoppel or otherwise. All rights in the Program not -expressly granted under this Agreement are reserved.

- -

This Agreement is governed by the laws of the -State of New York and the intellectual property laws of the United States of -America. No party to this Agreement will bring a legal action under this -Agreement more than one year after the cause of action arose. Each party waives -its rights to a jury trial in any resulting litigation.

- -

 

- -
- - - - \ No newline at end of file diff -Nru eclipse-aether-0.9.0.M2/src/main/assembly/resources/notice.html eclipse-aether-1.0.2/src/main/assembly/resources/notice.html --- eclipse-aether-0.9.0.M2/src/main/assembly/resources/notice.html 2013-02-16 19:52:37.000000000 +0000 +++ eclipse-aether-1.0.2/src/main/assembly/resources/notice.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,162 +0,0 @@ - - - - - - -Eclipse Foundation Software User Agreement - -

Eclipse Foundation Software User Agreement

-

February 1, 2011

- -

Usage Of Content

- -

THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS - (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND - CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE - OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR - NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND - CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.

- -

Applicable Licenses

- -

Unless otherwise indicated, all Content made available by the Eclipse - Foundation is provided to you under the terms and conditions of the -Eclipse Public License Version 1.0 - ("EPL"). A copy of the EPL is provided with this Content and is also - available at http://www.eclipse.org/legal/epl-v10.html. - For purposes of the EPL, "Program" will mean the Content.

- -

Content includes, but is not limited to, source code, object code, -documentation and other files maintained in the Eclipse Foundation -source code - repository ("Repository") in software modules ("Modules") and made -available as downloadable archives ("Downloads").

- -
    -
  • Content may be structured and packaged into modules to -facilitate delivering, extending, and upgrading the Content. Typical -modules may include plug-ins ("Plug-ins"), plug-in fragments -("Fragments"), and features ("Features").
  • -
  • Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".
  • -
  • A Feature is a bundle of one or more Plug-ins and/or -Fragments and associated material. Each Feature may be packaged as a -sub-directory in a directory named "features". Within a Feature, files -named "feature.xml" may contain a list of the names and version numbers -of the Plug-ins - and/or Fragments associated with that Feature.
  • -
  • Features may also include other Features ("Included -Features"). Within a Feature, files named "feature.xml" may contain a -list of the names and version numbers of Included Features.
  • -
- -

The terms and conditions governing Plug-ins and Fragments should be -contained in files named "about.html" ("Abouts"). The terms and -conditions governing Features and -Included Features should be contained in files named "license.html" -("Feature Licenses"). Abouts and Feature Licenses may be located in any - directory of a Download or Module -including, but not limited to the following locations:

- -
    -
  • The top-level (root) directory
  • -
  • Plug-in and Fragment directories
  • -
  • Inside Plug-ins and Fragments packaged as JARs
  • -
  • Sub-directories of the directory named "src" of certain Plug-ins
  • -
  • Feature directories
  • -
- -

Note: if a Feature made available by the Eclipse Foundation is -installed using the Provisioning Technology (as defined below), you must - agree to a license ("Feature Update License") during the -installation process. If the Feature contains Included Features, the -Feature Update License should either provide you with the terms and -conditions governing the Included Features or -inform you where you can locate them. Feature Update Licenses may be -found in the "license" property of files named "feature.properties" -found within a Feature. -Such Abouts, Feature Licenses, and Feature Update Licenses contain the -terms and conditions (or references to such terms and conditions) that -govern your use of the associated Content in -that directory.

- -

THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER -TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. - SOME OF THESE -OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):

- - - -

IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND -CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, -or Feature Update License is provided, please -contact the Eclipse Foundation to determine what terms and conditions -govern that particular Content.

- - -

Use of Provisioning Technology

- -

The Eclipse Foundation makes available provisioning software, -examples of which include, but are not limited to, p2 and the Eclipse - Update Manager ("Provisioning Technology") for the purpose of -allowing users to install software, documentation, information and/or - other materials (collectively "Installable Software"). This -capability is provided with the intent of allowing such users to - install, extend and update Eclipse-based products. Information about -packaging Installable Software is available at http://eclipse.org/equinox/p2/repository_packaging.html - ("Specification").

- -

You may use Provisioning Technology to allow other parties to install - Installable Software. You shall be responsible for enabling the - applicable license agreements relating to the Installable Software to - be presented to, and accepted by, the users of the Provisioning -Technology - in accordance with the Specification. By using Provisioning -Technology in such a manner and making it available in accordance with -the - Specification, you further acknowledge your agreement to, and the -acquisition of all necessary rights to permit the following:

- -
    -
  1. A series of actions may occur ("Provisioning Process") in -which a user may execute the Provisioning Technology - on a machine ("Target Machine") with the intent of installing, -extending or updating the functionality of an Eclipse-based - product.
  2. -
  3. During the Provisioning Process, the Provisioning Technology -may cause third party Installable Software or a portion thereof to be - accessed and copied to the Target Machine.
  4. -
  5. Pursuant to the Specification, you will provide to the user -the terms and conditions that govern the use of the Installable - Software ("Installable Software Agreement") and such Installable -Software Agreement shall be accessed from the Target - Machine in accordance with the Specification. Such Installable -Software Agreement must inform the user of the terms and conditions that - govern - the Installable Software and must solicit acceptance by the end -user in the manner prescribed in such Installable Software Agreement. -Upon such - indication of agreement by the user, the provisioning Technology -will complete installation of the Installable Software.
  6. -
- -

Cryptography

- -

Content may contain encryption software. The country in which you are - currently may have restrictions on the import, possession, and use, -and/or re-export to - another country, of encryption software. BEFORE using any encryption -software, please check the country's laws, regulations and policies -concerning the import, - possession, or use, and re-export of encryption software, to see if -this is permitted.

- -

Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.

- \ No newline at end of file