/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gradle.api.publication.maven.internal.wagon;
import org.apache.maven.wagon.ConnectionException;
import org.apache.maven.wagon.ResourceDoesNotExistException;
import org.apache.maven.wagon.TransferFailedException;
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.authorization.AuthorizationException;
import org.apache.maven.wagon.events.*;
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.resource.Resource;
import org.gradle.api.GradleException;
import org.gradle.internal.resource.local.FileLocalResource;
import org.gradle.internal.resource.local.LocalResource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import static org.apache.maven.wagon.events.SessionEvent.*;
import static org.apache.maven.wagon.events.TransferEvent.*;
/**
* A maven wagon intended to work with {@link org.apache.maven.artifact.manager.DefaultWagonManager} Maven uses reflection to initialize instances of this wagon see: {@link
* org.codehaus.plexus.component.factory.java.JavaComponentFactory#newInstance(org.codehaus.plexus.component.repository.ComponentDescriptor, org.codehaus.classworlds.ClassRealm,
* org.codehaus.plexus.PlexusContainer)}
*/
public class RepositoryTransportDeployWagon implements Wagon {
private static final ThreadLocal<RepositoryTransportWagonAdapter> CURRENT_DELEGATE = new InheritableThreadLocal<RepositoryTransportWagonAdapter>();
private SessionEventSupport sessionEventSupport = new SessionEventSupport();
private TransferEventSupport transferEventSupport = new TransferEventSupport();
private Repository mutatingRepository;
public static void contextualize(RepositoryTransportWagonAdapter adapter) {
CURRENT_DELEGATE.set(adapter);
}
public static void decontextualize() {
CURRENT_DELEGATE.remove();
}
@Override
public final void get(String resourceName, File destination) throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException {
Resource resource = new Resource(resourceName);
this.transferEventSupport.fireTransferInitiated(transferEvent(resource, TRANSFER_INITIATED, REQUEST_GET));
this.transferEventSupport.fireTransferStarted(transferEvent(resource, TRANSFER_STARTED, REQUEST_GET));
try {
if (!destination.exists()) {
destination.getParentFile().mkdirs();
destination.createNewFile();
}
if (!getDelegate().getRemoteFile(destination, resourceName)) {
throw new ResourceDoesNotExistException(String.format("Resource '%s' does not exist", resourceName));
}
this.transferEventSupport.fireTransferCompleted(transferEvent(resource, TRANSFER_COMPLETED, REQUEST_GET));
} catch (ResourceDoesNotExistException e) {
this.transferEventSupport.fireTransferError(transferEvent(resource, e, REQUEST_GET));
throw e;
} catch (Exception e) {
this.transferEventSupport.fireTransferError(transferEvent(resource, e, REQUEST_GET));
throw new TransferFailedException(String.format("Could not get resource '%s'", resourceName), e);
}
}
@Override
public final void put(File file, String resourceName) throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException {
Resource resource = new Resource(resourceName);
this.transferEventSupport.fireTransferInitiated(transferEvent(resource, TRANSFER_INITIATED, REQUEST_PUT));
try {
LocalResource localResource = new MavenTransferLoggingFileResource(file, resource);
getDelegate().putRemoteFile(localResource, resourceName);
} catch (Exception e) {
this.transferEventSupport.fireTransferError(transferEvent(resource, e, REQUEST_PUT));
throw new TransferFailedException(String.format("Could not write to resource '%s'", resourceName), e);
}
this.transferEventSupport.fireTransferCompleted(transferEvent(resource, TRANSFER_COMPLETED, REQUEST_PUT));
}
private RepositoryTransportWagonAdapter getDelegate() {
return CURRENT_DELEGATE.get();
}
@Override
public final boolean resourceExists(String resourceName) throws TransferFailedException, AuthorizationException {
throwNotImplemented("getIfNewer(String resourceName, File file, long timestamp)");
return false;
}
@Override
public final boolean getIfNewer(String resourceName, File file, long timestamp) throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException {
throwNotImplemented("getIfNewer(String resourceName, File file, long timestamp)");
return false;
}
@Override
public final void putDirectory(File file, String resourceName) throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException {
throwNotImplemented("putDirectory(File file, String resourceName)");
}
@Override
public final List getFileList(String resourceName) throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException {
throwNotImplemented("getFileList(String resourceName)");
return null;
}
@Override
public final boolean supportsDirectoryCopy() {
return false;
}
@Override
public final Repository getRepository() {
return this.mutatingRepository;
}
@Override
public final void openConnection() throws ConnectionException, AuthenticationException {
}
@Override
public final void connect(Repository repository) throws ConnectionException, AuthenticationException {
this.mutatingRepository = repository;
this.sessionEventSupport.fireSessionLoggedIn(sessionEvent(SESSION_LOGGED_IN));
this.sessionEventSupport.fireSessionOpened(sessionEvent(SESSION_OPENED));
}
@Override
public final void connect(Repository repository, ProxyInfo proxyInfo) throws ConnectionException, AuthenticationException {
connect(repository);
}
@Override
public final void connect(Repository repository, ProxyInfoProvider proxyInfoProvider) throws ConnectionException, AuthenticationException {
connect(repository);
}
@Override
public final void connect(Repository repository, AuthenticationInfo authenticationInfo) throws ConnectionException, AuthenticationException {
connect(repository);
}
@Override
public final void connect(Repository repository, AuthenticationInfo authenticationInfo, ProxyInfo proxyInfo) throws ConnectionException, AuthenticationException {
connect(repository);
}
@Override
public final void connect(Repository repository, AuthenticationInfo authenticationInfo, ProxyInfoProvider proxyInfoProvider) throws ConnectionException, AuthenticationException {
connect(repository);
}
@Override
public final void disconnect() throws ConnectionException {
this.sessionEventSupport.fireSessionDisconnecting(sessionEvent(SESSION_DISCONNECTING));
this.sessionEventSupport.fireSessionLoggedOff(sessionEvent(SESSION_LOGGED_OFF));
this.sessionEventSupport.fireSessionDisconnected(sessionEvent(SESSION_LOGGED_OFF));
}
@Override
public final void addSessionListener(SessionListener sessionListener) {
this.sessionEventSupport.addSessionListener(sessionListener);
}
@Override
public final void removeSessionListener(SessionListener sessionListener) {
this.sessionEventSupport.removeSessionListener(sessionListener);
}
@Override
public final boolean hasSessionListener(SessionListener sessionListener) {
return this.sessionEventSupport.hasSessionListener(sessionListener);
}
@Override
public final void addTransferListener(TransferListener transferListener) {
this.transferEventSupport.addTransferListener(transferListener);
}
@Override
public final void removeTransferListener(TransferListener transferListener) {
this.transferEventSupport.removeTransferListener(transferListener);
}
@Override
public final boolean hasTransferListener(TransferListener transferListener) {
return this.transferEventSupport.hasTransferListener(transferListener);
}
@Override
public final boolean isInteractive() {
return false;
}
@Override
public final void setInteractive(boolean b) {
}
@Override
public final void setTimeout(int i) {
}
@Override
public final int getTimeout() {
return 0;
}
@Override
public final void setReadTimeout(int i) {
}
@Override
public final int getReadTimeout() {
return 0;
}
private SessionEvent sessionEvent(int e) {
return new SessionEvent(this, e);
}
private void throwNotImplemented(String s) {
throw new GradleException("This wagon does not yet support the method:" + s);
}
private TransferEvent transferEvent(Resource resource, int eventType, int requestType) {
TransferEvent transferEvent = new TransferEvent(this, resource, eventType, requestType);
transferEvent.setTimestamp(new Date().getTime());
return transferEvent;
}
private TransferEvent transferEvent(Resource resource, Exception e, int requestType) {
return new TransferEvent(this, resource, e, requestType);
}
private class MavenTransferLoggingFileResource extends FileLocalResource {
private final Resource resource;
private MavenTransferLoggingFileResource(File file, Resource resource) {
super(file);
this.resource = resource;
}
@Override
public InputStream open() {
// Need to do this here, so that the transfer is 'restarted' when HttpClient reopens the resource (DIGEST AUTH only)
transferEventSupport.fireTransferStarted(transferEvent(resource, TRANSFER_STARTED, REQUEST_PUT));
return new ObservingInputStream(super.open(), resource);
}
protected class ObservingInputStream extends InputStream {
private final InputStream inputStream;
private final TransferEvent transferEvent;
private final byte[] singleByteBuffer = new byte[1];
public ObservingInputStream(InputStream inputStream, Resource resource) {
this.inputStream = inputStream;
this.transferEvent = transferEvent(resource, TransferEvent.TRANSFER_PROGRESS, REQUEST_PUT);
}
@Override
public void close() throws IOException {
inputStream.close();
}
@Override
public int read() throws IOException {
int result = inputStream.read();
if (result >= 0) {
singleByteBuffer[0] = (byte) result;
logTransfer(singleByteBuffer, 1);
}
return result;
}
public int read(byte[] b, int off, int len) throws IOException {
int read = inputStream.read(b, off, len);
if (read > 0) {
logTransfer(b, read);
}
return read;
}
private void logTransfer(byte[] bytes, int read) {
transferEventSupport.fireTransferProgress(transferEvent, bytes, read);
}
}
}
}