1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2024-12-01 18:52:08 +01:00

Streamline LastActivity API, add enable/disable

Allow LastActivity to be enabled/disabled. The API is now similar to the
ones of the other Managers. Added unit tests.
This commit is contained in:
Florian Schmaus 2014-03-23 14:18:41 +01:00
parent 978f692eb0
commit 010a86444a
4 changed files with 146 additions and 52 deletions

View file

@ -17,7 +17,9 @@
package org.jivesoftware.smack.filter; package org.jivesoftware.smack.filter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet; 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 * 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 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; Class<? extends Packet> packetType;
/** /**

View file

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,23 +17,25 @@
package org.jivesoftware.smackx.iqlast; 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.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.ConnectionCreationListener; import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.PacketListener; 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.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.IQTypeFilter; import org.jivesoftware.smack.filter.IQTypeFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter; import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.iqlast.packet.LastActivity; import org.jivesoftware.smackx.iqlast.packet.LastActivity;
/** /**
@ -79,25 +81,46 @@ import org.jivesoftware.smackx.iqlast.packet.LastActivity;
* </pre> * </pre>
* *
* @author Gabriel Guardincerri * @author Gabriel Guardincerri
* @author Florian Schmaus
* @see <a href="http://xmpp.org/extensions/xep-0012.html">XEP-0012: Last * @see <a href="http://xmpp.org/extensions/xep-0012.html">XEP-0012: Last
* Activity</a> * Activity</a>
*/ */
public class LastActivityManager { public class LastActivityManager extends Manager {
private static final Map<XMPPConnection, LastActivityManager> instances = new WeakHashMap<XMPPConnection, LastActivityManager>();
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 // Enable the LastActivity support on every established connection
static { static {
XMPPConnection.addConnectionCreationListener(new ConnectionCreationListener() { XMPPConnection.addConnectionCreationListener(new ConnectionCreationListener() {
public void connectionCreated(XMPPConnection connection) { 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. * 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. * The XMPPConnection that the last activity requests will use.
*/ */
private LastActivityManager(XMPPConnection connection) { private LastActivityManager(XMPPConnection connection) {
this.connection = connection; super(connection);
// Listen to all the sent messages to reset the idle time on each one // Listen to all the sent messages to reset the idle time on each one
connection.addPacketSendingListener(new PacketListener() { connection.addPacketSendingListener(new PacketListener() {
@ -123,9 +146,9 @@ public class LastActivityManager {
break; break;
} }
} }
}, new PacketTypeFilter(Presence.class)); }, PacketTypeFilter.PRESENCE);
connection.addPacketListener(new PacketListener() { connection.addPacketSendingListener(new PacketListener() {
@Override @Override
public void processPacket(Packet packet) { public void processPacket(Packet packet) {
Message message = (Message) packet; Message message = (Message) packet;
@ -133,12 +156,13 @@ public class LastActivityManager {
if (message.getType() == Message.Type.error) return; if (message.getType() == Message.Type.error) return;
resetIdleTime(); resetIdleTime();
} }
}, new PacketTypeFilter(Message.class)); }, PacketTypeFilter.MESSAGE);
// Register a listener for a last activity query // Register a listener for a last activity query
connection.addPacketListener(new PacketListener() { connection.addPacketListener(new PacketListener() {
public void processPacket(Packet packet) throws NotConnectedException { public void processPacket(Packet packet) throws NotConnectedException {
if (!enabled) return;
LastActivity message = new LastActivity(); LastActivity message = new LastActivity();
message.setType(IQ.Type.RESULT); message.setType(IQ.Type.RESULT);
message.setTo(packet.getFrom()); message.setTo(packet.getFrom());
@ -146,12 +170,26 @@ public class LastActivityManager {
message.setPacketID(packet.getPacketID()); message.setPacketID(packet.getPacketID());
message.setLastActivity(getIdleTime()); message.setLastActivity(getIdleTime());
LastActivityManager.this.connection.sendPacket(message); connection().sendPacket(message);
} }
}, new AndFilter(new IQTypeFilter(IQ.Type.GET), new PacketTypeFilter(LastActivity.class))); }, IQ_GET_LAST_FILTER);
ServiceDiscoveryManager.getInstanceFor(connection).addFeature(LastActivity.NAMESPACE);
if (enabledPerDefault) {
enable();
}
resetIdleTime(); 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 * Moreover, when the jid is a server or component (e.g., a JID of the form
* 'host') the last activity is the uptime. * 'host') the last activity is the uptime.
* *
* @param con
* the current XMPPConnection.
* @param jid * @param jid
* the JID of the user. * the JID of the user.
* @return the LastActivity packet of the jid. * @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 NoResponseException if there was no response from the server.
* @throws NotConnectedException * @throws NotConnectedException
*/ */
public static LastActivity getLastActivity(XMPPConnection con, String jid) public LastActivity getLastActivity(String jid) throws NoResponseException, XMPPErrorException,
throws NoResponseException, XMPPErrorException, NotConnectedException { NotConnectedException {
LastActivity activity = new LastActivity(); LastActivity activity = new LastActivity(jid);
activity.setTo(jid); return (LastActivity) connection().createPacketCollectorAndSend(activity).nextResultOrThrow();
LastActivity response = (LastActivity) con.createPacketCollectorAndSend(activity).nextResultOrThrow();
return response;
} }
/** /**
* Returns true if Last Activity (XEP-0012) is supported by a given JID * 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 * @param jid a JID to be tested for Last Activity support
* @return true if Last Activity is supported, otherwise false * @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 { public boolean isLastActivitySupported(String jid) throws NoResponseException, XMPPErrorException, NotConnectedException {
try { return ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(jid, LastActivity.NAMESPACE);
DiscoverInfo result =
ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
return result.containsFeature(LastActivity.NAMESPACE);
}
catch (XMPPException e) {
return false;
}
} }
} }

View file

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.SmackException;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider; import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
@ -32,6 +33,7 @@ import org.xmlpull.v1.XmlPullParserException;
* to get the last activity of a user. * to get the last activity of a user.
* *
* @author Derek DeMoro * @author Derek DeMoro
* @author Florian Schmaus
*/ */
public class LastActivity extends IQ { public class LastActivity extends IQ {
@ -44,14 +46,23 @@ public class LastActivity extends IQ {
setType(IQ.Type.GET); setType(IQ.Type.GET);
} }
public String getChildElementXML() { public LastActivity(String to) {
StringBuilder buf = new StringBuilder(); this();
buf.append("<query xmlns=\"" + NAMESPACE + "\""); setTo(to);
if (lastActivity != -1) {
buf.append(" seconds=\"").append(lastActivity).append("\"");
} }
buf.append("></query>");
return buf.toString(); @Override
public XmlStringBuilder getChildElementXML() {
XmlStringBuilder xml = new XmlStringBuilder();
xml.halfOpenElement("query");
xml.xmlnsAttribute(NAMESPACE);
if (lastActivity != -1) {
xml.attribute("seconds", Long.toString(lastActivity));
}
// 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(); LastActivity lastActivity = new LastActivity();
String seconds = parser.getAttributeValue("", "seconds"); String seconds = parser.getAttributeValue("", "seconds");
String message = null;
try {
message = parser.nextText();
} catch (IOException e1) {
// Ignore
}
if (seconds != null) { if (seconds != null) {
try { try {
lastActivity.setLastActivity(Long.parseLong(seconds)); lastActivity.setLastActivity(Long.parseLong(seconds));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
// Ignore throw new SmackException("Could not parse last activity number", e);
} }
} }
try {
if (message != null) { lastActivity.setMessage(parser.nextText());
lastActivity.setMessage(message); } catch (IOException e) {
throw new SmackException(e);
} }
return lastActivity; return lastActivity;
} }

View file

@ -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());
}
}