/*
* Copyright 2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazonaws.services.s3.transfer;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.model.ProgressListener;
import com.amazonaws.services.s3.transfer.internal.ProgressListenerChain;
/**
* Represents an asynchronous upload to or download from Amazon S3.
* Use this class to check a tranfer's progress,
* add listeners for progress events,
* check the state of a transfer,
* or wait for the transfer to complete.
* <p>
* See {@link TransferManager} for more information about creating transfers.
*
* @see TransferManager#upload(String, String, java.io.File)
* @see TransferManager#upload(com.amazonaws.services.s3.model.PutObjectRequest)
*/
public abstract class Transfer {
/**
* Enumeration of the possible transfer states.
*/
public static enum TransferState {
/** The transfer is waiting for resources to execute and has not started yet. */
Waiting,
/** The transfer is actively uploading or downloading and hasn't finished yet. */
InProgress,
/** The transfer completed successfully. */
Completed,
/** The transfer was canceled and did not complete successfully. */
Canceled,
/** The transfer failed. */
Failed;
}
/** The current state of this transfer. */
protected volatile TransferState state = TransferState.Waiting;
/** The progress of this transfer. */
private final TransferProgress transferProgress;
private final String description;
/** The private resources executing this transfer. */
protected volatile Future<?> future;
/** Hook for adding/removing more progress listeners. */
protected ProgressListenerChain progressListenerChain;
Transfer(String description, TransferProgress transferProgress, ProgressListenerChain progressListenerChain) {
this.description = description;
this.progressListenerChain = progressListenerChain;
this.transferProgress = transferProgress;
}
/**
* Returns whether or not the transfer is finished (i.e. completed successfully,
* failed, or was canceled).
*
* @return Returns <code>true</code> if this transfer is finished (i.e. completed successfully,
* failed, or was canceled). Returns <code>false</code> if otherwise.
*/
public synchronized boolean isDone() {
return (state == TransferState.Failed ||
state == TransferState.Completed ||
state == TransferState.Canceled);
}
/**
* Waits for this transfer to complete. This is a blocking call; the current
* thread is suspended until this transfer completes.
*
* @throws AmazonClientException
* If any errors were encountered in the client while making the
* request or handling the response.
* @throws AmazonServiceException
* If any errors occurred in Amazon S3 while processing the
* request.
* @throws InterruptedException
* If this thread is interrupted while waiting for the transfer
* to complete.
*/
public void waitForCompletion()
throws AmazonClientException, AmazonServiceException, InterruptedException {
try {
future.get();
} catch (ExecutionException e) {
rethrowExecutionException(e);
}
}
/**
* Waits for this transfer to finish and returns any error that occurred, or
* returns <code>null</code> if no errors occurred.
* This is a blocking call; the current thread
* will be suspended until this transfer either fails or completes
* successfully.
*
* @return Any error that occurred while processing this transfer.
* Otherwise returns <code>null</code> if no errors occurred.
*
* @throws InterruptedException
* If this thread is interrupted while waiting for the transfer
* to complete.
*/
public AmazonClientException waitForException() throws InterruptedException {
try {
future.get();
return null;
} catch (ExecutionException e) {
return unwrapExecutionException(e);
}
}
/**
* Returns a human-readable description of this transfer.
*
* @return A human-readable description of this transfer.
*/
public String getDescription() {
return description;
}
/**
* Returns the current state of this transfer.
*
* @return The current state of this transfer.
*/
public synchronized TransferState getState() {
return state;
}
/**
* Adds the specified progress listener to the list of listeners
* receiving updates about this transfer's progress.
*
* @param listener
* The progress listener to add.
*/
public synchronized void addProgressListener(ProgressListener listener) {
progressListenerChain.addProgressListener(listener);
}
/**
* Removes the specified progress listener from the list of progress
* listeners receiving updates about this transfer's progress.
*
* @param listener
* The progress listener to remove.
*/
public synchronized void removeProgressListener(ProgressListener listener) {
progressListenerChain.removeProgressListener(listener);
}
/**
* Returns progress information about this transfer.
*
* @return The progress information about this transfer.
*/
public TransferProgress getProgress() {
return transferProgress;
}
/*
* Non-Public Interface
*/
/**
* Examines the cause of the specified ExecutionException and either
* rethrows it directly (if it's a type of AmazonClientException) or wraps
* it in an AmazonClientException and rethrows it.
*
* @param e
* The execution exception to examine.
*/
protected void rethrowExecutionException(ExecutionException e) {
throw unwrapExecutionException(e);
}
/**
* Unwraps the root exception that caused the specified ExecutionException
* and returns it. If it was not an instance of AmazonClientException, it is
* wrapped as an AmazonClientException.
*
* @param e
* The ExecutionException to unwrap.
*
* @return The root exception that caused the specified ExecutionException.
*/
protected AmazonClientException unwrapExecutionException(ExecutionException e) {
Throwable t = e.getCause();
if (t instanceof AmazonClientException) return (AmazonClientException)t;
return new AmazonClientException("Unable to complete transfer: " + t.getMessage(), t);
}
}