mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-25 21:42:07 +01:00
Merge branch '4.1'
Conflicts: version.gradle
This commit is contained in:
commit
4a16ab9329
4 changed files with 94 additions and 13 deletions
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright © 2014 Florian Schmaus
|
* Copyright © 2014-2015 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.
|
||||||
|
@ -41,6 +41,11 @@ public class SynchronizationPoint<E extends Exception> {
|
||||||
private State state;
|
private State state;
|
||||||
private E failureException;
|
private E failureException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new synchronization point for the given connection.
|
||||||
|
*
|
||||||
|
* @param connection the connection of this synchronization point.
|
||||||
|
*/
|
||||||
public SynchronizationPoint(AbstractXMPPConnection connection) {
|
public SynchronizationPoint(AbstractXMPPConnection connection) {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.connectionLock = connection.getConnectionLock();
|
this.connectionLock = connection.getConnectionLock();
|
||||||
|
@ -48,6 +53,9 @@ public class SynchronizationPoint<E extends Exception> {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize (or reset) this synchronization point.
|
||||||
|
*/
|
||||||
public void init() {
|
public void init() {
|
||||||
connectionLock.lock();
|
connectionLock.lock();
|
||||||
state = State.Initial;
|
state = State.Initial;
|
||||||
|
@ -55,6 +63,13 @@ public class SynchronizationPoint<E extends Exception> {
|
||||||
connectionLock.unlock();
|
connectionLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the given top level stream element and wait for a response.
|
||||||
|
*
|
||||||
|
* @param request the plain stream element to send.
|
||||||
|
* @throws NoResponseException if no response was received.
|
||||||
|
* @throws NotConnectedException if the connection is not connected.
|
||||||
|
*/
|
||||||
public void sendAndWaitForResponse(TopLevelStreamElement request) throws NoResponseException,
|
public void sendAndWaitForResponse(TopLevelStreamElement request) throws NoResponseException,
|
||||||
NotConnectedException, InterruptedException {
|
NotConnectedException, InterruptedException {
|
||||||
assert (state == State.Initial);
|
assert (state == State.Initial);
|
||||||
|
@ -79,6 +94,14 @@ public class SynchronizationPoint<E extends Exception> {
|
||||||
checkForResponse();
|
checkForResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the given plain stream element and wait for a response.
|
||||||
|
*
|
||||||
|
* @param request the plain stream element to send.
|
||||||
|
* @throws E if an failure was reported.
|
||||||
|
* @throws NoResponseException if no response was received.
|
||||||
|
* @throws NotConnectedException if the connection is not connected.
|
||||||
|
*/
|
||||||
public void sendAndWaitForResponseOrThrow(PlainStreamElement request) throws E, NoResponseException,
|
public void sendAndWaitForResponseOrThrow(PlainStreamElement request) throws E, NoResponseException,
|
||||||
NotConnectedException, InterruptedException {
|
NotConnectedException, InterruptedException {
|
||||||
sendAndWaitForResponse(request);
|
sendAndWaitForResponse(request);
|
||||||
|
@ -93,6 +116,11 @@ public class SynchronizationPoint<E extends Exception> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this synchronization point is successful or wait the connections reply timeout.
|
||||||
|
* @throws NoResponseException if there was no response marking the synchronization point as success or failed.
|
||||||
|
* @throws E if there was a failure
|
||||||
|
*/
|
||||||
public void checkIfSuccessOrWaitOrThrow() throws NoResponseException, E {
|
public void checkIfSuccessOrWaitOrThrow() throws NoResponseException, E {
|
||||||
checkIfSuccessOrWait();
|
checkIfSuccessOrWait();
|
||||||
if (state == State.Failure) {
|
if (state == State.Failure) {
|
||||||
|
@ -100,6 +128,10 @@ public class SynchronizationPoint<E extends Exception> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this synchronization point is successful or wait the connections reply timeout.
|
||||||
|
* @throws NoResponseException if there was no response marking the synchronization point as success or failed.
|
||||||
|
*/
|
||||||
public void checkIfSuccessOrWait() throws NoResponseException {
|
public void checkIfSuccessOrWait() throws NoResponseException {
|
||||||
connectionLock.lock();
|
connectionLock.lock();
|
||||||
try {
|
try {
|
||||||
|
@ -114,33 +146,52 @@ public class SynchronizationPoint<E extends Exception> {
|
||||||
checkForResponse();
|
checkForResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report this synchronization point as successful.
|
||||||
|
*/
|
||||||
public void reportSuccess() {
|
public void reportSuccess() {
|
||||||
connectionLock.lock();
|
connectionLock.lock();
|
||||||
try {
|
try {
|
||||||
state = State.Success;
|
state = State.Success;
|
||||||
condition.signal();
|
condition.signalAll();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
connectionLock.unlock();
|
connectionLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated.
|
||||||
|
* @deprecated use {@link #reportFailure(Exception)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public void reportFailure() {
|
public void reportFailure() {
|
||||||
reportFailure(null);
|
reportFailure(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report this synchronization point as failed because of the given exception. The {@code failureException} must be set.
|
||||||
|
*
|
||||||
|
* @param failureException the exception causing this synchronization point to fail.
|
||||||
|
*/
|
||||||
public void reportFailure(E failureException) {
|
public void reportFailure(E failureException) {
|
||||||
|
assert failureException != null;
|
||||||
connectionLock.lock();
|
connectionLock.lock();
|
||||||
try {
|
try {
|
||||||
state = State.Failure;
|
state = State.Failure;
|
||||||
this.failureException = failureException;
|
this.failureException = failureException;
|
||||||
condition.signal();
|
condition.signalAll();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
connectionLock.unlock();
|
connectionLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this synchronization point was successful.
|
||||||
|
*
|
||||||
|
* @return true if the synchronization point was successful, false otherwise.
|
||||||
|
*/
|
||||||
public boolean wasSuccessful() {
|
public boolean wasSuccessful() {
|
||||||
connectionLock.lock();
|
connectionLock.lock();
|
||||||
try {
|
try {
|
||||||
|
@ -151,6 +202,11 @@ public class SynchronizationPoint<E extends Exception> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this synchronization point has its request already sent.
|
||||||
|
*
|
||||||
|
* @return true if the request was already sent, false otherwise.
|
||||||
|
*/
|
||||||
public boolean requestSent() {
|
public boolean requestSent() {
|
||||||
connectionLock.lock();
|
connectionLock.lock();
|
||||||
try {
|
try {
|
||||||
|
@ -161,16 +217,21 @@ public class SynchronizationPoint<E extends Exception> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for the condition to become something else as {@link State#RequestSent} or {@link State#Initial}.
|
||||||
|
* {@link #reportSuccess()}, {@link #reportFailure()} and {@link #reportFailure(Exception)} will either set this
|
||||||
|
* synchronization point to {@link State#Success} or {@link State#Failure}. If none of them is set after the
|
||||||
|
* connections reply timeout, this method will set the state of {@link State#NoResponse}.
|
||||||
|
*/
|
||||||
private void waitForConditionOrTimeout() {
|
private void waitForConditionOrTimeout() {
|
||||||
long remainingWait = TimeUnit.MILLISECONDS.toNanos(connection.getPacketReplyTimeout());
|
long remainingWait = TimeUnit.MILLISECONDS.toNanos(connection.getPacketReplyTimeout());
|
||||||
while (state == State.RequestSent || state == State.Initial) {
|
while (state == State.RequestSent || state == State.Initial) {
|
||||||
try {
|
try {
|
||||||
remainingWait = condition.awaitNanos(
|
|
||||||
remainingWait);
|
|
||||||
if (remainingWait <= 0) {
|
if (remainingWait <= 0) {
|
||||||
state = State.NoResponse;
|
state = State.NoResponse;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
remainingWait = condition.awaitNanos(remainingWait);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// This InterruptedException could be "spurious wakeups", see javadoc of awaitNanos()
|
// This InterruptedException could be "spurious wakeups", see javadoc of awaitNanos()
|
||||||
LOGGER.log(Level.WARNING, "Thread interrupt while waiting for condition or timeout ignored", e);
|
LOGGER.log(Level.WARNING, "Thread interrupt while waiting for condition or timeout ignored", e);
|
||||||
|
|
|
@ -24,21 +24,27 @@ import org.jivesoftware.smackx.pubsub.provider.ItemProvider;
|
||||||
* pubsub node. An <tt>Item</tt> has several properties that are dependent
|
* pubsub node. An <tt>Item</tt> has several properties that are dependent
|
||||||
* on the configuration of the node to which it has been or will be published.
|
* on the configuration of the node to which it has been or will be published.
|
||||||
*
|
*
|
||||||
* <h1>An Item received from a node (via {@link LeafNode#getItems()} or {@link LeafNode#addItemEventListener(org.jivesoftware.smackx.pubsub.listener.ItemEventListener)}</b>
|
* <h3>An Item received from a node (via {@link LeafNode#getItems()} or {@link LeafNode#addItemEventListener(org.jivesoftware.smackx.pubsub.listener.ItemEventListener)}</h3>
|
||||||
|
* <ul>
|
||||||
* <li>Will always have an id (either user or server generated) unless node configuration has both
|
* <li>Will always have an id (either user or server generated) unless node configuration has both
|
||||||
* {@link ConfigureForm#isPersistItems()} and {@link ConfigureForm#isDeliverPayloads()}set to false.
|
* {@link ConfigureForm#isPersistItems()} and {@link ConfigureForm#isDeliverPayloads()}set to false.
|
||||||
* <li>Will have a payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set
|
* <li>Will have a payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set
|
||||||
* to true, otherwise it will be null.
|
* to true, otherwise it will be null.
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* <h1>An Item created to send to a node (via {@link LeafNode#send()} or {@link LeafNode#publish()}</b>
|
* <h3>An Item created to send to a node (via {@link LeafNode#send()} or {@link LeafNode#publish()}</h3>
|
||||||
|
* <ul>
|
||||||
* <li>The id is optional, since the server will generate one if necessary, but should be used if it is
|
* <li>The id is optional, since the server will generate one if necessary, but should be used if it is
|
||||||
* meaningful in the context of the node. This value must be unique within the node that it is sent to, since
|
* meaningful in the context of the node. This value must be unique within the node that it is sent to, since
|
||||||
* resending an item with the same id will overwrite the one that already exists if the items are persisted.
|
* resending an item with the same id will overwrite the one that already exists if the items are persisted.
|
||||||
* <li>Will require payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set
|
* <li>Will require payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set
|
||||||
* to true.
|
* to true.
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* <p>To customise the payload object being returned from the {@link PayloadItem#getPayload()} method, you can
|
* <p>
|
||||||
|
* To customise the payload object being returned from the {@link PayloadItem#getPayload()} method, you can
|
||||||
* add a custom parser as explained in {@link ItemProvider}.
|
* add a custom parser as explained in {@link ItemProvider}.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @author Robin Collier
|
* @author Robin Collier
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -104,6 +104,13 @@ public class SASLDigestMD5Mechanism extends SASLMechanism {
|
||||||
String[] keyValue = part.split("=");
|
String[] keyValue = part.split("=");
|
||||||
assert (keyValue.length == 2);
|
assert (keyValue.length == 2);
|
||||||
String key = keyValue[0];
|
String key = keyValue[0];
|
||||||
|
// RFC 2831 § 7.1 about the formating of the digest-challenge:
|
||||||
|
// "The full form is "<n>#<m>element" indicating at least <n> and
|
||||||
|
// at most <m> elements, each separated by one or more commas
|
||||||
|
// (",") and OPTIONAL linear white space (LWS)."
|
||||||
|
// Which means the key value may be preceded by whitespace,
|
||||||
|
// which is what we remove: *Only the preceding whitespace*.
|
||||||
|
key = key.replaceFirst("^\\s+", "");
|
||||||
String value = keyValue[1];
|
String value = keyValue[1];
|
||||||
if ("nonce".equals(key)) {
|
if ("nonce".equals(key)) {
|
||||||
if (nonce != null) {
|
if (nonce != null) {
|
||||||
|
|
|
@ -1597,7 +1597,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
||||||
throw new StreamManagementException.StreamManagementNotEnabledException();
|
throw new StreamManagementException.StreamManagementNotEnabledException();
|
||||||
}
|
}
|
||||||
// Remove the listener after max. 12 hours
|
// Remove the listener after max. 12 hours
|
||||||
final int removeAfterSeconds = Math.min(getMaxSmResumptionTime() + 60, 12 * 60 * 60);
|
final int removeAfterSeconds = Math.min(getMaxSmResumptionTime(), 12 * 60 * 60);
|
||||||
schedule(new Runnable() {
|
schedule(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -1678,8 +1678,10 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
||||||
|
|
||||||
// See if resumption time is over
|
// See if resumption time is over
|
||||||
long current = System.currentTimeMillis();
|
long current = System.currentTimeMillis();
|
||||||
long maxResumptionMillies = getMaxSmResumptionTime() * 1000;
|
long maxResumptionMillies = ((long) getMaxSmResumptionTime()) * 1000;
|
||||||
if (shutdownTimestamp + maxResumptionMillies > current) {
|
if (current > shutdownTimestamp + maxResumptionMillies) {
|
||||||
|
// Stream resumption is *not* possible if the current timestamp is greater then the greatest timestamp where
|
||||||
|
// resumption is possible
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1688,8 +1690,13 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the maximum resumption time in seconds after which a managed stream can be resumed.
|
* Get the maximum resumption time in seconds after which a managed stream can be resumed.
|
||||||
|
* <p>
|
||||||
|
* This method will return {@link Integer#MAX_VALUE} if neither the client nor the server specify a maximum
|
||||||
|
* resumption time. Be aware of integer overflows when using this value, e.g. do not add arbitrary values to it
|
||||||
|
* without checking for overflows before.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @return the maximum resumption time in seconds.
|
* @return the maximum resumption time in seconds or {@link Integer#MAX_VALUE} if none set.
|
||||||
*/
|
*/
|
||||||
public int getMaxSmResumptionTime() {
|
public int getMaxSmResumptionTime() {
|
||||||
int clientResumptionTime = smClientMaxResumptionTime > 0 ? smClientMaxResumptionTime : Integer.MAX_VALUE;
|
int clientResumptionTime = smClientMaxResumptionTime > 0 ? smClientMaxResumptionTime : Integer.MAX_VALUE;
|
||||||
|
|
Loading…
Reference in a new issue