diff --git a/core/src/main/java/org/jivesoftware/smack/filter/PacketTypeFilter.java b/core/src/main/java/org/jivesoftware/smack/filter/PacketTypeFilter.java
index f18d78f0d..40cdd2ce4 100644
--- a/core/src/main/java/org/jivesoftware/smack/filter/PacketTypeFilter.java
+++ b/core/src/main/java/org/jivesoftware/smack/filter/PacketTypeFilter.java
@@ -17,7 +17,9 @@
package org.jivesoftware.smack.filter;
+import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.Presence;
/**
* Filters for packets of a particular type. The type is given as a Class object, so
@@ -32,6 +34,9 @@ import org.jivesoftware.smack.packet.Packet;
*/
public class PacketTypeFilter implements PacketFilter {
+ public static final PacketTypeFilter PRESENCE = new PacketTypeFilter(Presence.class);
+ public static final PacketTypeFilter MESSAGE = new PacketTypeFilter(Message.class);
+
Class extends Packet> packetType;
/**
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/iqlast/LastActivityManager.java b/extensions/src/main/java/org/jivesoftware/smackx/iqlast/LastActivityManager.java
index 534e34a1f..b1fa8331a 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/iqlast/LastActivityManager.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/iqlast/LastActivityManager.java
@@ -1,6 +1,6 @@
/**
*
- * Copyright 2003-2006 Jive Software.
+ * Copyright 2003-2006 Jive Software, 2014 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,23 +17,25 @@
package org.jivesoftware.smackx.iqlast;
-import org.jivesoftware.smack.SmackException;
+import java.util.Map;
+import java.util.WeakHashMap;
+
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.PacketListener;
-import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.IQTypeFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
-import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.iqlast.packet.LastActivity;
/**
@@ -79,25 +81,46 @@ import org.jivesoftware.smackx.iqlast.packet.LastActivity;
*
*
* @author Gabriel Guardincerri
+ * @author Florian Schmaus
* @see XEP-0012: Last
* Activity
*/
-public class LastActivityManager {
+public class LastActivityManager extends Manager {
+ private static final Map instances = new WeakHashMap();
+ private static final PacketFilter IQ_GET_LAST_FILTER = new AndFilter(new IQTypeFilter(
+ IQ.Type.GET), new PacketTypeFilter(LastActivity.class));
- private long lastMessageSent;
+ private static boolean enabledPerDefault = true;
- private XMPPConnection connection;
+ /**
+ * Enable or disable Last Activity for new XMPPConnections.
+ *
+ * @param enabledPerDefault
+ */
+ public static void setEnabledPerDefault(boolean enabledPerDefault) {
+ LastActivityManager.enabledPerDefault = enabledPerDefault;
+ }
// Enable the LastActivity support on every established connection
static {
XMPPConnection.addConnectionCreationListener(new ConnectionCreationListener() {
public void connectionCreated(XMPPConnection connection) {
- new LastActivityManager(connection);
+ LastActivityManager.getInstanceFor(connection);
}
});
}
+ public static synchronized LastActivityManager getInstanceFor(XMPPConnection connection) {
+ LastActivityManager lastActivityManager = instances.get(connection);
+ if (lastActivityManager == null)
+ lastActivityManager = new LastActivityManager(connection);
+ return lastActivityManager;
+ }
+
+ private long lastMessageSent;
+ private boolean enabled = false;
+
/**
* Creates a last activity manager to response last activity requests.
*
@@ -105,7 +128,7 @@ public class LastActivityManager {
* The XMPPConnection that the last activity requests will use.
*/
private LastActivityManager(XMPPConnection connection) {
- this.connection = connection;
+ super(connection);
// Listen to all the sent messages to reset the idle time on each one
connection.addPacketSendingListener(new PacketListener() {
@@ -123,9 +146,9 @@ public class LastActivityManager {
break;
}
}
- }, new PacketTypeFilter(Presence.class));
+ }, PacketTypeFilter.PRESENCE);
- connection.addPacketListener(new PacketListener() {
+ connection.addPacketSendingListener(new PacketListener() {
@Override
public void processPacket(Packet packet) {
Message message = (Message) packet;
@@ -133,12 +156,13 @@ public class LastActivityManager {
if (message.getType() == Message.Type.error) return;
resetIdleTime();
}
- }, new PacketTypeFilter(Message.class));
+ }, PacketTypeFilter.MESSAGE);
// Register a listener for a last activity query
connection.addPacketListener(new PacketListener() {
public void processPacket(Packet packet) throws NotConnectedException {
+ if (!enabled) return;
LastActivity message = new LastActivity();
message.setType(IQ.Type.RESULT);
message.setTo(packet.getFrom());
@@ -146,12 +170,26 @@ public class LastActivityManager {
message.setPacketID(packet.getPacketID());
message.setLastActivity(getIdleTime());
- LastActivityManager.this.connection.sendPacket(message);
+ connection().sendPacket(message);
}
- }, new AndFilter(new IQTypeFilter(IQ.Type.GET), new PacketTypeFilter(LastActivity.class)));
- ServiceDiscoveryManager.getInstanceFor(connection).addFeature(LastActivity.NAMESPACE);
+ }, IQ_GET_LAST_FILTER);
+
+ if (enabledPerDefault) {
+ enable();
+ }
resetIdleTime();
+ instances.put(connection, this);
+ }
+
+ public synchronized void enable() {
+ ServiceDiscoveryManager.getInstanceFor(connection()).addFeature(LastActivity.NAMESPACE);
+ enabled = true;
+ }
+
+ public synchronized void disable() {
+ ServiceDiscoveryManager.getInstanceFor(connection()).removeFeature(LastActivity.NAMESPACE);
+ enabled = false;
}
/**
@@ -188,8 +226,6 @@ public class LastActivityManager {
* Moreover, when the jid is a server or component (e.g., a JID of the form
* 'host') the last activity is the uptime.
*
- * @param con
- * the current XMPPConnection.
* @param jid
* the JID of the user.
* @return the LastActivity packet of the jid.
@@ -198,31 +234,22 @@ public class LastActivityManager {
* @throws NoResponseException if there was no response from the server.
* @throws NotConnectedException
*/
- public static LastActivity getLastActivity(XMPPConnection con, String jid)
- throws NoResponseException, XMPPErrorException, NotConnectedException {
- LastActivity activity = new LastActivity();
- activity.setTo(jid);
-
- LastActivity response = (LastActivity) con.createPacketCollectorAndSend(activity).nextResultOrThrow();
- return response;
+ public LastActivity getLastActivity(String jid) throws NoResponseException, XMPPErrorException,
+ NotConnectedException {
+ LastActivity activity = new LastActivity(jid);
+ return (LastActivity) connection().createPacketCollectorAndSend(activity).nextResultOrThrow();
}
/**
* Returns true if Last Activity (XEP-0012) is supported by a given JID
*
- * @param connection the connection to be used
* @param jid a JID to be tested for Last Activity support
* @return true if Last Activity is supported, otherwise false
- * @throws SmackException if there was no response from the server.
+ * @throws NotConnectedException
+ * @throws XMPPErrorException
+ * @throws NoResponseException
*/
- public static boolean isLastActivitySupported(XMPPConnection connection, String jid) throws SmackException {
- try {
- DiscoverInfo result =
- ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
- return result.containsFeature(LastActivity.NAMESPACE);
- }
- catch (XMPPException e) {
- return false;
- }
+ public boolean isLastActivitySupported(String jid) throws NoResponseException, XMPPErrorException, NotConnectedException {
+ return ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(jid, LastActivity.NAMESPACE);
}
}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/iqlast/packet/LastActivity.java b/extensions/src/main/java/org/jivesoftware/smackx/iqlast/packet/LastActivity.java
index c6478898f..933254b71 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/iqlast/packet/LastActivity.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/iqlast/packet/LastActivity.java
@@ -1,6 +1,6 @@
/**
*
- * Copyright 2003-2007 Jive Software.
+ * Copyright 2003-2007 Jive Software, 2014 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import java.io.IOException;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smack.util.XmlStringBuilder;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -32,6 +33,7 @@ import org.xmlpull.v1.XmlPullParserException;
* to get the last activity of a user.
*
* @author Derek DeMoro
+ * @author Florian Schmaus
*/
public class LastActivity extends IQ {
@@ -44,14 +46,23 @@ public class LastActivity extends IQ {
setType(IQ.Type.GET);
}
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("");
- return buf.toString();
+ // We don't support adding the optional message attribute, because it is usually only added
+ // by XMPP servers and not by client entities.
+ xml.closeEmptyElement();
+ return xml;
}
@@ -103,22 +114,17 @@ public class LastActivity extends IQ {
LastActivity lastActivity = new LastActivity();
String seconds = parser.getAttributeValue("", "seconds");
- String message = null;
- try {
- message = parser.nextText();
- } catch (IOException e1) {
- // Ignore
- }
if (seconds != null) {
try {
lastActivity.setLastActivity(Long.parseLong(seconds));
} catch (NumberFormatException e) {
- // Ignore
+ throw new SmackException("Could not parse last activity number", e);
}
}
-
- if (message != null) {
- lastActivity.setMessage(message);
+ try {
+ lastActivity.setMessage(parser.nextText());
+ } catch (IOException e) {
+ throw new SmackException(e);
}
return lastActivity;
}
diff --git a/extensions/src/test/java/org/jivesoftware/smackx/iqlast/LastActivityTest.java b/extensions/src/test/java/org/jivesoftware/smackx/iqlast/LastActivityTest.java
new file mode 100644
index 000000000..16b730499
--- /dev/null
+++ b/extensions/src/test/java/org/jivesoftware/smackx/iqlast/LastActivityTest.java
@@ -0,0 +1,56 @@
+/**
+ *
+ * Copyright 2014 Florian Schmaus
+ *
+ * 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.iqlast;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.jivesoftware.smack.DummyConnection;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.test.util.TestUtils;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.jivesoftware.smackx.InitExtensions;
+import org.jivesoftware.smackx.iqlast.packet.LastActivity;
+import org.junit.Test;
+
+import com.jamesmurty.utils.XMLBuilder;
+
+public class LastActivityTest extends InitExtensions {
+
+ @Test
+ public void checkProvider() throws Exception {
+ XMLBuilder xml = XMLBuilder.create("iq");
+ xml.a("from", "romeo@montague.net/orchard")
+ .a("id", "last2")
+ .a("to", "juliet@capulet.com/balcony")
+ .a("type", "get")
+ .e("query")
+ .namespace(LastActivity.NAMESPACE);
+
+ DummyConnection c = new DummyConnection();
+ IQ lastRequest = PacketParserUtils.parseIQ(TestUtils.getIQParser(xml.asString()), c);
+ assertTrue(lastRequest instanceof LastActivity);
+
+ c.processPacket(lastRequest);;
+ Packet reply = c.getSentPacket();
+ assertTrue(reply instanceof LastActivity);
+ LastActivity l = (LastActivity) reply;
+ assertEquals("last2", l.getPacketID());
+ assertEquals(IQ.Type.RESULT, l.getType());
+ }
+}