Add IQ request handler API

This also moves the logic to send error IQ replies from "when there is
no IQ provider registerd" to "when there is no IQ request handler
registered". Which has for example the advantage that IQ parsing no
longer asks for a connection instance.
This commit is contained in:
Florian Schmaus 2015-01-08 11:01:35 +01:00
parent fcb4844d10
commit bb8dcc9874
28 changed files with 533 additions and 317 deletions

View File

@ -58,7 +58,9 @@ import org.jivesoftware.smack.debugger.SmackDebugger;
import org.jivesoftware.smack.filter.IQReplyFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.iqrequest.IQRequestHandler;
import org.jivesoftware.smack.packet.Bind;
import org.jivesoftware.smack.packet.ErrorIQ;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Mechanisms;
import org.jivesoftware.smack.packet.Packet;
@ -68,6 +70,7 @@ import org.jivesoftware.smack.packet.RosterVer;
import org.jivesoftware.smack.packet.Session;
import org.jivesoftware.smack.packet.StartTls;
import org.jivesoftware.smack.packet.PlainStreamElement;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.parsing.ParsingExceptionCallback;
import org.jivesoftware.smack.parsing.UnparsablePacket;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
@ -279,6 +282,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
*/
protected boolean wasAuthenticated = false;
private final Map<String, IQRequestHandler> setIqRequestHandler = new HashMap<>();
private final Map<String, IQRequestHandler> getIqRequestHandler = new HashMap<>();
/**
* Create a new XMPPConnection to a XMPP server.
*
@ -907,7 +913,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
int parserDepth = parser.getDepth();
Packet stanza = null;
try {
stanza = PacketParserUtils.parseStanza(parser, this);
stanza = PacketParserUtils.parseStanza(parser);
}
catch (Exception e) {
CharSequence content = PacketParserUtils.parseContentDepth(parser,
@ -962,6 +968,81 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
* @param packet the packet to notify the PacketCollectors and receive listeners about.
*/
protected void invokePacketCollectorsAndNotifyRecvListeners(final Packet packet) {
if (packet instanceof IQ) {
final IQ iq = (IQ) packet;
final IQ.Type type = iq.getType();
switch (type) {
case set:
case get:
final String key = XmppStringUtils.generateKey(iq.getChildElementName(), iq.getChildElementNamespace());
IQRequestHandler iqRequestHandler = null;
switch (type) {
case set:
synchronized (setIqRequestHandler) {
iqRequestHandler = setIqRequestHandler.get(key);
}
break;
case get:
synchronized (getIqRequestHandler) {
iqRequestHandler = getIqRequestHandler.get(key);
}
break;
default:
throw new IllegalStateException("Should only encounter IQ type 'get' or 'set'");
}
if (iqRequestHandler == null) {
// If the IQ stanza is of type "get" or "set" with no registered IQ request handler, then answer an
// IQ of type "error" with code 501 ("feature-not-implemented")
ErrorIQ errorIQ = IQ.createErrorResponse(iq, new XMPPError(
XMPPError.Condition.feature_not_implemented));
try {
sendPacket(errorIQ);
}
catch (NotConnectedException e) {
LOGGER.log(Level.WARNING, "NotConnectedException while sending error IQ to unkown IQ request", e);
}
} else {
ExecutorService executorService = null;
switch (iqRequestHandler.getMode()) {
case sync:
executorService = singleThreadedExecutorService;
break;
case async:
executorService = cachedExecutorService;
break;
}
final IQRequestHandler finalIqRequestHandler = iqRequestHandler;
executorService.execute(new Runnable() {
@Override
public void run() {
IQ response = finalIqRequestHandler.handleIQRequest(iq);
if (response == null) {
// It is not ideal if the IQ request handler does not return an IQ response, because RFC
// 6120 § 8.1.2 does specify that a response is mandatory. But some APIs, mostly the
// file transfer one, does not always return a result, so we need to handle this case
// gracefully for now
// TODO Add a warning if response is null once all APIs using handleIQRequest return an
// IQ response. Later consider throwing an IllegalStateException
return;
}
try {
sendPacket(response);
}
catch (NotConnectedException e) {
LOGGER.log(Level.WARNING, "NotConnectedException while sending response to IQ request", e);
}
}
});
// The following returns makes it impossible for packet listeners and collectors to
// filter for IQ request stanzas, i.e. IQs of type 'set' or 'get'. This is the
// desired behavior.
return;
}
default:
break;
}
}
// First handle the async recv listeners. Note that this code is very similar to what follows a few lines below,
// the only difference is that asyncRecvListeners is used here and that the packet listeners are started in
// their own thread.
@ -1398,6 +1479,46 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
}, getPacketReplyTimeout(), TimeUnit.MILLISECONDS);
}
@Override
public IQRequestHandler registerIQRequestHandler(final IQRequestHandler iqRequestHandler) {
final String key = XmppStringUtils.generateKey(iqRequestHandler.getElement(), iqRequestHandler.getNamespace());
switch (iqRequestHandler.getType()) {
case set:
synchronized (setIqRequestHandler) {
return setIqRequestHandler.put(key, iqRequestHandler);
}
case get:
synchronized (getIqRequestHandler) {
return getIqRequestHandler.put(key, iqRequestHandler);
}
default:
throw new IllegalArgumentException("Only IQ type of 'get' and 'set' allowed");
}
}
@Override
public final IQRequestHandler unregisterIQRequestHandler(IQRequestHandler iqRequestHandler) {
return unregisterIQRequestHandler(iqRequestHandler.getElement(), iqRequestHandler.getNamespace(),
iqRequestHandler.getType());
}
@Override
public IQRequestHandler unregisterIQRequestHandler(String element, String namespace, IQ.Type type) {
final String key = XmppStringUtils.generateKey(element, namespace);
switch (type) {
case set:
synchronized (setIqRequestHandler) {
return setIqRequestHandler.remove(key);
}
case get:
synchronized (getIqRequestHandler) {
return getIqRequestHandler.remove(key);
}
default:
throw new IllegalArgumentException("Only IQ type of 'get' and 'set' allowed");
}
}
private long lastStanzaReceived;
public long getLastStanzaReceived() {

View File

@ -36,16 +36,18 @@ import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.SmackException.NotLoggedInException;
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.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.RosterPacket;
import org.jivesoftware.smack.packet.RosterVer;
import org.jivesoftware.smack.packet.RosterPacket.Item;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.packet.XMPPError.Condition;
import org.jivesoftware.smack.rosterstore.RosterStore;
import org.jxmpp.util.XmppStringUtils;
@ -67,9 +69,6 @@ public class Roster {
private static final Logger LOGGER = Logger.getLogger(Roster.class.getName());
private static final PacketFilter ROSTER_PUSH_FILTER = new AndFilter(new PacketTypeFilter(
RosterPacket.class), IQTypeFilter.SET);
private static final PacketFilter PRESENCE_PACKET_FILTER = new PacketTypeFilter(Presence.class);
/**
@ -130,7 +129,7 @@ public class Roster {
// Note that we use sync packet listeners because RosterListeners should be invoked in the same order as the
// roster stanzas arrive.
// Listen for any roster packets.
connection.addSyncPacketListener(new RosterPushListener(), ROSTER_PUSH_FILTER);
connection.registerIQRequestHandler(new RosterPushListener());
// Listen for any presence packets.
connection.addSyncPacketListener(presencePacketListener, PRESENCE_PACKET_FILTER);
@ -1118,10 +1117,15 @@ public class Roster {
/**
* Listens for all roster pushes and processes them.
*/
private class RosterPushListener implements PacketListener {
private class RosterPushListener extends AbstractIqRequestHandler {
public void processPacket(Packet packet) throws NotConnectedException {
RosterPacket rosterPacket = (RosterPacket) packet;
private RosterPushListener() {
super(RosterPacket.ELEMENT, RosterPacket.NAMESPACE, Type.set, Mode.sync);
}
@Override
public IQ handleIQRequest(IQ iqRequest) {
RosterPacket rosterPacket = (RosterPacket) iqRequest;
// Roster push (RFC 6121, 2.1.6)
// A roster push with a non-empty from not matching our address MUST be ignored
@ -1130,14 +1134,14 @@ public class Roster {
if (from != null && !from.equals(jid)) {
LOGGER.warning("Ignoring roster push with a non matching 'from' ourJid='" + jid + "' from='" + from
+ "'");
return;
return IQ.createErrorResponse(iqRequest, new XMPPError(Condition.service_unavailable));
}
// A roster push must contain exactly one entry
Collection<Item> items = rosterPacket.getRosterItems();
if (items.size() != 1) {
LOGGER.warning("Ignoring roster push with not exaclty one entry. size=" + items.size());
return;
return IQ.createErrorResponse(iqRequest, new XMPPError(Condition.bad_request));
}
Collection<String> addedEntries = new ArrayList<String>();
@ -1164,12 +1168,13 @@ public class Roster {
rosterStore.addEntry(item, version);
}
}
connection.sendPacket(IQ.createResultIQ(rosterPacket));
removeEmptyGroups();
// Fire event for roster listeners.
fireRosterChangedEvent(addedEntries, updatedEntries, deletedEntries);
return IQ.createResultIQ(rosterPacket);
}
}
}

View File

@ -21,6 +21,7 @@ import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.filter.IQReplyFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.iqrequest.IQRequestHandler;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
@ -565,6 +566,34 @@ public interface XMPPConnection {
*/
public void addOneTimeSyncCallback(PacketListener callback, PacketFilter packetFilter);
/**
* Register an IQ request handler with this connection.
* <p>
* IQ request handler process incoming IQ requests, i.e. incoming IQ stanzas of type 'get' or 'set', and return a result.
* </p>
* @param iqRequestHandler the IQ request handler to register.
* @return the previously registered IQ request handler or null.
*/
public IQRequestHandler registerIQRequestHandler(IQRequestHandler iqRequestHandler);
/**
* Convenience method for {@link #unregisterIQRequestHandler(String, String, org.jivesoftware.smack.packet.IQ.Type)}.
*
* @param iqRequestHandler
* @return the previously registered IQ request handler or null.
*/
public IQRequestHandler unregisterIQRequestHandler(IQRequestHandler iqRequestHandler);
/**
* Unregister an IQ request handler with this connection.
*
* @param element the IQ element the IQ request handler is responsible for.
* @param namespace the IQ namespace the IQ request handler is responsible for.
* @param type the IQ type the IQ request handler is responsible for.
* @return the previously registered IQ request handler or null.
*/
public IQRequestHandler unregisterIQRequestHandler(String element, String namespace, IQ.Type type);
/**
* Returns the timestamp in milliseconds when the last stanza was received.
*

View File

@ -0,0 +1,66 @@
/**
*
* Copyright 2015 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.smack.iqrequest;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.IQ.Type;
public abstract class AbstractIqRequestHandler implements IQRequestHandler {
private final String element;
private final String namespace;
private final Type type;
private final Mode mode;
protected AbstractIqRequestHandler(String element, String namespace, Type type, Mode mode) {
switch (type) {
case set:
case get:
break;
default:
throw new IllegalArgumentException("Only get and set IQ type allowed");
}
this.element = element;
this.namespace = namespace;
this.type = type;
this.mode = mode;
}
@Override
public abstract IQ handleIQRequest(IQ iqRequest);
@Override
public Mode getMode() {
return mode;
}
@Override
public Type getType() {
return type;
}
@Override
public String getElement() {
return element;
}
@Override
public String getNamespace() {
return namespace;
}
}

View File

@ -0,0 +1,47 @@
/**
*
* Copyright 2015 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.smack.iqrequest;
import org.jivesoftware.smack.packet.IQ;
public interface IQRequestHandler {
public enum Mode {
/**
* Process requests synchronously, i.e. in the order they arrive. Uses a single thread, which means that the other
* requests have to wait until all previous synchronous requests have been handled. Use {@link #async} if
* possible for performance reasons.
*/
sync,
/**
* Process IQ requests asynchronously, i.e. concurrent. This does not guarantee that requests are processed in the
* same order they arrive.
*/
async,
}
public IQ handleIQRequest(IQ iqRequest);
public Mode getMode();
public IQ.Type getType();
public String getElement();
public String getNamespace();
}

View File

@ -35,4 +35,5 @@ public class ErrorIQ extends SimpleIQ {
type = IQ.Type.error;
setError(xmppError);
}
}

View File

@ -224,12 +224,12 @@ public abstract class IQ extends Packet {
* {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set}.
* @return a new {@link Type#error IQ.Type.error} IQ based on the originating IQ.
*/
public static IQ createErrorResponse(final IQ request, final XMPPError error) {
public static ErrorIQ createErrorResponse(final IQ request, final XMPPError error) {
if (!(request.getType() == Type.get || request.getType() == Type.set)) {
throw new IllegalArgumentException(
"IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML());
}
final IQ result = new ErrorIQ(error);
final ErrorIQ result = new ErrorIQ(error);
result.setPacketID(request.getPacketID());
result.setFrom(request.getTo());
result.setTo(request.getFrom());

View File

@ -0,0 +1,39 @@
/**
*
* Copyright © 2015 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.smack.packet;
/**
* An IQ stanzas that could not be parsed because no provider was found.
*/
public class UnparsedIQ extends IQ {
public UnparsedIQ(String element, String namespace, CharSequence content) {
super(element, namespace);
this.content = content;
}
private final CharSequence content;
public CharSequence getContent() {
return content;
}
@Override
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
throw new UnsupportedOperationException();
}
}

View File

@ -29,7 +29,6 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.compress.packet.Compress;
import org.jivesoftware.smack.packet.DefaultPacketExtension;
import org.jivesoftware.smack.packet.EmptyResultIQ;
@ -42,6 +41,7 @@ import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Session;
import org.jivesoftware.smack.packet.StartTls;
import org.jivesoftware.smack.packet.StreamError;
import org.jivesoftware.smack.packet.UnparsedIQ;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
@ -128,32 +128,29 @@ public class PacketParserUtils {
return parser;
}
public static Packet parseStanza(String stanza) throws Exception {
public static Packet parseStanza(String stanza) throws XmlPullParserException, IOException, SmackException {
return parseStanza(getParserFor(stanza));
}
public static Packet parseStanza(XmlPullParser parser) throws Exception {
return parseStanza(parser, null);
}
/**
* Tries to parse and return either a Message, IQ or Presence stanza.
*
* connection is optional and is used to return feature-not-implemented errors for unknown IQ stanzas.
*
* @param parser
* @param connection
* @return a packet which is either a Message, IQ or Presence.
* @throws Exception
* @throws XmlPullParserException
* @throws SmackException
* @throws IOException
*/
public static Packet parseStanza(XmlPullParser parser, XMPPConnection connection) throws Exception {
public static Packet parseStanza(XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
ParserUtils.assertAtStartTag(parser);
final String name = parser.getName();
switch (name) {
case Message.ELEMENT:
return parseMessage(parser);
case IQ.ELEMENT:
return parse(parser, connection);
return parseIQ(parser);
case Presence.ELEMENT:
return parsePresence(parser);
default:
@ -597,11 +594,12 @@ public class PacketParserUtils {
* Parses an IQ packet.
*
* @param parser the XML parser, positioned at the start of an IQ packet.
* @param connection the optional XMPPConnection used to send feature-not-implemented replies.
* @return an IQ object.
* @throws Exception if an exception occurs while parsing the packet.
* @throws XmlPullParserException
* @throws IOException
* @throws SmackException
*/
public static IQ parse(XmlPullParser parser, XMPPConnection connection) throws Exception {
public static IQ parseIQ(XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
ParserUtils.assertAtStartTag(parser);
final int initialDepth = parser.getDepth();
IQ iqPacket = null;
@ -630,14 +628,12 @@ public class PacketParserUtils {
if (provider != null) {
iqPacket = provider.parse(parser);
}
// Only handle unknown IQs of type result. Types of 'get' and 'set' which are not understood
// have to be answered with an IQ error response. See the code a few lines below
// Note that if we reach this code, it is guranteed that the result IQ contained a child element
// (RFC 6120 § 8.2.3 6) because otherwhise we would have reached the END_TAG first.
else if (IQ.Type.result == type) {
else {
// No Provider found for the IQ stanza, parse it to an UnparsedIQ instance
// so that the content of the IQ can be examined later on
iqPacket = new UnparsedResultIQ(elementName, namespace, parseElement(parser));
iqPacket = new UnparsedIQ(elementName, namespace, parseElement(parser));
}
break;
}
@ -652,20 +648,6 @@ public class PacketParserUtils {
// Decide what to do when an IQ packet was not understood
if (iqPacket == null) {
switch (type) {
case get:
case set:
if (connection == null) {
return null;
}
// If the IQ stanza is of type "get" or "set" containing a child element qualified
// by a namespace with no registered Smack provider, then answer an IQ of type
// "error" with code 501 ("feature-not-implemented")
iqPacket = new ErrorIQ(new XMPPError(XMPPError.Condition.feature_not_implemented));
iqPacket.setPacketID(id);
iqPacket.setTo(from);
iqPacket.setFrom(to);
connection.sendPacket(iqPacket);
return null;
case error:
// If an IQ packet wasn't created above, create an empty error IQ packet.
iqPacket = new ErrorIQ(error);
@ -673,6 +655,8 @@ public class PacketParserUtils {
case result:
iqPacket = new EmptyResultIQ();
break;
default:
break;
}
}
@ -1044,28 +1028,4 @@ public class PacketParserUtils {
collection.add(packetExtension);
}
/**
* This class represents and unparsed IQ of the type 'result'. Usually it's created when no IQProvider
* was found for the IQ element.
*
* The child elements can be examined with the getChildElementXML() method.
*
*/
public static class UnparsedResultIQ extends IQ {
private UnparsedResultIQ(String element, String namespace, CharSequence content) {
super(element, namespace);
this.content = content;
}
private final CharSequence content;
public CharSequence getContent() {
return content;
}
@Override
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
throw new UnsupportedOperationException();
}
}
}

View File

@ -184,11 +184,9 @@ public class DummyConnection extends AbstractXMPPConnection {
* and that has not been returned by earlier calls to this method.
*
* @return a sent packet.
* @throws InterruptedException
*/
@SuppressWarnings("unchecked")
public <P extends TopLevelStreamElement> P getSentPacket() throws InterruptedException {
return (P) queue.poll(5, TimeUnit.MINUTES);
public <P extends TopLevelStreamElement> P getSentPacket() {
return getSentPacket(5 * 60);
}
/**
@ -198,11 +196,16 @@ public class DummyConnection extends AbstractXMPPConnection {
* have been sent yet.
*
* @return a sent packet.
* @throws InterruptedException
*/
@SuppressWarnings("unchecked")
public <P extends TopLevelStreamElement> P getSentPacket(int wait) throws InterruptedException {
return (P) queue.poll(wait, TimeUnit.SECONDS);
public <P extends TopLevelStreamElement> P getSentPacket(int wait) {
try {
return (P) queue.poll(wait, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
// TODO handle spurious interrupts
throw new IllegalStateException(e);
}
}
/**

View File

@ -17,6 +17,7 @@
package org.jivesoftware.smack;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@ -29,6 +30,7 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.jivesoftware.smack.packet.ErrorIQ;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
@ -36,6 +38,7 @@ import org.jivesoftware.smack.packet.RosterPacket;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.RosterPacket.Item;
import org.jivesoftware.smack.packet.RosterPacket.ItemType;
import org.jivesoftware.smack.packet.XMPPError.Condition;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.test.util.WaitForPacketListener;
import org.jivesoftware.smack.util.PacketParserUtils;
@ -329,7 +332,7 @@ public class RosterTest {
.append("</query>")
.append("</iq>");
final XmlPullParser parser = TestUtils.getIQParser(sb.toString());
final IQ rosterPush = PacketParserUtils.parse(parser, connection);
final IQ rosterPush = PacketParserUtils.parseIQ(parser);
initRoster();
rosterListener.reset();
@ -369,11 +372,14 @@ public class RosterTest {
packet.setFrom("mallory@example.com");
packet.addRosterItem(new Item("spam@example.com", "Cool products!"));
WaitForPacketListener waitForPacketListener = new WaitForPacketListener();
connection.addAsyncPacketListener(waitForPacketListener, null);
final String requestId = packet.getPacketID();
// Simulate receiving the roster push
connection.processPacket(packet);
waitForPacketListener.waitUntilInvocationOrTimeout();
// Smack should reply with an error IQ
ErrorIQ errorIQ = (ErrorIQ) connection.getSentPacket();
assertEquals(requestId, errorIQ.getPacketID());
assertEquals(Condition.service_unavailable, errorIQ.getError().getCondition());
assertNull("Contact was added to roster", connection.getRoster().getEntry("spam@example.com"));
}
@ -465,7 +471,7 @@ public class RosterTest {
.append("</query>")
.append("</iq>");
final XmlPullParser parser = TestUtils.getIQParser(sb.toString());
final IQ rosterPush = PacketParserUtils.parse(parser, connection);
final IQ rosterPush = PacketParserUtils.parseIQ(parser);
initRoster();
rosterListener.reset();

View File

@ -16,13 +16,9 @@
*/
package org.jivesoftware.smackx.bytestreams.ibb;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackException.NotConnectedException;
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.Packet;
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
/**
@ -34,45 +30,44 @@ import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
*
* @author Henning Staib
*/
class CloseListener implements PacketListener {
class CloseListener extends AbstractIqRequestHandler {
/* manager containing the listeners and the XMPP connection */
private final InBandBytestreamManager manager;
/* packet filter for all In-Band Bytestream close requests */
private final PacketFilter closeFilter = new AndFilter(new PacketTypeFilter(
Close.class), IQTypeFilter.SET);
/**
* Constructor.
*
* @param manager the In-Band Bytestream manager
*/
protected CloseListener(InBandBytestreamManager manager) {
super(Close.ELEMENT, Close.NAMESPACE, IQ.Type.set, Mode.async);
this.manager = manager;
}
public void processPacket(Packet packet) throws NotConnectedException {
Close closeRequest = (Close) packet;
@Override
public IQ handleIQRequest(IQ iqRequest) {
Close closeRequest = (Close) iqRequest;
InBandBytestreamSession ibbSession = this.manager.getSessions().get(
closeRequest.getSessionID());
if (ibbSession == null) {
this.manager.replyItemNotFoundPacket(closeRequest);
try {
this.manager.replyItemNotFoundPacket(closeRequest);
}
catch (NotConnectedException e) {
return null;
}
}
else {
ibbSession.closeByPeer(closeRequest);
try {
ibbSession.closeByPeer(closeRequest);
}
catch (NotConnectedException e) {
return null;
}
this.manager.getSessions().remove(closeRequest.getSessionID());
}
}
/**
* Returns the packet filter for In-Band Bytestream close requests.
*
* @return the packet filter for In-Band Bytestream close requests
*/
protected PacketFilter getFilter() {
return this.closeFilter;
return null;
}
}

View File

@ -210,8 +210,7 @@ public class InBandBytestreamManager implements BytestreamManager {
// register bytestream open packet listener
this.initiationListener = new InitiationListener(this);
this.connection.addAsyncPacketListener(this.initiationListener,
this.initiationListener.getFilter());
connection.registerIQRequestHandler(initiationListener);
// register bytestream data packet listener
this.dataListener = new DataListener(this);
@ -219,8 +218,7 @@ public class InBandBytestreamManager implements BytestreamManager {
// register bytestream close packet listener
this.closeListener = new CloseListener(this);
this.connection.addSyncPacketListener(this.closeListener, this.closeListener.getFilter());
connection.registerIQRequestHandler(closeListener);
}
/**
@ -543,9 +541,9 @@ public class InBandBytestreamManager implements BytestreamManager {
managers.remove(connection);
// remove all listeners registered by this manager
this.connection.removeAsyncPacketListener(this.initiationListener);
connection.unregisterIQRequestHandler(initiationListener);
this.connection.removeSyncPacketListener(this.dataListener);
this.connection.removeSyncPacketListener(this.closeListener);
connection.unregisterIQRequestHandler(closeListener);
// shutdown threads
this.initiationListener.shutdown();

View File

@ -21,12 +21,9 @@ import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackException.NotConnectedException;
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.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smackx.bytestreams.BytestreamListener;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
@ -44,16 +41,12 @@ import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
*
* @author Henning Staib
*/
class InitiationListener implements PacketListener {
class InitiationListener extends AbstractIqRequestHandler {
private static final Logger LOGGER = Logger.getLogger(InitiationListener.class.getName());
/* manager containing the listeners and the XMPP connection */
private final InBandBytestreamManager manager;
/* packet filter for all In-Band Bytestream requests */
private final PacketFilter initFilter = new AndFilter(new PacketTypeFilter(Open.class),
IQTypeFilter.SET);
/* executor service to process incoming requests concurrently */
private final ExecutorService initiationListenerExecutor;
@ -63,11 +56,13 @@ class InitiationListener implements PacketListener {
* @param manager the In-Band Bytestream manager
*/
protected InitiationListener(InBandBytestreamManager manager) {
super(Open.ELEMENT, Open.NAMESPACE, IQ.Type.set, Mode.async);
this.manager = manager;
initiationListenerExecutor = Executors.newCachedThreadPool();
}
}
public void processPacket(final Packet packet) {
@Override
public IQ handleIQRequest(final IQ packet) {
initiationListenerExecutor.execute(new Runnable() {
public void run() {
@ -79,6 +74,7 @@ class InitiationListener implements PacketListener {
}
}
});
return null;
}
private void processRequest(Packet packet) throws NotConnectedException {
@ -120,15 +116,6 @@ class InitiationListener implements PacketListener {
}
}
/**
* Returns the packet filter for In-Band Bytestream open requests.
*
* @return the packet filter for In-Band Bytestream open requests
*/
protected PacketFilter getFilter() {
return this.initFilter;
}
/**
* Shuts down the listeners executor service.
*/

View File

@ -21,12 +21,9 @@ import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackException.NotConnectedException;
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.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smackx.bytestreams.BytestreamListener;
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
@ -39,16 +36,12 @@ import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
*
* @author Henning Staib
*/
final class InitiationListener implements PacketListener {
final class InitiationListener extends AbstractIqRequestHandler {
private static final Logger LOGGER = Logger.getLogger(InitiationListener.class.getName());
/* manager containing the listeners and the XMPP connection */
private final Socks5BytestreamManager manager;
/* packet filter for all SOCKS5 Bytestream requests */
private final PacketFilter initFilter = new AndFilter(new PacketTypeFilter(Bytestream.class),
IQTypeFilter.SET);
/* executor service to process incoming requests concurrently */
private final ExecutorService initiationListenerExecutor;
@ -58,11 +51,14 @@ final class InitiationListener implements PacketListener {
* @param manager the SOCKS5 Bytestream manager
*/
protected InitiationListener(Socks5BytestreamManager manager) {
super(Bytestream.ELEMENT, Bytestream.NAMESPACE, IQ.Type.set, Mode.async);
this.manager = manager;
initiationListenerExecutor = Executors.newCachedThreadPool();
}
public void processPacket(final Packet packet) {
@Override
public IQ handleIQRequest(final IQ packet) {
initiationListenerExecutor.execute(new Runnable() {
public void run() {
@ -74,6 +70,8 @@ final class InitiationListener implements PacketListener {
}
}
});
return null;
}
private void processRequest(Packet packet) throws NotConnectedException {
@ -111,15 +109,6 @@ final class InitiationListener implements PacketListener {
}
}
/**
* Returns the packet filter for SOCKS5 Bytestream initialization requests.
*
* @return the packet filter for SOCKS5 Bytestream initialization requests
*/
protected PacketFilter getFilter() {
return this.initFilter;
}
/**
* Shuts down the listeners executor service.
*/

View File

@ -284,7 +284,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
public synchronized void disableService() {
// remove initiation packet listener
this.connection.removeAsyncPacketListener(this.initiationListener);
connection.unregisterIQRequestHandler(initiationListener);
// shutdown threads
this.initiationListener.shutdown();
@ -713,8 +713,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
*/
private void activate() {
// register bytestream initiation packet listener
this.connection.addAsyncPacketListener(this.initiationListener,
this.initiationListener.getFilter());
connection.registerIQRequestHandler(initiationListener);
// enable SOCKS5 feature
enableService();

View File

@ -28,7 +28,6 @@ import java.util.logging.Logger;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
@ -36,12 +35,9 @@ import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPConnectionRegistry;
import org.jivesoftware.smack.XMPPException;
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.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.commands.AdHocCommand.Action;
@ -73,9 +69,6 @@ public class AdHocCommandManager extends Manager {
*/
private static final int SESSION_TIMEOUT = 2 * 60;
private static final PacketFilter AD_HOC_COMMAND_FILTER = new AndFilter(
new PacketTypeFilter(AdHocCommandData.class), IQTypeFilter.SET);
/**
* Map a XMPPConnection with it AdHocCommandManager. This map have a key-value
* pair for every active connection.
@ -174,19 +167,20 @@ public class AdHocCommandManager extends Manager {
// The packet listener and the filter for processing some AdHoc Commands
// Packets
PacketListener listener = new PacketListener() {
public void processPacket(Packet packet) {
AdHocCommandData requestData = (AdHocCommandData) packet;
connection.registerIQRequestHandler(new AbstractIqRequestHandler(AdHocCommandData.ELEMENT,
AdHocCommandData.NAMESPACE, IQ.Type.set, Mode.async) {
@Override
public IQ handleIQRequest(IQ iqRequest) {
AdHocCommandData requestData = (AdHocCommandData) iqRequest;
try {
processAdHocCommand(requestData);
return processAdHocCommand(requestData);
}
catch (NotConnectedException | NoResponseException e) {
catch (NoResponseException | NotConnectedException e) {
LOGGER.log(Level.INFO, "processAdHocCommand threw exceptino", e);
return null;
}
}
};
connection.addAsyncPacketListener(listener, AD_HOC_COMMAND_FILTER);
});
sessionsSweeper = null;
}
@ -325,7 +319,7 @@ public class AdHocCommandManager extends Manager {
* @throws NotConnectedException
* @throws NoResponseException
*/
private void processAdHocCommand(AdHocCommandData requestData) throws NotConnectedException, NoResponseException {
private IQ processAdHocCommand(AdHocCommandData requestData) throws NoResponseException, NotConnectedException {
// Creates the response with the corresponding data
AdHocCommandData response = new AdHocCommandData();
response.setTo(requestData.getFrom());
@ -342,8 +336,7 @@ public class AdHocCommandManager extends Manager {
if (!commands.containsKey(commandNode)) {
// Requested command does not exist so return
// item_not_found error.
respondError(response, XMPPError.Condition.item_not_found);
return;
return respondError(response, XMPPError.Condition.item_not_found);
}
// Create new session ID
@ -361,24 +354,21 @@ public class AdHocCommandManager extends Manager {
// Answer forbidden error if requester permissions are not
// enough to execute the requested command
if (!command.hasPermission(requestData.getFrom())) {
respondError(response, XMPPError.Condition.forbidden);
return;
return respondError(response, XMPPError.Condition.forbidden);
}
Action action = requestData.getAction();
// If the action is unknown then respond an error.
if (action != null && action.equals(Action.unknown)) {
respondError(response, XMPPError.Condition.bad_request,
return respondError(response, XMPPError.Condition.bad_request,
AdHocCommand.SpecificErrorCondition.malformedAction);
return;
}
// If the action is not execute, then it is an invalid action.
if (action != null && !action.equals(Action.execute)) {
respondError(response, XMPPError.Condition.bad_request,
return respondError(response, XMPPError.Condition.bad_request,
AdHocCommand.SpecificErrorCondition.badAction);
return;
}
// Increase the state number, so the command knows in witch
@ -441,7 +431,7 @@ public class AdHocCommandManager extends Manager {
}
// Sends the response packet
connection().sendPacket(response);
return response;
}
catch (XMPPErrorException e) {
@ -457,7 +447,7 @@ public class AdHocCommandManager extends Manager {
response.setStatus(Status.canceled);
executingCommands.remove(sessionId);
}
respondError(response, error);
return respondError(response, error);
}
}
else {
@ -467,9 +457,8 @@ public class AdHocCommandManager extends Manager {
// This also handles if the command was removed in the meanwhile
// of getting the key and the value of the map.
if (command == null) {
respondError(response, XMPPError.Condition.bad_request,
return respondError(response, XMPPError.Condition.bad_request,
AdHocCommand.SpecificErrorCondition.badSessionid);
return;
}
// Check if the Session data has expired (default is 10 minutes)
@ -479,9 +468,8 @@ public class AdHocCommandManager extends Manager {
executingCommands.remove(sessionId);
// Answer a not_allowed error (session-expired)
respondError(response, XMPPError.Condition.not_allowed,
return respondError(response, XMPPError.Condition.not_allowed,
AdHocCommand.SpecificErrorCondition.sessionExpired);
return;
}
/*
@ -494,9 +482,8 @@ public class AdHocCommandManager extends Manager {
// If the action is unknown the respond an error
if (action != null && action.equals(Action.unknown)) {
respondError(response, XMPPError.Condition.bad_request,
return respondError(response, XMPPError.Condition.bad_request,
AdHocCommand.SpecificErrorCondition.malformedAction);
return;
}
// If the user didn't specify an action or specify the execute
@ -508,9 +495,8 @@ public class AdHocCommandManager extends Manager {
// Check that the specified action was previously
// offered
if (!command.isValidAction(action)) {
respondError(response, XMPPError.Condition.bad_request,
return respondError(response, XMPPError.Condition.bad_request,
AdHocCommand.SpecificErrorCondition.badAction);
return;
}
try {
@ -556,7 +542,7 @@ public class AdHocCommandManager extends Manager {
executingCommands.remove(sessionId);
}
connection().sendPacket(response);
return response;
}
catch (XMPPErrorException e) {
// If there is an exception caused by the next, complete,
@ -571,7 +557,7 @@ public class AdHocCommandManager extends Manager {
response.setStatus(Status.canceled);
executingCommands.remove(sessionId);
}
respondError(response, error);
return respondError(response, error);
}
}
}
@ -584,9 +570,9 @@ public class AdHocCommandManager extends Manager {
* @param condition the condition of the error.
* @throws NotConnectedException
*/
private void respondError(AdHocCommandData response,
XMPPError.Condition condition) throws NotConnectedException {
respondError(response, new XMPPError(condition));
private IQ respondError(AdHocCommandData response,
XMPPError.Condition condition) {
return respondError(response, new XMPPError(condition));
}
/**
@ -597,11 +583,11 @@ public class AdHocCommandManager extends Manager {
* @param specificCondition the adhoc command error condition.
* @throws NotConnectedException
*/
private void respondError(AdHocCommandData response, XMPPError.Condition condition,
AdHocCommand.SpecificErrorCondition specificCondition) throws NotConnectedException
private static IQ respondError(AdHocCommandData response, XMPPError.Condition condition,
AdHocCommand.SpecificErrorCondition specificCondition)
{
XMPPError error = new XMPPError(condition, new AdHocCommandData.SpecificError(specificCondition));
respondError(response, error);
return respondError(response, error);
}
/**
@ -611,10 +597,10 @@ public class AdHocCommandManager extends Manager {
* @param error the error to send.
* @throws NotConnectedException
*/
private void respondError(AdHocCommandData response, XMPPError error) throws NotConnectedException {
private static IQ respondError(AdHocCommandData response, XMPPError error) {
response.setType(IQ.Type.error);
response.setError(error);
connection().sendPacket(response);
return response;
}
/**

View File

@ -21,13 +21,10 @@ 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.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.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
@ -67,9 +64,6 @@ public class ServiceDiscoveryManager extends Manager {
private static final Logger LOGGER = Logger.getLogger(ServiceDiscoveryManager.class.getName());
private static final PacketFilter GET_DISCOVER_ITEMS = new AndFilter(IQTypeFilter.GET, new PacketTypeFilter(DiscoverItems.class));
private static final PacketFilter GET_DISCOVER_INFO = new AndFilter(IQTypeFilter.GET, new PacketTypeFilter(DiscoverInfo.class));
private static final String DEFAULT_IDENTITY_NAME = "Smack";
private static final String DEFAULT_IDENTITY_CATEGORY = "client";
private static final String DEFAULT_IDENTITY_TYPE = "pc";
@ -122,9 +116,10 @@ public class ServiceDiscoveryManager extends Manager {
addFeature(DiscoverItems.NAMESPACE);
// Listen for disco#items requests and answer with an empty result
PacketListener packetListener = new PacketListener() {
public void processPacket(Packet packet) throws NotConnectedException {
DiscoverItems discoverItems = (DiscoverItems) packet;
connection.registerIQRequestHandler(new AbstractIqRequestHandler(DiscoverItems.ELEMENT, DiscoverItems.NAMESPACE, IQ.Type.get, Mode.async) {
@Override
public IQ handleIQRequest(IQ iqRequest) {
DiscoverItems discoverItems = (DiscoverItems) iqRequest;
DiscoverItems response = new DiscoverItems();
response.setType(IQ.Type.result);
response.setTo(discoverItems.getFrom());
@ -145,16 +140,16 @@ public class ServiceDiscoveryManager extends Manager {
response.setType(IQ.Type.error);
response.setError(new XMPPError(XMPPError.Condition.item_not_found));
}
connection().sendPacket(response);
return response;
}
};
connection.addAsyncPacketListener(packetListener, GET_DISCOVER_ITEMS);
});
// Listen for disco#info requests and answer the client's supported features
// To add a new feature as supported use the #addFeature message
packetListener = new PacketListener() {
public void processPacket(Packet packet) throws NotConnectedException {
DiscoverInfo discoverInfo = (DiscoverInfo) packet;
connection.registerIQRequestHandler(new AbstractIqRequestHandler(DiscoverInfo.ELEMENT, DiscoverInfo.NAMESPACE, IQ.Type.get, Mode.async) {
@Override
public IQ handleIQRequest(IQ iqRequest) {
DiscoverInfo discoverInfo = (DiscoverInfo) iqRequest;
// Answer the client's supported features if the request is of the GET type
DiscoverInfo response = new DiscoverInfo();
response.setType(IQ.Type.result);
@ -184,10 +179,9 @@ public class ServiceDiscoveryManager extends Manager {
response.setError(new XMPPError(XMPPError.Condition.item_not_found));
}
}
connection().sendPacket(response);
return response;
}
};
connection.addAsyncPacketListener(packetListener, GET_DISCOVER_INFO);
});
}
/**

View File

@ -28,14 +28,16 @@ import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.XMPPConnectionRegistry;
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.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.packet.XMPPError.Condition;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.iqlast.packet.LastActivity;
@ -89,8 +91,8 @@ import org.jivesoftware.smackx.iqlast.packet.LastActivity;
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(IQTypeFilter.GET,
new PacketTypeFilter(LastActivity.class));
// private static final PacketFilter IQ_GET_LAST_FILTER = new AndFilter(IQTypeFilter.GET,
// new PacketTypeFilter(LastActivity.class));
private static boolean enabledPerDefault = true;
@ -160,21 +162,22 @@ public class LastActivityManager extends Manager {
}, PacketTypeFilter.MESSAGE);
// Register a listener for a last activity query
connection.addAsyncPacketListener(new PacketListener() {
public void processPacket(Packet packet) throws NotConnectedException {
if (!enabled) return;
connection.registerIQRequestHandler(new AbstractIqRequestHandler(LastActivity.ELEMENT, LastActivity.NAMESPACE,
Type.get, Mode.async) {
@Override
public IQ handleIQRequest(IQ iqRequest) {
if (!enabled)
return IQ.createErrorResponse(iqRequest, new XMPPError(Condition.not_acceptable));
LastActivity message = new LastActivity();
message.setType(IQ.Type.result);
message.setTo(packet.getFrom());
message.setFrom(packet.getTo());
message.setPacketID(packet.getPacketID());
message.setTo(iqRequest.getFrom());
message.setFrom(iqRequest.getTo());
message.setPacketID(iqRequest.getPacketID());
message.setLastActivity(getIdleTime());
connection().sendPacket(message);
return message;
}
}, IQ_GET_LAST_FILTER);
});
if (enabledPerDefault) {
enable();

View File

@ -26,14 +26,13 @@ import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnectionRegistry;
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.Packet;
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.packet.XMPPError.Condition;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.iqversion.packet.Version;
@ -56,8 +55,6 @@ import org.jivesoftware.smackx.iqversion.packet.Version;
public class VersionManager extends Manager {
private static final Map<XMPPConnection, VersionManager> INSTANCES = new WeakHashMap<XMPPConnection, VersionManager>();
private static final PacketFilter PACKET_FILTER = new AndFilter(new PacketTypeFilter(Version.class), IQTypeFilter.GET);
private static Version defaultVersion;
private Version ourVersion = defaultVersion;
@ -86,19 +83,17 @@ public class VersionManager extends Manager {
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
sdm.addFeature(Version.NAMESPACE);
connection.addAsyncPacketListener(new PacketListener() {
/**
* Sends a Version reply on request
* @throws NotConnectedException
*/
public void processPacket(Packet packet) throws NotConnectedException {
if (ourVersion == null)
return;
connection.registerIQRequestHandler(new AbstractIqRequestHandler(Version.ELEMENT, Version.NAMESPACE, IQ.Type.get,
Mode.async) {
@Override
public IQ handleIQRequest(IQ iqRequest) {
if (ourVersion == null) {
return IQ.createErrorResponse(iqRequest, new XMPPError(Condition.not_acceptable));
}
connection().sendPacket(Version.createResultFor(packet, ourVersion));
return Version.createResultFor(iqRequest, ourVersion);
}
}
, PACKET_FILTER);
});
}
public static synchronized VersionManager getInstanceFor(XMPPConnection connection) {

View File

@ -35,15 +35,13 @@ 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.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.Packet;
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.util.SmackExecutorThreadFactory;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.ping.packet.Ping;
@ -66,9 +64,6 @@ public class PingManager extends Manager {
private static final Map<XMPPConnection, PingManager> INSTANCES = new WeakHashMap<XMPPConnection, PingManager>();
private static final PacketFilter PING_PACKET_FILTER = new AndFilter(
new PacketTypeFilter(Ping.class), IQTypeFilter.GET);
static {
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
public void connectionCreated(XMPPConnection connection) {
@ -127,14 +122,13 @@ public class PingManager extends Manager {
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
sdm.addFeature(Ping.NAMESPACE);
connection.addAsyncPacketListener(new PacketListener() {
// Send a Pong for every Ping
connection.registerIQRequestHandler(new AbstractIqRequestHandler(Ping.ELEMENT, Ping.NAMESPACE, Type.get, Mode.async) {
@Override
public void processPacket(Packet packet) throws NotConnectedException {
Ping ping = (Ping) packet;
connection().sendPacket(ping.getPong());
public IQ handleIQRequest(IQ iqRequest) {
Ping ping = (Ping) iqRequest;
return ping.getPong();
}
}, PING_PACKET_FILTER);
});
connection.addConnectionListener(new AbstractConnectionClosedListener() {
@Override
public void authenticated(XMPPConnection connection, boolean resumed) {

View File

@ -37,6 +37,8 @@ import org.jivesoftware.smack.filter.IQResultReplyFilter;
import org.jivesoftware.smack.filter.IQTypeFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
@ -65,8 +67,6 @@ public class PrivacyListManager extends Manager {
public static final PacketFilter PRIVACY_FILTER = new PacketTypeFilter(Privacy.class);
private static final PacketFilter PRIVACY_SET = new AndFilter(IQTypeFilter.SET, PRIVACY_FILTER);
private static final PacketFilter PRIVACY_RESULT = new AndFilter(IQTypeFilter.RESULT, PRIVACY_FILTER);
// Keep the list of instances of this class.
@ -97,10 +97,11 @@ public class PrivacyListManager extends Manager {
private PrivacyListManager(XMPPConnection connection) {
super(connection);
connection.addSyncPacketListener(new PacketListener() {
connection.registerIQRequestHandler(new AbstractIqRequestHandler(Privacy.ELEMENT, Privacy.NAMESPACE,
IQ.Type.set, Mode.sync) {
@Override
public void processPacket(Packet packet) throws NotConnectedException {
Privacy privacy = (Privacy) packet;
public IQ handleIQRequest(IQ iqRequest) {
Privacy privacy = (Privacy) iqRequest;
// Notifies the event to the listeners.
for (PrivacyListListener listener : listeners) {
@ -117,11 +118,9 @@ public class PrivacyListManager extends Manager {
}
}
// Send a result package acknowledging the reception of a privacy package.
IQ iq = IQ.createResultIQ(privacy);
connection().sendPacket(iq);
return IQ.createResultIQ(privacy);
}
}, PRIVACY_SET);
});
// cached(Active|Default)ListName handling
connection.addPacketSendingListener(new PacketListener() {

View File

@ -24,14 +24,14 @@ 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.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.Packet;
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.packet.XMPPError.Condition;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.time.packet.Time;
@ -39,9 +39,6 @@ public class EntityTimeManager extends Manager {
private static final Map<XMPPConnection, EntityTimeManager> INSTANCES = new WeakHashMap<XMPPConnection, EntityTimeManager>();
private static final PacketFilter TIME_PACKET_FILTER = new AndFilter(new PacketTypeFilter(
Time.class), IQTypeFilter.GET);
private static boolean autoEnable = true;
static {
@ -72,14 +69,18 @@ public class EntityTimeManager extends Manager {
if (autoEnable)
enable();
connection.addAsyncPacketListener(new PacketListener() {
connection.registerIQRequestHandler(new AbstractIqRequestHandler(Time.ELEMENT, Time.NAMESPACE, Type.get,
Mode.async) {
@Override
public void processPacket(Packet packet) throws NotConnectedException {
if (!enabled)
return;
connection().sendPacket(Time.createResponse(packet));
public IQ handleIQRequest(IQ iqRequest) {
if (enabled) {
return Time.createResponse(iqRequest);
}
else {
return IQ.createErrorResponse(iqRequest, new XMPPError(Condition.not_acceptable));
}
}
}, TIME_PACKET_FILTER);
});
}
public synchronized void enable() {

View File

@ -17,7 +17,6 @@
package org.jivesoftware.smackx.time.packet;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jxmpp.util.XmppDateTime;
import java.util.Calendar;
@ -123,7 +122,7 @@ public class Time extends IQ {
this.tzo = tzo;
}
public static Time createResponse(Packet request) {
public static Time createResponse(IQ request) {
Time time = new Time(Calendar.getInstance());
time.setType(Type.result);
time.setTo(request.getFrom());

View File

@ -61,7 +61,7 @@ public class CloseListenerTest {
close.setFrom(initiatorJID);
close.setTo(targetJID);
closeListener.processPacket(close);
closeListener.handleIQRequest(close);
// wait because packet is processed in an extra thread
Thread.sleep(200);

View File

@ -79,7 +79,7 @@ public class InitiationListenerTest {
public void shouldRespondWithError() throws Exception {
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -107,7 +107,7 @@ public class InitiationListenerTest {
byteStreamManager.setMaximumBlockSize(1024);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -137,7 +137,7 @@ public class InitiationListenerTest {
byteStreamManager.addIncomingBytestreamListener(listener);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -165,7 +165,7 @@ public class InitiationListenerTest {
byteStreamManager.addIncomingBytestreamListener(listener, initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -193,7 +193,7 @@ public class InitiationListenerTest {
byteStreamManager.addIncomingBytestreamListener(listener, "other_" + initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -231,7 +231,7 @@ public class InitiationListenerTest {
byteStreamManager.addIncomingBytestreamListener(userRequestsListener, initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -265,7 +265,7 @@ public class InitiationListenerTest {
+ initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -300,7 +300,7 @@ public class InitiationListenerTest {
byteStreamManager.ignoreBytestreamRequestOnce(sessionID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -314,7 +314,7 @@ public class InitiationListenerTest {
verify(allRequestsListener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
// run the listener with the initiation packet again
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);

View File

@ -86,7 +86,7 @@ public class InitiationListenerTest {
public void shouldRespondWithError() throws Exception {
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -116,7 +116,7 @@ public class InitiationListenerTest {
byteStreamManager.addIncomingBytestreamListener(listener);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -144,7 +144,7 @@ public class InitiationListenerTest {
byteStreamManager.addIncomingBytestreamListener(listener, initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -172,7 +172,7 @@ public class InitiationListenerTest {
byteStreamManager.addIncomingBytestreamListener(listener, "other_" + initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -210,7 +210,7 @@ public class InitiationListenerTest {
byteStreamManager.addIncomingBytestreamListener(userRequestsListener, initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -244,7 +244,7 @@ public class InitiationListenerTest {
+ initiatorJID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -279,7 +279,7 @@ public class InitiationListenerTest {
byteStreamManager.ignoreBytestreamRequestOnce(sessionID);
// run the listener with the initiation packet
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);
@ -293,7 +293,7 @@ public class InitiationListenerTest {
verify(allRequestsListener, never()).incomingBytestreamRequest(byteStreamRequest.capture());
// run the listener with the initiation packet again
initiationListener.processPacket(initBytestream);
initiationListener.handleIQRequest(initBytestream);
// wait because packet is processed in an extra thread
Thread.sleep(200);

View File

@ -45,7 +45,7 @@ public class PubSubProviderTest {
"</iq>";
// @formatter:on
XmlPullParser parser = TestUtils.getIQParser(resultStanza);
PubSub pubsubResult = (PubSub) PacketParserUtils.parse(parser, null);
PubSub pubsubResult = (PubSub) PacketParserUtils.parseIQ(parser);
SubscriptionsExtension subElem = pubsubResult.getExtension(PubSubElementType.SUBSCRIPTIONS);
List<Subscription> subscriptions = subElem.getSubscriptions();
assertEquals(2, subscriptions.size());