blob: 67af4eb05626d0c1d203d9d0c0a57941ae444c92 [file] [log] [blame]
/****************************************************************************
* Copyright (c) 2004, 2010 Composent, Inc. and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Composent, Inc. - initial API and implementation
* Benjamin Cabe <benjamin.cabe@anyware-tech.com> - bug 220258
* Henrich Kraemer - bug 295030, Update Manager doesn't work with SOCKS proxy
*
* SPDX-License-Identifier: EPL-2.0
*****************************************************************************/
package org.eclipse.ecf.provider.filetransfer.retrieve;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.Map;
import org.eclipse.core.net.proxy.IProxyData;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdapterManager;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.ecf.core.identity.ID;
import org.eclipse.ecf.core.identity.IDFactory;
import org.eclipse.ecf.core.identity.Namespace;
import org.eclipse.ecf.core.security.IConnectContext;
import org.eclipse.ecf.core.util.Proxy;
import org.eclipse.ecf.filetransfer.FileTransferJob;
import org.eclipse.ecf.filetransfer.IFileRangeSpecification;
import org.eclipse.ecf.filetransfer.IFileTransferListener;
import org.eclipse.ecf.filetransfer.IFileTransferPausable;
import org.eclipse.ecf.filetransfer.IFileTransferRunnable;
import org.eclipse.ecf.filetransfer.IIncomingFileTransfer;
import org.eclipse.ecf.filetransfer.IRetrieveFileTransferOptions;
import org.eclipse.ecf.filetransfer.IncomingFileTransferException;
import org.eclipse.ecf.filetransfer.UserCancelledException;
import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveDataEvent;
import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveDoneEvent;
import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceivePausedEvent;
import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveResumedEvent;
import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveStartEvent;
import org.eclipse.ecf.filetransfer.identity.IFileID;
import org.eclipse.ecf.filetransfer.service.IRetrieveFileTransfer;
import org.eclipse.ecf.internal.provider.filetransfer.Activator;
import org.eclipse.ecf.internal.provider.filetransfer.Messages;
import org.eclipse.ecf.provider.filetransfer.identity.FileTransferNamespace;
import org.eclipse.ecf.provider.filetransfer.util.PollingInputStream;
import org.eclipse.ecf.provider.filetransfer.util.ProxySetupHelper;
import org.eclipse.ecf.provider.filetransfer.util.TimeoutInputStream;
import org.eclipse.osgi.util.NLS;
public abstract class AbstractRetrieveFileTransfer implements IIncomingFileTransfer, IRetrieveFileTransfer, IFileTransferPausable {
public static final int DEFAULT_BUF_LENGTH = 4096;
protected static final int POLLING_RETRY_ATTEMPTS = Integer.parseInt(System.getProperty("org.eclipse.ecf.provider.filetransfer.retrieve.retryAttempts", "30")); //$NON-NLS-1$ //$NON-NLS-2$;;
protected static final int TIMEOUT_INPUTSTREAM_BUFFER_SIZE = 8192;
protected static final int READ_TIMEOUT = Integer.parseInt(System.getProperty("org.eclipse.ecf.provider.filetransfer.retrieve.readTimeout", "1000")); //$NON-NLS-1$ //$NON-NLS-2$;
protected static final int CLOSE_TIMEOUT = Integer.parseInt(System.getProperty("org.eclipse.ecf.provider.filetransfer.retrieve.closeTimeout", "1000")); //$NON-NLS-1$ //$NON-NLS-2$;
private static final String readTimeoutMessage = "Timeout while reading input stream.\n" + //$NON-NLS-1$
"The following system properties can be used to adjust the readTimeout, retryAttempts, and closeTimeout\n" + //$NON-NLS-1$
"\torg.eclipse.ecf.provider.filetransfer.retrieve.readTimeout=<default:1000>\n" + //$NON-NLS-1$
"\torg.eclipse.ecf.provider.filetransfer.retrieve.retryAttempts=<default:30>\n" + //$NON-NLS-1$
"\torg.eclipse.ecf.provider.filetransfer.retrieve.closeTimeout=<default:1000>\n"; //$NON-NLS-1$
private static final String closeTimeoutMessage = "Timeout while closing input stream.\n" + //$NON-NLS-1$
"The following system properties can be used to adjust the readTimeout, retryAttempts, and closeTimeout\n" + //$NON-NLS-1$
"\torg.eclipse.ecf.provider.filetransfer.retrieve.readTimeout=<default:1000>\n" + //$NON-NLS-1$
"\torg.eclipse.ecf.provider.filetransfer.retrieve.retryAttempts=<default:30>\n" + //$NON-NLS-1$
"\torg.eclipse.ecf.provider.filetransfer.retrieve.closeTimeout=<default:1000>\n"; //$NON-NLS-1$
protected Object jobLock = new Object();
protected Job job;
protected URL remoteFileURL;
protected IFileID remoteFileID;
protected IFileTransferListener listener;
protected int buff_length = DEFAULT_BUF_LENGTH;
protected boolean done = false;
protected volatile long bytesReceived = 0;
protected InputStream remoteFileContents;
protected OutputStream localFileContents;
protected boolean closeOutputStream = true;
protected Exception exception;
protected long fileLength = -1;
protected long lastModifiedTime = 0L;
protected Map options = null;
protected boolean paused = false;
protected IFileRangeSpecification rangeSpecification = null;
protected Proxy proxy;
protected IConnectContext connectContext;
protected long transferStartTime;
protected double downloadRateBytesPerSecond = 0L;
/**
* @since 3.1
*/
protected Map responseHeaders;
public AbstractRetrieveFileTransfer() {
//
}
protected InputStream wrapTransferReadInputStream(InputStream inputStream, IProgressMonitor monitor) {
return new PollingInputStream(inputStream, getRetryAttempts(), monitor, readTimeoutMessage, closeTimeoutMessage);
}
private int getRetryAttempts() {
int result = POLLING_RETRY_ATTEMPTS;
Map localOptions = getOptions();
if (localOptions != null) {
// See if the property is present, if so set
Object o = localOptions.get("org.eclipse.ecf.provider.filetransfer.retrieve.retryAttempts"); //$NON-NLS-1$
if (o != null) {
if (o instanceof Integer) {
result = ((Integer) o).intValue();
} else if (o instanceof String) {
result = Integer.parseInt(((String) o));
}
}
}
return result;
}
private IFileTransferRunnable fileTransferRunnable = new IFileTransferRunnable() {
public IStatus performFileTransfer(IProgressMonitor monitor) {
transferStartTime = System.currentTimeMillis();
final byte[] buf = new byte[buff_length];
final long totalWork = ((fileLength == -1) ? 100 : fileLength);
double factor = (totalWork > Integer.MAX_VALUE) ? (((double) Integer.MAX_VALUE) / ((double) totalWork)) : 1.0;
int work = (totalWork > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) totalWork;
monitor.beginTask(getRemoteFileURL().toString() + Messages.AbstractRetrieveFileTransfer_Progress_Data, work);
InputStream readInputStream = null;
try {
// We will test for remoteFileContents is null...if it is null then we can't continue.
// See bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=425868
if (remoteFileContents == null)
throw new IOException("input stream cannot be null"); //$NON-NLS-1$
// Create read input stream
readInputStream = wrapTransferReadInputStream(remoteFileContents, monitor);
while (!isDone() && !isPaused()) {
try {
final int bytes = readInputStream.read(buf);
handleReceivedData(buf, bytes, factor, monitor);
} catch (OperationCanceledException e) {
throw new UserCancelledException(Messages.AbstractRetrieveFileTransfer_Exception_User_Cancelled);
}
}
} catch (final Exception e) {
if (!isDone()) {
setDoneException(e);
}
} finally {
try {
if (readInputStream != null)
readInputStream.close();
} catch (final IOException e) {
Activator a = Activator.getDefault();
if (a != null)
a.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, "hardClose", e)); //$NON-NLS-1$
}
hardClose();
monitor.done();
try {
if (isPaused())
fireTransferReceivePausedEvent();
else
fireTransferReceiveDoneEvent();
} catch (Exception e) {
// simply log
Activator a = Activator.getDefault();
if (a != null)
a.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, Messages.AbstractRetrieveFileTransfer_EXCEPTION_IN_FINALLY, e));
}
}
return getFinalStatus(exception);
}
};
protected URL getRemoteFileURL() {
return remoteFileURL;
}
protected int getSocketReadTimeout() {
int result = READ_TIMEOUT;
Map localOptions = getOptions();
if (localOptions != null) {
// See if the connect timeout option is present, if so set
Object o = localOptions.get(IRetrieveFileTransferOptions.READ_TIMEOUT);
if (o != null) {
if (o instanceof Integer) {
result = ((Integer) o).intValue();
} else if (o instanceof String) {
result = Integer.parseInt(((String) o));
}
return result;
}
o = localOptions.get("org.eclipse.ecf.provider.filetransfer.httpclient.retrieve.readTimeout"); //$NON-NLS-1$
if (o != null) {
if (o instanceof Integer) {
result = ((Integer) o).intValue();
} else if (o instanceof String) {
result = Integer.parseInt(((String) o));
}
}
}
return result;
}
protected int getSocketCloseTimeout() {
int result = CLOSE_TIMEOUT;
Map localOptions = getOptions();
if (localOptions != null) {
// See if the property is present, if so set
Object o = localOptions.get("org.eclipse.ecf.provider.filetransfer.retrieve.closeTimeout"); //$NON-NLS-1$
if (o != null) {
if (o instanceof Integer) {
result = ((Integer) o).intValue();
} else if (o instanceof String) {
result = Integer.parseInt(((String) o));
}
}
}
return result;
}
protected void setInputStream(InputStream ins) {
remoteFileContents = new TimeoutInputStream(ins, TIMEOUT_INPUTSTREAM_BUFFER_SIZE, getSocketReadTimeout(), getSocketCloseTimeout());
}
protected void setOutputStream(OutputStream outs) {
localFileContents = outs;
}
protected void setCloseOutputStream(boolean close) {
closeOutputStream = close;
}
protected void setFileLength(long length) {
fileLength = length;
}
protected void setLastModifiedTime(long timestamp) {
lastModifiedTime = timestamp;
}
protected Map getOptions() {
return options;
}
protected synchronized void handleReceivedData(byte[] buf, int bytes, double factor, IProgressMonitor monitor) throws IOException {
if (bytes != -1) {
bytesReceived += bytes;
localFileContents.write(buf, 0, bytes);
downloadRateBytesPerSecond = (bytesReceived / ((System.currentTimeMillis() + 1 - transferStartTime) / 1000.0));
monitor.setTaskName(createJobName() + Messages.AbstractRetrieveFileTransfer_Progress_Data + NLS.bind(Messages.AbstractRetrieveFileTransfer_InfoTransferRate, toHumanReadableBytes(downloadRateBytesPerSecond)));
monitor.worked((int) Math.round(factor * bytes));
fireTransferReceiveDataEvent();
} else
setDone(true);
}
public static String toHumanReadableBytes(double size) {
double convertedSize;
String unit;
if (size / (1024 * 1024 * 1024) >= 1) {
convertedSize = size / (1024 * 1024 * 1024);
unit = Messages.AbstractRetrieveFileTransfer_SizeUnitGB;
} else if (size / (1024 * 1024) >= 1) {
convertedSize = size / (1024 * 1024);
unit = Messages.AbstractRetrieveFileTransfer_SizeUnitMB;
} else if (size / 1024 >= 1) {
convertedSize = size / 1024;
unit = Messages.AbstractRetrieveFileTransfer_SizeUnitKB;
} else {
convertedSize = size;
unit = Messages.AbstractRetrieveFileTransfer_SizeUnitBytes;
}
DecimalFormat df = new DecimalFormat(NLS.bind(Messages.AbstractRetrieveFileTransfer_TransferRateFormat, unit));
return df.format(convertedSize);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.core.identity.IIdentifiable#getID()
*/
public ID getID() {
return remoteFileID;
}
protected IStatus getFinalStatus(Throwable exception1) {
return Status.OK_STATUS;
}
protected void hardClose() {
try {
if (remoteFileContents != null)
remoteFileContents.close();
} catch (final IOException e) {
Activator.getDefault().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, "hardClose", e)); //$NON-NLS-1$
}
try {
if (localFileContents != null && closeOutputStream)
localFileContents.close();
} catch (final IOException e) {
Activator.getDefault().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, "hardClose", e)); //$NON-NLS-1$
}
// leave job intact to ensure only one done event is fired
remoteFileContents = null;
localFileContents = null;
}
protected void fireTransferReceivePausedEvent() {
listener.handleTransferEvent(new IIncomingFileTransferReceivePausedEvent() {
public IIncomingFileTransfer getSource() {
return AbstractRetrieveFileTransfer.this;
}
public String toString() {
final StringBuffer sb = new StringBuffer("IIncomingFileTransferReceivePausedEvent["); //$NON-NLS-1$
sb.append("bytesReceived=").append(bytesReceived) //$NON-NLS-1$
.append(";fileLength=").append(fileLength).append("]"); //$NON-NLS-1$ //$NON-NLS-2$
return sb.toString();
}
});
}
protected void fireTransferReceiveDoneEvent() {
listener.handleTransferEvent(new IIncomingFileTransferReceiveDoneEvent() {
public IIncomingFileTransfer getSource() {
return AbstractRetrieveFileTransfer.this;
}
public Exception getException() {
return AbstractRetrieveFileTransfer.this.getException();
}
public String toString() {
final StringBuffer sb = new StringBuffer("IIncomingFileTransferReceiveDoneEvent["); //$NON-NLS-1$
sb.append("bytesReceived=").append(bytesReceived) //$NON-NLS-1$
.append(";fileLength=").append(fileLength).append(";exception=").append(getException()) //$NON-NLS-1$ //$NON-NLS-2$
.append("]"); //$NON-NLS-1$
return sb.toString();
}
});
}
protected void fireTransferReceiveDataEvent() {
listener.handleTransferEvent(new IIncomingFileTransferReceiveDataEvent() {
public IIncomingFileTransfer getSource() {
return AbstractRetrieveFileTransfer.this;
}
public String toString() {
final StringBuffer sb = new StringBuffer("IIncomingFileTransferReceiveDataEvent["); //$NON-NLS-1$
sb.append("bytesReceived=").append(bytesReceived) //$NON-NLS-1$
.append(";fileLength=").append(fileLength) //$NON-NLS-1$
.append("]"); //$NON-NLS-1$
return sb.toString();
}
});
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#
* setConnectContextForAuthentication
* (org.eclipse.ecf.core.security.IConnectContext)
*/
public void setConnectContextForAuthentication(IConnectContext connectContext) {
this.connectContext = connectContext;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#setProxy
* (org.eclipse.ecf.core.util.Proxy)
*/
public void setProxy(Proxy proxy) {
this.proxy = proxy;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ecf.filetransfer.IIncomingFileTransfer#getBytesReceived()
*/
public long getBytesReceived() {
return bytesReceived;
}
/**
* @return UserCancelledException if some user cancellation
* @since 3.0
*/
protected UserCancelledException newUserCancelledException() {
return new UserCancelledException(Messages.AbstractRetrieveFileTransfer_Exception_User_Cancelled);
}
protected synchronized void resetDoneAndException() {
setDone(false);
this.exception = null;
}
protected synchronized void setDone(boolean done) {
this.done = done;
}
protected synchronized void setDoneException(Exception e) {
this.done = true;
this.exception = e;
}
protected synchronized boolean isCanceled() {
return done && exception instanceof UserCancelledException;
}
protected void setDoneCanceled() {
setDoneCanceled(newUserCancelledException());
}
protected synchronized void setDoneCanceled(Exception e) {
this.done = true;
if (e instanceof UserCancelledException) {
exception = e;
} else {
exception = newUserCancelledException();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.filetransfer.IFileTransfer#cancel()
*/
public void cancel() {
if (isPaused()) {
setDoneCanceled();
fireTransferReceiveDoneEvent();
return;
}
synchronized (jobLock) {
if (job != null)
job.cancel();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.filetransfer.IFileTransfer#getException()
*/
public synchronized Exception getException() {
return exception;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.filetransfer.IFileTransfer#getPercentComplete()
*/
public double getPercentComplete() {
if (fileLength == -1 || fileLength == 0)
return fileLength;
return ((double) bytesReceived / (double) fileLength);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.filetransfer.IFileTransfer#getFileLength()
*/
public long getFileLength() {
return fileLength;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer
* #getRemoteLastModified()
*/
public Date getRemoteLastModified() {
return lastModifiedTime == 0L ? null : new Date(lastModifiedTime);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.filetransfer.IFileTransfer#isDone()
*/
public synchronized boolean isDone() {
return done;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class adapter) {
if (adapter == null)
return null;
if (adapter.isInstance(this)) {
return this;
}
final IAdapterManager adapterManager = Activator.getDefault().getAdapterManager();
return (adapterManager == null) ? null : adapterManager.loadAdapter(this, adapter.getName());
}
/**
* Open incoming and outgoing streams associated with this file transfer.
* Subclasses must implement this method to open input and output streams.
* The <code>remoteFileContents</code> and <code>localFileContent</code>
* must be non-<code>null</code> after successful completion of the
* implementation of this method.
*
* @throws IncomingFileTransferException if some problem
*/
protected abstract void openStreams() throws IncomingFileTransferException;
/*
* (non-Javadoc)
*
* @seeorg.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#
* sendRetrieveRequest(org.eclipse.ecf.filetransfer.identity.IFileID,
* org.eclipse.ecf.filetransfer.IFileTransferListener, java.util.Map)
*/
public void sendRetrieveRequest(final IFileID remoteFileID1, IFileTransferListener transferListener, Map options1) throws IncomingFileTransferException {
sendRetrieveRequest(remoteFileID1, null, transferListener, options1);
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#
* getRetrieveNamespace()
*/
public Namespace getRetrieveNamespace() {
return IDFactory.getDefault().getNamespaceByName(FileTransferNamespace.PROTOCOL);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.filetransfer.IFileTransferPausable#isPaused()
*/
public boolean isPaused() {
return paused;
}
/**
* Subclass overridable version of {@link #pause()}. Subclasses must provide
* an implementation of this method to support {@link IFileTransferPausable}
* .
*
* @return true if the pause is successful. <code>false</code> otherwise.
*/
protected abstract boolean doPause();
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.filetransfer.IFileTransferPausable#pause()
*/
public boolean pause() {
return doPause();
}
/**
* Subclass overridable version of {@link #resume()}. Subclasses must
* provide an implementation of this method to support
* {@link IFileTransferPausable}.
*
* @return true if the resume is successful. <code>false</code> otherwise.
*/
protected abstract boolean doResume();
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.filetransfer.IFileTransferPausable#resume()
*/
public boolean resume() {
return doResume();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.filetransfer.IIncomingFileTransfer#getListener()
*/
public IFileTransferListener getListener() {
return listener;
}
protected String createRangeName() {
if (rangeSpecification == null)
return ""; //$NON-NLS-1$
return "[" + rangeSpecification.getStartPosition() + "," + rangeSpecification.getEndPosition() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
protected String createJobName() {
return getRemoteFileURL().toString() + createRangeName();
}
protected void setupAndScheduleJob(FileTransferJob fileTransferJob) {
if (fileTransferJob == null) {
// Create our own
fileTransferJob = new FileTransferJob(createJobName());
}
// Now set to our runnable
fileTransferJob.setFileTransferRunnable(fileTransferRunnable);
fileTransferJob.setFileTransfer(this);
if (isDone()) {
return;
}
synchronized (jobLock) {
job = fileTransferJob;
job.schedule();
}
}
protected void fireReceiveStartEvent() {
listener.handleTransferEvent(new IIncomingFileTransferReceiveStartEvent() {
/*
* (non-Javadoc)
*
* @seeorg.eclipse.ecf.filetransfer.events.
* IIncomingFileTransferEvent#getFileID()
*/
public IIncomingFileTransfer getSource() {
return AbstractRetrieveFileTransfer.this;
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.ecf.filetransfer.events.
* IIncomingFileTransferReceiveStartEvent#getFileID()
*/
public IFileID getFileID() {
return remoteFileID;
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.ecf.filetransfer.events.
* IIncomingFileTransferReceiveStartEvent
* #receive(java.io.File)
*/
public IIncomingFileTransfer receive(File localFileToSave) throws IOException {
return receive(localFileToSave, null);
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.ecf.filetransfer.events.
* IIncomingFileTransferReceiveStartEvent
* #receive(java.io.File,
* org.eclipse.ecf.filetransfer.FileTransferJob)
*/
public IIncomingFileTransfer receive(File localFileToSave, FileTransferJob fileTransferJob) throws IOException {
setOutputStream(new BufferedOutputStream(new FileOutputStream(localFileToSave)));
setupAndScheduleJob(fileTransferJob);
return AbstractRetrieveFileTransfer.this;
}
/**
* @param streamToStore
* @return incoming file transfer instance.
* @throws IOException
* not thrown in this implementation.
*/
public IIncomingFileTransfer receive(OutputStream streamToStore) throws IOException {
return receive(streamToStore, null);
}
/**
* @throws IOException
* not actually thrown by this implementation.
*/
public IIncomingFileTransfer receive(OutputStream streamToStore, FileTransferJob fileTransferJob) throws IOException {
setOutputStream(streamToStore);
setCloseOutputStream(false);
setupAndScheduleJob(fileTransferJob);
return AbstractRetrieveFileTransfer.this;
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.ecf.filetransfer.events.
* IIncomingFileTransferReceiveStartEvent#cancel()
*/
public void cancel() {
AbstractRetrieveFileTransfer.this.cancel();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
public String toString() {
final StringBuffer sb = new StringBuffer("IIncomingFileTransferReceiveStartEvent["); //$NON-NLS-1$
sb.append("isdone=").append(isDone()).append(";"); //$NON-NLS-1$ //$NON-NLS-2$
sb.append("bytesReceived=").append(bytesReceived) //$NON-NLS-1$
.append("]"); //$NON-NLS-1$
return sb.toString();
}
public Map getResponseHeaders() {
return responseHeaders;
}
});
}
protected void fireReceiveResumedEvent() {
listener.handleTransferEvent(new IIncomingFileTransferReceiveResumedEvent() {
public IIncomingFileTransfer getSource() {
return AbstractRetrieveFileTransfer.this;
}
public IFileID getFileID() {
return remoteFileID;
}
public IIncomingFileTransfer receive(File localFileToSave, boolean append) throws IOException {
return receive(localFileToSave, null, append);
}
public IIncomingFileTransfer receive(File localFileToSave, FileTransferJob fileTransferJob, boolean append) throws IOException {
setOutputStream(new BufferedOutputStream(new FileOutputStream(localFileToSave.getName(), append)));
setupAndScheduleJob(fileTransferJob);
return AbstractRetrieveFileTransfer.this;
}
/**
* @param streamToStore
* @return incoming file transfer instance.
* @throws IOException
* not thrown in this implementation.
*/
public IIncomingFileTransfer receive(OutputStream streamToStore) throws IOException {
return receive(streamToStore, null);
}
/**
* @throws IOException
* not actually thrown by this implementation.
*/
public IIncomingFileTransfer receive(OutputStream streamToStore, FileTransferJob fileTransferJob) throws IOException {
setOutputStream(streamToStore);
setCloseOutputStream(false);
setupAndScheduleJob(fileTransferJob);
return AbstractRetrieveFileTransfer.this;
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.ecf.filetransfer.events.
* IIncomingFileTransferReceiveStartEvent#cancel()
*/
public void cancel() {
hardClose();
}
public String toString() {
final StringBuffer sb = new StringBuffer("IIncomingFileTransferReceiveResumedEvent["); //$NON-NLS-1$
sb.append("isdone=").append(isDone()).append(";"); //$NON-NLS-1$ //$NON-NLS-2$
sb.append("bytesReceived=").append(bytesReceived) //$NON-NLS-1$
.append("]"); //$NON-NLS-1$
return sb.toString();
}
public Map getResponseHeaders() {
return responseHeaders;
}
});
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ecf.filetransfer.IIncomingFileTransfer#getFileRangeSpecification
* ()
*/
public IFileRangeSpecification getFileRangeSpecification() {
return rangeSpecification;
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#
* sendRetrieveRequest(org.eclipse.ecf.filetransfer.identity.IFileID,
* org.eclipse.ecf.filetransfer.IFileRangeSpecification,
* org.eclipse.ecf.filetransfer.IFileTransferListener, java.util.Map)
*/
/**
* @throws IncomingFileTransferException if some problem sending retrieve request
*/
public void sendRetrieveRequest(IFileID rFileID, IFileRangeSpecification rangeSpec, IFileTransferListener transferListener, Map ops) throws IncomingFileTransferException {
Assert.isNotNull(rFileID, Messages.AbstractRetrieveFileTransfer_RemoteFileID_Not_Null);
Assert.isNotNull(transferListener, Messages.AbstractRetrieveFileTransfer_TransferListener_Not_Null);
synchronized (jobLock) {
this.job = null;
}
this.remoteFileURL = null;
this.remoteFileID = rFileID;
this.listener = transferListener;
this.remoteFileContents = null;
this.localFileContents = null;
this.closeOutputStream = true;
resetDoneAndException();
this.bytesReceived = 0;
this.fileLength = -1;
this.options = ops;
this.paused = false;
this.rangeSpecification = rangeSpec;
try {
this.remoteFileURL = rFileID.getURL();
} catch (final MalformedURLException e) {
setDoneException(e);
fireTransferReceiveDoneEvent();
return;
}
try {
setupProxies();
openStreams();
} catch (final IncomingFileTransferException e) {
setDoneException(e);
fireTransferReceiveDoneEvent();
}
}
/**
* Setup ECF proxy. Subclasses must override this method to do appropriate
* proxy setup. This method will be called from within
* {@link #sendRetrieveRequest(IFileID, IFileTransferListener, Map)} and
* {@link #sendRetrieveRequest(IFileID, IFileRangeSpecification, IFileTransferListener, Map)}
* , prior to the actual call to {@link #openStreams()}.
*
* @param proxy
* the proxy to be setup. Will not be <code>null</code>.
*/
protected abstract void setupProxy(Proxy proxy);
/**
* Select a single proxy from a set of proxies available for the given host.
* This implementation selects in the following manner: 1) If proxies
* provided is null or array of 0 length, null is returned. If only one
* proxy is available (array of length 1) then the entry is returned. If
* proxies provided is length greater than 1, then if the type of a proxy in the array
* matches the given protocol (e.g. http, https), then the first matching
* proxy is returned. If the protocol does not match any of the proxies,
* then the *first* proxy (i.e. proxies[0]) is returned. Subclasses may
* override if desired.
*
* @param protocol
* the target protocol (e.g. http, https, scp, etc). Will not be
* <code>null</code>.
* @param proxies
* the proxies to select from. May be <code>null</code> or array
* of length 0.
* @return proxy data selected from the proxies provided.
*/
protected IProxyData selectProxyFromProxies(String protocol, IProxyData[] proxies) {
if (proxies == null || proxies.length == 0)
return null;
// If only one proxy is available, then use that
if (proxies.length == 1)
return proxies[0];
// If more than one proxy is available, then if http/https protocol then
// look for that
// one...if not found then use first
if (protocol.equalsIgnoreCase("http")) { //$NON-NLS-1$
for (IProxyData proxie : proxies) {
if (proxie.getType().equals(IProxyData.HTTP_PROXY_TYPE)) {
return proxie;
}
}
} else if (protocol.equalsIgnoreCase("https")) { //$NON-NLS-1$
for (IProxyData proxie : proxies) {
if (proxie.getType().equals(IProxyData.HTTPS_PROXY_TYPE)) {
return proxie;
}
}
}
// If we haven't found it yet, then return the first one.
return proxies[0];
}
protected void setupProxies() {
// If it's been set directly (via ECF API) then this overrides platform
// settings
if (proxy == null) {
try {
proxy = ProxySetupHelper.getProxy(getRemoteFileURL().toExternalForm());
} catch (NoClassDefFoundError e) {
// If the proxy API is not available a NoClassDefFoundError will be thrown here.
// If that happens then we just want to continue on.
Activator.logNoProxyWarning(e);
}
}
if (proxy != null)
setupProxy(proxy);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ecf.filetransfer.IIncomingFileTransfer#getRemoteFileName()
*/
public String getRemoteFileName() {
String pathStr = getRemoteFileURL().getPath();
if (pathStr.length() > 0) {
IPath path = Path.fromPortableString(pathStr);
if (path.segmentCount() > 0)
return path.lastSegment();
}
return null;
}
protected boolean targetHasGzSuffix(String target) {
if (target == null)
return false;
if (target.endsWith(".gz")) //$NON-NLS-1$
return true;
return false;
}
}