blob: 125b87e63ba1a6925518329716b291b2ed9d3acf [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001/**
2 * Copyright 2013 Georg Lukas
3 *
4 * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.jivesoftware.smackx.receipts;
18
19import java.util.Collections;
20import java.util.HashSet;
21import java.util.Map;
22import java.util.Set;
23import java.util.WeakHashMap;
24
25import org.jivesoftware.smack.Connection;
26import org.jivesoftware.smack.ConnectionCreationListener;
27import org.jivesoftware.smack.PacketListener;
28import org.jivesoftware.smack.XMPPException;
29import org.jivesoftware.smack.filter.PacketExtensionFilter;
30import org.jivesoftware.smack.packet.Message;
31import org.jivesoftware.smack.packet.Packet;
32import org.jivesoftware.smackx.ServiceDiscoveryManager;
33import org.jivesoftware.smackx.packet.DiscoverInfo;
34
35/**
36 * Manager for XEP-0184: Message Delivery Receipts. This class implements
37 * the manager for {@link DeliveryReceipt} support, enabling and disabling of
38 * automatic DeliveryReceipt transmission.
39 *
40 * @author Georg Lukas
41 */
42public class DeliveryReceiptManager implements PacketListener {
43
44 private static Map<Connection, DeliveryReceiptManager> instances =
45 Collections.synchronizedMap(new WeakHashMap<Connection, DeliveryReceiptManager>());
46
47 static {
48 Connection.addConnectionCreationListener(new ConnectionCreationListener() {
49 public void connectionCreated(Connection connection) {
50 new DeliveryReceiptManager(connection);
51 }
52 });
53 }
54
55 private Connection connection;
56 private boolean auto_receipts_enabled = false;
57 private Set<ReceiptReceivedListener> receiptReceivedListeners = Collections
58 .synchronizedSet(new HashSet<ReceiptReceivedListener>());
59
60 private DeliveryReceiptManager(Connection connection) {
61 ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
62 sdm.addFeature(DeliveryReceipt.NAMESPACE);
63 this.connection = connection;
64 instances.put(connection, this);
65
66 // register listener for delivery receipts and requests
67 connection.addPacketListener(this, new PacketExtensionFilter(DeliveryReceipt.NAMESPACE));
68 }
69
70 /**
71 * Obtain the DeliveryReceiptManager responsible for a connection.
72 *
73 * @param connection the connection object.
74 *
75 * @return the DeliveryReceiptManager instance for the given connection
76 */
77 synchronized public static DeliveryReceiptManager getInstanceFor(Connection connection) {
78 DeliveryReceiptManager receiptManager = instances.get(connection);
79
80 if (receiptManager == null) {
81 receiptManager = new DeliveryReceiptManager(connection);
82 }
83
84 return receiptManager;
85 }
86
87 /**
88 * Returns true if Delivery Receipts are supported by a given JID
89 *
90 * @param jid
91 * @return true if supported
92 */
93 public boolean isSupported(String jid) {
94 try {
95 DiscoverInfo result =
96 ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
97 return result.containsFeature(DeliveryReceipt.NAMESPACE);
98 }
99 catch (XMPPException e) {
100 return false;
101 }
102 }
103
104 // handle incoming receipts and receipt requests
105 @Override
106 public void processPacket(Packet packet) {
107 DeliveryReceipt dr = (DeliveryReceipt)packet.getExtension(
108 DeliveryReceipt.ELEMENT, DeliveryReceipt.NAMESPACE);
109 if (dr != null) {
110 // notify listeners of incoming receipt
111 for (ReceiptReceivedListener l : receiptReceivedListeners) {
112 l.onReceiptReceived(packet.getFrom(), packet.getTo(), dr.getId());
113 }
114
115 }
116
117 // if enabled, automatically send a receipt
118 if (auto_receipts_enabled) {
119 DeliveryReceiptRequest drr = (DeliveryReceiptRequest)packet.getExtension(
120 DeliveryReceiptRequest.ELEMENT, DeliveryReceipt.NAMESPACE);
121 if (drr != null) {
122 Message ack = new Message(packet.getFrom(), Message.Type.normal);
123 ack.addExtension(new DeliveryReceipt(packet.getPacketID()));
124 connection.sendPacket(ack);
125 }
126 }
127 }
128
129 /**
130 * Configure whether the {@link DeliveryReceiptManager} should automatically
131 * reply to incoming {@link DeliveryReceipt}s. By default, this feature is off.
132 *
133 * @param new_state whether automatic transmission of
134 * DeliveryReceipts should be enabled or disabled
135 */
136 public void setAutoReceiptsEnabled(boolean new_state) {
137 auto_receipts_enabled = new_state;
138 }
139
140 /**
141 * Helper method to enable automatic DeliveryReceipt transmission.
142 */
143 public void enableAutoReceipts() {
144 setAutoReceiptsEnabled(true);
145 }
146
147 /**
148 * Helper method to disable automatic DeliveryReceipt transmission.
149 */
150 public void disableAutoReceipts() {
151 setAutoReceiptsEnabled(false);
152 }
153
154 /**
155 * Check if AutoReceipts are enabled on this connection.
156 */
157 public boolean getAutoReceiptsEnabled() {
158 return this.auto_receipts_enabled;
159 }
160
161 /**
162 * Get informed about incoming delivery receipts with a {@link ReceiptReceivedListener}.
163 *
164 * @param listener the listener to be informed about new receipts
165 */
166 public void addReceiptReceivedListener(ReceiptReceivedListener listener) {
167 receiptReceivedListeners.add(listener);
168 }
169
170 /**
171 * Stop getting informed about incoming delivery receipts.
172 *
173 * @param listener the listener to be removed
174 */
175 public void removeReceiptReceivedListener(ReceiptReceivedListener listener) {
176 receiptReceivedListeners.remove(listener);
177 }
178
179 /**
180 * Test if a packet requires a delivery receipt.
181 *
182 * @param p Packet object to check for a DeliveryReceiptRequest
183 *
184 * @return true if a delivery receipt was requested
185 */
186 public static boolean hasDeliveryReceiptRequest(Packet p) {
187 return (p.getExtension(DeliveryReceiptRequest.ELEMENT,
188 DeliveryReceipt.NAMESPACE) != null);
189 }
190
191 /**
192 * Add a delivery receipt request to an outgoing packet.
193 *
194 * Only message packets may contain receipt requests as of XEP-0184,
195 * therefore only allow Message as the parameter type.
196 *
197 * @param m Message object to add a request to
198 */
199 public static void addDeliveryReceiptRequest(Message m) {
200 m.addExtension(new DeliveryReceiptRequest());
201 }
202}