From 27f6922cf637438103a3341a35a7bc9a1b75cf74 Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Sun, 20 Aug 2017 14:58:46 +0200 Subject: [PATCH] Simplify file API, allow sending hash with file --- .../jivesoftware/smackx/jet/JetManager.java | 15 +- .../JingleFileTransferManager.java | 25 +- .../component/AbstractJingleFileOffer.java | 2 +- .../component/AbstractJingleFileRequest.java | 7 +- .../component/JingleFile.java | 154 ++++++++++++ .../component/JingleFileTransfer.java | 13 +- .../component/JingleFileTransferFile.java | 225 ------------------ .../component/JingleIncomingFileOffer.java | 13 +- .../component/JingleIncomingFileRequest.java | 9 +- .../component/JingleOutgoingFileOffer.java | 13 +- .../component/JingleOutgoingFileRequest.java | 9 +- .../JingleFileTransferController.java | 4 +- .../smackx/jet/JetIntegrationTest.java | 4 +- 13 files changed, 199 insertions(+), 294 deletions(-) create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleFile.java delete mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleFileTransferFile.java 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 50bb66d1f..e84834fa2 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 @@ -45,7 +45,7 @@ import org.jivesoftware.smackx.jingle.component.JingleSession; import org.jivesoftware.smackx.jingle.element.JingleContentElement; import org.jivesoftware.smackx.jingle.util.Role; import org.jivesoftware.smackx.jingle_filetransfer.JingleFileTransferManager; -import org.jivesoftware.smackx.jingle_filetransfer.component.JingleFileTransferFile; +import org.jivesoftware.smackx.jingle_filetransfer.component.JingleFile; import org.jivesoftware.smackx.jingle_filetransfer.component.JingleOutgoingFileOffer; import org.jivesoftware.smackx.jingle_filetransfer.controller.OutgoingFileOfferController; @@ -88,10 +88,10 @@ public final class JetManager extends Manager implements JingleDescriptionManage } public OutgoingFileOfferController sendEncryptedFile(File file, FullJid recipient, JingleEnvelopeManager envelopeManager) throws Exception { - return sendEncryptedFile(file, null, recipient, envelopeManager); + return sendEncryptedFile(file, JingleFile.fromFile(file, null, null, null), recipient, envelopeManager); } - public OutgoingFileOfferController sendEncryptedFile(File file, String filename, FullJid recipient, JingleEnvelopeManager envelopeManager) throws Exception { + public OutgoingFileOfferController sendEncryptedFile(File file, JingleFile metadata, FullJid recipient, JingleEnvelopeManager envelopeManager) throws Exception { if (file == null || !file.exists()) { throw new IllegalArgumentException("File MUST NOT be null and MUST exist."); } @@ -103,10 +103,7 @@ public final class JetManager extends Manager implements JingleDescriptionManage JingleContent content = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); session.addContent(content); - JingleOutgoingFileOffer offer = new JingleOutgoingFileOffer(file); - if (filename != null) { - offer.getFile().setName(filename); - } + JingleOutgoingFileOffer offer = new JingleOutgoingFileOffer(file, metadata); content.setDescription(offer); JingleTransportManager transportManager = jingleManager.getBestAvailableTransportManager(recipient); @@ -119,7 +116,7 @@ public final class JetManager extends Manager implements JingleDescriptionManage return offer; } - public OutgoingFileOfferController sendEncryptedStream(InputStream inputStream, JingleFileTransferFile.StreamFile file, FullJid recipient, JingleEnvelopeManager envelopeManager) + public OutgoingFileOfferController sendEncryptedStream(InputStream inputStream, JingleFile metadata, FullJid recipient, JingleEnvelopeManager envelopeManager) throws XMPPException.XMPPErrorException, SmackException.FeatureNotSupportedException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, JingleEnvelopeManager.JingleEncryptionException, NoSuchProviderException, InvalidAlgorithmParameterException { @@ -130,7 +127,7 @@ public final class JetManager extends Manager implements JingleDescriptionManage JingleContent content = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); session.addContent(content); - JingleOutgoingFileOffer offer = new JingleOutgoingFileOffer(file, inputStream); + JingleOutgoingFileOffer offer = new JingleOutgoingFileOffer(inputStream, metadata); 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 725209e6a..86d418805 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 @@ -18,7 +18,9 @@ package org.jivesoftware.smackx.jingle_filetransfer; import java.io.File; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -41,7 +43,7 @@ import org.jivesoftware.smackx.jingle.element.JingleContentElement; import org.jivesoftware.smackx.jingle.util.Role; import org.jivesoftware.smackx.jingle_filetransfer.adapter.JingleFileTransferAdapter; import org.jivesoftware.smackx.jingle_filetransfer.component.JingleFileTransfer; -import org.jivesoftware.smackx.jingle_filetransfer.component.JingleFileTransferFile; +import org.jivesoftware.smackx.jingle_filetransfer.component.JingleFile; import org.jivesoftware.smackx.jingle_filetransfer.component.JingleIncomingFileOffer; import org.jivesoftware.smackx.jingle_filetransfer.component.JingleIncomingFileRequest; import org.jivesoftware.smackx.jingle_filetransfer.component.JingleOutgoingFileOffer; @@ -95,13 +97,11 @@ 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, FileNotFoundException { - return sendFile(file, null, to); + SmackException.NoResponseException, SmackException.FeatureNotSupportedException, IOException, NoSuchAlgorithmException { + return sendFile(file, JingleFile.fromFile(file, null, null, null), to); } - public OutgoingFileOfferController sendFile(File file, String alternativeFilename, FullJid to) - throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, - SmackException.NoResponseException, SmackException.FeatureNotSupportedException, FileNotFoundException { + public OutgoingFileOfferController sendFile(File file, JingleFile metadata, FullJid to) throws SmackException.FeatureNotSupportedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, FileNotFoundException { if (file == null || !file.exists()) { throw new IllegalArgumentException("File MUST NOT be null and MUST exist."); } @@ -115,10 +115,7 @@ public final class JingleFileTransferManager extends Manager implements JingleDe JingleContent content = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); session.addContent(content); - JingleOutgoingFileOffer offer = new JingleOutgoingFileOffer(file); - if (alternativeFilename != null) { - offer.getFile().setName(alternativeFilename); - } + JingleOutgoingFileOffer offer = new JingleOutgoingFileOffer(file, metadata); content.setDescription(offer); JingleTransportManager transportManager = jingleManager.getBestAvailableTransportManager(to); @@ -130,7 +127,7 @@ public final class JingleFileTransferManager extends Manager implements JingleDe return offer; } - public OutgoingFileOfferController sendStream(final InputStream stream, JingleFileTransferFile.StreamFile file, FullJid recipient) throws SmackException.FeatureNotSupportedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { + public OutgoingFileOfferController sendStream(final InputStream stream, JingleFile metadata, 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); } @@ -140,7 +137,7 @@ public final class JingleFileTransferManager extends Manager implements JingleDe JingleContent content = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); session.addContent(content); - JingleOutgoingFileOffer outgoingFileOffer = new JingleOutgoingFileOffer(file, stream); + JingleOutgoingFileOffer outgoingFileOffer = new JingleOutgoingFileOffer(stream, metadata); content.setDescription(outgoingFileOffer); @@ -153,8 +150,8 @@ public final class JingleFileTransferManager extends Manager implements JingleDe return outgoingFileOffer; } - public OutgoingFileRequestController requestFile(JingleFileTransferFile.RemoteFile file, FullJid from) { - JingleOutgoingFileRequest request = new JingleOutgoingFileRequest(file); + public OutgoingFileRequestController requestFile(JingleFile metadata, FullJid from) { + JingleOutgoingFileRequest request = new JingleOutgoingFileRequest(metadata); //TODO at some point. diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/AbstractJingleFileOffer.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/AbstractJingleFileOffer.java index ad5583f69..e53fd55d9 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/AbstractJingleFileOffer.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/AbstractJingleFileOffer.java @@ -21,7 +21,7 @@ package org.jivesoftware.smackx.jingle_filetransfer.component; */ public abstract class AbstractJingleFileOffer extends JingleFileTransfer { - AbstractJingleFileOffer(JingleFileTransferFile fileTransferFile) { + AbstractJingleFileOffer(JingleFile fileTransferFile) { super(fileTransferFile); } } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/AbstractJingleFileRequest.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/AbstractJingleFileRequest.java index 6a783d049..94f3b50c2 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/AbstractJingleFileRequest.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/AbstractJingleFileRequest.java @@ -19,12 +19,9 @@ package org.jivesoftware.smackx.jingle_filetransfer.component; /** * Created by vanitas on 22.07.17. */ -public abstract class AbstractJingleFileRequest extends JingleFileTransfer { +public abstract class AbstractJingleFileRequest extends JingleFileTransfer { - AbstractJingleFileRequest(D fileTransferFile) { + AbstractJingleFileRequest(JingleFile fileTransferFile) { super(fileTransferFile); } - - @Override - public abstract D getFile(); } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleFile.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleFile.java new file mode 100644 index 000000000..53b7e58e0 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleFile.java @@ -0,0 +1,154 @@ +/** + * + * Copyright 2017 Paul Schaub + * + * 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.jingle_filetransfer.component; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Date; + +import org.jivesoftware.smackx.hashes.HashManager; +import org.jivesoftware.smackx.hashes.element.HashElement; +import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChildElement; + +import com.sun.istack.internal.NotNull; +import com.sun.istack.internal.Nullable; + +/** + * Represent a file sent in a file transfer. + * This can be both LocalFile (available to the client), or RemoteFile (file not yet available). + */ +public class JingleFile { + + private String name, description, mediaType; + private long size; + private Date date; + private HashElement hashElement; + + public static JingleFile fromFile(@NotNull File file, @Nullable String description, @Nullable String mediaType, @Nullable HashManager.ALGORITHM hashAlgorithm) throws NoSuchAlgorithmException, IOException { + + HashElement hashElement = null; + if (hashAlgorithm != null) { + hashElement = calculateHash(file, hashAlgorithm); + } + + return new JingleFile(file.getName(), description, file.length(), mediaType, new Date(file.lastModified()), hashElement); + } + + public JingleFile(String name, String description, long size, String mediaType, Date date, HashElement hashElement) { + this.name = name; + this.description = description; + this.size = size; + this.mediaType = mediaType; + this.date = date; + this.hashElement = hashElement; + } + + public JingleFile(JingleFileTransferChildElement element) { + this.name = element.getName(); + this.description = element.getDescription(); + this.size = element.getSize(); + this.mediaType = element.getMediaType(); + this.date = element.getDate(); + this.hashElement = element.getHash(); + } + + public static HashElement calculateHash(File file, HashManager.ALGORITHM algorithm) throws NoSuchAlgorithmException, IOException { + if (file == null || !file.exists()) { + throw new IllegalArgumentException("File MUST NOT be null and MUST exist."); + } + + MessageDigest digest = HashManager.getMessageDigest(algorithm); + if (digest == null) { + throw new NoSuchAlgorithmException("No algorithm for " + algorithm + " found."); + } + + FileInputStream fi = new FileInputStream(file); + DigestInputStream di = new DigestInputStream(fi, digest); + + while (di.available() > 0) { + di.read(); + } + + byte[] d = di.getMessageDigest().digest(); + + return new HashElement(algorithm, d); + } + + public JingleFileTransferChildElement getElement() { + JingleFileTransferChildElement.Builder builder = JingleFileTransferChildElement.getBuilder(); + builder.setDate(getDate()); + builder.setSize(getSize()); + builder.setName(getName()); + builder.setDescription(getDescription()); + builder.setMediaType(getMediaType()); + builder.setHash(getHashElement()); + + return builder.build(); + } + + public Date getDate() { + return date; + } + + public long getSize() { + return size; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public String getMediaType() { + return mediaType; + } + + public HashElement getHashElement() { + return hashElement; + } + + public void setName(String name) { + this.name = name; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setMediaType(String mediaType) { + this.mediaType = mediaType; + } + + public void setSize(long size) { + this.size = size; + } + + public void setDate(Date date) { + this.date = date; + } + + public void setHashElement(HashElement hashElement) { + this.hashElement = hashElement; + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleFileTransfer.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleFileTransfer.java index ae472f5b8..358ae8b23 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleFileTransfer.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleFileTransfer.java @@ -39,12 +39,12 @@ public abstract class JingleFileTransfer extends JingleDescription progressListeners = Collections.synchronizedList(new ArrayList()); - JingleFileTransfer(JingleFileTransferFile file) { - this.file = file; + JingleFileTransfer(JingleFile metadata) { + this.metadata = metadata; } public abstract boolean isOffer(); @@ -108,11 +108,16 @@ public abstract class JingleFileTransfer extends JingleDescription= 0) { target.write(bufbuf, 0, length); read += length; - LOGGER.log(Level.INFO, "Read " + read + " (" + length + ") of " + file.getSize() + " bytes."); - if (read == (int) file.getSize()) { + LOGGER.log(Level.INFO, "Read " + read + " (" + length + ") of " + metadata.getSize() + " bytes."); + if (read == (int) metadata.getSize()) { break; } } @@ -171,9 +171,4 @@ public class JingleIncomingFileOffer extends AbstractJingleFileOffer implements session.sendAccept(connection); } } - - @Override - public JingleFileTransferFile.RemoteFile getFile() { - return (JingleFileTransferFile.RemoteFile) this.file; - } } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleIncomingFileRequest.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleIncomingFileRequest.java index 36390e09d..54e39dce3 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleIncomingFileRequest.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/component/JingleIncomingFileRequest.java @@ -27,10 +27,10 @@ import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferEle * Created by vanitas on 27.07.17. * TODO: RemoteFile???? */ -public class JingleIncomingFileRequest extends AbstractJingleFileRequest implements IncomingFileRequestController { +public class JingleIncomingFileRequest extends AbstractJingleFileRequest implements IncomingFileRequestController { public JingleIncomingFileRequest(JingleFileTransferChildElement request) { - super(new JingleFileTransferFile.RemoteFile(request)); + super(new JingleFile(request)); } @Override @@ -57,9 +57,4 @@ public class JingleIncomingFileRequest extends AbstractJingleFileRequest implements OutgoingFileRequestController { +public class JingleOutgoingFileRequest extends AbstractJingleFileRequest implements OutgoingFileRequestController { - public JingleOutgoingFileRequest(JingleFileTransferFile.RemoteFile file) { + public JingleOutgoingFileRequest(JingleFile file) { super(file); } - @Override - public JingleFileTransferFile.RemoteFile getFile() { - return (JingleFileTransferFile.RemoteFile) file; - } - @Override public JingleElement handleDescriptionInfo(JingleContentDescriptionInfoElement info) { return null; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/controller/JingleFileTransferController.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/controller/JingleFileTransferController.java index 4324e415e..887fa85c6 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/controller/JingleFileTransferController.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/controller/JingleFileTransferController.java @@ -19,7 +19,7 @@ package org.jivesoftware.smackx.jingle_filetransfer.controller; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smackx.jingle.JingleDescriptionController; -import org.jivesoftware.smackx.jingle_filetransfer.component.JingleFileTransferFile; +import org.jivesoftware.smackx.jingle_filetransfer.component.JingleFile; import org.jivesoftware.smackx.jingle_filetransfer.listener.ProgressListener; /** @@ -31,7 +31,7 @@ public interface JingleFileTransferController extends JingleDescriptionControlle void removeProgressListener(ProgressListener listener); - JingleFileTransferFile getFile(); + JingleFile getMetadata(); void cancel(XMPPConnection connection) throws SmackException.NotConnectedException, InterruptedException; } 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 871359da6..6b5ff08f5 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 @@ -33,7 +33,7 @@ import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smackx.jingle.transport.jingle_ibb.JingleIBBTransportManager; import org.jivesoftware.smackx.jingle.transport.jingle_s5b.JingleS5BTransportManager; import org.jivesoftware.smackx.jingle_filetransfer.JingleFileTransferManager; -import org.jivesoftware.smackx.jingle_filetransfer.component.JingleFileTransferFile; +import org.jivesoftware.smackx.jingle_filetransfer.component.JingleFile; import org.jivesoftware.smackx.jingle_filetransfer.controller.IncomingFileOfferController; import org.jivesoftware.smackx.jingle_filetransfer.listener.IncomingFileOfferListener; import org.jivesoftware.smackx.jingle_filetransfer.listener.ProgressListener; @@ -128,7 +128,7 @@ public class JetIntegrationTest extends AbstractOmemoIntegrationTest { } }); - ja.sendEncryptedStream(sourceStream, new JingleFileTransferFile.StreamFile("test", sourceBytes.length, "desc", null, null, null), conTwo.getUser().asFullJidOrThrow(), oa); + ja.sendEncryptedStream(sourceStream, new JingleFile("test", "desc", (long) sourceBytes.length, null, null, null), conTwo.getUser().asFullJidOrThrow(), oa); received.waitForResult(60 * 1000);