From e53165a96c951f375244395665e4e013355fcbe2 Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Tue, 15 Aug 2017 17:43:06 +0200 Subject: [PATCH] Improve JFT API --- .../jivesoftware/smackx/jet/JetManager.java | 9 ++- .../JingleFileTransferManager.java | 63 +++++++++++++++++-- .../component/JingleIncomingFileOffer.java | 48 ++++++++------ .../component/JingleOutgoingFileOffer.java | 6 +- .../IncomingFileOfferController.java | 6 +- .../smackx/jet/JetIntegrationTest.java | 8 +-- .../JingleFileTransferIntegrationTest.java | 4 +- ...nsferTransportFallbackIntegrationTest.java | 8 +-- 8 files changed, 112 insertions(+), 40 deletions(-) diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jet/JetManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jet/JetManager.java index 77207e749..759acc79f 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jet/JetManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jet/JetManager.java @@ -78,7 +78,11 @@ public final class JetManager extends Manager implements JingleDescriptionManage return manager; } - public OutgoingFileOfferController sendEncryptedFile(FullJid recipient, File file, JingleEncryptionMethod method) throws Exception { + public OutgoingFileOfferController sendEncryptedFile(File file, FullJid recipient, JingleEncryptionMethod method) throws Exception { + return sendEncryptedFile(file, null, recipient, method); + } + + public OutgoingFileOfferController sendEncryptedFile(File file, String filename, FullJid recipient, JingleEncryptionMethod method) throws Exception { if (file == null || !file.exists()) { throw new IllegalArgumentException("File MUST NOT be null and MUST exist."); } @@ -94,6 +98,9 @@ public final class JetManager extends Manager implements JingleDescriptionManage session.addContent(content); JingleOutgoingFileOffer offer = new JingleOutgoingFileOffer(file); + if (filename != null) { + offer.getFile().setName(filename); + } content.setDescription(offer); JingleTransportManager transportManager = jingleManager.getBestAvailableTransportManager(recipient); diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java index b82a06a86..a2e9aaba5 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java @@ -17,7 +17,9 @@ package org.jivesoftware.smackx.jingle_filetransfer; import java.io.File; +import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -29,6 +31,7 @@ import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smackx.bytestreams.BytestreamSession; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.jingle.JingleDescriptionManager; import org.jivesoftware.smackx.jingle.JingleManager; @@ -64,6 +67,7 @@ public final class JingleFileTransferManager extends Manager implements JingleDe private final List offerListeners = Collections.synchronizedList(new ArrayList()); + private final List requestListeners = Collections.synchronizedList(new ArrayList()); @@ -93,7 +97,7 @@ public final class JingleFileTransferManager extends Manager implements JingleDe public OutgoingFileOfferController sendFile(File file, FullJid to) throws SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException, SmackException.NoResponseException, SmackException.FeatureNotSupportedException { - return sendFile(file, null, to); + return sendFile(file, null, to); } public OutgoingFileOfferController sendFile(File file, String alternativeFilename, FullJid to) @@ -127,9 +131,60 @@ public final class JingleFileTransferManager extends Manager implements JingleDe return offer; } - public OutgoingFileOfferController sendStream(InputStream stream, String filename, FullJid to) { - //TODO: Implement - return null; + public OutgoingFileOfferController sendStream(final InputStream stream, JingleFileTransferFile.LocalFile file, FullJid recipient) throws SmackException.FeatureNotSupportedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { + if (!ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(recipient, getNamespace())) { + throw new SmackException.FeatureNotSupportedException(getNamespace(), recipient); + } + + JingleSession session = jingleManager.createSession(Role.initiator, recipient); + + JingleContent content = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + session.addContent(content); + + JingleOutgoingFileOffer outgoingFileOffer = new JingleOutgoingFileOffer(file) { + + @Override + public void onBytestreamReady(BytestreamSession bytestreamSession) { + OutputStream outputStream; + try { + outputStream = bytestreamSession.getOutputStream(); + + byte[] buf = new byte[4096]; + while (true) { + int r = stream.read(buf); + if (r < 0) { + break; + } + outputStream.write(buf, 0, r); + } + outputStream.flush(); + outputStream.close(); + + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Exception while sending file: " + e, e); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Could not close FileInputStream: " + e, e); + } + } + } + + notifyProgressListenersFinished(); + } + }; + + content.setDescription(outgoingFileOffer); + + JingleTransportManager transportManager = jingleManager.getBestAvailableTransportManager(recipient); + JingleTransport transport = transportManager.createTransportForInitiator(content); + content.setTransport(transport); + + session.sendInitiate(connection()); + + return outgoingFileOffer; } public OutgoingFileRequestController requestFile(JingleFileTransferFile.RemoteFile file, FullJid from) { diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleIncomingFileOffer.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleIncomingFileOffer.java index fa2810515..20390ff88 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleIncomingFileOffer.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleIncomingFileOffer.java @@ -21,7 +21,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.Logger; @@ -42,8 +41,7 @@ import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChi public class JingleIncomingFileOffer extends AbstractJingleFileOffer implements IncomingFileOfferController { private static final Logger LOGGER = Logger.getLogger(JingleIncomingFileOffer.class.getName()); - - private File target; + private OutputStream target; public JingleIncomingFileOffer(JingleFileTransferChildElement offer) { super(new JingleFileTransferFile.RemoteFile(offer)); @@ -56,27 +54,21 @@ public class JingleIncomingFileOffer extends AbstractJingleFileOffer= 0) { - outputStream.write(bufbuf, 0, length); + target.write(bufbuf, 0, length); read += length; LOGGER.log(Level.INFO, "Read " + read + " (" + length + ") of " + file.getSize() + " bytes."); if (read == (int) file.getSize()) { @@ -96,9 +88,9 @@ public class JingleIncomingFileOffer extends AbstractJingleFileOffer accept(XMPPConnection connection, File target) + public void accept(XMPPConnection connection, File target) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, - SmackException.NoResponseException { - this.target = target; + SmackException.NoResponseException, IOException { + + if (!target.exists()) { + target.createNewFile(); + } + + this.target = new FileOutputStream(target); + JingleSession session = getParent().getParent(); if (session.getSessionState() == JingleSession.SessionState.pending) { session.sendAccept(connection); } + } - return null; + @Override + public void accept(XMPPConnection connection, OutputStream stream) + throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, + SmackException.NoResponseException { + target = stream; + + JingleSession session = getParent().getParent(); + if (session.getSessionState() == JingleSession.SessionState.pending) { + session.sendAccept(connection); + } } @Override diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleOutgoingFileOffer.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleOutgoingFileOffer.java index 52ea3f7d9..d1ff19ea9 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleOutgoingFileOffer.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleOutgoingFileOffer.java @@ -36,7 +36,11 @@ public class JingleOutgoingFileOffer extends AbstractJingleFileOffer accept(XMPPConnection connection, File target) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException; + void accept(XMPPConnection connection, File target) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException, IOException; + void accept(XMPPConnection connection, OutputStream outputStream) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException, IOException; } diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/jet/JetIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jet/JetIntegrationTest.java index a8a437191..25093db65 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/jet/JetIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jet/JetIntegrationTest.java @@ -25,7 +25,7 @@ import static org.junit.Assert.assertArrayEquals; import java.io.File; import java.io.FileInputStream; -import java.util.concurrent.Future; +import java.io.IOException; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; @@ -123,14 +123,14 @@ public class JetIntegrationTest extends AbstractOmemoIntegrationTest { received.signal(); } }); - Future f = offer.accept(conTwo, target); - } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) { + offer.accept(conTwo, target); + } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException | IOException e) { received.signal(e); } } }); - ja.sendEncryptedFile(conTwo.getUser().asFullJidOrThrow(), source, oa); + ja.sendEncryptedFile(source, conTwo.getUser().asFullJidOrThrow(), oa); received.waitForResult(60 * 1000); diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferIntegrationTest.java index 44e5e92ba..d4967183c 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferIntegrationTest.java @@ -107,8 +107,8 @@ public class JingleFileTransferIntegrationTest extends AbstractSmackIntegrationT }); try { - receiveFuture.add(offer.accept(conTwo, target)); - } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) { + offer.accept(conTwo, target); + } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException | IOException e) { fail(e.toString()); } } diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferTransportFallbackIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferTransportFallbackIntegrationTest.java index 0df4f93a6..6f720ac4a 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferTransportFallbackIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferTransportFallbackIntegrationTest.java @@ -23,8 +23,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.concurrent.Future; import java.util.logging.Level; import org.jivesoftware.smack.SmackException; @@ -95,8 +93,6 @@ public class JingleFileTransferTransportFallbackIntegrationTest extends Abstract JingleFileTransferManager aftm = JingleFileTransferManager.getInstanceFor(conOne); JingleFileTransferManager bftm = JingleFileTransferManager.getInstanceFor(conTwo); - final ArrayList> receiveFuture = new ArrayList<>(); //Uglaay - bftm.addIncomingFileOfferListener(new IncomingFileOfferListener() { @Override public void onIncomingFileOffer(IncomingFileOfferController offer) { @@ -120,8 +116,8 @@ public class JingleFileTransferTransportFallbackIntegrationTest extends Abstract }); try { - receiveFuture.add(offer.accept(conTwo, target)); - } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) { + offer.accept(conTwo, target); + } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException | IOException e) { fail(e.toString()); } }