aboutsummaryrefslogtreecommitdiff
path: root/src/org/jivesoftware/smackx/filetransfer/IncomingFileTransfer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/jivesoftware/smackx/filetransfer/IncomingFileTransfer.java')
-rw-r--r--src/org/jivesoftware/smackx/filetransfer/IncomingFileTransfer.java215
1 files changed, 215 insertions, 0 deletions
diff --git a/src/org/jivesoftware/smackx/filetransfer/IncomingFileTransfer.java b/src/org/jivesoftware/smackx/filetransfer/IncomingFileTransfer.java
new file mode 100644
index 0000000..91a5a0d
--- /dev/null
+++ b/src/org/jivesoftware/smackx/filetransfer/IncomingFileTransfer.java
@@ -0,0 +1,215 @@
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 Jive Software.
+ *
+ * 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.
+ * 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.jivesoftware.smackx.filetransfer;
+
+import org.jivesoftware.smack.XMPPException;
+
+import java.io.*;
+import java.util.concurrent.*;
+
+/**
+ * An incoming file transfer is created when the
+ * {@link FileTransferManager#createIncomingFileTransfer(FileTransferRequest)}
+ * method is invoked. It is a file being sent to the local user from another
+ * user on the jabber network. There are two stages of the file transfer to be
+ * concerned with and they can be handled in different ways depending upon the
+ * method that is invoked on this class.
+ * <p/>
+ * The first way that a file is recieved is by calling the
+ * {@link #recieveFile()} method. This method, negotiates the appropriate stream
+ * method and then returns the <b><i>InputStream</b></i> to read the file
+ * data from.
+ * <p/>
+ * The second way that a file can be recieved through this class is by invoking
+ * the {@link #recieveFile(File)} method. This method returns immediatly and
+ * takes as its parameter a file on the local file system where the file
+ * recieved from the transfer will be put.
+ *
+ * @author Alexander Wenckus
+ */
+public class IncomingFileTransfer extends FileTransfer {
+
+ private FileTransferRequest recieveRequest;
+
+ private InputStream inputStream;
+
+ protected IncomingFileTransfer(FileTransferRequest request,
+ FileTransferNegotiator transferNegotiator) {
+ super(request.getRequestor(), request.getStreamID(), transferNegotiator);
+ this.recieveRequest = request;
+ }
+
+ /**
+ * Negotiates the stream method to transfer the file over and then returns
+ * the negotiated stream.
+ *
+ * @return The negotiated InputStream from which to read the data.
+ * @throws XMPPException If there is an error in the negotiation process an exception
+ * is thrown.
+ */
+ public InputStream recieveFile() throws XMPPException {
+ if (inputStream != null) {
+ throw new IllegalStateException("Transfer already negotiated!");
+ }
+
+ try {
+ inputStream = negotiateStream();
+ }
+ catch (XMPPException e) {
+ setException(e);
+ throw e;
+ }
+
+ return inputStream;
+ }
+
+ /**
+ * This method negotitates the stream and then transfer's the file over the
+ * negotiated stream. The transfered file will be saved at the provided
+ * location.
+ * <p/>
+ * This method will return immedialtly, file transfer progress can be
+ * monitored through several methods:
+ * <p/>
+ * <UL>
+ * <LI>{@link FileTransfer#getStatus()}
+ * <LI>{@link FileTransfer#getProgress()}
+ * <LI>{@link FileTransfer#isDone()}
+ * </UL>
+ *
+ * @param file The location to save the file.
+ * @throws XMPPException when the file transfer fails
+ * @throws IllegalArgumentException This exception is thrown when the the provided file is
+ * either null, or cannot be written to.
+ */
+ public void recieveFile(final File file) throws XMPPException {
+ if (file != null) {
+ if (!file.exists()) {
+ try {
+ file.createNewFile();
+ }
+ catch (IOException e) {
+ throw new XMPPException(
+ "Could not create file to write too", e);
+ }
+ }
+ if (!file.canWrite()) {
+ throw new IllegalArgumentException("Cannot write to provided file");
+ }
+ }
+ else {
+ throw new IllegalArgumentException("File cannot be null");
+ }
+
+ Thread transferThread = new Thread(new Runnable() {
+ public void run() {
+ try {
+ inputStream = negotiateStream();
+ }
+ catch (XMPPException e) {
+ handleXMPPException(e);
+ return;
+ }
+
+ OutputStream outputStream = null;
+ try {
+ outputStream = new FileOutputStream(file);
+ setStatus(Status.in_progress);
+ writeToStream(inputStream, outputStream);
+ }
+ catch (XMPPException e) {
+ setStatus(Status.error);
+ setError(Error.stream);
+ setException(e);
+ }
+ catch (FileNotFoundException e) {
+ setStatus(Status.error);
+ setError(Error.bad_file);
+ setException(e);
+ }
+
+ if (getStatus().equals(Status.in_progress)) {
+ setStatus(Status.complete);
+ }
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ }
+ catch (Throwable io) {
+ /* Ignore */
+ }
+ }
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ }
+ catch (Throwable io) {
+ /* Ignore */
+ }
+ }
+ }
+ }, "File Transfer " + streamID);
+ transferThread.start();
+ }
+
+ private void handleXMPPException(XMPPException e) {
+ setStatus(FileTransfer.Status.error);
+ setException(e);
+ }
+
+ private InputStream negotiateStream() throws XMPPException {
+ setStatus(Status.negotiating_transfer);
+ final StreamNegotiator streamNegotiator = negotiator
+ .selectStreamNegotiator(recieveRequest);
+ setStatus(Status.negotiating_stream);
+ FutureTask<InputStream> streamNegotiatorTask = new FutureTask<InputStream>(
+ new Callable<InputStream>() {
+
+ public InputStream call() throws Exception {
+ return streamNegotiator
+ .createIncomingStream(recieveRequest.getStreamInitiation());
+ }
+ });
+ streamNegotiatorTask.run();
+ InputStream inputStream;
+ try {
+ inputStream = streamNegotiatorTask.get(15, TimeUnit.SECONDS);
+ }
+ catch (InterruptedException e) {
+ throw new XMPPException("Interruption while executing", e);
+ }
+ catch (ExecutionException e) {
+ throw new XMPPException("Error in execution", e);
+ }
+ catch (TimeoutException e) {
+ throw new XMPPException("Request timed out", e);
+ }
+ finally {
+ streamNegotiatorTask.cancel(true);
+ }
+ setStatus(Status.negotiated);
+ return inputStream;
+ }
+
+ public void cancel() {
+ setStatus(Status.cancelled);
+ }
+
+}