Introduce XMPPConnection.add(Message|Presence)Interceptor

add deprecate addStanzaInterceptor().
This commit is contained in:
Florian Schmaus 2019-10-25 13:57:18 +02:00
parent 5db6191110
commit e2d206e741
24 changed files with 419 additions and 102 deletions

View File

@ -100,8 +100,12 @@ import org.jivesoftware.smack.packet.FullyQualifiedElement;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Mechanisms; import org.jivesoftware.smack.packet.Mechanisms;
import org.jivesoftware.smack.packet.Message; 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.Nonza;
import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.PresenceBuilder;
import org.jivesoftware.smack.packet.Session; import org.jivesoftware.smack.packet.Session;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.StanzaError; 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.sasl.packet.SaslNonza;
import org.jivesoftware.smack.util.Async; import org.jivesoftware.smack.util.Async;
import org.jivesoftware.smack.util.CollectionUtil; import org.jivesoftware.smack.util.CollectionUtil;
import org.jivesoftware.smack.util.Consumer;
import org.jivesoftware.smack.util.DNSUtil; import org.jivesoftware.smack.util.DNSUtil;
import org.jivesoftware.smack.util.MultiMap; import org.jivesoftware.smack.util.MultiMap;
import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.util.ParserUtils; import org.jivesoftware.smack.util.ParserUtils;
import org.jivesoftware.smack.util.Predicate;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.dns.HostAddress; import org.jivesoftware.smack.util.dns.HostAddress;
import org.jivesoftware.smack.util.dns.SmackDaneProvider; import org.jivesoftware.smack.util.dns.SmackDaneProvider;
@ -243,6 +249,10 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
private final Map<StanzaListener, InterceptorWrapper> interceptors = private final Map<StanzaListener, InterceptorWrapper> interceptors =
new HashMap<>(); 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; private XmlEnvironment incomingStreamXmlEnvironment;
protected XmlEnvironment outgoingStreamXmlEnvironment; 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 // Invoke interceptors for the new stanza that is about to be sent. Interceptors may modify
// the content of the stanza. // the content of the stanza.
firePacketInterceptors(stanza); Stanza stanzaAfterInterceptors = firePacketInterceptors(stanza);
sendStanzaInternal(stanza); sendStanzaInternal(stanzaAfterInterceptors);
} }
/** /**
@ -1204,6 +1214,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
}); });
} }
@Deprecated
@Override @Override
public void addStanzaInterceptor(StanzaListener packetInterceptor, public void addStanzaInterceptor(StanzaListener packetInterceptor,
StanzaFilter packetFilter) { StanzaFilter packetFilter) {
@ -1216,6 +1227,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
} }
} }
@Deprecated
@Override @Override
public void removeStanzaInterceptor(StanzaListener packetInterceptor) { public void removeStanzaInterceptor(StanzaListener packetInterceptor) {
synchronized (interceptors) { 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. * 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 * 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 * is important that interceptors perform their work as soon as possible so that the
* thread does not remain blocked for a long period. * 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<>(); List<StanzaListener> interceptorsToInvoke = new LinkedList<>();
synchronized (interceptors) { synchronized (interceptors) {
for (InterceptorWrapper interceptorWrapper : interceptors.values()) { for (InterceptorWrapper interceptorWrapper : interceptors.values()) {
@ -1247,6 +1327,22 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
LOGGER.log(Level.SEVERE, "Packet interceptor threw exception", e); 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. * A wrapper class to associate a stanza filter with an interceptor.
*/ */
@Deprecated
// TODO: Remove once addStanzaInterceptor is gone.
protected static class InterceptorWrapper { protected static class InterceptorWrapper {
private final StanzaListener packetInterceptor; 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 @Override
public int getConnectionCounter() { public int getConnectionCounter() {
return connectionCounterValue; return connectionCounterValue;

View File

@ -27,9 +27,15 @@ import org.jivesoftware.smack.iqrequest.IQRequestHandler;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.FullyQualifiedElement; import org.jivesoftware.smack.packet.FullyQualifiedElement;
import org.jivesoftware.smack.packet.IQ; 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.Nonza;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.PresenceBuilder;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.StanzaFactory; 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.DomainBareJid;
import org.jxmpp.jid.EntityFullJid; import org.jxmpp.jid.EntityFullJid;
@ -361,7 +367,7 @@ public interface XMPPConnection {
boolean removeStanzaListener(StanzaListener stanzaListener); 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 * 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. * the same stanza listener is added again with a different filter, only the new filter will be used.
* <p> * <p>
@ -446,16 +452,65 @@ public interface XMPPConnection {
* *
* @param stanzaInterceptor the stanza interceptor to notify of stanzas about to be sent. * @param stanzaInterceptor the stanza interceptor to notify of stanzas about to be sent.
* @param stanzaFilter the stanza filter to use. * @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); void addStanzaInterceptor(StanzaListener stanzaInterceptor, StanzaFilter stanzaFilter);
/** /**
* Removes a stanza interceptor. * Removes a stanza interceptor.
* *
* @param stanzaInterceptor the stanza interceptor to remove. * @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); 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 * Returns the current value of the reply timeout in milliseconds for request for this
* XMPPConnection instance. * XMPPConnection instance.

View File

@ -18,6 +18,7 @@
package org.jivesoftware.smack.filter; package org.jivesoftware.smack.filter;
import org.jivesoftware.smack.packet.Stanza; 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 * 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 * @see org.jivesoftware.smack.StanzaListener
* @author Matt Tucker * @author Matt Tucker
*/ */
public interface StanzaFilter { public interface StanzaFilter extends Predicate<Stanza> {
/** /**
* Tests whether or not the specified stanza should pass the filter. * 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. * @return true if and only if <code>stanza</code> passes the filter.
*/ */
boolean accept(Stanza stanza); boolean accept(Stanza stanza);
@Override
default boolean test(Stanza stanza) {
return accept(stanza);
}
} }

View File

@ -60,7 +60,8 @@ import org.jxmpp.stringprep.XmppStringprepException;
* *
* @author Matt Tucker * @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 ELEMENT = "message";
public static final String BODY = "body"; public static final String BODY = "body";
@ -534,6 +535,7 @@ public final class Message extends Stanza implements MessageView, TypedCloneable
return ELEMENT; return ELEMENT;
} }
@Override
public MessageBuilder asBuilder() { public MessageBuilder asBuilder() {
return StanzaBuilder.buildMessageFrom(this, getStanzaId()); 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 ELEMENT = "body";
public static final String NAMESPACE = StreamOpen.CLIENT_NAMESPACE; public static final String NAMESPACE = StreamOpen.CLIENT_NAMESPACE;
public static final QName QNAME = new QName(NAMESPACE, ELEMENT);
enum BodyElementNamespace { enum BodyElementNamespace {
client(StreamOpen.CLIENT_NAMESPACE), client(StreamOpen.CLIENT_NAMESPACE),

View File

@ -22,7 +22,7 @@ import org.jivesoftware.smack.packet.id.StanzaIdSource;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.ToStringUtil; 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(() -> { static final MessageBuilder EMPTY = new MessageBuilder(() -> {
return null; return null;
}); });
@ -153,6 +153,7 @@ public final class MessageBuilder extends StanzaBuilder<MessageBuilder> implemen
return this; return this;
} }
@Override
public Message build() { public Message build() {
return new Message(this); return new Message(this);
} }

View File

@ -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();
}

View File

@ -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();
}

View File

@ -61,7 +61,8 @@ import org.jxmpp.jid.Jid;
* *
* @author Matt Tucker * @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"; public static final String ELEMENT = "presence";
@ -277,6 +278,7 @@ public final class Presence extends Stanza implements PresenceView, TypedCloneab
return ELEMENT; return ELEMENT;
} }
@Override
public PresenceBuilder asBuilder() { public PresenceBuilder asBuilder() {
return StanzaBuilder.buildPresenceFrom(this, getStanzaId()); return StanzaBuilder.buildPresenceFrom(this, getStanzaId());
} }

View File

@ -21,7 +21,7 @@ import org.jivesoftware.smack.packet.id.StanzaIdSource;
import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.ToStringUtil; 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(() -> { static final PresenceBuilder EMPTY = new PresenceBuilder(() -> {
return null; return null;
}); });
@ -102,6 +102,7 @@ public final class PresenceBuilder extends StanzaBuilder<PresenceBuilder> implem
return this; return this;
} }
@Override
public Presence build() { public Presence build() {
return new Presence(this); return new Presence(this);
} }

View File

@ -456,12 +456,8 @@ public abstract class Stanza implements StanzaView, TopLevelStreamElement {
} }
} }
/** // Overridden in order to avoid an extra copy.
* Check if a stanza extension with the given namespace exists. @Override
*
* @param namespace TODO javadoc me please
* @return true if a stanza extension exists, false otherwise.
*/
public boolean hasExtension(String namespace) { public boolean hasExtension(String namespace) {
synchronized (extensionElements) { synchronized (extensionElements) {
for (ExtensionElement packetExtension : extensionElements.values()) { for (ExtensionElement packetExtension : extensionElements.values()) {

View File

@ -63,6 +63,26 @@ public interface StanzaView extends XmlLangElement {
<E extends ExtensionElement> E getExtension(QName qname); <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") @SuppressWarnings("unchecked")
default <E extends ExtensionElement> E getExtension(Class<E> extensionElementClass) { default <E extends ExtensionElement> E getExtension(Class<E> extensionElementClass) {
QName qname = XmppElementUtil.getQNameFor(extensionElementClass); QName qname = XmppElementUtil.getQNameFor(extensionElementClass);

View File

@ -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);
}

View File

@ -120,18 +120,10 @@ public final class ChatMarkersManager extends Manager {
chatManager = ChatManager.getInstanceFor(connection); chatManager = ChatManager.getInstanceFor(connection);
connection.addStanzaInterceptor(new StanzaListener() { connection.addMessageInterceptor(mb -> mb.addExtension(ChatMarkersElements.MarkableExtension.INSTANCE),
@Override m -> {
public void processStanza(Stanza packet) return OUTGOING_MESSAGE_FILTER.accept(m);
throws });
NotConnectedException,
InterruptedException,
SmackException.NotLoggedInException {
Message message = (Message) packet;
// add a markable extension
message.addExtension(ChatMarkersElements.MarkableExtension.INSTANCE);
}
}, OUTGOING_MESSAGE_FILTER);
connection.addSyncStanzaListener(new StanzaListener() { connection.addSyncStanzaListener(new StanzaListener() {
@Override @Override

View File

@ -21,7 +21,6 @@ import java.util.WeakHashMap;
import org.jivesoftware.smack.ConnectionCreationListener; import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPConnectionRegistry; import org.jivesoftware.smack.XMPPConnectionRegistry;
import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.AndFilter;
@ -31,8 +30,9 @@ import org.jivesoftware.smack.filter.StanzaExtensionFilter;
import org.jivesoftware.smack.filter.StanzaFilter; import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.filter.ToTypeFilter; import org.jivesoftware.smack.filter.ToTypeFilter;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.MessageBuilder;
import org.jivesoftware.smack.util.Consumer;
import org.jivesoftware.smack.util.Predicate;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.sid.element.OriginIdElement; import org.jivesoftware.smackx.sid.element.OriginIdElement;
@ -62,12 +62,12 @@ public final class StableUniqueStanzaIdManager extends Manager {
private static final StanzaFilter ORIGIN_ID_FILTER = new StanzaExtensionFilter(OriginIdElement.ELEMENT, NAMESPACE); private static final StanzaFilter ORIGIN_ID_FILTER = new StanzaExtensionFilter(OriginIdElement.ELEMENT, NAMESPACE);
// Listener for outgoing stanzas that adds origin-ids to outgoing stanzas. // Listener for outgoing stanzas that adds origin-ids to outgoing stanzas.
private static final StanzaListener ADD_ORIGIN_ID_INTERCEPTOR = new StanzaListener() { private static final Consumer<MessageBuilder> ADD_ORIGIN_ID_INTERCEPTOR = mb -> OriginIdElement.addOriginId(mb);
@Override
public void processStanza(Stanza stanza) { // We need a filter for outgoing messages that do not carry an origin-id already.
Message message = (Message) stanza; private static final StanzaFilter ADD_ORIGIN_ID_FILTER = new AndFilter(OUTGOING_FILTER, new NotFilter(ORIGIN_ID_FILTER));
OriginIdElement.addOriginId(message); private static final Predicate<Message> ADD_ORIGIN_ID_PREDICATE = m -> {
} return ADD_ORIGIN_ID_FILTER.accept(m);
}; };
static { static {
@ -112,10 +112,8 @@ public final class StableUniqueStanzaIdManager extends Manager {
* Start appending origin-id elements to outgoing stanzas and add the feature to disco. * Start appending origin-id elements to outgoing stanzas and add the feature to disco.
*/ */
public synchronized void enable() { public synchronized void enable() {
connection().addMessageInterceptor(ADD_ORIGIN_ID_INTERCEPTOR, ADD_ORIGIN_ID_PREDICATE);
ServiceDiscoveryManager.getInstanceFor(connection()).addFeature(NAMESPACE); ServiceDiscoveryManager.getInstanceFor(connection()).addFeature(NAMESPACE);
// We need a filter for outgoing messages that do not carry an origin-id already
StanzaFilter filter = new AndFilter(OUTGOING_FILTER, new NotFilter(ORIGIN_ID_FILTER));
connection().addStanzaInterceptor(ADD_ORIGIN_ID_INTERCEPTOR, filter);
} }
/** /**
@ -123,7 +121,7 @@ public final class StableUniqueStanzaIdManager extends Manager {
*/ */
public synchronized void disable() { public synchronized void disable() {
ServiceDiscoveryManager.getInstanceFor(connection()).removeFeature(NAMESPACE); ServiceDiscoveryManager.getInstanceFor(connection()).removeFeature(NAMESPACE);
connection().removeStanzaInterceptor(ADD_ORIGIN_ID_INTERCEPTOR); connection().removeMessageInterceptor(ADD_ORIGIN_ID_INTERCEPTOR);
} }
/** /**

View File

@ -17,6 +17,7 @@
package org.jivesoftware.smackx.sid.element; package org.jivesoftware.smackx.sid.element;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.MessageBuilder;
import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager; import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager;
@ -38,7 +39,10 @@ public class OriginIdElement extends StableAndUniqueIdElement {
* *
* @param message message. * @param message message.
* @return the added origin-id element. * @return the added origin-id element.
* @deprecated use {@link #addOriginId(MessageBuilder)} instead.
*/ */
@Deprecated
// TODO: Remove in Smack 4.5.
public static OriginIdElement addOriginId(Message message) { public static OriginIdElement addOriginId(Message message) {
OriginIdElement originId = new OriginIdElement(); OriginIdElement originId = new OriginIdElement();
message.addExtension(originId); message.addExtension(originId);
@ -47,6 +51,20 @@ public class OriginIdElement extends StableAndUniqueIdElement {
return originId; return originId;
} }
/**
* Add an origin-id element to a message and set the stanzas id to the same id as in the origin-id element.
*
* @param messageBuilder the message builder to add an origin ID to.
* @return the added origin-id element.
*/
public static OriginIdElement addOriginId(MessageBuilder messageBuilder) {
OriginIdElement originId = new OriginIdElement();
messageBuilder.addExtension(originId);
// TODO: Find solution to have both the originIds stanzaId and a nice to look at incremental stanzaID.
// message.setStanzaId(originId.getId());
return originId;
}
/** /**
* Return true, if the message contains a origin-id element. * Return true, if the message contains a origin-id element.
* *

View File

@ -23,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.MessageBuilder;
import org.jivesoftware.smack.packet.StanzaBuilder; import org.jivesoftware.smack.packet.StanzaBuilder;
import org.jivesoftware.smack.test.util.SmackTestSuite; import org.jivesoftware.smack.test.util.SmackTestSuite;
import org.jivesoftware.smack.test.util.TestUtils; import org.jivesoftware.smack.test.util.TestUtils;
@ -71,12 +72,15 @@ public class StableUniqueStanzaIdTest extends SmackTestSuite {
@Test @Test
public void fromMessageTest() { public void fromMessageTest() {
Message message = StanzaBuilder.buildMessage().build(); MessageBuilder messageBuilder = StanzaBuilder.buildMessage();
Message message = messageBuilder.build();
assertFalse(OriginIdElement.hasOriginId(message)); assertFalse(OriginIdElement.hasOriginId(message));
assertFalse(StanzaIdElement.hasStanzaId(message)); assertFalse(StanzaIdElement.hasStanzaId(message));
OriginIdElement.addOriginId(message); OriginIdElement.addOriginId(messageBuilder);
message = messageBuilder.build();
assertTrue(OriginIdElement.hasOriginId(message)); assertTrue(OriginIdElement.hasOriginId(message));
StanzaIdElement stanzaId = new StanzaIdElement("alice@wonderland.lit"); StanzaIdElement stanzaId = new StanzaIdElement("alice@wonderland.lit");

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017-2018 Florian Schmaus. * Copyright 2017-2019 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.
@ -24,7 +24,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
import org.jivesoftware.smack.AsyncButOrdered; import org.jivesoftware.smack.AsyncButOrdered;
import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.AndFilter;
@ -36,6 +35,7 @@ import org.jivesoftware.smack.filter.StanzaExtensionFilter;
import org.jivesoftware.smack.filter.StanzaFilter; import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.filter.ToTypeFilter; import org.jivesoftware.smack.filter.ToTypeFilter;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.MessageView;
import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.roster.AbstractRosterListener; import org.jivesoftware.smack.roster.AbstractRosterListener;
@ -124,22 +124,20 @@ public final class ChatManager extends Manager {
} }
}, INCOMING_MESSAGE_FILTER); }, INCOMING_MESSAGE_FILTER);
connection.addStanzaInterceptor(new StanzaListener() { connection.addMessageInterceptor(messageBuilder -> {
@Override if (!shouldAcceptMessage(messageBuilder)) {
public void processStanza(Stanza stanza) throws NotConnectedException, InterruptedException { return;
Message message = (Message) stanza;
if (!shouldAcceptMessage(message)) {
return;
}
final EntityBareJid to = message.getTo().asEntityBareJidOrThrow();
final Chat chat = chatWith(to);
for (OutgoingChatMessageListener listener : outgoingListeners) {
listener.newOutgoingMessage(to, message, chat);
}
} }
}, OUTGOING_MESSAGE_FILTER);
final EntityBareJid to = messageBuilder.getTo().asEntityBareJidOrThrow();
final Chat chat = chatWith(to);
for (OutgoingChatMessageListener listener : outgoingListeners) {
listener.newOutgoingMessage(to, messageBuilder, chat);
}
}, m -> {
return OUTGOING_MESSAGE_FILTER.accept(m);
});
Roster roster = Roster.getInstanceFor(connection); Roster roster = Roster.getInstanceFor(connection);
roster.addRosterListener(new AbstractRosterListener() { roster.addRosterListener(new AbstractRosterListener() {
@ -181,8 +179,8 @@ public final class ChatManager extends Manager {
}); });
} }
private boolean shouldAcceptMessage(Message message) { private boolean shouldAcceptMessage(MessageView message) {
if (!message.getBodies().isEmpty()) { if (message.hasExtension(Message.Body.QNAME)) {
return true; return true;
} }

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017 Florian Schmaus. * Copyright 2017-2019 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.
@ -16,12 +16,12 @@
*/ */
package org.jivesoftware.smack.chat2; package org.jivesoftware.smack.chat2;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.MessageBuilder;
import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.EntityBareJid;
public interface OutgoingChatMessageListener { public interface OutgoingChatMessageListener {
void newOutgoingMessage(EntityBareJid to, Message message, Chat chat); void newOutgoingMessage(EntityBareJid to, MessageBuilder messageBuilder, Chat chat);
} }

View File

@ -51,9 +51,11 @@ import org.jivesoftware.smack.filter.StanzaTypeFilter;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.PresenceBuilder;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.roster.AbstractPresenceEventListener; import org.jivesoftware.smack.roster.AbstractPresenceEventListener;
import org.jivesoftware.smack.roster.Roster; import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.util.Consumer;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.stringencoder.Base64; import org.jivesoftware.smack.util.stringencoder.Base64;
@ -308,6 +310,15 @@ public final class EntityCapsManager extends Manager {
*/ */
private String entityNode = DEFAULT_ENTITY_NODE; private String entityNode = DEFAULT_ENTITY_NODE;
// Intercept presence packages and add caps data when intended.
// XEP-0115 specifies that a client SHOULD include entity capabilities
// with every presence notification it sends.
private final Consumer<PresenceBuilder> presenceInterceptor = presenceBuilder -> {
CapsVersionAndHash capsVersionAndHash = getCapsVersionAndHash();
CapsExtension caps = new CapsExtension(entityNode, capsVersionAndHash.version, capsVersionAndHash.hash);
presenceBuilder.overrideExtension(caps);
};
private EntityCapsManager(XMPPConnection connection) { private EntityCapsManager(XMPPConnection connection) {
super(connection); super(connection);
this.sdm = ServiceDiscoveryManager.getInstanceFor(connection); this.sdm = ServiceDiscoveryManager.getInstanceFor(connection);
@ -379,23 +390,9 @@ public final class EntityCapsManager extends Manager {
} }
}, PresenceTypeFilter.OUTGOING_PRESENCE_BROADCAST); }, PresenceTypeFilter.OUTGOING_PRESENCE_BROADCAST);
// Intercept presence packages and add caps data when intended.
// XEP-0115 specifies that a client SHOULD include entity capabilities enableEntityCaps();
// with every presence notification it sends.
StanzaListener packetInterceptor = new StanzaListener() {
@Override
public void processStanza(Stanza packet) {
if (!entityCapsEnabled) {
// Be sure to not send stanzas with the caps extension if it's not enabled
packet.removeExtension(CapsExtension.ELEMENT, CapsExtension.NAMESPACE);
return;
}
CapsVersionAndHash capsVersionAndHash = getCapsVersionAndHash();
CapsExtension caps = new CapsExtension(entityNode, capsVersionAndHash.version, capsVersionAndHash.hash);
packet.overrideExtension(caps);
}
};
connection.addStanzaInterceptor(packetInterceptor, PresenceTypeFilter.AVAILABLE);
// It's important to do this as last action. Since it changes the // It's important to do this as last action. Since it changes the
// behavior of the SDM in some ways // behavior of the SDM in some ways
sdm.addEntityCapabilitiesChangedListener(new EntityCapabilitiesChangedListener() { sdm.addEntityCapabilitiesChangedListener(new EntityCapabilitiesChangedListener() {
@ -424,6 +421,10 @@ public final class EntityCapsManager extends Manager {
} }
public synchronized void enableEntityCaps() { public synchronized void enableEntityCaps() {
connection().addPresenceInterceptor(presenceInterceptor, p -> {
return PresenceTypeFilter.AVAILABLE.accept(p);
});
// Add Entity Capabilities (XEP-0115) feature node. // Add Entity Capabilities (XEP-0115) feature node.
sdm.addFeature(NAMESPACE); sdm.addFeature(NAMESPACE);
updateLocalEntityCaps(); updateLocalEntityCaps();
@ -433,6 +434,8 @@ public final class EntityCapsManager extends Manager {
public synchronized void disableEntityCaps() { public synchronized void disableEntityCaps() {
entityCapsEnabled = false; entityCapsEnabled = false;
sdm.removeFeature(NAMESPACE); sdm.removeFeature(NAMESPACE);
connection().removePresenceInterceptor(presenceInterceptor);
} }
public boolean entityCapsEnabled() { public boolean entityCapsEnabled() {

View File

@ -37,11 +37,11 @@ import org.jivesoftware.smack.chat2.OutgoingChatMessageListener;
import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.FromTypeFilter; import org.jivesoftware.smack.filter.FromTypeFilter;
import org.jivesoftware.smack.filter.MessageTypeFilter; import org.jivesoftware.smack.filter.MessageTypeFilter;
import org.jivesoftware.smack.filter.NotFilter;
import org.jivesoftware.smack.filter.StanzaExtensionFilter; import org.jivesoftware.smack.filter.StanzaExtensionFilter;
import org.jivesoftware.smack.filter.StanzaFilter; import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.MessageBuilder;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.StanzaBuilder; import org.jivesoftware.smack.packet.StanzaBuilder;
@ -73,7 +73,6 @@ public final class ChatStateManager extends Manager {
private static final Map<XMPPConnection, ChatStateManager> INSTANCES = new WeakHashMap<>(); private static final Map<XMPPConnection, ChatStateManager> INSTANCES = new WeakHashMap<>();
private static final StanzaFilter filter = new NotFilter(new StanzaExtensionFilter(NAMESPACE));
private static final StanzaFilter INCOMING_MESSAGE_FILTER = private static final StanzaFilter INCOMING_MESSAGE_FILTER =
new AndFilter(MessageTypeFilter.NORMAL_OR_CHAT, FromTypeFilter.ENTITY_FULL_JID); new AndFilter(MessageTypeFilter.NORMAL_OR_CHAT, FromTypeFilter.ENTITY_FULL_JID);
private static final StanzaFilter INCOMING_CHAT_STATE_FILTER = new AndFilter(INCOMING_MESSAGE_FILTER, new StanzaExtensionFilter(NAMESPACE)); private static final StanzaFilter INCOMING_CHAT_STATE_FILTER = new AndFilter(INCOMING_MESSAGE_FILTER, new StanzaExtensionFilter(NAMESPACE));
@ -117,13 +116,13 @@ public final class ChatStateManager extends Manager {
ChatManager chatManager = ChatManager.getInstanceFor(connection); ChatManager chatManager = ChatManager.getInstanceFor(connection);
chatManager.addOutgoingListener(new OutgoingChatMessageListener() { chatManager.addOutgoingListener(new OutgoingChatMessageListener() {
@Override @Override
public void newOutgoingMessage(EntityBareJid to, Message message, Chat chat) { public void newOutgoingMessage(EntityBareJid to, MessageBuilder message, Chat chat) {
if (chat == null) { if (chat == null) {
return; return;
} }
// if message already has a chatStateExtension, then do nothing, // if message already has a chatStateExtension, then do nothing,
if (!filter.accept(message)) { if (message.hasExtension(ChatStateExtension.NAMESPACE)) {
return; return;
} }

View File

@ -358,7 +358,7 @@ public class MultiUserChat {
); );
// @formatter:on // @formatter:on
connection.addSyncStanzaListener(declinesListener, new AndFilter(fromRoomFilter, DECLINE_FILTER)); connection.addSyncStanzaListener(declinesListener, new AndFilter(fromRoomFilter, DECLINE_FILTER));
connection.addStanzaInterceptor(presenceInterceptor, new AndFilter(ToMatchesFilter.create(room), connection.addStanzaSendingListener(presenceInterceptor, new AndFilter(ToMatchesFilter.create(room),
StanzaTypeFilter.PRESENCE)); StanzaTypeFilter.PRESENCE));
messageCollector = connection.createStanzaCollector(fromRoomGroupchatFilter); messageCollector = connection.createStanzaCollector(fromRoomGroupchatFilter);
@ -2122,7 +2122,7 @@ public class MultiUserChat {
connection.removeSyncStanzaListener(presenceListener); connection.removeSyncStanzaListener(presenceListener);
connection.removeSyncStanzaListener(subjectListener); connection.removeSyncStanzaListener(subjectListener);
connection.removeSyncStanzaListener(declinesListener); connection.removeSyncStanzaListener(declinesListener);
connection.removeStanzaInterceptor(presenceInterceptor); connection.removeStanzaSendingListener(presenceInterceptor);
if (messageCollector != null) { if (messageCollector != null) {
messageCollector.cancel(); messageCollector.cancel();
messageCollector = null; messageCollector = null;

View File

@ -38,9 +38,11 @@ import org.jivesoftware.smack.filter.StanzaExtensionFilter;
import org.jivesoftware.smack.filter.StanzaFilter; import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.filter.StanzaTypeFilter; import org.jivesoftware.smack.filter.StanzaTypeFilter;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.MessageBuilder;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.StanzaBuilder; import org.jivesoftware.smack.packet.StanzaBuilder;
import org.jivesoftware.smack.roster.Roster; import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.util.Consumer;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
@ -271,13 +273,7 @@ public final class DeliveryReceiptManager extends Manager {
); );
// @formatter:on // @formatter:on
private static final StanzaListener AUTO_ADD_DELIVERY_RECEIPT_REQUESTS_LISTENER = new StanzaListener() { private static final Consumer<MessageBuilder> AUTO_ADD_DELIVERY_RECEIPT_REQUESTS_LISTENER = mb -> DeliveryReceiptRequest.addTo(mb);
@Override
public void processStanza(Stanza packet) throws NotConnectedException {
Message message = (Message) packet;
DeliveryReceiptRequest.addTo(message);
}
};
/** /**
* Enables automatic requests of delivery receipts for outgoing messages of * Enables automatic requests of delivery receipts for outgoing messages of
@ -288,8 +284,9 @@ public final class DeliveryReceiptManager extends Manager {
* @see #dontAutoAddDeliveryReceiptRequests() * @see #dontAutoAddDeliveryReceiptRequests()
*/ */
public void autoAddDeliveryReceiptRequests() { public void autoAddDeliveryReceiptRequests() {
connection().addStanzaInterceptor(AUTO_ADD_DELIVERY_RECEIPT_REQUESTS_LISTENER, connection().addMessageInterceptor(AUTO_ADD_DELIVERY_RECEIPT_REQUESTS_LISTENER, m -> {
MESSAGES_TO_REQUEST_RECEIPTS_FOR); return MESSAGES_TO_REQUEST_RECEIPTS_FOR.accept(m);
});
} }
/** /**
@ -299,7 +296,7 @@ public final class DeliveryReceiptManager extends Manager {
* @see #autoAddDeliveryReceiptRequests() * @see #autoAddDeliveryReceiptRequests()
*/ */
public void dontAutoAddDeliveryReceiptRequests() { public void dontAutoAddDeliveryReceiptRequests() {
connection().removeStanzaInterceptor(AUTO_ADD_DELIVERY_RECEIPT_REQUESTS_LISTENER); connection().removeMessageInterceptor(AUTO_ADD_DELIVERY_RECEIPT_REQUESTS_LISTENER);
} }
/** /**

View File

@ -21,8 +21,10 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.xml.namespace.QName;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.MessageView;
import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smack.util.XmlStringBuilder;
/** /**
@ -40,6 +42,8 @@ public class XHTMLExtension implements ExtensionElement {
public static final String ELEMENT = "html"; public static final String ELEMENT = "html";
public static final String NAMESPACE = "http://jabber.org/protocol/xhtml-im"; public static final String NAMESPACE = "http://jabber.org/protocol/xhtml-im";
public static final QName QNAME = new QName(NAMESPACE, ELEMENT);
private final List<CharSequence> bodies = new ArrayList<>(); private final List<CharSequence> bodies = new ArrayList<>();
/** /**
@ -125,7 +129,7 @@ public class XHTMLExtension implements ExtensionElement {
} }
} }
public static XHTMLExtension from(Message message) { public static XHTMLExtension from(MessageView message) {
return message.getExtension(ELEMENT, NAMESPACE); return message.getExtension(QNAME);
} }
} }

View File

@ -17,6 +17,7 @@
package org.jivesoftware.smack.chat2; package org.jivesoftware.smack.chat2;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.MessageBuilder;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.igniterealtime.smack.inttest.SmackIntegrationTest; import org.igniterealtime.smack.inttest.SmackIntegrationTest;
@ -36,7 +37,8 @@ public class OutgoingMessageListenerIntegrationTest extends AbstractChatIntegrat
final SimpleResultSyncPoint syncPoint = new SimpleResultSyncPoint(); final SimpleResultSyncPoint syncPoint = new SimpleResultSyncPoint();
final OutgoingChatMessageListener listener = new OutgoingChatMessageListener() { final OutgoingChatMessageListener listener = new OutgoingChatMessageListener() {
@Override @Override
public void newOutgoingMessage(EntityBareJid to, Message message, Chat chat) { public void newOutgoingMessage(EntityBareJid to, MessageBuilder messageBuilder, Chat chat) {
Message message = messageBuilder.build();
if (message.getBody().equals(body)) { if (message.getBody().equals(body)) {
syncPoint.signal(); syncPoint.signal();
} }