mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-26 00:02:06 +01:00
Rework Bits of Binary implementation
This commit is contained in:
parent
c688acaa0f
commit
9328182912
12 changed files with 166 additions and 300 deletions
|
@ -128,8 +128,9 @@ public class PacketParserUtils {
|
||||||
return parser;
|
return parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stanza parseStanza(String stanza) throws Exception {
|
@SuppressWarnings("unchecked")
|
||||||
return parseStanza(getParserFor(stanza));
|
public static <S extends Stanza> S parseStanza(String stanza) throws Exception {
|
||||||
|
return (S) parseStanza(getParserFor(stanza));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2016 Fernando Ramirez
|
* Copyright 2016-2017 Fernando Ramirez, Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,34 +16,50 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.bob;
|
package org.jivesoftware.smackx.bob;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
|
||||||
import org.jivesoftware.smack.util.stringencoder.Base64;
|
import org.jivesoftware.smack.util.stringencoder.Base64;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bits of Binary data class.
|
* Bits of Binary data class.
|
||||||
*
|
*
|
||||||
* @author Fernando Ramirez
|
* @author Fernando Ramirez
|
||||||
|
* @author Florian Schmaus
|
||||||
* @see <a href="http://xmpp.org/extensions/xep-0231.html">XEP-0231: Bits of
|
* @see <a href="http://xmpp.org/extensions/xep-0231.html">XEP-0231: Bits of
|
||||||
* Binary</a>
|
* Binary</a>
|
||||||
*/
|
*/
|
||||||
public class BoBData {
|
public class BoBData {
|
||||||
|
|
||||||
private final long maxAge;
|
private final int maxAge;
|
||||||
private final String type;
|
private final String type;
|
||||||
private final byte[] content;
|
|
||||||
|
private byte[] contentBinary;
|
||||||
|
private String contentString;
|
||||||
|
|
||||||
|
public BoBData(String type, byte[] content) {
|
||||||
|
this(type, content, -1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BoB data constructor.
|
* BoB data constructor.
|
||||||
*
|
*
|
||||||
* @param maxAge
|
|
||||||
* @param type
|
* @param type
|
||||||
* @param content
|
* @param content
|
||||||
|
* @param maxAge
|
||||||
*/
|
*/
|
||||||
public BoBData(long maxAge, String type, byte[] content) {
|
public BoBData(String type, byte[] content, int maxAge) {
|
||||||
this.maxAge = maxAge;
|
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.content = content;
|
this.contentBinary = content;
|
||||||
|
this.maxAge = maxAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoBData(String type, String content) {
|
||||||
|
this(type, content, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoBData(String type, String content, int maxAge) {
|
||||||
|
this.type = type;
|
||||||
|
this.contentString = content;
|
||||||
|
this.maxAge = maxAge;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,7 +67,7 @@ public class BoBData {
|
||||||
*
|
*
|
||||||
* @return the max age
|
* @return the max age
|
||||||
*/
|
*/
|
||||||
public long getMaxAge() {
|
public int getMaxAge() {
|
||||||
return maxAge;
|
return maxAge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,13 +80,21 @@ public class BoBData {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setContentBinaryIfRequired() {
|
||||||
|
if (contentBinary == null) {
|
||||||
|
assert(StringUtils.isNotEmpty(contentString));
|
||||||
|
contentBinary = Base64.decode(contentString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the content.
|
* Get the content.
|
||||||
*
|
*
|
||||||
* @return the content
|
* @return the content
|
||||||
*/
|
*/
|
||||||
public byte[] getContent() {
|
public byte[] getContent() {
|
||||||
return content;
|
setContentBinaryIfRequired();
|
||||||
|
return contentBinary.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,13 +102,20 @@ public class BoBData {
|
||||||
*
|
*
|
||||||
* @return the content in a Base64 encoded String
|
* @return the content in a Base64 encoded String
|
||||||
*/
|
*/
|
||||||
public String getBase64Encoded() {
|
public String getContentBase64Encoded() {
|
||||||
byte[] bytes = Base64.encode(content);
|
if (contentString == null) {
|
||||||
try {
|
contentString = Base64.encodeToString(getContent());
|
||||||
return new String(bytes, "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new IllegalStateException("UTF-8 is not supported.");
|
|
||||||
}
|
}
|
||||||
|
return contentString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the data is of reasonable size. XEP-0231 suggest that the size should not be more than 8 KiB.
|
||||||
|
*
|
||||||
|
* @return true if the data if of reasonable size.
|
||||||
|
*/
|
||||||
|
public boolean isOfReasonableSize() {
|
||||||
|
setContentBinaryIfRequired();
|
||||||
|
return contentBinary.length <= 8 * 1024;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2016 Fernando Ramirez
|
* Copyright 2016-2017 Fernando Ramirez, Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,10 +16,13 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.bob;
|
package org.jivesoftware.smackx.bob;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bits of Binary hash class.
|
* Bits of Binary hash class.
|
||||||
*
|
*
|
||||||
* @author Fernando Ramirez
|
* @author Fernando Ramirez
|
||||||
|
* @author Florian Schmaus
|
||||||
* @see <a href="http://xmpp.org/extensions/xep-0231.html">XEP-0231: Bits of
|
* @see <a href="http://xmpp.org/extensions/xep-0231.html">XEP-0231: Bits of
|
||||||
* Binary</a>
|
* Binary</a>
|
||||||
*/
|
*/
|
||||||
|
@ -27,6 +30,7 @@ public class BoBHash {
|
||||||
|
|
||||||
private final String hash;
|
private final String hash;
|
||||||
private final String hashType;
|
private final String hashType;
|
||||||
|
private final String cid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BoB hash constructor.
|
* BoB hash constructor.
|
||||||
|
@ -35,8 +39,9 @@ public class BoBHash {
|
||||||
* @param hashType
|
* @param hashType
|
||||||
*/
|
*/
|
||||||
public BoBHash(String hash, String hashType) {
|
public BoBHash(String hash, String hashType) {
|
||||||
this.hash = hash;
|
this.hash = StringUtils.requireNotNullOrEmpty(hash, "hash must not be null or empty");
|
||||||
this.hashType = hashType;
|
this.hashType = StringUtils.requireNotNullOrEmpty(hashType, "hashType must not be null or empty");
|
||||||
|
this.cid = this.hashType + '+' + this.hash + "@bob.xmpp.org";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,7 +68,7 @@ public class BoBHash {
|
||||||
* @return src attribute string
|
* @return src attribute string
|
||||||
*/
|
*/
|
||||||
public String toSrc() {
|
public String toSrc() {
|
||||||
return "cid:" + toCid();
|
return "cid:" + getCid();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,8 +76,22 @@ public class BoBHash {
|
||||||
*
|
*
|
||||||
* @return cid attribute string
|
* @return cid attribute string
|
||||||
*/
|
*/
|
||||||
public String toCid() {
|
public String getCid() {
|
||||||
return this.hashType + "+" + this.hash + "@bob.xmpp.org";
|
return cid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (other instanceof BoBHash) {
|
||||||
|
BoBHash otherBob = (BoBHash) other;
|
||||||
|
return cid.equals(otherBob.cid);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return cid.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2016 Fernando Ramirez
|
* Copyright 2017 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,18 +16,23 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.bob;
|
package org.jivesoftware.smackx.bob;
|
||||||
|
|
||||||
/**
|
import java.util.Set;
|
||||||
* Bits of Binary Saver Manager interface.
|
|
||||||
*
|
|
||||||
* @author Fernando Ramirez
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public interface BoBSaverManager {
|
|
||||||
|
|
||||||
public void addBoB(BoBHash bobHash, BoBData bobData);
|
public class BoBInfo {
|
||||||
|
|
||||||
public void removeBoB(BoBHash bobHash);
|
private final Set<BoBHash> hashes;
|
||||||
|
private final BoBData data;
|
||||||
|
|
||||||
public BoBData getBoB(BoBHash bobHash);
|
BoBInfo(Set<BoBHash> hashes, BoBData data) {
|
||||||
|
this.hashes = hashes;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<BoBHash> getHashes() {
|
||||||
|
return hashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoBData getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2016 Fernando Ramirez
|
* Copyright 2016-2017 Fernando Ramirez, Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,8 +16,11 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.bob;
|
package org.jivesoftware.smackx.bob;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.jivesoftware.smack.ConnectionCreationListener;
|
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||||
import org.jivesoftware.smack.Manager;
|
import org.jivesoftware.smack.Manager;
|
||||||
|
@ -31,27 +34,29 @@ import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
|
||||||
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
|
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smack.packet.IQ.Type;
|
import org.jivesoftware.smack.packet.IQ.Type;
|
||||||
|
import org.jivesoftware.smack.util.SHA1;
|
||||||
import org.jivesoftware.smackx.bob.element.BoBIQ;
|
import org.jivesoftware.smackx.bob.element.BoBIQ;
|
||||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
import org.jxmpp.jid.Jid;
|
import org.jxmpp.jid.Jid;
|
||||||
|
import org.jxmpp.util.cache.LruCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bits of Binary manager class.
|
* Bits of Binary manager class.
|
||||||
*
|
*
|
||||||
* @author Fernando Ramirez
|
* @author Fernando Ramirez
|
||||||
|
* @author Florian Schmaus
|
||||||
* @see <a href="http://xmpp.org/extensions/xep-0231.html">XEP-0231: Bits of
|
* @see <a href="http://xmpp.org/extensions/xep-0231.html">XEP-0231: Bits of
|
||||||
* Binary</a>
|
* Binary</a>
|
||||||
*/
|
*/
|
||||||
public final class BoBManager extends Manager {
|
public final class BoBManager extends Manager {
|
||||||
|
|
||||||
public static final String NAMESPACE = "urn:xmpp:bob";
|
public static final String NAMESPACE = "urn:xmpp:bob";
|
||||||
public static BoBSaverManager bobSaverManager;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
|
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||||
@Override
|
@Override
|
||||||
public void connectionCreated(XMPPConnection connection) {
|
public void connectionCreated(XMPPConnection connection) {
|
||||||
getInstanceFor(connection, bobSaverManager);
|
getInstanceFor(connection);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -62,16 +67,9 @@ public final class BoBManager extends Manager {
|
||||||
* Get the singleton instance of BoBManager.
|
* Get the singleton instance of BoBManager.
|
||||||
*
|
*
|
||||||
* @param connection
|
* @param connection
|
||||||
* @param saverManager
|
|
||||||
* @return the instance of BoBManager
|
* @return the instance of BoBManager
|
||||||
*/
|
*/
|
||||||
public static synchronized BoBManager getInstanceFor(XMPPConnection connection, BoBSaverManager saverManager) {
|
public static synchronized BoBManager getInstanceFor(XMPPConnection connection) {
|
||||||
if (saverManager == null) {
|
|
||||||
bobSaverManager = new DefaultBoBSaverManager();
|
|
||||||
} else {
|
|
||||||
bobSaverManager = saverManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
BoBManager bobManager = INSTANCES.get(connection);
|
BoBManager bobManager = INSTANCES.get(connection);
|
||||||
if (bobManager == null) {
|
if (bobManager == null) {
|
||||||
bobManager = new BoBManager(connection);
|
bobManager = new BoBManager(connection);
|
||||||
|
@ -81,36 +79,33 @@ public final class BoBManager extends Manager {
|
||||||
return bobManager;
|
return bobManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final LruCache<BoBHash, BoBData> BOB_CACHE = new LruCache<>(128);
|
||||||
|
|
||||||
|
private final Map<BoBHash, BoBInfo> bobs = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private BoBManager(XMPPConnection connection) {
|
private BoBManager(XMPPConnection connection) {
|
||||||
super(connection);
|
super(connection);
|
||||||
ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(connection);
|
ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(connection);
|
||||||
serviceDiscoveryManager.addFeature(NAMESPACE);
|
serviceDiscoveryManager.addFeature(NAMESPACE);
|
||||||
|
|
||||||
connection.registerIQRequestHandler(
|
connection.registerIQRequestHandler(
|
||||||
new AbstractIqRequestHandler(BoBIQ.ELEMENT, BoBIQ.NAMESPACE, Type.get, Mode.sync) {
|
new AbstractIqRequestHandler(BoBIQ.ELEMENT, BoBIQ.NAMESPACE, Type.get, Mode.async) {
|
||||||
@Override
|
@Override
|
||||||
public IQ handleIQRequest(IQ iqRequest) {
|
public IQ handleIQRequest(IQ iqRequest) {
|
||||||
BoBIQ getBoBIQ = (BoBIQ) iqRequest;
|
BoBIQ bobIQRequest = (BoBIQ) iqRequest;
|
||||||
|
|
||||||
BoBData bobData = bobSaverManager.getBoB(getBoBIQ.getBoBHash());
|
BoBInfo bobInfo = bobs.get(bobIQRequest.getBoBHash());
|
||||||
BoBIQ responseBoBIQ = null;
|
if (bobInfo == null) {
|
||||||
try {
|
// TODO return item-not-found
|
||||||
responseBoBIQ = responseBoB(getBoBIQ, bobData);
|
|
||||||
} catch (NotConnectedException | NotLoggedInException | InterruptedException e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
return responseBoBIQ;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
connection.registerIQRequestHandler(
|
|
||||||
new AbstractIqRequestHandler(BoBIQ.ELEMENT, BoBIQ.NAMESPACE, Type.result, Mode.sync) {
|
|
||||||
@Override
|
|
||||||
public IQ handleIQRequest(IQ iqRequest) {
|
|
||||||
BoBIQ resultBoBIQ = (BoBIQ) iqRequest;
|
|
||||||
bobSaverManager.addBoB(resultBoBIQ.getBoBHash(), resultBoBIQ.getBoBData());
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BoBData bobData = bobInfo.getData();
|
||||||
|
BoBIQ responseBoBIQ = new BoBIQ(bobIQRequest.getBoBHash(), bobData);
|
||||||
|
responseBoBIQ.setType(Type.result);
|
||||||
|
responseBoBIQ.setTo(bobIQRequest.getFrom());
|
||||||
|
return responseBoBIQ;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,21 +137,46 @@ public final class BoBManager extends Manager {
|
||||||
*/
|
*/
|
||||||
public BoBData requestBoB(Jid to, BoBHash bobHash) throws NotLoggedInException, NoResponseException,
|
public BoBData requestBoB(Jid to, BoBHash bobHash) throws NotLoggedInException, NoResponseException,
|
||||||
XMPPErrorException, NotConnectedException, InterruptedException {
|
XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
BoBData bobData = BOB_CACHE.lookup(bobHash);
|
||||||
|
if (bobData != null) {
|
||||||
|
return bobData;
|
||||||
|
}
|
||||||
|
|
||||||
BoBIQ requestBoBIQ = new BoBIQ(bobHash);
|
BoBIQ requestBoBIQ = new BoBIQ(bobHash);
|
||||||
requestBoBIQ.setType(Type.get);
|
requestBoBIQ.setType(Type.get);
|
||||||
requestBoBIQ.setTo(to);
|
requestBoBIQ.setTo(to);
|
||||||
|
|
||||||
XMPPConnection connection = getAuthenticatedConnectionOrThrow();
|
XMPPConnection connection = getAuthenticatedConnectionOrThrow();
|
||||||
BoBIQ responseBoBIQ = connection.createPacketCollectorAndSend(requestBoBIQ).nextResultOrThrow();
|
BoBIQ responseBoBIQ = connection.createPacketCollectorAndSend(requestBoBIQ).nextResultOrThrow();
|
||||||
return responseBoBIQ.getBoBData();
|
|
||||||
|
bobData = responseBoBIQ.getBoBData();
|
||||||
|
BOB_CACHE.put(bobHash, bobData);
|
||||||
|
|
||||||
|
return bobData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoBIQ responseBoB(BoBIQ requestBoBIQ, BoBData bobData)
|
public BoBInfo addBoB(BoBData bobData) {
|
||||||
throws NotConnectedException, InterruptedException, NotLoggedInException {
|
// We only support SHA-1 for now.
|
||||||
BoBIQ responseBoBIQ = new BoBIQ(requestBoBIQ.getBoBHash(), bobData);
|
BoBHash bobHash = new BoBHash("sha1", SHA1.hex(bobData.getContent()));
|
||||||
responseBoBIQ.setType(Type.result);
|
|
||||||
responseBoBIQ.setTo(requestBoBIQ.getFrom());
|
Set<BoBHash> bobHashes = Collections.singleton(bobHash);
|
||||||
return responseBoBIQ;
|
bobHashes = Collections.unmodifiableSet(bobHashes);
|
||||||
|
|
||||||
|
BoBInfo bobInfo = new BoBInfo(bobHashes, bobData);
|
||||||
|
|
||||||
|
bobs.put(bobHash, bobInfo);
|
||||||
|
|
||||||
|
return bobInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BoBInfo removeBoB(BoBHash bobHash) {
|
||||||
|
BoBInfo bobInfo = bobs.remove(bobHash);
|
||||||
|
if (bobInfo == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (BoBHash otherBobHash : bobInfo.getHashes()) {
|
||||||
|
bobs.remove(otherBobHash);
|
||||||
|
}
|
||||||
|
return bobInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2016 Fernando Ramirez
|
|
||||||
*
|
|
||||||
* 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.bob;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default Bits of Binary Saver Manager class.
|
|
||||||
*
|
|
||||||
* @author Fernando Ramirez
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class DefaultBoBSaverManager implements BoBSaverManager {
|
|
||||||
|
|
||||||
HashMap<BoBHash, BoBData> bobs = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addBoB(BoBHash bobHash, BoBData bobData) {
|
|
||||||
bobs.put(bobHash, bobData);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeBoB(BoBHash bobHash) {
|
|
||||||
bobs.remove(bobHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BoBData getBoB(BoBHash bobHash) {
|
|
||||||
return bobs.get(bobHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -84,13 +84,13 @@ public class BoBIQ extends IQ {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
xml.attribute("cid", bobHash.toCid());
|
xml.attribute("cid", bobHash.getCid());
|
||||||
|
|
||||||
if (bobData != null) {
|
if (bobData != null) {
|
||||||
xml.attribute("max-age", String.valueOf(bobData.getMaxAge()));
|
xml.optIntAttribute("max_age", bobData.getMaxAge());
|
||||||
xml.attribute("type", bobData.getType());
|
xml.attribute("type", bobData.getType());
|
||||||
xml.rightAngleBracket();
|
xml.rightAngleBracket();
|
||||||
xml.escape(bobData.getBase64Encoded());
|
xml.escape(bobData.getContentBase64Encoded());
|
||||||
} else {
|
} else {
|
||||||
xml.setEmptyElement();
|
xml.setEmptyElement();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2016 Fernando Ramirez
|
|
||||||
*
|
|
||||||
* 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.bob.provider;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
|
||||||
import org.jivesoftware.smackx.bob.BoBHash;
|
|
||||||
import org.jivesoftware.smackx.bob.element.BoBExtension;
|
|
||||||
import org.jivesoftware.smackx.xhtmlim.XHTMLText;
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bits of Binary extension provider class.
|
|
||||||
*
|
|
||||||
* @author Fernando Ramirez
|
|
||||||
* @see <a href="http://xmpp.org/extensions/xep-0231.html">XEP-0231: Bits of
|
|
||||||
* Binary</a>
|
|
||||||
*/
|
|
||||||
public class BoBExtensionProvider extends ExtensionElementProvider<BoBExtension> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BoBExtension parse(XmlPullParser parser, int initialDepth) throws Exception {
|
|
||||||
BoBHash bobHash = null;
|
|
||||||
String alt = null;
|
|
||||||
|
|
||||||
outerloop: while (true) {
|
|
||||||
int eventType = parser.next();
|
|
||||||
|
|
||||||
switch (eventType) {
|
|
||||||
|
|
||||||
case XmlPullParser.START_TAG:
|
|
||||||
if (parser.getName().equals(XHTMLText.IMG)) {
|
|
||||||
alt = parser.getAttributeValue("", "alt");
|
|
||||||
|
|
||||||
String src = parser.getAttributeValue("", "src");
|
|
||||||
bobHash = BoBHash.fromSrc(src);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case XmlPullParser.END_TAG:
|
|
||||||
if (parser.getDepth() == initialDepth) {
|
|
||||||
break outerloop;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BoBExtension(bobHash, alt, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2016 Fernando Ramirez
|
* Copyright 2017 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
package org.jivesoftware.smackx.bob.provider;
|
package org.jivesoftware.smackx.bob.provider;
|
||||||
|
|
||||||
import org.jivesoftware.smack.provider.IQProvider;
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
import org.jivesoftware.smack.util.stringencoder.Base64;
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
import org.jivesoftware.smackx.bob.BoBData;
|
import org.jivesoftware.smackx.bob.BoBData;
|
||||||
import org.jivesoftware.smackx.bob.BoBHash;
|
import org.jivesoftware.smackx.bob.BoBHash;
|
||||||
import org.jivesoftware.smackx.bob.element.BoBIQ;
|
import org.jivesoftware.smackx.bob.element.BoBIQ;
|
||||||
|
@ -26,7 +26,7 @@ import org.xmlpull.v1.XmlPullParser;
|
||||||
/**
|
/**
|
||||||
* Bits of Binary IQ provider class.
|
* Bits of Binary IQ provider class.
|
||||||
*
|
*
|
||||||
* @author Fernando Ramirez
|
* @author Florian Schmaus
|
||||||
* @see <a href="http://xmpp.org/extensions/xep-0231.html">XEP-0231: Bits of
|
* @see <a href="http://xmpp.org/extensions/xep-0231.html">XEP-0231: Bits of
|
||||||
* Binary</a>
|
* Binary</a>
|
||||||
*/
|
*/
|
||||||
|
@ -34,34 +34,19 @@ public class BoBIQProvider extends IQProvider<BoBIQ> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BoBIQ parse(XmlPullParser parser, int initialDepth) throws Exception {
|
public BoBIQ parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
BoBHash bobHash = null;
|
|
||||||
BoBData bobData = null;
|
|
||||||
|
|
||||||
parser.next();
|
|
||||||
|
|
||||||
if (parser.getName().equals(BoBIQ.ELEMENT)) {
|
|
||||||
String cid = parser.getAttributeValue("", "cid");
|
String cid = parser.getAttributeValue("", "cid");
|
||||||
bobHash = BoBHash.fromCid(cid);
|
BoBHash bobHash = BoBHash.fromCid(cid);
|
||||||
|
|
||||||
String dataType = parser.getAttributeValue("", "type");
|
String dataType = parser.getAttributeValue("", "type");
|
||||||
String maxAgeString = parser.getAttributeValue("", "max-age");
|
int maxAge = ParserUtils.getIntegerAttribute(parser, "max-age", -1);
|
||||||
|
|
||||||
long maxAge = 0;
|
String base64EncodedData = parser.nextText();
|
||||||
if (maxAgeString != null) {
|
|
||||||
maxAge = Long.parseLong(maxAgeString);
|
|
||||||
}
|
|
||||||
|
|
||||||
String base64EncodedData = null;
|
|
||||||
try {
|
|
||||||
base64EncodedData = parser.nextText();
|
|
||||||
} catch (Exception e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (base64EncodedData != null && dataType != null) {
|
|
||||||
byte[] base64EncodedDataBytes = base64EncodedData.getBytes();
|
|
||||||
bobData = new BoBData(maxAge, dataType, Base64.decode(base64EncodedDataBytes));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
BoBData bobData;
|
||||||
|
if (dataType != null) {
|
||||||
|
bobData = new BoBData(dataType, base64EncodedData, maxAge);
|
||||||
|
} else {
|
||||||
|
bobData = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BoBIQ(bobHash, bobData);
|
return new BoBIQ(bobHash, bobData);
|
||||||
|
|
|
@ -538,11 +538,6 @@
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- XEP-0231: Bits of Binary -->
|
<!-- XEP-0231: Bits of Binary -->
|
||||||
<extensionProvider>
|
|
||||||
<elementName>html</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/xhtml-im</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.bob.provider.BoBExtensionProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>data</elementName>
|
<elementName>data</elementName>
|
||||||
<namespace>urn:xmpp:bob</namespace>
|
<namespace>urn:xmpp:bob</namespace>
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2016 Fernando Ramirez
|
|
||||||
*
|
|
||||||
* 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.bob;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.Message;
|
|
||||||
import org.jivesoftware.smack.packet.Message.Type;
|
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
|
||||||
import org.jivesoftware.smackx.bob.element.BoBExtension;
|
|
||||||
import org.jivesoftware.smackx.bob.provider.BoBExtensionProvider;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
|
||||||
|
|
||||||
public class BoBExtensionTest {
|
|
||||||
|
|
||||||
String sampleMessageWithBoBExtension = "<message to='macbeth@chat.shakespeare.lit' id='sarasa' type='groupchat'>"
|
|
||||||
+ "<body>Yet here's a spot.</body>" + "<html xmlns='http://jabber.org/protocol/xhtml-im'>"
|
|
||||||
+ "<body xmlns='http://www.w3.org/1999/xhtml'>"
|
|
||||||
+ "<img alt='A spot' src='cid:sha1+8f35fef110ffc5df08d579a50083ff9308fb6242@bob.xmpp.org'/>" + "</body>"
|
|
||||||
+ "</html>" + "</message>";
|
|
||||||
|
|
||||||
String sampleBoBExtension = "<html xmlns='http://jabber.org/protocol/xhtml-im'>"
|
|
||||||
+ "<body xmlns='http://www.w3.org/1999/xhtml'>"
|
|
||||||
+ "<img alt='A spot' src='cid:sha1+8f35fef110ffc5df08d579a50083ff9308fb6242@bob.xmpp.org'/>" + "</body>"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void checkBoBMessageExtension() throws Exception {
|
|
||||||
Message message = (Message) PacketParserUtils.parseStanza(sampleMessageWithBoBExtension);
|
|
||||||
|
|
||||||
BoBHash bobHash = new BoBHash("8f35fef110ffc5df08d579a50083ff9308fb6242", "sha1");
|
|
||||||
|
|
||||||
Message createdMessage = new Message(JidCreate.from("macbeth@chat.shakespeare.lit"));
|
|
||||||
createdMessage.setStanzaId("sarasa");
|
|
||||||
createdMessage.setType(Type.groupchat);
|
|
||||||
createdMessage.setBody("Yet here's a spot.");
|
|
||||||
createdMessage.addExtension(new BoBExtension(bobHash, "A spot", null));
|
|
||||||
|
|
||||||
Assert.assertEquals(message.toXML().toString(), createdMessage.toXML().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void checkBoBExtensionProvider() throws Exception {
|
|
||||||
XmlPullParser parser = PacketParserUtils.getParserFor(sampleBoBExtension);
|
|
||||||
BoBExtension bobExtension = new BoBExtensionProvider().parse(parser);
|
|
||||||
|
|
||||||
Assert.assertEquals("A spot", bobExtension.getAlt());
|
|
||||||
Assert.assertEquals("sha1", bobExtension.getBoBHash().getHashType());
|
|
||||||
Assert.assertEquals("8f35fef110ffc5df08d579a50083ff9308fb6242", bobExtension.getBoBHash().getHash());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -20,11 +20,9 @@ import org.jivesoftware.smack.packet.IQ.Type;
|
||||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
import org.jivesoftware.smackx.bob.element.BoBIQ;
|
import org.jivesoftware.smackx.bob.element.BoBIQ;
|
||||||
import org.jivesoftware.smackx.bob.provider.BoBIQProvider;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
|
||||||
|
|
||||||
public class BoBIQTest extends SmackTestSuite {
|
public class BoBIQTest extends SmackTestSuite {
|
||||||
|
|
||||||
|
@ -37,12 +35,6 @@ public class BoBIQTest extends SmackTestSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkBoBIQRequest() throws Exception {
|
public void checkBoBIQRequest() throws Exception {
|
||||||
XmlPullParser parser = PacketParserUtils.getParserFor(sampleBoBIQRequest);
|
|
||||||
BoBIQ bobIQ = new BoBIQProvider().parse(parser);
|
|
||||||
bobIQ.setStanzaId("sarasa");
|
|
||||||
bobIQ.setTo(JidCreate.from("ladymacbeth@shakespeare.lit/castle"));
|
|
||||||
bobIQ.setType(Type.get);
|
|
||||||
|
|
||||||
BoBHash bobHash = new BoBHash("8f35fef110ffc5df08d579a50083ff9308fb6242", "sha1");
|
BoBHash bobHash = new BoBHash("8f35fef110ffc5df08d579a50083ff9308fb6242", "sha1");
|
||||||
|
|
||||||
BoBIQ createdBoBIQ = new BoBIQ(bobHash);
|
BoBIQ createdBoBIQ = new BoBIQ(bobHash);
|
||||||
|
@ -55,14 +47,10 @@ public class BoBIQTest extends SmackTestSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkBoBIQResponse() throws Exception {
|
public void checkBoBIQResponse() throws Exception {
|
||||||
XmlPullParser parser = PacketParserUtils.getParserFor(sampleBoBIQResponse);
|
BoBIQ bobIQ = PacketParserUtils.parseStanza(sampleBoBIQResponse);
|
||||||
BoBIQ bobIQ = new BoBIQProvider().parse(parser);
|
|
||||||
bobIQ.setStanzaId("sarasa");
|
|
||||||
bobIQ.setTo(JidCreate.from("doctor@shakespeare.lit/pda"));
|
|
||||||
bobIQ.setType(Type.result);
|
|
||||||
|
|
||||||
BoBHash bobHash = new BoBHash("8f35fef110ffc5df08d579a50083ff9308fb6242", "sha1");
|
BoBHash bobHash = new BoBHash("8f35fef110ffc5df08d579a50083ff9308fb6242", "sha1");
|
||||||
BoBData bobData = new BoBData(86400, "image/png", "sarasade2354j2".getBytes());
|
BoBData bobData = new BoBData("image/png", "sarasade2354j2".getBytes(), 86400);
|
||||||
|
|
||||||
BoBIQ createdBoBIQ = new BoBIQ(bobHash, bobData);
|
BoBIQ createdBoBIQ = new BoBIQ(bobHash, bobData);
|
||||||
createdBoBIQ.setStanzaId("sarasa");
|
createdBoBIQ.setStanzaId("sarasa");
|
||||||
|
@ -73,7 +61,7 @@ public class BoBIQTest extends SmackTestSuite {
|
||||||
Assert.assertEquals(bobIQ.getBoBHash().getHashType(), createdBoBIQ.getBoBHash().getHashType());
|
Assert.assertEquals(bobIQ.getBoBHash().getHashType(), createdBoBIQ.getBoBHash().getHashType());
|
||||||
Assert.assertEquals(bobIQ.getBoBData().getMaxAge(), createdBoBIQ.getBoBData().getMaxAge());
|
Assert.assertEquals(bobIQ.getBoBData().getMaxAge(), createdBoBIQ.getBoBData().getMaxAge());
|
||||||
Assert.assertEquals(bobIQ.getBoBData().getType(), createdBoBIQ.getBoBData().getType());
|
Assert.assertEquals(bobIQ.getBoBData().getType(), createdBoBIQ.getBoBData().getType());
|
||||||
Assert.assertEquals(bobIQ.getBoBData().getBase64Encoded(), createdBoBIQ.getBoBData().getBase64Encoded());
|
Assert.assertEquals(bobIQ.getBoBData().getContentBase64Encoded(), createdBoBIQ.getBoBData().getContentBase64Encoded());
|
||||||
Assert.assertEquals(bobIQ.toXML().toString(), createdBoBIQ.toXML().toString());
|
Assert.assertEquals(bobIQ.toXML().toString(), createdBoBIQ.toXML().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue