/** * $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); } }