1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-06-25 21:04:50 +02:00
Smack/extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java
Florian Schmaus fcc8414a92 "not connected" is now a checked Exception thrown by sendPacket()
There is a unsolveable race condition between the connection state and
sendPacket(), i.e. the connection could go down, right after the
method calling sendPacket is called, but before sendPacket() is
invoked. Before this change, sendPacket() has thrown an unchecked
IllegalStateException, which could be ignored by the Smack user, who
would also not notice the race condition. We have decided to throw a
checked Exception in this case now, to make the Smack user aware of
this situation.

SMACK-426
2014-03-19 15:56:41 +01:00

201 lines
7 KiB
Java

/**
*
* Copyright 2013 Georg Lukas
*
* 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.receipts;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketExtensionFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
/**
* Manager for XEP-0184: Message Delivery Receipts. This class implements
* the manager for {@link DeliveryReceipt} support, enabling and disabling of
* automatic DeliveryReceipt transmission.
*
* @author Georg Lukas
*/
public class DeliveryReceiptManager extends Manager implements PacketListener {
private static Map<XMPPConnection, DeliveryReceiptManager> instances =
Collections.synchronizedMap(new WeakHashMap<XMPPConnection, DeliveryReceiptManager>());
static {
XMPPConnection.addConnectionCreationListener(new ConnectionCreationListener() {
public void connectionCreated(XMPPConnection connection) {
getInstanceFor(connection);
}
});
}
private boolean auto_receipts_enabled = false;
private Set<ReceiptReceivedListener> receiptReceivedListeners = Collections
.synchronizedSet(new HashSet<ReceiptReceivedListener>());
private DeliveryReceiptManager(XMPPConnection connection) {
super(connection);
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
sdm.addFeature(DeliveryReceipt.NAMESPACE);
instances.put(connection, this);
// register listener for delivery receipts and requests
connection.addPacketListener(this, new PacketExtensionFilter(DeliveryReceipt.NAMESPACE));
}
/**
* Obtain the DeliveryReceiptManager responsible for a connection.
*
* @param connection the connection object.
*
* @return the DeliveryReceiptManager instance for the given connection
*/
public static synchronized DeliveryReceiptManager getInstanceFor(XMPPConnection connection) {
DeliveryReceiptManager receiptManager = instances.get(connection);
if (receiptManager == null) {
receiptManager = new DeliveryReceiptManager(connection);
}
return receiptManager;
}
/**
* Returns true if Delivery Receipts are supported by a given JID
*
* @param jid
* @return true if supported
* @throws SmackException if there was no response from the server.
* @throws XMPPException
*/
public boolean isSupported(String jid) throws SmackException, XMPPException {
return ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(jid,
DeliveryReceipt.NAMESPACE);
}
// handle incoming receipts and receipt requests
@Override
public void processPacket(Packet packet) throws NotConnectedException {
DeliveryReceipt dr = (DeliveryReceipt)packet.getExtension(
DeliveryReceipt.ELEMENT, DeliveryReceipt.NAMESPACE);
if (dr != null) {
// notify listeners of incoming receipt
for (ReceiptReceivedListener l : receiptReceivedListeners) {
l.onReceiptReceived(packet.getFrom(), packet.getTo(), dr.getId());
}
}
// if enabled, automatically send a receipt
if (auto_receipts_enabled) {
DeliveryReceiptRequest drr = (DeliveryReceiptRequest)packet.getExtension(
DeliveryReceiptRequest.ELEMENT, DeliveryReceipt.NAMESPACE);
if (drr != null) {
XMPPConnection connection = connection();
Message ack = new Message(packet.getFrom(), Message.Type.normal);
ack.addExtension(new DeliveryReceipt(packet.getPacketID()));
connection.sendPacket(ack);
}
}
}
/**
* Configure whether the {@link DeliveryReceiptManager} should automatically
* reply to incoming {@link DeliveryReceipt}s. By default, this feature is off.
*
* @param new_state whether automatic transmission of
* DeliveryReceipts should be enabled or disabled
*/
public void setAutoReceiptsEnabled(boolean new_state) {
auto_receipts_enabled = new_state;
}
/**
* Helper method to enable automatic DeliveryReceipt transmission.
*/
public void enableAutoReceipts() {
setAutoReceiptsEnabled(true);
}
/**
* Helper method to disable automatic DeliveryReceipt transmission.
*/
public void disableAutoReceipts() {
setAutoReceiptsEnabled(false);
}
/**
* Check if AutoReceipts are enabled on this connection.
*/
public boolean getAutoReceiptsEnabled() {
return this.auto_receipts_enabled;
}
/**
* Get informed about incoming delivery receipts with a {@link ReceiptReceivedListener}.
*
* @param listener the listener to be informed about new receipts
*/
public void addReceiptReceivedListener(ReceiptReceivedListener listener) {
receiptReceivedListeners.add(listener);
}
/**
* Stop getting informed about incoming delivery receipts.
*
* @param listener the listener to be removed
*/
public void removeReceiptReceivedListener(ReceiptReceivedListener listener) {
receiptReceivedListeners.remove(listener);
}
/**
* Test if a packet requires a delivery receipt.
*
* @param p Packet object to check for a DeliveryReceiptRequest
*
* @return true if a delivery receipt was requested
*/
public static boolean hasDeliveryReceiptRequest(Packet p) {
return (p.getExtension(DeliveryReceiptRequest.ELEMENT,
DeliveryReceipt.NAMESPACE) != null);
}
/**
* Add a delivery receipt request to an outgoing packet.
*
* Only message packets may contain receipt requests as of XEP-0184,
* therefore only allow Message as the parameter type.
*
* @param m Message object to add a request to
*/
public static void addDeliveryReceiptRequest(Message m) {
m.addExtension(new DeliveryReceiptRequest());
}
}