mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-22 12:02:05 +01:00
Refactor FileTransfer(Manager|Negotiator)
to use WeakHashMaps and extend Manager. SMACK-579
This commit is contained in:
parent
fdaf7940fb
commit
09425609af
8 changed files with 66 additions and 133 deletions
|
@ -33,9 +33,8 @@ to enable the user to easily send a file.
|
|||
|
||||
<b>Usage</b><p>
|
||||
|
||||
In order to send a file you must first construct an instance of the <b><i>FileTransferManager</i></b>
|
||||
class. This class has one constructor with one parameter which is your XMPPConnection.
|
||||
In order to instantiate the manager you should call <i>new FileTransferManager(connection)</i>
|
||||
In order to send a file you must first construct an instance of the <b><i>FileTransferManager</i></b> class.
|
||||
In order to instantiate the manager you should call <i>FileTransferManager.getInstanceFor(connection)</i>
|
||||
|
||||
<p>Once you have your <b><i>FileTransferManager</i></b> you will need to create an outgoing
|
||||
file transfer to send a file. The method to use on the <b><i>FileTransferManager</i></b>
|
||||
|
@ -62,7 +61,7 @@ In this example we can see how to send a file: <br>
|
|||
<blockquote>
|
||||
<pre>
|
||||
<font color="#3f7f5f">// Create the file transfer manager</font>
|
||||
FileTransferManager manager = new FileTransferManager(connection);
|
||||
FileTransferManager manager = FileTransferManager.getInstanceFor(connection);
|
||||
|
||||
<font color="#3f7f5f">// Create the outgoing file transfer</font>
|
||||
OutgoingFileTransfer transfer = manager.createOutgoingFileTransfer(<font color="#0000FF">"romeo@montague.net"</font>);
|
||||
|
@ -85,9 +84,8 @@ manager.</p>
|
|||
|
||||
<b>Usage</b><p>
|
||||
|
||||
In order to recieve a file you must first construct an instance of the <b><i>FileTransferManager</i></b>
|
||||
class. This class has one constructor with one parameter which is your XMPPConnection.
|
||||
In order to instantiate the manager you should call <i>new FileTransferManager(connection)</i>
|
||||
In order to recieve a file you must first construct an instance of the <b><i>FileTransferManager</i></b> class.
|
||||
In order to instantiate the manager you should call <i>FileTransferManager.getInstanceFor(connection)</i>
|
||||
|
||||
<p>Once you have your <b><i>FileTransferManager</i></b> you will need to register a listener
|
||||
with it. The FileTransferListner interface has one method, <b>fileTransferRequest(request)</b>.
|
||||
|
@ -114,7 +112,7 @@ consult the Javadoc for more information.
|
|||
In this example we can see how to approve or reject a file transfer request: <br>
|
||||
<blockquote>
|
||||
<pre> <font color="#3f7f5f">// Create the file transfer manager</font>
|
||||
final FileTransferManager manager = new FileTransferManager(connection);
|
||||
FileTransferManager manager = FileTransferManager.getInstanceFor(connection);
|
||||
|
||||
<font color="#3f7f5f">// Create the listener</font>
|
||||
manager.addFileTransferListener(new FileTransferListener() {
|
||||
|
|
|
@ -23,6 +23,9 @@ public abstract class Manager {
|
|||
final WeakReference<XMPPConnection> weakConnection;
|
||||
|
||||
public Manager(XMPPConnection connection) {
|
||||
if (connection == null) {
|
||||
throw new IllegalArgumentException("XMPPConnection must not be null");
|
||||
}
|
||||
weakConnection = new WeakReference<XMPPConnection>(connection);
|
||||
}
|
||||
|
||||
|
|
|
@ -161,9 +161,6 @@ public class FaultTolerantNegotiator extends StreamNegotiator {
|
|||
return namespaces;
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
private class NegotiatorService implements Callable<InputStream> {
|
||||
|
||||
private PacketCollector collector;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.jivesoftware.smackx.filetransfer;
|
||||
|
||||
import org.jivesoftware.smack.Manager;
|
||||
import org.jivesoftware.smack.PacketListener;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
|
@ -28,8 +29,10 @@ import org.jivesoftware.smack.packet.XMPPError;
|
|||
import org.jivesoftware.smackx.si.packet.StreamInitiation;
|
||||
import org.jxmpp.util.XmppStringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* The file transfer manager class handles the sending and recieving of files.
|
||||
|
@ -43,13 +46,22 @@ import java.util.List;
|
|||
* @author Alexander Wenckus
|
||||
*
|
||||
*/
|
||||
public class FileTransferManager {
|
||||
public class FileTransferManager extends Manager {
|
||||
|
||||
private static final Map<XMPPConnection, FileTransferManager> INSTANCES = new WeakHashMap<XMPPConnection, FileTransferManager>();
|
||||
|
||||
public static synchronized FileTransferManager getInstanceFor(XMPPConnection connection) {
|
||||
FileTransferManager fileTransferManager = INSTANCES.get(connection);
|
||||
if (fileTransferManager == null) {
|
||||
fileTransferManager = new FileTransferManager(connection);
|
||||
INSTANCES.put(connection, fileTransferManager);
|
||||
}
|
||||
return fileTransferManager;
|
||||
}
|
||||
|
||||
private final FileTransferNegotiator fileTransferNegotiator;
|
||||
|
||||
private List<FileTransferListener> listeners;
|
||||
|
||||
private XMPPConnection connection;
|
||||
private final List<FileTransferListener> listeners = new CopyOnWriteArrayList<FileTransferListener>();
|
||||
|
||||
/**
|
||||
* Creates a file transfer manager to initiate and receive file transfers.
|
||||
|
@ -57,10 +69,19 @@ public class FileTransferManager {
|
|||
* @param connection
|
||||
* The XMPPConnection that the file transfers will use.
|
||||
*/
|
||||
public FileTransferManager(XMPPConnection connection) {
|
||||
this.connection = connection;
|
||||
private FileTransferManager(XMPPConnection connection) {
|
||||
super(connection);
|
||||
this.fileTransferNegotiator = FileTransferNegotiator
|
||||
.getInstanceFor(connection);
|
||||
connection.addPacketListener(new PacketListener() {
|
||||
public void processPacket(Packet packet) {
|
||||
StreamInitiation si = (StreamInitiation) packet;
|
||||
FileTransferRequest request = new FileTransferRequest(FileTransferManager.this, si);
|
||||
for (FileTransferListener listener : listeners) {
|
||||
listener.fileTransferRequest(request);
|
||||
}
|
||||
}
|
||||
}, new AndFilter(new PacketTypeFilter(StreamInitiation.class), IQTypeFilter.SET));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,35 +94,7 @@ public class FileTransferManager {
|
|||
* @see FileTransferListener
|
||||
*/
|
||||
public void addFileTransferListener(final FileTransferListener li) {
|
||||
if (listeners == null) {
|
||||
initListeners();
|
||||
}
|
||||
synchronized (this.listeners) {
|
||||
listeners.add(li);
|
||||
}
|
||||
}
|
||||
|
||||
private void initListeners() {
|
||||
listeners = new ArrayList<FileTransferListener>();
|
||||
|
||||
connection.addPacketListener(new PacketListener() {
|
||||
public void processPacket(Packet packet) {
|
||||
fireNewRequest((StreamInitiation) packet);
|
||||
}
|
||||
}, new AndFilter(new PacketTypeFilter(StreamInitiation.class),
|
||||
IQTypeFilter.SET));
|
||||
}
|
||||
|
||||
protected void fireNewRequest(StreamInitiation initiation) {
|
||||
FileTransferListener[] listeners = null;
|
||||
synchronized (this.listeners) {
|
||||
listeners = new FileTransferListener[this.listeners.size()];
|
||||
this.listeners.toArray(listeners);
|
||||
}
|
||||
FileTransferRequest request = new FileTransferRequest(this, initiation);
|
||||
for (int i = 0; i < listeners.length; i++) {
|
||||
listeners[i].fileTransferRequest(request);
|
||||
}
|
||||
listeners.add(li);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,12 +105,7 @@ public class FileTransferManager {
|
|||
* @see FileTransferListener
|
||||
*/
|
||||
public void removeFileTransferListener(final FileTransferListener li) {
|
||||
if (listeners == null) {
|
||||
return;
|
||||
}
|
||||
synchronized (this.listeners) {
|
||||
listeners.remove(li);
|
||||
}
|
||||
listeners.remove(li);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,7 +128,7 @@ public class FileTransferManager {
|
|||
throw new IllegalArgumentException("The provided user id was not a full JID (i.e. with resource part)");
|
||||
}
|
||||
|
||||
return new OutgoingFileTransfer(connection.getUser(), userID,
|
||||
return new OutgoingFileTransfer(connection().getUser(), userID,
|
||||
fileTransferNegotiator.getNextStreamID(),
|
||||
fileTransferNegotiator);
|
||||
}
|
||||
|
@ -175,6 +163,6 @@ public class FileTransferManager {
|
|||
initiation.getPacketID(), initiation.getFrom(), initiation
|
||||
.getTo(), IQ.Type.error);
|
||||
rejection.setError(new XMPPError(XMPPError.Condition.no_acceptable));
|
||||
connection.sendPacket(rejection);
|
||||
connection().sendPacket(rejection);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,9 +24,9 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.jivesoftware.smack.AbstractConnectionListener;
|
||||
import org.jivesoftware.smack.Manager;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.PacketCollector;
|
||||
|
@ -50,16 +50,13 @@ import org.jivesoftware.smackx.xdata.packet.DataForm;
|
|||
* @author Alexander Wenckus
|
||||
* @see <a href="http://xmpp.org/extensions/xep-0096.html">XEP-0096: SI File Transfer</a>
|
||||
*/
|
||||
public class FileTransferNegotiator {
|
||||
public class FileTransferNegotiator extends Manager {
|
||||
|
||||
// Static
|
||||
public static final String SI_NAMESPACE = "http://jabber.org/protocol/si";
|
||||
public static final String SI_PROFILE_FILE_TRANSFER_NAMESPACE = "http://jabber.org/protocol/si/profile/file-transfer";
|
||||
private static final String[] NAMESPACE = { SI_NAMESPACE, SI_PROFILE_FILE_TRANSFER_NAMESPACE };
|
||||
|
||||
private static final String[] NAMESPACE = {
|
||||
"http://jabber.org/protocol/si/profile/file-transfer",
|
||||
"http://jabber.org/protocol/si"};
|
||||
|
||||
private static final Map<XMPPConnection, FileTransferNegotiator> transferObject =
|
||||
new ConcurrentHashMap<XMPPConnection, FileTransferNegotiator>();
|
||||
private static final Map<XMPPConnection, FileTransferNegotiator> INSTANCES = new WeakHashMap<XMPPConnection, FileTransferNegotiator>();
|
||||
|
||||
private static final String STREAM_INIT_PREFIX = "jsi_";
|
||||
|
||||
|
@ -80,27 +77,16 @@ public class FileTransferNegotiator {
|
|||
* service is automatically enabled.
|
||||
*
|
||||
* @param connection The connection for which the transfer manager is desired
|
||||
* @return The IMFileTransferManager
|
||||
* @return The FileTransferNegotiator
|
||||
*/
|
||||
public static FileTransferNegotiator getInstanceFor(
|
||||
public static synchronized FileTransferNegotiator getInstanceFor(
|
||||
final XMPPConnection connection) {
|
||||
if (connection == null) {
|
||||
throw new IllegalArgumentException("XMPPConnection cannot be null");
|
||||
}
|
||||
if (!connection.isConnected()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (transferObject.containsKey(connection)) {
|
||||
return transferObject.get(connection);
|
||||
}
|
||||
else {
|
||||
FileTransferNegotiator transfer = new FileTransferNegotiator(
|
||||
connection);
|
||||
setServiceEnabled(connection, true);
|
||||
transferObject.put(connection, transfer);
|
||||
return transfer;
|
||||
FileTransferNegotiator fileTransferNegotiator = INSTANCES.get(connection);
|
||||
if (fileTransferNegotiator == null) {
|
||||
fileTransferNegotiator = new FileTransferNegotiator(connection);
|
||||
INSTANCES.put(connection, fileTransferNegotiator);
|
||||
}
|
||||
return fileTransferNegotiator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,7 +96,7 @@ public class FileTransferNegotiator {
|
|||
* @param connection The connection on which to enable or disable the services.
|
||||
* @param isEnabled True to enable, false to disable.
|
||||
*/
|
||||
public static void setServiceEnabled(final XMPPConnection connection,
|
||||
private static void setServiceEnabled(final XMPPConnection connection,
|
||||
final boolean isEnabled) {
|
||||
ServiceDiscoveryManager manager = ServiceDiscoveryManager
|
||||
.getInstanceFor(connection);
|
||||
|
@ -124,14 +110,11 @@ public class FileTransferNegotiator {
|
|||
|
||||
for (String namespace : namespaces) {
|
||||
if (isEnabled) {
|
||||
if (!manager.includesFeature(namespace)) {
|
||||
manager.addFeature(namespace);
|
||||
}
|
||||
manager.addFeature(namespace);
|
||||
} else {
|
||||
manager.removeFeature(namespace);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -200,38 +183,16 @@ public class FileTransferNegotiator {
|
|||
|
||||
// non-static
|
||||
|
||||
private final XMPPConnection connection;
|
||||
|
||||
private final StreamNegotiator byteStreamTransferManager;
|
||||
|
||||
private final StreamNegotiator inbandTransferManager;
|
||||
|
||||
private FileTransferNegotiator(final XMPPConnection connection) {
|
||||
configureConnection(connection);
|
||||
|
||||
this.connection = connection;
|
||||
super(connection);
|
||||
byteStreamTransferManager = new Socks5TransferNegotiator(connection);
|
||||
inbandTransferManager = new IBBTransferNegotiator(connection);
|
||||
}
|
||||
|
||||
private void configureConnection(final XMPPConnection connection) {
|
||||
connection.addConnectionListener(new AbstractConnectionListener() {
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
cleanup(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosedOnError(Exception e) {
|
||||
cleanup(connection);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void cleanup(final XMPPConnection connection) {
|
||||
if (transferObject.remove(connection) != null) {
|
||||
inbandTransferManager.cleanup();
|
||||
}
|
||||
setServiceEnabled(connection, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -255,7 +216,7 @@ public class FileTransferNegotiator {
|
|||
IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(),
|
||||
IQ.Type.error);
|
||||
iqPacket.setError(error);
|
||||
connection.sendPacket(iqPacket);
|
||||
connection().sendPacket(iqPacket);
|
||||
throw new XMPPErrorException(errorMessage, error);
|
||||
}
|
||||
|
||||
|
@ -269,7 +230,7 @@ public class FileTransferNegotiator {
|
|||
IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(),
|
||||
IQ.Type.error);
|
||||
iqPacket.setError(e.getXMPPError());
|
||||
connection.sendPacket(iqPacket);
|
||||
connection().sendPacket(iqPacket);
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
@ -308,9 +269,8 @@ public class FileTransferNegotiator {
|
|||
throw new XMPPErrorException(error);
|
||||
}
|
||||
|
||||
//if (isByteStream && isIBB && field.getType().equals(FormField.TYPE_LIST_MULTI)) {
|
||||
if (isByteStream && isIBB) {
|
||||
return new FaultTolerantNegotiator(connection,
|
||||
return new FaultTolerantNegotiator(connection(),
|
||||
byteStreamTransferManager,
|
||||
inbandTransferManager);
|
||||
}
|
||||
|
@ -333,7 +293,7 @@ public class FileTransferNegotiator {
|
|||
IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(),
|
||||
IQ.Type.error);
|
||||
iqPacket.setError(error);
|
||||
connection.sendPacket(iqPacket);
|
||||
connection().sendPacket(iqPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,11 +354,11 @@ public class FileTransferNegotiator {
|
|||
|
||||
si.setFeatureNegotiationForm(createDefaultInitiationForm());
|
||||
|
||||
si.setFrom(connection.getUser());
|
||||
si.setFrom(connection().getUser());
|
||||
si.setTo(userID);
|
||||
si.setType(IQ.Type.set);
|
||||
|
||||
PacketCollector collector = connection.createPacketCollectorAndSend(si);
|
||||
PacketCollector collector = connection().createPacketCollectorAndSend(si);
|
||||
Packet siResponse = collector.nextResult(responseTimeout);
|
||||
collector.cancel();
|
||||
|
||||
|
@ -439,7 +399,7 @@ public class FileTransferNegotiator {
|
|||
}
|
||||
|
||||
if (isByteStream && isIBB) {
|
||||
return new FaultTolerantNegotiator(connection,
|
||||
return new FaultTolerantNegotiator(connection(),
|
||||
byteStreamTransferManager, inbandTransferManager);
|
||||
}
|
||||
else if (isByteStream) {
|
||||
|
|
|
@ -106,9 +106,6 @@ public class IBBTransferNegotiator extends StreamNegotiator {
|
|||
return session.getInputStream();
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This PacketFilter accepts an incoming In-Band Bytestream open request
|
||||
* with a specified session ID.
|
||||
|
|
|
@ -122,11 +122,6 @@ public class Socks5TransferNegotiator extends StreamNegotiator {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
/**
|
||||
* This PacketFilter accepts an incoming SOCKS5 Bytestream request with a specified session ID.
|
||||
*/
|
||||
|
|
|
@ -157,9 +157,4 @@ public abstract class StreamNegotiator {
|
|||
*/
|
||||
public abstract String[] getNamespaces();
|
||||
|
||||
/**
|
||||
* Cleanup any and all resources associated with this negotiator.
|
||||
*/
|
||||
public abstract void cleanup();
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue