mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-10 18:15:58 +01:00
Add BundleAndDeferCallback to smack-tcp
This commit is contained in:
parent
aa8daba1cf
commit
d415661e35
3 changed files with 144 additions and 0 deletions
|
@ -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.tcp;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
||||
public class BundleAndDefer {
|
||||
|
||||
private final AtomicBoolean isStopped;
|
||||
|
||||
BundleAndDefer(AtomicBoolean isStopped) {
|
||||
this.isStopped = isStopped;
|
||||
}
|
||||
|
||||
public void stopCurrentBundleAndDefer() {
|
||||
synchronized (isStopped) {
|
||||
if (isStopped.get()) {
|
||||
return;
|
||||
}
|
||||
isStopped.set(true);
|
||||
isStopped.notify();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
*
|
||||
* 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.tcp;
|
||||
|
||||
/**
|
||||
* This callback is used to get the current value of the period in which Smack does bundle and defer
|
||||
* outgoing stanzas.
|
||||
* <p>
|
||||
* Smack will bundle and defer stanzas if the connection is authenticated, the send queue is empty
|
||||
* and if a bundle and defer callback is set, either via
|
||||
* {@link XMPPTCPConnection#setDefaultBundleAndDeferCallback(BundleAndDeferCallback)} or
|
||||
* {@link XMPPTCPConnection#setBundleandDeferCallback(BundleAndDeferCallback)}, and
|
||||
* {@link #getBundleAndDeferMillis(BundleAndDefer)} returns a positive value. In a mobile environment, bundling
|
||||
* and deferring outgoing stanzas may reduce battery consumption. It heavily depends on the
|
||||
* environment, but recommend values for the bundle and defer period range from 20-60 seconds. But
|
||||
* keep in mind that longer periods decrease the realtime aspect of Smack.
|
||||
* </p>
|
||||
* <p>
|
||||
* Smack will invoke the callback when it needs to know the length of the bundle and defer period.
|
||||
* If {@link #getBundleAndDeferMillis(BundleAndDefer)} returns 0 or a negative value, then the
|
||||
* stanzas will send immediately. You can also prematurely abort the bundling of stanzas by calling
|
||||
* {@link BundleAndDefer#stopCurrentBundleAndDefer()}.
|
||||
* </p>
|
||||
*/
|
||||
public interface BundleAndDeferCallback {
|
||||
|
||||
/**
|
||||
* Return the bundle and defer period used by Smack in milliseconds.
|
||||
*
|
||||
* @param bundleAndDefer used to premature abort bundle and defer.
|
||||
* @return the bundle and defer period in milliseconds.
|
||||
*/
|
||||
public int getBundleAndDeferMillis(BundleAndDefer bundleAndDefer);
|
||||
|
||||
}
|
|
@ -125,6 +125,7 @@ import java.util.concurrent.BlockingQueue;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -184,6 +185,10 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
|||
private final SynchronizationPoint<XMPPException> compressSyncPoint = new SynchronizationPoint<XMPPException>(
|
||||
this);
|
||||
|
||||
private static BundleAndDeferCallback defaultBundleAndDeferCallback;
|
||||
|
||||
private BundleAndDeferCallback bundleAndDeferCallback = defaultBundleAndDeferCallback;
|
||||
|
||||
private static boolean useSmDefault = false;
|
||||
|
||||
private static boolean useSmResumptionDefault = true;
|
||||
|
@ -1269,6 +1274,30 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
|||
if (element == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get a local version of the bundle and defer callback, in case it's unset
|
||||
// between the null check and the method invocation
|
||||
final BundleAndDeferCallback localBundleAndDeferCallback = bundleAndDeferCallback;
|
||||
// If the preconditions are given (e.g. bundleAndDefer callback is set, queue is
|
||||
// empty), then we could wait a bit for further stanzas attempting to decrease
|
||||
// our energy consumption
|
||||
if (localBundleAndDeferCallback != null && isAuthenticated() && queue.isEmpty()) {
|
||||
final AtomicBoolean bundlingAndDeferringStopped = new AtomicBoolean();
|
||||
final int bundleAndDeferMillis = localBundleAndDeferCallback.getBundleAndDeferMillis(new BundleAndDefer(
|
||||
bundlingAndDeferringStopped));
|
||||
if (bundleAndDeferMillis > 0) {
|
||||
long remainingWait = bundleAndDeferMillis;
|
||||
final long waitStart = System.currentTimeMillis();
|
||||
synchronized (bundlingAndDeferringStopped) {
|
||||
while (!bundlingAndDeferringStopped.get() && remainingWait > 0) {
|
||||
bundlingAndDeferringStopped.wait(remainingWait);
|
||||
remainingWait = bundleAndDeferMillis
|
||||
- (System.currentTimeMillis() - waitStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Stanza packet = null;
|
||||
if (element instanceof Stanza) {
|
||||
packet = (Stanza) element;
|
||||
|
@ -1709,4 +1738,31 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
|||
|
||||
serverHandledStanzasCount = handledCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default bundle and defer callback used for new connections.
|
||||
*
|
||||
* @param defaultBundleAndDeferCallback
|
||||
* @see BundleAndDeferCallback
|
||||
* @since 4.1
|
||||
*/
|
||||
public static void setDefaultBundleAndDeferCallback(BundleAndDeferCallback defaultBundleAndDeferCallback) {
|
||||
XMPPTCPConnection.defaultBundleAndDeferCallback = defaultBundleAndDeferCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bundle and defer callback used for this connection.
|
||||
* <p>
|
||||
* You can use <code>null</code> as argument to reset the callback. Outgoing stanzas will then
|
||||
* no longer get deferred.
|
||||
* </p>
|
||||
*
|
||||
* @param bundleAndDeferCallback the callback or <code>null</code>.
|
||||
* @see BundleAndDeferCallback
|
||||
* @since 4.1
|
||||
*/
|
||||
public void setBundleandDeferCallback(BundleAndDeferCallback bundleAndDeferCallback) {
|
||||
this.bundleAndDeferCallback = bundleAndDeferCallback;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue