mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-29 17:52:06 +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:
parent
978f692eb0
commit
010a86444a
4 changed files with 146 additions and 52 deletions
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue