mirror of
https://github.com/vanitasvitae/Smack.git
synced 2025-09-10 01:29:38 +02:00
Introduce XMPPConnection.add(Message|Presence)Interceptor
add deprecate addStanzaInterceptor().
This commit is contained in:
parent
5db6191110
commit
e2d206e741
24 changed files with 419 additions and 102 deletions
|
@ -100,8 +100,12 @@ import org.jivesoftware.smack.packet.FullyQualifiedElement;
|
|||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.Mechanisms;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.packet.MessageBuilder;
|
||||
import org.jivesoftware.smack.packet.MessageOrPresence;
|
||||
import org.jivesoftware.smack.packet.MessageOrPresenceBuilder;
|
||||
import org.jivesoftware.smack.packet.Nonza;
|
||||
import org.jivesoftware.smack.packet.Presence;
|
||||
import org.jivesoftware.smack.packet.PresenceBuilder;
|
||||
import org.jivesoftware.smack.packet.Session;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smack.packet.StanzaError;
|
||||
|
@ -123,11 +127,13 @@ import org.jivesoftware.smack.sasl.core.SASLAnonymous;
|
|||
import org.jivesoftware.smack.sasl.packet.SaslNonza;
|
||||
import org.jivesoftware.smack.util.Async;
|
||||
import org.jivesoftware.smack.util.CollectionUtil;
|
||||
import org.jivesoftware.smack.util.Consumer;
|
||||
import org.jivesoftware.smack.util.DNSUtil;
|
||||
import org.jivesoftware.smack.util.MultiMap;
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||
import org.jivesoftware.smack.util.ParserUtils;
|
||||
import org.jivesoftware.smack.util.Predicate;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smack.util.dns.HostAddress;
|
||||
import org.jivesoftware.smack.util.dns.SmackDaneProvider;
|
||||
|
@ -243,6 +249,10 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
private final Map<StanzaListener, InterceptorWrapper> interceptors =
|
||||
new HashMap<>();
|
||||
|
||||
private final Map<Consumer<MessageBuilder>, GenericInterceptorWrapper<MessageBuilder, Message>> messageInterceptors = new HashMap<>();
|
||||
|
||||
private final Map<Consumer<PresenceBuilder>, GenericInterceptorWrapper<PresenceBuilder, Presence>> presenceInterceptors = new HashMap<>();
|
||||
|
||||
private XmlEnvironment incomingStreamXmlEnvironment;
|
||||
|
||||
protected XmlEnvironment outgoingStreamXmlEnvironment;
|
||||
|
@ -849,8 +859,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
}
|
||||
// Invoke interceptors for the new stanza that is about to be sent. Interceptors may modify
|
||||
// the content of the stanza.
|
||||
firePacketInterceptors(stanza);
|
||||
sendStanzaInternal(stanza);
|
||||
Stanza stanzaAfterInterceptors = firePacketInterceptors(stanza);
|
||||
sendStanzaInternal(stanzaAfterInterceptors);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1204,6 +1214,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
});
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void addStanzaInterceptor(StanzaListener packetInterceptor,
|
||||
StanzaFilter packetFilter) {
|
||||
|
@ -1216,6 +1227,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void removeStanzaInterceptor(StanzaListener packetInterceptor) {
|
||||
synchronized (interceptors) {
|
||||
|
@ -1223,15 +1235,83 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
}
|
||||
}
|
||||
|
||||
private static <MPB extends MessageOrPresenceBuilder<MP, MPB>, MP extends MessageOrPresence<MPB>> void addInterceptor(
|
||||
Map<Consumer<MPB>, GenericInterceptorWrapper<MPB, MP>> interceptors, Consumer<MPB> interceptor,
|
||||
Predicate<MP> filter) {
|
||||
Objects.requireNonNull(interceptor, "Interceptor must not be null");
|
||||
|
||||
GenericInterceptorWrapper<MPB, MP> interceptorWrapper = new GenericInterceptorWrapper<>(interceptor, filter);
|
||||
|
||||
synchronized (interceptors) {
|
||||
interceptors.put(interceptor, interceptorWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
private static <MPB extends MessageOrPresenceBuilder<MP, MPB>, MP extends MessageOrPresence<MPB>> void removeInterceptor(
|
||||
Map<Consumer<MPB>, GenericInterceptorWrapper<MPB, MP>> interceptors, Consumer<MPB> interceptor) {
|
||||
synchronized (interceptors) {
|
||||
interceptors.remove(interceptor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMessageInterceptor(Consumer<MessageBuilder> messageInterceptor, Predicate<Message> messageFilter) {
|
||||
addInterceptor(messageInterceptors, messageInterceptor, messageFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMessageInterceptor(Consumer<MessageBuilder> messageInterceptor) {
|
||||
removeInterceptor(messageInterceptors, messageInterceptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPresenceInterceptor(Consumer<PresenceBuilder> presenceInterceptor,
|
||||
Predicate<Presence> presenceFilter) {
|
||||
addInterceptor(presenceInterceptors, presenceInterceptor, presenceFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePresenceInterceptor(Consumer<PresenceBuilder> presenceInterceptor) {
|
||||
removeInterceptor(presenceInterceptors, presenceInterceptor);
|
||||
}
|
||||
|
||||
private static <MPB extends MessageOrPresenceBuilder<MP, MPB>, MP extends MessageOrPresence<MPB>> MP fireMessageOrPresenceInterceptors(
|
||||
MP messageOrPresence, Map<Consumer<MPB>, GenericInterceptorWrapper<MPB, MP>> interceptors) {
|
||||
List<Consumer<MPB>> interceptorsToInvoke = new LinkedList<>();
|
||||
synchronized (interceptors) {
|
||||
for (GenericInterceptorWrapper<MPB, MP> interceptorWrapper : interceptors.values()) {
|
||||
if (interceptorWrapper.filterMatches(messageOrPresence)) {
|
||||
Consumer<MPB> interceptor = interceptorWrapper.getInterceptor();
|
||||
interceptorsToInvoke.add(interceptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid transforming the stanza to a builder if there is no interceptor.
|
||||
if (interceptorsToInvoke.isEmpty()) {
|
||||
return messageOrPresence;
|
||||
}
|
||||
|
||||
MPB builder = messageOrPresence.asBuilder();
|
||||
for (Consumer<MPB> interceptor : interceptorsToInvoke) {
|
||||
interceptor.accept(builder);
|
||||
}
|
||||
|
||||
// Now that the interceptors have (probably) modified the stanza in its builder form, we need to re-assemble it.
|
||||
messageOrPresence = builder.build();
|
||||
return messageOrPresence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process interceptors. Interceptors may modify the stanza that is about to be sent.
|
||||
* Since the thread that requested to send the stanza will invoke all interceptors, it
|
||||
* is important that interceptors perform their work as soon as possible so that the
|
||||
* thread does not remain blocked for a long period.
|
||||
*
|
||||
* @param packet the stanza that is going to be sent to the server
|
||||
* @param packet the stanza that is going to be sent to the server.
|
||||
* @return the, potentially modified stanza, after the interceptors are run.
|
||||
*/
|
||||
private void firePacketInterceptors(Stanza packet) {
|
||||
private Stanza firePacketInterceptors(Stanza packet) {
|
||||
List<StanzaListener> interceptorsToInvoke = new LinkedList<>();
|
||||
synchronized (interceptors) {
|
||||
for (InterceptorWrapper interceptorWrapper : interceptors.values()) {
|
||||
|
@ -1247,6 +1327,22 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
LOGGER.log(Level.SEVERE, "Packet interceptor threw exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
final Stanza stanzaAfterInterceptors;
|
||||
if (packet instanceof Message) {
|
||||
Message message = (Message) packet;
|
||||
stanzaAfterInterceptors = fireMessageOrPresenceInterceptors(message, messageInterceptors);
|
||||
}
|
||||
else if (packet instanceof Presence) {
|
||||
Presence presence = (Presence) packet;
|
||||
stanzaAfterInterceptors = fireMessageOrPresenceInterceptors(presence, presenceInterceptors);
|
||||
} else {
|
||||
// We do not (yet) support interceptors for IQ stanzas.
|
||||
assert packet instanceof IQ;
|
||||
stanzaAfterInterceptors = packet;
|
||||
}
|
||||
|
||||
return stanzaAfterInterceptors;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1674,6 +1770,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
/**
|
||||
* A wrapper class to associate a stanza filter with an interceptor.
|
||||
*/
|
||||
@Deprecated
|
||||
// TODO: Remove once addStanzaInterceptor is gone.
|
||||
protected static class InterceptorWrapper {
|
||||
|
||||
private final StanzaListener packetInterceptor;
|
||||
|
@ -1699,6 +1797,24 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
}
|
||||
}
|
||||
|
||||
private static final class GenericInterceptorWrapper<MPB extends MessageOrPresenceBuilder<MP, MPB>, MP extends MessageOrPresence<MPB>> {
|
||||
private final Consumer<MPB> stanzaInterceptor;
|
||||
private final Predicate<MP> stanzaFilter;
|
||||
|
||||
private GenericInterceptorWrapper(Consumer<MPB> stanzaInterceptor, Predicate<MP> stanzaFilter) {
|
||||
this.stanzaInterceptor = stanzaInterceptor;
|
||||
this.stanzaFilter = stanzaFilter;
|
||||
}
|
||||
|
||||
private boolean filterMatches(MP stanza) {
|
||||
return stanzaFilter == null || stanzaFilter.test(stanza);
|
||||
}
|
||||
|
||||
public Consumer<MPB> getInterceptor() {
|
||||
return stanzaInterceptor;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getConnectionCounter() {
|
||||
return connectionCounterValue;
|
||||
|
|
|
@ -27,9 +27,15 @@ import org.jivesoftware.smack.iqrequest.IQRequestHandler;
|
|||
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||
import org.jivesoftware.smack.packet.FullyQualifiedElement;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.packet.MessageBuilder;
|
||||
import org.jivesoftware.smack.packet.Nonza;
|
||||
import org.jivesoftware.smack.packet.Presence;
|
||||
import org.jivesoftware.smack.packet.PresenceBuilder;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smack.packet.StanzaFactory;
|
||||
import org.jivesoftware.smack.util.Consumer;
|
||||
import org.jivesoftware.smack.util.Predicate;
|
||||
|
||||
import org.jxmpp.jid.DomainBareJid;
|
||||
import org.jxmpp.jid.EntityFullJid;
|
||||
|
@ -361,7 +367,7 @@ public interface XMPPConnection {
|
|||
boolean removeStanzaListener(StanzaListener stanzaListener);
|
||||
|
||||
/**
|
||||
* Registers a <b>synchronous</b> stanza listener with this connection. A stanza listener will be invoked only when
|
||||
* Registers a <b>synchronous</b> stanza listener with this connection. A stanza listener will be invoked only when
|
||||
* an incoming stanza is received. A stanza filter determines which stanzas will be delivered to the listener. If
|
||||
* the same stanza listener is added again with a different filter, only the new filter will be used.
|
||||
* <p>
|
||||
|
@ -446,16 +452,65 @@ public interface XMPPConnection {
|
|||
*
|
||||
* @param stanzaInterceptor the stanza interceptor to notify of stanzas about to be sent.
|
||||
* @param stanzaFilter the stanza filter to use.
|
||||
* @deprecated use {@link #addMessageInterceptor(Consumer, Predicate)} or {@link #addPresenceInterceptor(Consumer, Predicate)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
// TODO: Remove in Smack 4.5.
|
||||
void addStanzaInterceptor(StanzaListener stanzaInterceptor, StanzaFilter stanzaFilter);
|
||||
|
||||
/**
|
||||
* Removes a stanza interceptor.
|
||||
*
|
||||
* @param stanzaInterceptor the stanza interceptor to remove.
|
||||
* @deprecated use {@link #removeMessageInterceptor(Consumer)} or {@link #removePresenceInterceptor(Consumer)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
// TODO: Remove in Smack 4.5.
|
||||
void removeStanzaInterceptor(StanzaListener stanzaInterceptor);
|
||||
|
||||
/**
|
||||
* Registers a stanza interceptor with this connection. The interceptor will be
|
||||
* invoked every time a stanza is about to be sent by this connection. Interceptors
|
||||
* may modify the stanza to be sent. A stanza filter determines which stanzas
|
||||
* will be delivered to the interceptor.
|
||||
*
|
||||
* <p>
|
||||
* NOTE: For a similar functionality on incoming stanzas, see {@link #addAsyncStanzaListener(StanzaListener, StanzaFilter)}.
|
||||
* </p>
|
||||
*
|
||||
* @param messageInterceptor the stanza interceptor to notify of stanzas about to be sent.
|
||||
* @param messageFilter the stanza filter to use.
|
||||
*/
|
||||
void addMessageInterceptor(Consumer<MessageBuilder> messageInterceptor, Predicate<Message> messageFilter);
|
||||
|
||||
/**
|
||||
* Removes a message interceptor.
|
||||
*
|
||||
* @param messageInterceptor the message interceptor to remove.
|
||||
*/
|
||||
void removeMessageInterceptor(Consumer<MessageBuilder> messageInterceptor);
|
||||
|
||||
/**
|
||||
* Registers a stanza interceptor with this connection. The interceptor will be
|
||||
* invoked every time a stanza is about to be sent by this connection. Interceptors
|
||||
* may modify the stanza to be sent. A stanza filter determines which stanzas
|
||||
* will be delivered to the interceptor.
|
||||
*
|
||||
* <p>
|
||||
* NOTE: For a similar functionality on incoming stanzas, see {@link #addAsyncStanzaListener(StanzaListener, StanzaFilter)}.
|
||||
* </p>
|
||||
*
|
||||
* @param presenceInterceptor the stanza interceptor to notify of stanzas about to be sent.
|
||||
* @param presenceFilter the stanza filter to use.
|
||||
*/
|
||||
void addPresenceInterceptor(Consumer<PresenceBuilder> presenceInterceptor, Predicate<Presence> presenceFilter);
|
||||
|
||||
/**
|
||||
* Removes a presence interceptor.
|
||||
*
|
||||
* @param presenceInterceptor the stanza interceptor to remove.
|
||||
*/
|
||||
void removePresenceInterceptor(Consumer<PresenceBuilder> presenceInterceptor);
|
||||
/**
|
||||
* Returns the current value of the reply timeout in milliseconds for request for this
|
||||
* XMPPConnection instance.
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.jivesoftware.smack.filter;
|
||||
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smack.util.Predicate;
|
||||
|
||||
/**
|
||||
* Defines a way to filter stanzas for particular attributes. Stanza filters are used when
|
||||
|
@ -51,7 +52,7 @@ import org.jivesoftware.smack.packet.Stanza;
|
|||
* @see org.jivesoftware.smack.StanzaListener
|
||||
* @author Matt Tucker
|
||||
*/
|
||||
public interface StanzaFilter {
|
||||
public interface StanzaFilter extends Predicate<Stanza> {
|
||||
|
||||
/**
|
||||
* Tests whether or not the specified stanza should pass the filter.
|
||||
|
@ -60,4 +61,9 @@ public interface StanzaFilter {
|
|||
* @return true if and only if <code>stanza</code> passes the filter.
|
||||
*/
|
||||
boolean accept(Stanza stanza);
|
||||
|
||||
@Override
|
||||
default boolean test(Stanza stanza) {
|
||||
return accept(stanza);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,8 @@ import org.jxmpp.stringprep.XmppStringprepException;
|
|||
*
|
||||
* @author Matt Tucker
|
||||
*/
|
||||
public final class Message extends Stanza implements MessageView, TypedCloneable<Message> {
|
||||
public final class Message extends MessageOrPresence<MessageBuilder>
|
||||
implements MessageView, TypedCloneable<Message> {
|
||||
|
||||
public static final String ELEMENT = "message";
|
||||
public static final String BODY = "body";
|
||||
|
@ -534,6 +535,7 @@ public final class Message extends Stanza implements MessageView, TypedCloneable
|
|||
return ELEMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageBuilder asBuilder() {
|
||||
return StanzaBuilder.buildMessageFrom(this, getStanzaId());
|
||||
}
|
||||
|
@ -664,6 +666,7 @@ public final class Message extends Stanza implements MessageView, TypedCloneable
|
|||
|
||||
public static final String ELEMENT = "body";
|
||||
public static final String NAMESPACE = StreamOpen.CLIENT_NAMESPACE;
|
||||
public static final QName QNAME = new QName(NAMESPACE, ELEMENT);
|
||||
|
||||
enum BodyElementNamespace {
|
||||
client(StreamOpen.CLIENT_NAMESPACE),
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.jivesoftware.smack.packet.id.StanzaIdSource;
|
|||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smack.util.ToStringUtil;
|
||||
|
||||
public final class MessageBuilder extends StanzaBuilder<MessageBuilder> implements MessageView {
|
||||
public final class MessageBuilder extends MessageOrPresenceBuilder<Message, MessageBuilder> implements MessageView {
|
||||
static final MessageBuilder EMPTY = new MessageBuilder(() -> {
|
||||
return null;
|
||||
});
|
||||
|
@ -153,6 +153,7 @@ public final class MessageBuilder extends StanzaBuilder<MessageBuilder> implemen
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message build() {
|
||||
return new Message(this);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019 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;
|
||||
|
||||
public abstract class MessageOrPresence<MPB extends MessageOrPresenceBuilder<?, ?>> extends Stanza {
|
||||
|
||||
@Deprecated
|
||||
// TODO: Remove in Smack 4.5.
|
||||
protected MessageOrPresence() {
|
||||
}
|
||||
|
||||
protected MessageOrPresence(StanzaBuilder<?> stanzaBuilder) {
|
||||
super(stanzaBuilder);
|
||||
}
|
||||
|
||||
protected MessageOrPresence(Stanza other) {
|
||||
super(other);
|
||||
}
|
||||
|
||||
public abstract MPB asBuilder();
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019 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;
|
||||
|
||||
import org.jivesoftware.smack.packet.id.StanzaIdSource;
|
||||
|
||||
public abstract class MessageOrPresenceBuilder<MP extends MessageOrPresence<? extends MessageOrPresenceBuilder<MP, SB>>, SB extends StanzaBuilder<SB>>
|
||||
extends StanzaBuilder<SB> {
|
||||
|
||||
protected MessageOrPresenceBuilder(Stanza stanza, StanzaIdSource stanzaIdSource) {
|
||||
super(stanza, stanzaIdSource);
|
||||
}
|
||||
|
||||
protected MessageOrPresenceBuilder(Stanza stanza, String stanzaId) {
|
||||
super(stanza, stanzaId);
|
||||
}
|
||||
|
||||
protected MessageOrPresenceBuilder(StanzaIdSource stanzaIdSource) {
|
||||
super(stanzaIdSource);
|
||||
}
|
||||
|
||||
protected MessageOrPresenceBuilder(String stanzaId) {
|
||||
super(stanzaId);
|
||||
}
|
||||
|
||||
public abstract MP build();
|
||||
|
||||
}
|
|
@ -61,7 +61,8 @@ import org.jxmpp.jid.Jid;
|
|||
*
|
||||
* @author Matt Tucker
|
||||
*/
|
||||
public final class Presence extends Stanza implements PresenceView, TypedCloneable<Presence> {
|
||||
public final class Presence extends MessageOrPresence<PresenceBuilder>
|
||||
implements PresenceView, TypedCloneable<Presence> {
|
||||
|
||||
public static final String ELEMENT = "presence";
|
||||
|
||||
|
@ -277,6 +278,7 @@ public final class Presence extends Stanza implements PresenceView, TypedCloneab
|
|||
return ELEMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PresenceBuilder asBuilder() {
|
||||
return StanzaBuilder.buildPresenceFrom(this, getStanzaId());
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import org.jivesoftware.smack.packet.id.StanzaIdSource;
|
|||
import org.jivesoftware.smack.util.Objects;
|
||||
import org.jivesoftware.smack.util.ToStringUtil;
|
||||
|
||||
public final class PresenceBuilder extends StanzaBuilder<PresenceBuilder> implements PresenceView {
|
||||
public final class PresenceBuilder extends MessageOrPresenceBuilder<Presence, PresenceBuilder> implements PresenceView {
|
||||
static final PresenceBuilder EMPTY = new PresenceBuilder(() -> {
|
||||
return null;
|
||||
});
|
||||
|
@ -102,6 +102,7 @@ public final class PresenceBuilder extends StanzaBuilder<PresenceBuilder> implem
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Presence build() {
|
||||
return new Presence(this);
|
||||
}
|
||||
|
|
|
@ -456,12 +456,8 @@ public abstract class Stanza implements StanzaView, TopLevelStreamElement {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a stanza extension with the given namespace exists.
|
||||
*
|
||||
* @param namespace TODO javadoc me please
|
||||
* @return true if a stanza extension exists, false otherwise.
|
||||
*/
|
||||
// Overridden in order to avoid an extra copy.
|
||||
@Override
|
||||
public boolean hasExtension(String namespace) {
|
||||
synchronized (extensionElements) {
|
||||
for (ExtensionElement packetExtension : extensionElements.values()) {
|
||||
|
|
|
@ -63,6 +63,26 @@ public interface StanzaView extends XmlLangElement {
|
|||
|
||||
<E extends ExtensionElement> E getExtension(QName qname);
|
||||
|
||||
default boolean hasExtension(QName qname) {
|
||||
return getExtension(qname) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a extension element with the given namespace exists.
|
||||
*
|
||||
* @param namespace the namespace of the extension element to check for.
|
||||
* @return true if a stanza extension exists, false otherwise.
|
||||
*/
|
||||
default boolean hasExtension(String namespace) {
|
||||
for (ExtensionElement packetExtension : getExtensions()) {
|
||||
if (packetExtension.getNamespace().equals(namespace)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
default <E extends ExtensionElement> E getExtension(Class<E> extensionElementClass) {
|
||||
QName qname = XmppElementUtil.getQNameFor(extensionElementClass);
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019 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.util;
|
||||
|
||||
// TODO: Replace with java.util.function.Predicate once Smack's minimum Android SDK level is 24 or higher.
|
||||
public interface Predicate<T> {
|
||||
|
||||
boolean test(T t);
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue