1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2025-09-10 18:59:41 +02:00

Improve packet send and result collecting API

Instead of repeating the same pattern, when sending an IQ get/set packet
and collecting the response

PacketFilter filter = new PacketIDFilter(request.getPacketID()),
PacketCollector collector = connection.createPacketCollector(filter);
connection.sendPacket(reg);
IQ result = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
// Stop queuing results
collector.cancel();
if (result == null) {
    throw new XMPPException("No response from server.");
}
else if (result.getType() == IQ.Type.ERROR) {
    throw new XMPPException(result.getError());
}

the API got redesigned, so that the above code block can be replaced
with

Packet result = connection.createPacketCollectorAndSend(request).nextResultOrThrow();
This commit is contained in:
Florian Schmaus 2014-02-18 15:05:19 +01:00
parent e6d5385129
commit 7bd7b3d24c
50 changed files with 333 additions and 1489 deletions

View file

@ -227,19 +227,7 @@ public class AccountManager {
attributes.put("username",username);
attributes.put("password",password);
reg.setAttributes(attributes);
PacketFilter filter = new AndFilter(new PacketIDFilter(reg.getPacketID()),
new PacketTypeFilter(IQ.class));
PacketCollector collector = connection.createPacketCollector(filter);
connection.sendPacket(reg);
IQ result = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
// Stop queuing results
collector.cancel();
if (result == null) {
throw new XMPPException("No response from server.");
}
else if (result.getType() == IQ.Type.ERROR) {
throw new XMPPException(result.getError());
}
connection.createPacketCollectorAndSend(reg).nextResultOrThrow();
}
/**
@ -262,15 +250,7 @@ public class AccountManager {
new PacketTypeFilter(IQ.class));
PacketCollector collector = connection.createPacketCollector(filter);
connection.sendPacket(reg);
IQ result = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
// Stop queuing results
collector.cancel();
if (result == null) {
throw new XMPPException("No response from server.");
}
else if (result.getType() == IQ.Type.ERROR) {
throw new XMPPException(result.getError());
}
collector.nextResultOrThrow();
}
/**
@ -292,19 +272,7 @@ public class AccountManager {
// To delete an account, we add a single attribute, "remove", that is blank.
attributes.put("remove", "");
reg.setAttributes(attributes);
PacketFilter filter = new AndFilter(new PacketIDFilter(reg.getPacketID()),
new PacketTypeFilter(IQ.class));
PacketCollector collector = connection.createPacketCollector(filter);
connection.sendPacket(reg);
IQ result = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
// Stop queuing results
collector.cancel();
if (result == null) {
throw new XMPPException("No response from server.");
}
else if (result.getType() == IQ.Type.ERROR) {
throw new XMPPException(result.getError());
}
connection.createPacketCollectorAndSend(reg).nextResultOrThrow();
}
/**
@ -315,21 +283,6 @@ public class AccountManager {
private synchronized void getRegistrationInfo() throws XMPPException {
Registration reg = new Registration();
reg.setTo(connection.getServiceName());
PacketFilter filter = new AndFilter(new PacketIDFilter(reg.getPacketID()),
new PacketTypeFilter(IQ.class));
PacketCollector collector = connection.createPacketCollector(filter);
connection.sendPacket(reg);
IQ result = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
// Stop queuing results
collector.cancel();
if (result == null) {
throw new XMPPException("No response from server.");
}
else if (result.getType() == IQ.Type.ERROR) {
throw new XMPPException(result.getError());
}
else {
info = (Registration)result;
}
info = (Registration) connection.createPacketCollectorAndSend(reg).nextResultOrThrow();
}
}

View file

@ -37,6 +37,7 @@ import org.jivesoftware.smack.compression.XMPPInputOutputStream;
import org.jivesoftware.smack.compression.Java7ZlibInputOutputStream;
import org.jivesoftware.smack.debugger.SmackDebugger;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
@ -172,6 +173,11 @@ public abstract class Connection {
*/
private ChatManager chatManager = null;
/**
*
*/
private long packetReplyTimeout = SmackConfiguration.getDefaultPacketReplyTimeout();
/**
* The SmackDebugger allows to log and debug XML traffic.
*/
@ -563,6 +569,24 @@ public abstract class Connection {
return connectionListeners;
}
/**
* Creates a new packet collector collecting packets that are replies to <code>packet</code>.
* Does also send <code>packet</code>. Note that the packet filter is at the moment created as
* ID filter of <code>packet</code>'s ID. This may change in the future to also check the
* correct "from JID" value.
*
* @param packet the packet to filter responses from
* @return a new packet collector.
*/
public PacketCollector createPacketCollectorAndSend(Packet packet) {
PacketFilter packetFilter = new PacketIDFilter(packet.getPacketID());
// Create the packet collector before sending the packet
PacketCollector packetCollector = createPacketCollector(packetFilter);
// Now we can send the packet as the collector has been created
sendPacket(packet);
return packetCollector;
}
/**
* Creates a new packet collector for this connection. A packet filter determines
* which packets will be accumulated by the collector. A PacketCollector is
@ -848,6 +872,10 @@ public abstract class Connection {
rosterVersioningSupported = true;
}
public long getPacketReplyTimeout() {
return packetReplyTimeout;
}
/**
* A wrapper class to associate a packet filter with a listener.
*/

View file

@ -17,9 +17,9 @@
package org.jivesoftware.smack;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.packet.Authentication;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.PasswordCallback;
@ -60,22 +60,9 @@ class NonSASLAuthentication implements UserAuthentication {
discoveryAuth.setType(IQ.Type.GET);
discoveryAuth.setUsername(username);
PacketCollector collector =
connection.createPacketCollector(new PacketIDFilter(discoveryAuth.getPacketID()));
// Send the packet
connection.sendPacket(discoveryAuth);
// Wait up to a certain number of seconds for a response from the server.
IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
if (response == null) {
throw new XMPPException("No response from the server.");
}
// If the server replied with an error, throw an exception.
else if (response.getType() == IQ.Type.ERROR) {
throw new XMPPException(response.getError());
}
// Otherwise, no error so continue processing.
Authentication authTypes = (Authentication) response;
collector.cancel();
Authentication authTypes = (Authentication) connection.createPacketCollectorAndSend(
discoveryAuth).nextResultOrThrow();
// Now, create the authentication packet we'll send to the server.
Authentication auth = new Authentication();
@ -94,19 +81,7 @@ class NonSASLAuthentication implements UserAuthentication {
auth.setResource(resource);
collector = connection.createPacketCollector(new PacketIDFilter(auth.getPacketID()));
// Send the packet.
connection.sendPacket(auth);
// Wait up to a certain number of seconds for a response from the server.
response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
if (response == null) {
throw new XMPPException("Authentication failed.");
}
else if (response.getType() == IQ.Type.ERROR) {
throw new XMPPException(response.getError());
}
// We're done with the collector, so explicitly cancel it.
collector.cancel();
Packet response = connection.createPacketCollectorAndSend(auth).nextResultOrThrow();
return response.getTo();
}
@ -115,20 +90,7 @@ class NonSASLAuthentication implements UserAuthentication {
// Create the authentication packet we'll send to the server.
Authentication auth = new Authentication();
PacketCollector collector =
connection.createPacketCollector(new PacketIDFilter(auth.getPacketID()));
// Send the packet.
connection.sendPacket(auth);
// Wait up to a certain number of seconds for a response from the server.
IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
if (response == null) {
throw new XMPPException("Anonymous login failed.");
}
else if (response.getType() == IQ.Type.ERROR) {
throw new XMPPException(response.getError());
}
// We're done with the collector, so explicitly cancel it.
collector.cancel();
Packet response = connection.createPacketCollectorAndSend(auth).nextResultOrThrow();
if (response.getTo() != null) {
return response.getTo();

View file

@ -22,6 +22,7 @@ import java.util.concurrent.TimeUnit;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.XMPPError;
/**
* Provides a mechanism to collect packets into a result queue that pass a
@ -105,26 +106,35 @@ public class PacketCollector {
}
/**
* Returns the next available packet. The method call will block (not return)
* until a packet is available.
*
* Returns the next available packet. The method call will block (not return) until a packet is
* available.
*
* @return the next available packet.
*/
public Packet nextResult() {
public Packet nextResultBlockForever() {
try {
return resultQueue.take();
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
return resultQueue.take();
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
/**
* Returns the next available packet. The method call will block until the connection's default
* timeout has elapsed.
*
* @return the next availabe packet.
*/
public Packet nextResult() {
return nextResult(connection.getPacketReplyTimeout());
}
/**
* Returns the next available packet. The method call will block (not return)
* until a packet is available or the <tt>timeout</tt> has elapased. If the
* until a packet is available or the <tt>timeout</tt> has elapsed. If the
* timeout elapses without a result, <tt>null</tt> will be returned.
*
* @param timeout the amount of time to wait for the next packet (in milleseconds).
* @return the next available packet.
*/
public Packet nextResult(long timeout) {
@ -136,6 +146,41 @@ public class PacketCollector {
}
}
/**
* Returns the next available packet. The method call will block until a packet is available or
* the connections reply timeout has elapsed. If the timeout elapses without a result,
* <tt>null</tt> will be returned. This method does also cancel the PacketCollector.
*
* @return the next available packet.
* @throws XMPPException
*/
public Packet nextResultOrThrow() throws XMPPException {
return nextResultOrThrow(connection.getPacketReplyTimeout());
}
/**
* Returns the next available packet. The method call will block until a packet is available or
* the <tt>timeout</tt> has elapsed. This method does also cancel the PacketCollector.
*
* @param timeout the amount of time to wait for the next packet (in milleseconds).
* @return the next available packet.
* @throws XMPPException in case of no response or error response
*/
public Packet nextResultOrThrow(long timeout) throws XMPPException {
Packet result = nextResult(timeout);
cancel();
if (result == null) {
throw new XMPPException(SmackError.NO_RESPONSE_FROM_SERVER);
}
XMPPError xmppError = result.getError();
if (xmppError != null) {
throw new XMPPException(xmppError);
}
return result;
}
/**
* Processes a packet to see if it meets the criteria for this packet collector.
* If so, the packet is added to the result queue.

View file

@ -108,7 +108,7 @@ class PacketReader {
// (although this is a rare thing). Therefore, we continue waiting
// until either a connectionID has been set (and hence a notify was
// made) or the total wait time has elapsed.
int waitTime = SmackConfiguration.getPacketReplyTimeout();
int waitTime = SmackConfiguration.getDefaultPacketReplyTimeout();
wait(3 * waitTime);
}
catch (InterruptedException ie) {

View file

@ -277,19 +277,7 @@ public class Roster {
}
}
rosterPacket.addRosterItem(item);
// Wait up to a certain number of seconds for a reply from the server.
PacketCollector collector = connection.createPacketCollector(
new PacketIDFilter(rosterPacket.getPacketID()));
connection.sendPacket(rosterPacket);
IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
collector.cancel();
if (response == null) {
throw new XMPPException("No response from the server.");
}
// If the server replied with an error, throw an exception.
else if (response.getType() == IQ.Type.ERROR) {
throw new XMPPException(response.getError());
}
connection.createPacketCollectorAndSend(rosterPacket).nextResultOrThrow();
// Create a presence subscription packet and send.
Presence presencePacket = new Presence(Presence.Type.subscribe);
@ -326,18 +314,7 @@ public class Roster {
// Set the item type as REMOVE so that the server will delete the entry
item.setItemType(RosterPacket.ItemType.remove);
packet.addRosterItem(item);
PacketCollector collector = connection.createPacketCollector(
new PacketIDFilter(packet.getPacketID()));
connection.sendPacket(packet);
IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
collector.cancel();
if (response == null) {
throw new XMPPException("No response from the server.");
}
// If the server replied with an error, throw an exception.
else if (response.getType() == IQ.Type.ERROR) {
throw new XMPPException(response.getError());
}
connection.createPacketCollectorAndSend(packet).nextResultOrThrow();
}
/**

View file

@ -178,15 +178,7 @@ public class RosterGroup {
}
}
if (collector != null) {
IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
collector.cancel();
if (response == null) {
throw new XMPPException("No response from the server.");
}
// If the server replied with an error, throw an exception.
else if (response.getType() == IQ.Type.ERROR) {
throw new XMPPException(response.getError());
}
collector.nextResultOrThrow();
}
}
@ -220,15 +212,7 @@ public class RosterGroup {
}
}
if (collector != null) {
IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
collector.cancel();
if (response == null) {
throw new XMPPException("No response from the server.");
}
// If the server replied with an error, throw an exception.
else if (response.getType() == IQ.Type.ERROR) {
throw new XMPPException(response.getError());
}
collector.nextResultOrThrow();
}
}

View file

@ -17,9 +17,7 @@
package org.jivesoftware.smack;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.packet.Bind;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Session;
import org.jivesoftware.smack.sasl.*;
@ -443,37 +441,12 @@ public class SASLAuthentication implements UserAuthentication {
Bind bindResource = new Bind();
bindResource.setResource(resource);
PacketCollector collector = connection
.createPacketCollector(new PacketIDFilter(bindResource.getPacketID()));
// Send the packet
connection.sendPacket(bindResource);
// Wait up to a certain number of seconds for a response from the server.
Bind response = (Bind) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
collector.cancel();
if (response == null) {
throw new XMPPException("No response from the server.");
}
// If the server replied with an error, throw an exception.
else if (response.getType() == IQ.Type.ERROR) {
throw new XMPPException(response.getError());
}
Bind response = (Bind) connection.createPacketCollectorAndSend(bindResource).nextResultOrThrow();
String userJID = response.getJid();
if (sessionSupported) {
Session session = new Session();
collector = connection.createPacketCollector(new PacketIDFilter(session.getPacketID()));
// Send the packet
connection.sendPacket(session);
// Wait up to a certain number of seconds for a response from the server.
IQ ack = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
collector.cancel();
if (ack == null) {
throw new XMPPException("No response from the server.");
}
// If the server replied with an error, throw an exception.
else if (ack.getType() == IQ.Type.ERROR) {
throw new XMPPException(ack.getError());
}
connection.createPacketCollectorAndSend(session).nextResultOrThrow();
}
return userJID;
}

View file

@ -58,7 +58,7 @@ public final class SmackConfiguration {
private static InputStream configFileStream;
private static int packetReplyTimeout = 5000;
private static int defaultPacketReplyTimeout = 5000;
private static List<String> defaultMechs = new ArrayList<String>();
private static boolean localSocks5ProxyEnabled = true;
@ -150,14 +150,14 @@ public final class SmackConfiguration {
*
* @return the milliseconds to wait for a response from the server
*/
public static int getPacketReplyTimeout() {
public static int getDefaultPacketReplyTimeout() {
initialize();
// The timeout value must be greater than 0 otherwise we will answer the default value
if (packetReplyTimeout <= 0) {
packetReplyTimeout = 5000;
if (defaultPacketReplyTimeout <= 0) {
defaultPacketReplyTimeout = 5000;
}
return packetReplyTimeout;
return defaultPacketReplyTimeout;
}
/**
@ -166,13 +166,13 @@ public final class SmackConfiguration {
*
* @param timeout the milliseconds to wait for a response from the server
*/
public static void setPacketReplyTimeout(int timeout) {
public static void setDefaultPacketReplyTimeout(int timeout) {
initialize();
if (timeout <= 0) {
throw new IllegalArgumentException();
}
packetReplyTimeout = timeout;
defaultPacketReplyTimeout = timeout;
}
/**
@ -442,8 +442,8 @@ public final class SmackConfiguration {
else if (parser.getName().equals("optionalStartupClasses")) {
parseClassesToLoad(parser, true);
}
else if (parser.getName().equals("packetReplyTimeout")) {
packetReplyTimeout = parseIntProperty(parser, packetReplyTimeout);
else if (parser.getName().equals("defaultPacketReplyTimeout")) {
defaultPacketReplyTimeout = parseIntProperty(parser, defaultPacketReplyTimeout);
}
else if (parser.getName().equals("mechName")) {
defaultMechs.add(parser.nextText());

View file

@ -367,7 +367,7 @@ public class XMPPConnection extends Connection {
if (!roster.rosterInitialized) {
try {
synchronized (roster) {
long waitTime = SmackConfiguration.getPacketReplyTimeout();
long waitTime = SmackConfiguration.getDefaultPacketReplyTimeout();
long start = System.currentTimeMillis();
while (!roster.rosterInitialized) {
if (waitTime <= 0) {
@ -930,7 +930,7 @@ public class XMPPConnection extends Connection {
// Wait until compression is being used or a timeout happened
synchronized (this) {
try {
this.wait(SmackConfiguration.getPacketReplyTimeout() * 5);
this.wait(SmackConfiguration.getDefaultPacketReplyTimeout() * 5);
}
catch (InterruptedException e) {
// Ignore.

View file

@ -1,67 +0,0 @@
/**
*
* Copyright the original author or authors
*
* 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.util;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.SmackError;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.packet.Packet;
/**
* Utility class for doing synchronous calls to the server. Provides several
* methods for sending a packet to the server and waiting for the reply.
*
* @author Robin Collier
*/
final public class SyncPacketSend
{
private SyncPacketSend()
{ }
static public Packet getReply(Connection connection, Packet packet, long timeout)
throws XMPPException
{
PacketFilter responseFilter = new PacketIDFilter(packet.getPacketID());
PacketCollector response = connection.createPacketCollector(responseFilter);
connection.sendPacket(packet);
// Wait up to a certain number of seconds for a reply.
Packet result = response.nextResult(timeout);
// Stop queuing results
response.cancel();
if (result == null) {
throw new XMPPException(SmackError.NO_RESPONSE_FROM_SERVER);
}
else if (result.getError() != null) {
throw new XMPPException(result.getError());
}
return result;
}
static public Packet getReply(Connection connection, Packet packet)
throws XMPPException
{
return getReply(connection, packet, SmackConfiguration.getPacketReplyTimeout());
}
}

View file

@ -2,8 +2,8 @@
<!-- Smack configuration file. -->
<smack>
<!-- Packet reply timeout in milliseconds -->
<packetReplyTimeout>5000</packetReplyTimeout>
<!-- Default Packet reply timeout in milliseconds -->
<defaultPacketReplyTimeout>5000</defaultPacketReplyTimeout>
<!-- Enable/Disable local Socks5 proxy -->
<localSocks5ProxyEnabled>true</localSocks5ProxyEnabled>

View file

@ -38,10 +38,10 @@ public class PacketCollectorTest
}
// Assert that '0' has rolled off
assertEquals("1", collector.nextResult().getPacketID());
assertEquals("2", collector.nextResult().getPacketID());
assertEquals("3", collector.nextResult().getPacketID());
assertEquals("4", collector.nextResult().getPacketID());
assertEquals("1", collector.nextResultBlockForever().getPacketID());
assertEquals("2", collector.nextResultBlockForever().getPacketID());
assertEquals("3", collector.nextResultBlockForever().getPacketID());
assertEquals("4", collector.nextResultBlockForever().getPacketID());
assertEquals("5", collector.pollResult().getPacketID());
assertNull(collector.pollResult());
@ -51,10 +51,10 @@ public class PacketCollectorTest
collector.processPacket(testPacket);
}
assertEquals("10", collector.nextResult().getPacketID());
assertEquals("11", collector.nextResult().getPacketID());
assertEquals("12", collector.nextResult().getPacketID());
assertEquals("13", collector.nextResult().getPacketID());
assertEquals("10", collector.nextResultBlockForever().getPacketID());
assertEquals("11", collector.nextResultBlockForever().getPacketID());
assertEquals("12", collector.nextResultBlockForever().getPacketID());
assertEquals("13", collector.nextResultBlockForever().getPacketID());
assertEquals("14", collector.pollResult().getPacketID());
assertNull(collector.pollResult());
@ -87,7 +87,8 @@ public class PacketCollectorTest
catch (InterruptedException e)
{
}
Packet packet = collector.nextResult();
@SuppressWarnings("unused")
Packet packet = collector.nextResultBlockForever();
// System.out.println(Thread.currentThread().getName() + " packet: " + packet);
}
}

View file

@ -25,7 +25,7 @@ public class SmackConfigurationTest {
@Test
public void testSmackConfiguration() {
try {
SmackConfiguration.getPacketReplyTimeout();
SmackConfiguration.getDefaultPacketReplyTimeout();
} catch (Throwable t) {
fail("SmackConfiguration threw Throwable");
}