/****************************************************************************
* Copyright (c) 2004 Composent, Inc. and others.
* 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:
* Composent, Inc. - initial API and implementation
*****************************************************************************/
package org.eclipse.ecf.internal.provider.xmpp.filetransfer;
import java.io.File;
import java.io.FileInputStream;
import org.eclipse.core.runtime.IAdapterManager;
import org.eclipse.ecf.core.identity.ID;
import org.eclipse.ecf.core.identity.IDCreateException;
import org.eclipse.ecf.core.identity.IDFactory;
import org.eclipse.ecf.filetransfer.FileTransferJob;
import org.eclipse.ecf.filetransfer.IFileTransferInfo;
import org.eclipse.ecf.filetransfer.IFileTransferListener;
import org.eclipse.ecf.filetransfer.IOutgoingFileTransfer;
import org.eclipse.ecf.filetransfer.UserCancelledException;
import org.eclipse.ecf.filetransfer.events.IFileTransferEvent;
import org.eclipse.ecf.filetransfer.events.IOutgoingFileTransferResponseEvent;
import org.eclipse.ecf.filetransfer.events.IOutgoingFileTransferSendDoneEvent;
import org.eclipse.ecf.internal.provider.xmpp.XmppPlugin;
import org.eclipse.ecf.provider.xmpp.identity.XMPPID;
import org.eclipse.osgi.util.NLS;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.filetransfer.FileTransfer;
import org.jivesoftware.smackx.filetransfer.FileTransfer.Status;
import org.jivesoftware.smackx.filetransfer.FileTransferManager;
import org.jivesoftware.smackx.filetransfer.OutgoingFileTransfer;
public class XMPPOutgoingFileTransfer implements IOutgoingFileTransfer {
private final ID sessionID;
private final XMPPID remoteTarget;
private final IFileTransferListener listener;
private File localFile;
private long fileSize;
private final OutgoingFileTransfer outgoingFileTransfer;
private Status status;
private Exception exception;
private int originalOutputRequestTimeout = -1;
private boolean localCancelled = false;
public XMPPOutgoingFileTransfer(FileTransferManager manager,
XMPPID remoteTarget, IFileTransferInfo fileTransferInfo,
IFileTransferListener listener, int outgoingRequestTimeout) {
this.remoteTarget = remoteTarget;
this.listener = listener;
this.sessionID = createSessionID();
final String fullyQualifiedName = remoteTarget.getFQName();
// Set request timeout if we have a new value
if (outgoingRequestTimeout != -1) {
originalOutputRequestTimeout = OutgoingFileTransfer
.getResponseTimeout();
OutgoingFileTransfer.setResponseTimeout(outgoingRequestTimeout);
}
outgoingFileTransfer = manager
.createOutgoingFileTransfer(fullyQualifiedName);
}
private ID createSessionID() {
try {
return IDFactory.getDefault().createGUID();
} catch (final IDCreateException e) {
throw new NullPointerException(
"cannot create id for XMPPOutgoingFileTransfer"); //$NON-NLS-1$
}
}
public synchronized ID getRemoteTargetID() {
return remoteTarget;
}
public ID getID() {
return sessionID;
}
private void fireTransferListenerEvent(IFileTransferEvent event) {
listener.handleTransferEvent(event);
}
private void setStatus(Status s) {
this.status = s;
}
private void setException(Exception e) {
this.exception = e;
}
private Status getStatus() {
return this.status;
}
private void setErrorStatus(Exception e) {
setStatus(FileTransfer.Status.error);
setException(e);
}
public synchronized void startSend(File localFile, String description)
throws XMPPException {
this.localFile = localFile;
this.fileSize = localFile.length();
setStatus(Status.initial);
outgoingFileTransfer.sendFile(localFile, description);
final Thread transferThread = new Thread(new Runnable() {
public void run() {
setStatus(outgoingFileTransfer.getStatus());
boolean negotiation = true;
try {
while (negotiation && !localCancelled) {
// check the state of the progress
try {
Thread.sleep(300);
} catch (final InterruptedException e) {
setErrorStatus(e);
return;
}
final Status s = outgoingFileTransfer.getStatus();
setStatus(s);
final boolean negotiated = getStatus().equals(
Status.negotiated);
if (s.equals(Status.negotiated)
|| s.equals(Status.cancelled)
|| s.equals(Status.complete)
|| s.equals(Status.error)
|| s.equals(Status.refused)) {
fireTransferListenerEvent(new IOutgoingFileTransferResponseEvent() {
public boolean requestAccepted() {
return negotiated;
}
public IOutgoingFileTransfer getSource() {
return XMPPOutgoingFileTransfer.this;
}
public String toString() {
final StringBuffer buf = new StringBuffer(
"OutgoingFileTransferResponseEvent["); //$NON-NLS-1$
buf.append("requestAccepted=").append(requestAccepted()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$
return buf.toString();
}
public void setFileTransferJob(
FileTransferJob job) {
// does nothing with this implementation
}
});
// And negotiation is over
negotiation = false;
}
}
if (localCancelled) {
setErrorStatus(new UserCancelledException(
"Transfer cancelled by sender")); //$NON-NLS-1$
return;
}
outgoingFileTransfer.sendStream(new FileInputStream(
XMPPOutgoingFileTransfer.this.localFile),
XMPPOutgoingFileTransfer.this.localFile.getName(),
fileSize, "Ein File");
setStatus(Status.complete);
} catch (final Exception e) {
setStatus(FileTransfer.Status.error);
setException(e);
} finally {
// Reset request timeout
if (originalOutputRequestTimeout != -1) {
OutgoingFileTransfer
.setResponseTimeout(originalOutputRequestTimeout);
}
// Then notify that the sending is done
fireTransferListenerEvent(new IOutgoingFileTransferSendDoneEvent() {
public IOutgoingFileTransfer getSource() {
return XMPPOutgoingFileTransfer.this;
}
public String toString() {
final StringBuffer buf = new StringBuffer(
"IOutgoingFileTransferSendDoneEvent["); //$NON-NLS-1$
buf.append("isDone=" + getSource().isDone()); //$NON-NLS-1$
buf.append(";bytesSent=").append(getSource().getBytesSent()); //$NON-NLS-1$
buf.append(";exception=").append(getException()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$
return buf.toString();
}
});
}
}
}, NLS.bind("XMPP send {0}", remoteTarget.toExternalForm())); //$NON-NLS-1$
transferThread.start();
}
public synchronized void cancel() {
localCancelled = true;
}
public synchronized File getLocalFile() {
return localFile;
}
/*
* (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 = XmppPlugin.getDefault()
.getAdapterManager();
return (adapterManager == null) ? null : adapterManager.loadAdapter(
this, adapter.getName());
}
public long getBytesSent() {
return outgoingFileTransfer.getBytesSent();
}
public Exception getException() {
return exception;
}
public double getPercentComplete() {
return (fileSize <= 0) ? 1.0 : (((double) outgoingFileTransfer
.getAmountWritten()) / ((double) fileSize));
}
public boolean isDone() {
return status == Status.cancelled || status == Status.error
|| status == Status.complete;
}
public ID getSessionID() {
return sessionID;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.filetransfer.IFileTransfer#getFileLength()
*/
public long getFileLength() {
return fileSize;
}
}