1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-06-21 19:04:49 +02:00
Smack/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java
Florian Schmaus 717090d272 Rework incoming packet listeners and Roster
Differentiate between asynchronous and synchronous ones. Asynchronous
are the ones where the invocation order may not be the same as the order
in which the stanzas arrived.

Since it's no longer guaranteed that when a unit test calls

processPacket(stanza)

the stanza will be completely processed when the call returns, it was
necessary to extend the unit tests (mostly Roster and ChatManager) with
a packet listener that waits for his invocation. Since we now also use
LinkedHashMaps as Map for the packet listeners (SMACK-531, SMACK-424),
adding a packet listeners as last also means that it will be called as
last. We exploit this behavior change now in the unit tests.

Rename 'recvListeners' to 'syncRecvListeners' in AbstractXMPPConnection.

Rename 'rosterInitialized' to 'loaded' in Roster.

Add Roster.isLoaded().

Reset 'loaded' to false in
Roster.setOfflinePresencesAndResetLoaded() (was setOfflinePresences()).

Fixes SMACK-583, SMACK-532, SMACK-424
2015-01-07 14:35:23 +01:00

198 lines
7 KiB
Java

/**
*
* Copyright 2013-2014 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.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
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.XMPPConnectionRegistry;
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 = new WeakHashMap<XMPPConnection, DeliveryReceiptManager>();
static {
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
public void connectionCreated(XMPPConnection connection) {
getInstanceFor(connection);
}
});
}
private boolean auto_receipts_enabled = false;
private final Set<ReceiptReceivedListener> receiptReceivedListeners = new CopyOnWriteArraySet<ReceiptReceivedListener>();
private DeliveryReceiptManager(XMPPConnection connection) {
super(connection);
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
sdm.addFeature(DeliveryReceipt.NAMESPACE);
// register listener for delivery receipts and requests
connection.addAsyncPacketListener(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);
instances.put(connection, receiptManager);
}
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.from(packet);
if (dr != null) {
// notify listeners of incoming receipt
for (ReceiptReceivedListener l : receiptReceivedListeners) {
l.onReceiptReceived(packet.getFrom(), packet.getTo(), dr.getId(), packet);
}
}
// if enabled, automatically send a receipt
if (auto_receipts_enabled) {
DeliveryReceiptRequest drr = DeliveryReceiptRequest.from(packet);
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 (DeliveryReceiptRequest.from(p) != 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
* @return the Message ID which will be used as receipt ID
* @deprecated use {@link DeliveryReceiptRequest#addTo(Message)}
*/
@Deprecated
public static String addDeliveryReceiptRequest(Message m) {
return DeliveryReceiptRequest.addTo(m);
}
}