mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-26 05:52:06 +01:00
Compare commits
16 commits
926c5892ad
...
9d626bf787
Author | SHA1 | Date | |
---|---|---|---|
|
9d626bf787 | ||
|
a7a298c5d8 | ||
|
eb4c2c5572 | ||
|
b0277d7e74 | ||
|
2915101843 | ||
|
6d1252755b | ||
|
ee699f24dd | ||
|
63a4212f7e | ||
|
63ba524758 | ||
|
e2223254cf | ||
|
69767e9538 | ||
|
6e32305987 | ||
|
36072fb25a | ||
|
4b01892129 | ||
|
e2d206e741 | ||
|
5db6191110 |
234 changed files with 4056 additions and 1411 deletions
|
@ -15,7 +15,11 @@ Smack Key Advantages
|
||||||
AbstractXMPPConnection connection = new XMPPTCPConnection("mtucker", "password", "jabber.org");
|
AbstractXMPPConnection connection = new XMPPTCPConnection("mtucker", "password", "jabber.org");
|
||||||
connection.connect().login();
|
connection.connect().login();
|
||||||
|
|
||||||
Message message = new Message("jsmith@jivesoftware.com", "Howdy! How are you?");
|
Message message = connection.getStanzaFactory()
|
||||||
|
.buildMessageStanza()
|
||||||
|
.to("jsmith@jivesoftware.com")
|
||||||
|
.setBody("Howdy! How are you?")
|
||||||
|
.build();
|
||||||
connection.sendStanza(message);
|
connection.sendStanza(message);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -28,17 +28,17 @@ SMACK_EXCEPTIONS[InterruptedException]="if the calling thread was interrupted."
|
||||||
SMACK_EXCEPTIONS[XMPPErrorException]="if there was an XMPP error returned."
|
SMACK_EXCEPTIONS[XMPPErrorException]="if there was an XMPP error returned."
|
||||||
SMACK_EXCEPTIONS[NoResponseException]="if there was no response from the remote entity."
|
SMACK_EXCEPTIONS[NoResponseException]="if there was no response from the remote entity."
|
||||||
SMACK_EXCEPTIONS[NotLoggedInException]="if the XMPP connection is not authenticated."
|
SMACK_EXCEPTIONS[NotLoggedInException]="if the XMPP connection is not authenticated."
|
||||||
SMACK_EXCEPTIONS[BOSHException]="if an BOSH related error occured."
|
SMACK_EXCEPTIONS[BOSHException]="if an BOSH related error occurred."
|
||||||
SMACK_EXCEPTIONS[IOException]="if an I/O error occured."
|
SMACK_EXCEPTIONS[IOException]="if an I/O error occurred."
|
||||||
SMACK_EXCEPTIONS[SmackException]="if Smack detected an exceptional situation."
|
SMACK_EXCEPTIONS[SmackException]="if Smack detected an exceptional situation."
|
||||||
SMACK_EXCEPTIONS[XMPPException]="if an XMPP protocol error was received."
|
SMACK_EXCEPTIONS[XMPPException]="if an XMPP protocol error was received."
|
||||||
SMACK_EXCEPTIONS[SmackSaslException]="if a SASL specific error occured."
|
SMACK_EXCEPTIONS[SmackSaslException]="if a SASL specific error occurred."
|
||||||
SMACK_EXCEPTIONS[SASLErrorException]="if a SASL protocol error was returned."
|
SMACK_EXCEPTIONS[SASLErrorException]="if a SASL protocol error was returned."
|
||||||
SMACK_EXCEPTIONS[NotAMucServiceException]="if the entity is not a MUC serivce."
|
SMACK_EXCEPTIONS[NotAMucServiceException]="if the entity is not a MUC serivce."
|
||||||
SMACK_EXCEPTIONS[NoSuchAlgorithmException]="if no such algorithm is available."
|
SMACK_EXCEPTIONS[NoSuchAlgorithmException]="if no such algorithm is available."
|
||||||
SMACK_EXCEPTIONS[KeyManagementException]="if there was a key mangement error."
|
SMACK_EXCEPTIONS[KeyManagementException]="if there was a key mangement error."
|
||||||
SMACK_EXCEPTIONS[XmppStringprepException]="if the provided string is invalid."
|
SMACK_EXCEPTIONS[XmppStringprepException]="if the provided string is invalid."
|
||||||
SMACK_EXCEPTIONS[XmlPullParserException]="if an error in the XML parser occured."
|
SMACK_EXCEPTIONS[XmlPullParserException]="if an error in the XML parser occurred."
|
||||||
SMACK_EXCEPTIONS[SmackParsingException]="if the Smack parser (provider) encountered invalid input."
|
SMACK_EXCEPTIONS[SmackParsingException]="if the Smack parser (provider) encountered invalid input."
|
||||||
SMACK_EXCEPTIONS[MucNotJoinedException]="if not joined to the Multi-User Chat."
|
SMACK_EXCEPTIONS[MucNotJoinedException]="if not joined to the Multi-User Chat."
|
||||||
SMACK_EXCEPTIONS[MucAlreadyJoinedException]="if already joined the Multi-User Chat."7y
|
SMACK_EXCEPTIONS[MucAlreadyJoinedException]="if already joined the Multi-User Chat."7y
|
||||||
|
@ -54,7 +54,7 @@ SMACK_EXCEPTIONS[IllegalArgumentException]="if an illegal argument was given."
|
||||||
SMACK_EXCEPTIONS[NotAPubSubNodeException]="if a involved node is not a PubSub node."
|
SMACK_EXCEPTIONS[NotAPubSubNodeException]="if a involved node is not a PubSub node."
|
||||||
SMACK_EXCEPTIONS[NoAcceptableTransferMechanisms]="if no acceptable transfer mechanisms are available"
|
SMACK_EXCEPTIONS[NoAcceptableTransferMechanisms]="if no acceptable transfer mechanisms are available"
|
||||||
SMACK_EXCEPTIONS[NoSuchMethodException]="if no such method is declared"
|
SMACK_EXCEPTIONS[NoSuchMethodException]="if no such method is declared"
|
||||||
SMACK_EXCEPTIONS[Exception]="if an exception occured."
|
SMACK_EXCEPTIONS[Exception]="if an exception occurred."
|
||||||
SMACK_EXCEPTIONS[TestNotPossibleException]="if the test is not possible."
|
SMACK_EXCEPTIONS[TestNotPossibleException]="if the test is not possible."
|
||||||
SMACK_EXCEPTIONS[TimeoutException]="if there was a timeout."
|
SMACK_EXCEPTIONS[TimeoutException]="if there was a timeout."
|
||||||
SMACK_EXCEPTIONS[IllegalStateException]="if an illegal state was encountered"
|
SMACK_EXCEPTIONS[IllegalStateException]="if an illegal state was encountered"
|
||||||
|
|
|
@ -517,8 +517,8 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
|
||||||
if ("urn:ietf:params:xml:ns:xmpp-streams".equals(parser.getNamespace(null))) {
|
if ("urn:ietf:params:xml:ns:xmpp-streams".equals(parser.getNamespace(null))) {
|
||||||
throw new StreamErrorException(PacketParserUtils.parseStreamError(parser));
|
throw new StreamErrorException(PacketParserUtils.parseStreamError(parser));
|
||||||
} else {
|
} else {
|
||||||
StanzaError.Builder builder = PacketParserUtils.parseError(parser);
|
StanzaError stanzaError = PacketParserUtils.parseError(parser);
|
||||||
throw new XMPPException.XMPPErrorException(null, builder.build());
|
throw new XMPPException.XMPPErrorException(null, stanzaError);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
parseAndProcessNonza(parser);
|
parseAndProcessNonza(parser);
|
||||||
|
|
|
@ -100,16 +100,22 @@ 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;
|
||||||
|
import org.jivesoftware.smack.packet.StanzaFactory;
|
||||||
import org.jivesoftware.smack.packet.StartTls;
|
import org.jivesoftware.smack.packet.StartTls;
|
||||||
import org.jivesoftware.smack.packet.StreamError;
|
import org.jivesoftware.smack.packet.StreamError;
|
||||||
import org.jivesoftware.smack.packet.StreamOpen;
|
import org.jivesoftware.smack.packet.StreamOpen;
|
||||||
import org.jivesoftware.smack.packet.TopLevelStreamElement;
|
import org.jivesoftware.smack.packet.TopLevelStreamElement;
|
||||||
import org.jivesoftware.smack.packet.XmlEnvironment;
|
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
|
import org.jivesoftware.smack.packet.id.StanzaIdSource;
|
||||||
import org.jivesoftware.smack.parsing.ParsingExceptionCallback;
|
import org.jivesoftware.smack.parsing.ParsingExceptionCallback;
|
||||||
import org.jivesoftware.smack.parsing.SmackParsingException;
|
import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||||
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||||
|
@ -121,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;
|
||||||
|
@ -241,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;
|
||||||
|
@ -402,6 +414,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
private final Map<QName, IQRequestHandler> setIqRequestHandler = new HashMap<>();
|
private final Map<QName, IQRequestHandler> setIqRequestHandler = new HashMap<>();
|
||||||
private final Map<QName, IQRequestHandler> getIqRequestHandler = new HashMap<>();
|
private final Map<QName, IQRequestHandler> getIqRequestHandler = new HashMap<>();
|
||||||
|
|
||||||
|
private final StanzaFactory stanzaFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new XMPPConnection to an XMPP server.
|
* Create a new XMPPConnection to an XMPP server.
|
||||||
*
|
*
|
||||||
|
@ -440,6 +454,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
for (ConnectionCreationListener listener : XMPPConnectionRegistry.getConnectionCreationListeners()) {
|
for (ConnectionCreationListener listener : XMPPConnectionRegistry.getConnectionCreationListeners()) {
|
||||||
listener.connectionCreated(this);
|
listener.connectionCreated(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StanzaIdSource stanzaIdSource = configuration.constructStanzaIdSource();
|
||||||
|
stanzaFactory = new StanzaFactory(stanzaIdSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -518,7 +535,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
*
|
*
|
||||||
* @throws XMPPException if an error occurs on the XMPP protocol level.
|
* @throws XMPPException if an error occurs on the XMPP protocol level.
|
||||||
* @throws SmackException if an error occurs somewhere else besides XMPP protocol level.
|
* @throws SmackException if an error occurs somewhere else besides XMPP protocol level.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @return a reference to this object, to chain <code>connect()</code> with <code>login()</code>.
|
* @return a reference to this object, to chain <code>connect()</code> with <code>login()</code>.
|
||||||
* @throws InterruptedException if the calling thread was interrupted.
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
*/
|
*/
|
||||||
|
@ -558,7 +575,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
* login if the previous connection state was logged (authenticated).
|
* login if the previous connection state was logged (authenticated).
|
||||||
*
|
*
|
||||||
* @throws SmackException if Smack detected an exceptional situation.
|
* @throws SmackException if Smack detected an exceptional situation.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws XMPPException if an XMPP protocol error was received.
|
* @throws XMPPException if an XMPP protocol error was received.
|
||||||
* @throws InterruptedException if the calling thread was interrupted.
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
*/
|
*/
|
||||||
|
@ -611,7 +628,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
* @param password TODO javadoc me please
|
* @param password TODO javadoc me please
|
||||||
* @throws XMPPException if an XMPP protocol error was received.
|
* @throws XMPPException if an XMPP protocol error was received.
|
||||||
* @throws SmackException if Smack detected an exceptional situation.
|
* @throws SmackException if Smack detected an exceptional situation.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws InterruptedException if the calling thread was interrupted.
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
* @see #login
|
* @see #login
|
||||||
*/
|
*/
|
||||||
|
@ -629,7 +646,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
* @param resource TODO javadoc me please
|
* @param resource TODO javadoc me please
|
||||||
* @throws XMPPException if an XMPP protocol error was received.
|
* @throws XMPPException if an XMPP protocol error was received.
|
||||||
* @throws SmackException if Smack detected an exceptional situation.
|
* @throws SmackException if Smack detected an exceptional situation.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws InterruptedException if the calling thread was interrupted.
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
* @see #login
|
* @see #login
|
||||||
*/
|
*/
|
||||||
|
@ -733,7 +750,11 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
// eventually load the roster. And we should load the roster before we
|
// eventually load the roster. And we should load the roster before we
|
||||||
// send the initial presence.
|
// send the initial presence.
|
||||||
if (config.isSendPresence() && !resumed) {
|
if (config.isSendPresence() && !resumed) {
|
||||||
sendStanza(new Presence(Presence.Type.available));
|
Presence availablePresence = getStanzaFactory()
|
||||||
|
.buildPresenceStanza()
|
||||||
|
.ofType(Presence.Type.available)
|
||||||
|
.build();
|
||||||
|
sendStanza(availablePresence);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,6 +835,11 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final StanzaFactory getStanzaFactory() {
|
||||||
|
return stanzaFactory;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void sendStanza(Stanza stanza) throws NotConnectedException, InterruptedException {
|
public final void sendStanza(Stanza stanza) throws NotConnectedException, InterruptedException {
|
||||||
Objects.requireNonNull(stanza, "Stanza must not be null");
|
Objects.requireNonNull(stanza, "Stanza must not be null");
|
||||||
|
@ -833,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -847,9 +873,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
* @return the used SASLMechanism.
|
* @return the used SASLMechanism.
|
||||||
* @throws XMPPErrorException if there was an XMPP error returned.
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
||||||
* @throws SASLErrorException if a SASL protocol error was returned.
|
* @throws SASLErrorException if a SASL protocol error was returned.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws InterruptedException if the calling thread was interrupted.
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
* @throws SmackSaslException if a SASL specific error occured.
|
* @throws SmackSaslException if a SASL specific error occurred.
|
||||||
* @throws NotConnectedException if the XMPP connection is not connected.
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
||||||
* @throws NoResponseException if there was no response from the remote entity.
|
* @throws NoResponseException if there was no response from the remote entity.
|
||||||
* @throws SmackWrappedException in case of an exception.
|
* @throws SmackWrappedException in case of an exception.
|
||||||
|
@ -893,7 +919,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
Presence unavailablePresence = null;
|
Presence unavailablePresence = null;
|
||||||
if (isAuthenticated()) {
|
if (isAuthenticated()) {
|
||||||
unavailablePresence = new Presence(Presence.Type.unavailable);
|
unavailablePresence = getStanzaFactory().buildPresenceStanza()
|
||||||
|
.ofType(Presence.Type.unavailable)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
disconnect(unavailablePresence);
|
disconnect(unavailablePresence);
|
||||||
|
@ -1186,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) {
|
||||||
|
@ -1198,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) {
|
||||||
|
@ -1205,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()) {
|
||||||
|
@ -1229,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1416,7 +1530,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
// If the IQ stanza is of type "get" or "set" with no registered IQ request handler, then answer an
|
// If the IQ stanza is of type "get" or "set" with no registered IQ request handler, then answer an
|
||||||
// IQ of type 'error' with condition 'service-unavailable'.
|
// IQ of type 'error' with condition 'service-unavailable'.
|
||||||
final ErrorIQ errorIQ = IQ.createErrorResponse(iq, StanzaError.getBuilder(
|
final ErrorIQ errorIQ = IQ.createErrorResponse(iq, StanzaError.getBuilder(
|
||||||
replyCondition));
|
replyCondition).build());
|
||||||
// Use async sendStanza() here, since if sendStanza() would block, then some connections, e.g.
|
// Use async sendStanza() here, since if sendStanza() would block, then some connections, e.g.
|
||||||
// XmppNioTcpConnection, would deadlock, as this operation is performed in the same thread that is
|
// XmppNioTcpConnection, would deadlock, as this operation is performed in the same thread that is
|
||||||
asyncGo(() -> {
|
asyncGo(() -> {
|
||||||
|
@ -1656,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;
|
||||||
|
@ -1681,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;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2018 Florian Schmaus
|
* Copyright 2018-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,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smack;
|
package org.jivesoftware.smack;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
@ -51,9 +52,17 @@ import java.util.concurrent.Executor;
|
||||||
*/
|
*/
|
||||||
public class AsyncButOrdered<K> {
|
public class AsyncButOrdered<K> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map with the currently pending runnables for a given key. Note that this is a weak hash map so we do not have
|
||||||
|
* to take care of removing the keys ourselfs from the map.
|
||||||
|
*/
|
||||||
private final Map<K, Queue<Runnable>> pendingRunnables = new WeakHashMap<>();
|
private final Map<K, Queue<Runnable>> pendingRunnables = new WeakHashMap<>();
|
||||||
|
|
||||||
private final Map<K, Boolean> threadActiveMap = new WeakHashMap<>();
|
/**
|
||||||
|
* A marker map if there is an active thread for the given key. Holds the responsible handler thread if one is
|
||||||
|
* active, otherwise the key is non-existend in the map.
|
||||||
|
*/
|
||||||
|
private final Map<K, Handler> threadActiveMap = new HashMap<>();
|
||||||
|
|
||||||
private final Executor executor;
|
private final Executor executor;
|
||||||
|
|
||||||
|
@ -65,6 +74,14 @@ public class AsyncButOrdered<K> {
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void scheduleHandler(Handler handler) {
|
||||||
|
if (executor == null) {
|
||||||
|
AbstractXMPPConnection.asyncGo(handler);
|
||||||
|
} else {
|
||||||
|
executor.execute(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke the given {@link Runnable} asynchronous but ordered in respect to the given key.
|
* Invoke the given {@link Runnable} asynchronous but ordered in respect to the given key.
|
||||||
*
|
*
|
||||||
|
@ -73,6 +90,7 @@ public class AsyncButOrdered<K> {
|
||||||
* @return true if a new thread was created
|
* @return true if a new thread was created
|
||||||
*/
|
*/
|
||||||
public boolean performAsyncButOrdered(K key, Runnable runnable) {
|
public boolean performAsyncButOrdered(K key, Runnable runnable) {
|
||||||
|
// First check if a key queue already exists, create one if not.
|
||||||
Queue<Runnable> keyQueue;
|
Queue<Runnable> keyQueue;
|
||||||
synchronized (pendingRunnables) {
|
synchronized (pendingRunnables) {
|
||||||
keyQueue = pendingRunnables.get(key);
|
keyQueue = pendingRunnables.get(key);
|
||||||
|
@ -82,29 +100,27 @@ public class AsyncButOrdered<K> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Then add the task to the queue.
|
||||||
keyQueue.add(runnable);
|
keyQueue.add(runnable);
|
||||||
|
|
||||||
boolean newHandler;
|
// Finally check if there is already a handler working on that queue, create one if not.
|
||||||
|
Handler newlyCreatedHandler = null;
|
||||||
synchronized (threadActiveMap) {
|
synchronized (threadActiveMap) {
|
||||||
Boolean threadActive = threadActiveMap.get(key);
|
if (!threadActiveMap.containsKey(key)) {
|
||||||
if (threadActive == null) {
|
newlyCreatedHandler = new Handler(keyQueue, key);
|
||||||
threadActive = false;
|
|
||||||
threadActiveMap.put(key, threadActive);
|
|
||||||
}
|
|
||||||
|
|
||||||
newHandler = !threadActive;
|
// Mark that there is thread active for the given key. Note that this has to be done before scheduling
|
||||||
if (newHandler) {
|
// the handler thread.
|
||||||
Handler handler = new Handler(keyQueue, key);
|
threadActiveMap.put(key, newlyCreatedHandler);
|
||||||
threadActiveMap.put(key, true);
|
|
||||||
if (executor == null) {
|
|
||||||
AbstractXMPPConnection.asyncGo(handler);
|
|
||||||
} else {
|
|
||||||
executor.execute(handler);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return newHandler;
|
if (newlyCreatedHandler != null) {
|
||||||
|
scheduleHandler(newlyCreatedHandler);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Executor asExecutorFor(final K key) {
|
public Executor asExecutorFor(final K key) {
|
||||||
|
@ -134,11 +150,14 @@ public class AsyncButOrdered<K> {
|
||||||
try {
|
try {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
// The run() method threw, this handler thread is going to terminate because of that. Ensure we note
|
// The run() method threw, this handler thread is going to terminate because of that. We create
|
||||||
// that in the map.
|
// a new handler to continue working on the queue while throwing the throwable so that the
|
||||||
|
// executor can handle it.
|
||||||
|
Handler newlyCreatedHandler = new Handler(keyQueue, key);
|
||||||
synchronized (threadActiveMap) {
|
synchronized (threadActiveMap) {
|
||||||
threadActiveMap.put(key, false);
|
threadActiveMap.put(key, newlyCreatedHandler);
|
||||||
}
|
}
|
||||||
|
scheduleHandler(newlyCreatedHandler);
|
||||||
throw t;
|
throw t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,7 +165,7 @@ public class AsyncButOrdered<K> {
|
||||||
synchronized (threadActiveMap) {
|
synchronized (threadActiveMap) {
|
||||||
// If the queue is empty, stop this handler, otherwise continue looping.
|
// If the queue is empty, stop this handler, otherwise continue looping.
|
||||||
if (keyQueue.isEmpty()) {
|
if (keyQueue.isEmpty()) {
|
||||||
threadActiveMap.put(key, false);
|
threadActiveMap.remove(key);
|
||||||
break mainloop;
|
break mainloop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,9 @@ import javax.net.ssl.X509TrustManager;
|
||||||
import javax.security.auth.callback.CallbackHandler;
|
import javax.security.auth.callback.CallbackHandler;
|
||||||
|
|
||||||
import org.jivesoftware.smack.debugger.SmackDebuggerFactory;
|
import org.jivesoftware.smack.debugger.SmackDebuggerFactory;
|
||||||
|
import org.jivesoftware.smack.packet.id.StandardStanzaIdSource;
|
||||||
|
import org.jivesoftware.smack.packet.id.StanzaIdSource;
|
||||||
|
import org.jivesoftware.smack.packet.id.StanzaIdSourceFactory;
|
||||||
import org.jivesoftware.smack.proxy.ProxyInfo;
|
import org.jivesoftware.smack.proxy.ProxyInfo;
|
||||||
import org.jivesoftware.smack.sasl.SASLMechanism;
|
import org.jivesoftware.smack.sasl.SASLMechanism;
|
||||||
import org.jivesoftware.smack.sasl.core.SASLAnonymous;
|
import org.jivesoftware.smack.sasl.core.SASLAnonymous;
|
||||||
|
@ -159,6 +162,8 @@ public abstract class ConnectionConfiguration {
|
||||||
|
|
||||||
private final boolean compressionEnabled;
|
private final boolean compressionEnabled;
|
||||||
|
|
||||||
|
private final StanzaIdSourceFactory stanzaIdSourceFactory;
|
||||||
|
|
||||||
protected ConnectionConfiguration(Builder<?, ?> builder) {
|
protected ConnectionConfiguration(Builder<?, ?> builder) {
|
||||||
authzid = builder.authzid;
|
authzid = builder.authzid;
|
||||||
username = builder.username;
|
username = builder.username;
|
||||||
|
@ -213,6 +218,8 @@ public abstract class ConnectionConfiguration {
|
||||||
|
|
||||||
compressionEnabled = builder.compressionEnabled;
|
compressionEnabled = builder.compressionEnabled;
|
||||||
|
|
||||||
|
stanzaIdSourceFactory = builder.stanzaIdSourceFactory;
|
||||||
|
|
||||||
// If the enabledSaslmechanisms are set, then they must not be empty
|
// If the enabledSaslmechanisms are set, then they must not be empty
|
||||||
assert enabledSaslMechanisms == null || !enabledSaslMechanisms.isEmpty();
|
assert enabledSaslMechanisms == null || !enabledSaslMechanisms.isEmpty();
|
||||||
|
|
||||||
|
@ -568,6 +575,10 @@ public abstract class ConnectionConfiguration {
|
||||||
return Collections.unmodifiableSet(enabledSaslMechanisms);
|
return Collections.unmodifiableSet(enabledSaslMechanisms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StanzaIdSource constructStanzaIdSource() {
|
||||||
|
return stanzaIdSourceFactory.constructStanzaIdSource();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A builder for XMPP connection configurations.
|
* A builder for XMPP connection configurations.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -612,6 +623,7 @@ public abstract class ConnectionConfiguration {
|
||||||
private Set<String> enabledSaslMechanisms;
|
private Set<String> enabledSaslMechanisms;
|
||||||
private X509TrustManager customX509TrustManager;
|
private X509TrustManager customX509TrustManager;
|
||||||
private boolean compressionEnabled = false;
|
private boolean compressionEnabled = false;
|
||||||
|
private StanzaIdSourceFactory stanzaIdSourceFactory = new StandardStanzaIdSource.Factory();
|
||||||
|
|
||||||
protected Builder() {
|
protected Builder() {
|
||||||
if (SmackConfiguration.DEBUG) {
|
if (SmackConfiguration.DEBUG) {
|
||||||
|
@ -1134,6 +1146,17 @@ public abstract class ConnectionConfiguration {
|
||||||
return getThis();
|
return getThis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the factory for stanza ID sources to use.
|
||||||
|
*
|
||||||
|
* @param stanzaIdSourceFactory the factory for stanza ID sources to use.
|
||||||
|
* @return a reference to this builder.
|
||||||
|
* @since 4.4
|
||||||
|
*/
|
||||||
|
public B setStanzaIdSourceFactory(StanzaIdSourceFactory stanzaIdSourceFactory) {
|
||||||
|
this.stanzaIdSourceFactory = Objects.requireNonNull(stanzaIdSourceFactory);
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
public abstract C build();
|
public abstract C build();
|
||||||
|
|
||||||
|
|
|
@ -175,9 +175,9 @@ public final class SASLAuthentication {
|
||||||
* @return the used SASLMechanism.
|
* @return the used SASLMechanism.
|
||||||
* @throws XMPPErrorException if there was an XMPP error returned.
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
||||||
* @throws SASLErrorException if a SASL protocol error was returned.
|
* @throws SASLErrorException if a SASL protocol error was returned.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws InterruptedException if the calling thread was interrupted.
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
* @throws SmackSaslException if a SASL specific error occured.
|
* @throws SmackSaslException if a SASL specific error occurred.
|
||||||
* @throws NotConnectedException if the XMPP connection is not connected.
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
||||||
* @throws NoResponseException if there was no response from the remote entity.
|
* @throws NoResponseException if there was no response from the remote entity.
|
||||||
*/
|
*/
|
||||||
|
@ -233,7 +233,7 @@ public final class SASLAuthentication {
|
||||||
*
|
*
|
||||||
* @param challenge a base64 encoded string representing the challenge.
|
* @param challenge a base64 encoded string representing the challenge.
|
||||||
* @param finalChallenge true if this is the last challenge send by the server within the success stanza
|
* @param finalChallenge true if this is the last challenge send by the server within the success stanza
|
||||||
* @throws SmackSaslException if a SASL specific error occured.
|
* @throws SmackSaslException if a SASL specific error occurred.
|
||||||
* @throws NotConnectedException if the XMPP connection is not connected.
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
||||||
* @throws InterruptedException if the calling thread was interrupted.
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
*/
|
*/
|
||||||
|
@ -252,7 +252,7 @@ public final class SASLAuthentication {
|
||||||
* @throws SmackException if Smack detected an exceptional situation.
|
* @throws SmackException if Smack detected an exceptional situation.
|
||||||
* @throws InterruptedException if the calling thread was interrupted.
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
* @throws NotConnectedException if the XMPP connection is not connected.
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
||||||
* @throws SmackSaslException if a SASL specific error occured.
|
* @throws SmackSaslException if a SASL specific error occurred.
|
||||||
*/
|
*/
|
||||||
void authenticated(Success success) throws InterruptedException, SmackSaslException, NotConnectedException {
|
void authenticated(Success success) throws InterruptedException, SmackSaslException, NotConnectedException {
|
||||||
// RFC6120 6.3.10 "At the end of the authentication exchange, the SASL server (the XMPP
|
// RFC6120 6.3.10 "At the end of the authentication exchange, the SASL server (the XMPP
|
||||||
|
|
|
@ -49,7 +49,6 @@ import org.jivesoftware.smack.sasl.core.ScramSha1PlusMechanism;
|
||||||
import org.jivesoftware.smack.util.CloseableUtil;
|
import org.jivesoftware.smack.util.CloseableUtil;
|
||||||
import org.jivesoftware.smack.util.FileUtils;
|
import org.jivesoftware.smack.util.FileUtils;
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
|
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,8 +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.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;
|
||||||
|
@ -178,6 +185,8 @@ public interface XMPPConnection {
|
||||||
*/
|
*/
|
||||||
boolean isUsingCompression();
|
boolean isUsingCompression();
|
||||||
|
|
||||||
|
StanzaFactory getStanzaFactory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the specified stanza to the server.
|
* Sends the specified stanza to the server.
|
||||||
*
|
*
|
||||||
|
@ -443,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.
|
||||||
|
|
|
@ -19,7 +19,6 @@ package org.jivesoftware.smack.compress.provider;
|
||||||
import org.jivesoftware.smack.compress.packet.Compressed;
|
import org.jivesoftware.smack.compress.packet.Compressed;
|
||||||
import org.jivesoftware.smack.packet.XmlEnvironment;
|
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
import org.jivesoftware.smack.provider.NonzaProvider;
|
import org.jivesoftware.smack.provider.NonzaProvider;
|
||||||
|
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
|
||||||
public final class CompressedProvider extends NonzaProvider<Compressed> {
|
public final class CompressedProvider extends NonzaProvider<Compressed> {
|
||||||
|
|
|
@ -26,7 +26,6 @@ import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
import org.jivesoftware.smack.parsing.SmackParsingException;
|
import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||||
import org.jivesoftware.smack.provider.NonzaProvider;
|
import org.jivesoftware.smack.provider.NonzaProvider;
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
|
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParserException;
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
|
|
||||||
|
@ -62,8 +61,7 @@ public final class FailureProvider extends NonzaProvider<Failure> {
|
||||||
case StreamOpen.SERVER_NAMESPACE:
|
case StreamOpen.SERVER_NAMESPACE:
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case StanzaError.ERROR:
|
case StanzaError.ERROR:
|
||||||
StanzaError.Builder stanzaErrorBuilder = PacketParserUtils.parseError(parser, failureXmlEnvironment);
|
stanzaError = PacketParserUtils.parseError(parser, failureXmlEnvironment);
|
||||||
stanzaError = stanzaErrorBuilder.build();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGGER.warning("Unknown element in " + namespace + ": " + name);
|
LOGGER.warning("Unknown element in " + namespace + ": " + name);
|
||||||
|
|
|
@ -76,7 +76,7 @@ public class Java7ZlibInputOutputStream extends XMPPInputOutputStream {
|
||||||
* byte without blocking, 0 means that the system is known to block for more input.
|
* byte without blocking, 0 means that the system is known to block for more input.
|
||||||
*
|
*
|
||||||
* @return 0 if no data is available, 1 otherwise
|
* @return 0 if no data is available, 1 otherwise
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int available() throws IOException {
|
public int available() throws IOException {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
import org.jivesoftware.smack.util.ToStringUtil;
|
||||||
|
|
||||||
|
public abstract class AbstractIqBuilder<IB extends AbstractIqBuilder<IB>> extends StanzaBuilder<IB> implements IqView {
|
||||||
|
|
||||||
|
protected IQ.Type type = IQ.Type.get;
|
||||||
|
|
||||||
|
AbstractIqBuilder(AbstractIqBuilder<?> other) {
|
||||||
|
super(other);
|
||||||
|
type = other.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractIqBuilder(StanzaIdSource stanzaIdSource) {
|
||||||
|
super(stanzaIdSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractIqBuilder(String stanzaId) {
|
||||||
|
super(stanzaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IqData createResponse(IqView request) {
|
||||||
|
return createResponse(request, IQ.ResponseType.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IqData createErrorResponse(IqView request) {
|
||||||
|
return createResponse(request, IQ.ResponseType.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static IqData createResponse(IqView request, IQ.ResponseType responseType) {
|
||||||
|
if (!(request.getType() == IQ.Type.get || request.getType() == IQ.Type.set)) {
|
||||||
|
throw new IllegalArgumentException("IQ request must be of type 'set' or 'get'. Original IQ: " + request);
|
||||||
|
}
|
||||||
|
|
||||||
|
IqData commonResponseIqData = buildResponse(request, s -> {
|
||||||
|
return StanzaBuilder.buildIqData(s);
|
||||||
|
});
|
||||||
|
commonResponseIqData.ofType(responseType.getType());
|
||||||
|
|
||||||
|
return commonResponseIqData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final void addStanzaSpecificAttributes(ToStringUtil.Builder builder) {
|
||||||
|
builder.addValue("type", getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final IQ.Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright © 2014 Florian Schmaus
|
* Copyright © 2014-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.
|
||||||
|
@ -18,14 +18,18 @@ package org.jivesoftware.smack.packet;
|
||||||
|
|
||||||
public class EmptyResultIQ extends IQ {
|
public class EmptyResultIQ extends IQ {
|
||||||
|
|
||||||
|
EmptyResultIQ(IqData iqBuilder) {
|
||||||
|
super(iqBuilder, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Deprecate when stanza builder and parsing logic is ready.
|
||||||
public EmptyResultIQ() {
|
public EmptyResultIQ() {
|
||||||
super(null, null);
|
super(null, null);
|
||||||
setType(IQ.Type.result);
|
setType(IQ.Type.result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EmptyResultIQ(IQ request) {
|
public EmptyResultIQ(IQ request) {
|
||||||
this();
|
this(AbstractIqBuilder.createResponse(request));
|
||||||
initializeAsResultFor(request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -27,13 +27,13 @@ public class ErrorIQ extends SimpleIQ {
|
||||||
* <p>
|
* <p>
|
||||||
* According to RFC 6120 § 8.3.1 "4. An error stanza MUST contain an <error/> child element.", so the xmppError argument is mandatory.
|
* According to RFC 6120 § 8.3.1 "4. An error stanza MUST contain an <error/> child element.", so the xmppError argument is mandatory.
|
||||||
* </p>
|
* </p>
|
||||||
* @param xmppErrorBuilder the XMPPError builder (required).
|
* @param stanzaError the stanzaError (required).
|
||||||
*/
|
*/
|
||||||
public ErrorIQ(StanzaError.Builder xmppErrorBuilder) {
|
public ErrorIQ(StanzaError stanzaError) {
|
||||||
super(ELEMENT, null);
|
super(ELEMENT, null);
|
||||||
Objects.requireNonNull(xmppErrorBuilder, "xmppErrorBuilder must not be null");
|
Objects.requireNonNull(stanzaError, "stanzaError must not be null");
|
||||||
setType(IQ.Type.error);
|
setType(IQ.Type.error);
|
||||||
setError(xmppErrorBuilder);
|
setError(stanzaError);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ package org.jivesoftware.smack.packet;
|
||||||
|
|
||||||
import javax.xml.namespace.QName;
|
import javax.xml.namespace.QName;
|
||||||
|
|
||||||
public interface FullyQualifiedElement extends NamedElement {
|
public interface FullyQualifiedElement extends NamedElement, XmlLangElement {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the root element XML namespace.
|
* Returns the root element XML namespace.
|
||||||
|
@ -33,11 +33,7 @@ public interface FullyQualifiedElement extends NamedElement {
|
||||||
return new QName(namespaceURI, localPart);
|
return new QName(namespaceURI, localPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the xml:lang of this XML element, or null if one has not been set.
|
|
||||||
*
|
|
||||||
* @return the xml:lang of this XML element, or null.
|
|
||||||
*/
|
|
||||||
default String getLanguage() {
|
default String getLanguage() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
*
|
*
|
||||||
* @author Matt Tucker
|
* @author Matt Tucker
|
||||||
*/
|
*/
|
||||||
public abstract class IQ extends Stanza {
|
public abstract class IQ extends Stanza implements IqView {
|
||||||
|
|
||||||
// Don't name this field 'ELEMENT'. When it comes to IQ, ELEMENT is the child element!
|
// Don't name this field 'ELEMENT'. When it comes to IQ, ELEMENT is the child element!
|
||||||
public static final String IQ_ELEMENT = "iq";
|
public static final String IQ_ELEMENT = "iq";
|
||||||
|
@ -54,7 +54,7 @@ public abstract class IQ extends Stanza {
|
||||||
|
|
||||||
private Type type = Type.get;
|
private Type type = Type.get;
|
||||||
|
|
||||||
public IQ(IQ iq) {
|
protected IQ(IQ iq) {
|
||||||
super(iq);
|
super(iq);
|
||||||
type = iq.getType();
|
type = iq.getType();
|
||||||
this.childElementName = iq.childElementName;
|
this.childElementName = iq.childElementName;
|
||||||
|
@ -62,7 +62,16 @@ public abstract class IQ extends Stanza {
|
||||||
this.childElementQName = iq.childElementQName;
|
this.childElementQName = iq.childElementQName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Deprecate when stanza builder is ready.
|
||||||
protected IQ(String childElementName, String childElementNamespace) {
|
protected IQ(String childElementName, String childElementNamespace) {
|
||||||
|
this(IqData.EMPTY, childElementName, childElementNamespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IQ(AbstractIqBuilder<?> iqBuilder, String childElementName, String childElementNamespace) {
|
||||||
|
super(iqBuilder);
|
||||||
|
|
||||||
|
type = iqBuilder.type;
|
||||||
|
|
||||||
this.childElementName = childElementName;
|
this.childElementName = childElementName;
|
||||||
this.childElementNamespace = childElementNamespace;
|
this.childElementNamespace = childElementNamespace;
|
||||||
if (childElementName == null) {
|
if (childElementName == null) {
|
||||||
|
@ -72,11 +81,7 @@ public abstract class IQ extends Stanza {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the type of the IQ packet.
|
|
||||||
*
|
|
||||||
* @return the type of the IQ packet.
|
|
||||||
*/
|
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
@ -90,6 +95,7 @@ public abstract class IQ extends Stanza {
|
||||||
*
|
*
|
||||||
* @param type the type of the IQ packet.
|
* @param type the type of the IQ packet.
|
||||||
*/
|
*/
|
||||||
|
// TODO: Mark this as deprecated once StanzaBuilder is ready and all call sites are gone.
|
||||||
public void setType(Type type) {
|
public void setType(Type type) {
|
||||||
this.type = Objects.requireNonNull(type, "type must not be null");
|
this.type = Objects.requireNonNull(type, "type must not be null");
|
||||||
}
|
}
|
||||||
|
@ -260,19 +266,6 @@ public abstract class IQ extends Stanza {
|
||||||
*/
|
*/
|
||||||
protected abstract IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml);
|
protected abstract IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml);
|
||||||
|
|
||||||
protected final void initializeAsResultFor(IQ request) {
|
|
||||||
assert this != request;
|
|
||||||
|
|
||||||
if (!(request.getType() == Type.get || request.getType() == Type.set)) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML());
|
|
||||||
}
|
|
||||||
setStanzaId(request.getStanzaId());
|
|
||||||
setFrom(request.getTo());
|
|
||||||
setTo(request.getFrom());
|
|
||||||
setType(Type.result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method to create a new empty {@link Type#result IQ.Type.result}
|
* Convenience method to create a new empty {@link Type#result IQ.Type.result}
|
||||||
* IQ based on a {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set}
|
* IQ based on a {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set}
|
||||||
|
@ -311,7 +304,7 @@ public abstract class IQ extends Stanza {
|
||||||
* {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set}.
|
* {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set}.
|
||||||
* @return a new {@link Type#error IQ.Type.error} IQ based on the originating IQ.
|
* @return a new {@link Type#error IQ.Type.error} IQ based on the originating IQ.
|
||||||
*/
|
*/
|
||||||
public static ErrorIQ createErrorResponse(final IQ request, final StanzaError.Builder error) {
|
public static ErrorIQ createErrorResponse(final IQ request, final StanzaError error) {
|
||||||
if (!request.isRequestIQ()) {
|
if (!request.isRequestIQ()) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML());
|
"IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML());
|
||||||
|
@ -321,35 +314,25 @@ public abstract class IQ extends Stanza {
|
||||||
result.setFrom(request.getTo());
|
result.setFrom(request.getTo());
|
||||||
result.setTo(request.getFrom());
|
result.setTo(request.getFrom());
|
||||||
|
|
||||||
error.setStanza(result);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ErrorIQ createErrorResponse(final IQ request, final StanzaError.Condition condition) {
|
/**
|
||||||
return createErrorResponse(request, StanzaError.getBuilder(condition));
|
* Deprecated.
|
||||||
|
*
|
||||||
|
* @param request the request.
|
||||||
|
* @param error the error.
|
||||||
|
* @return an error IQ.
|
||||||
|
* @deprecated use {@link #createErrorResponse(IQ, StanzaError)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
|
public static ErrorIQ createErrorResponse(final IQ request, final StanzaError.Builder error) {
|
||||||
|
return createErrorResponse(request, error.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static ErrorIQ createErrorResponse(final IQ request, final StanzaError.Condition condition) {
|
||||||
* Convenience method to create a new {@link Type#error IQ.Type.error} IQ
|
return createErrorResponse(request, StanzaError.getBuilder(condition).build());
|
||||||
* based on a {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set}
|
|
||||||
* IQ. The new stanza will be initialized with:<ul>
|
|
||||||
* <li>The sender set to the recipient of the originating IQ.
|
|
||||||
* <li>The recipient set to the sender of the originating IQ.
|
|
||||||
* <li>The type set to {@link Type#error IQ.Type.error}.
|
|
||||||
* <li>The id set to the id of the originating IQ.
|
|
||||||
* <li>The child element contained in the associated originating IQ.
|
|
||||||
* <li>The provided {@link StanzaError XMPPError}.
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param request the {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set} IQ packet.
|
|
||||||
* @param error the error to associate with the created IQ packet.
|
|
||||||
* @throws IllegalArgumentException if the IQ stanza does not have a type of
|
|
||||||
* {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set}.
|
|
||||||
* @return a new {@link Type#error IQ.Type.error} IQ based on the originating IQ.
|
|
||||||
*/
|
|
||||||
public static ErrorIQ createErrorResponse(final IQ request, final StanzaError error) {
|
|
||||||
return createErrorResponse(request, StanzaError.getBuilder(error));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -392,6 +375,25 @@ public abstract class IQ extends Stanza {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ResponseType {
|
||||||
|
|
||||||
|
result(Type.result),
|
||||||
|
|
||||||
|
error(Type.error),
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
final Type type;
|
||||||
|
|
||||||
|
ResponseType(Type type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class IQChildElementXmlStringBuilder extends XmlStringBuilder {
|
public static class IQChildElementXmlStringBuilder extends XmlStringBuilder {
|
||||||
private final String element;
|
private final String element;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.XMPPConnection;
|
||||||
|
import org.jivesoftware.smack.util.Objects;
|
||||||
|
|
||||||
|
public abstract class IqBuilder<IB extends IqBuilder<IB, I>, I extends IQ>
|
||||||
|
extends AbstractIqBuilder<IB> {
|
||||||
|
|
||||||
|
protected IqBuilder(AbstractIqBuilder<?> other) {
|
||||||
|
super(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IqBuilder(XMPPConnection connection) {
|
||||||
|
super(connection.getStanzaFactory().getStanzaIdSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IqBuilder(String stanzaId) {
|
||||||
|
super(stanzaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IB ofType(IQ.Type type) {
|
||||||
|
this.type = Objects.requireNonNull(type);
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract I build();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.StandardStanzaIdSource;
|
||||||
|
import org.jivesoftware.smack.packet.id.StanzaIdSource;
|
||||||
|
import org.jivesoftware.smack.util.Objects;
|
||||||
|
|
||||||
|
public final class IqData extends AbstractIqBuilder<IqData> {
|
||||||
|
|
||||||
|
static final IqData EMPTY = new IqData(StandardStanzaIdSource.DEFAULT);
|
||||||
|
|
||||||
|
IqData(StanzaIdSource stanzaIdSource) {
|
||||||
|
super(stanzaIdSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
IqData(String stanzaId) {
|
||||||
|
super(stanzaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IqData ofType(IQ.Type type) {
|
||||||
|
this.type = Objects.requireNonNull(type);
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IqData getThis() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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 interface IqView extends StanzaView {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of the IQ packet.
|
||||||
|
*
|
||||||
|
* @return the type of the IQ packet.
|
||||||
|
*/
|
||||||
|
IQ.Type getType();
|
||||||
|
|
||||||
|
}
|
|
@ -24,6 +24,8 @@ import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
|
|
||||||
import org.jivesoftware.smack.util.EqualsUtil;
|
import org.jivesoftware.smack.util.EqualsUtil;
|
||||||
import org.jivesoftware.smack.util.HashCode;
|
import org.jivesoftware.smack.util.HashCode;
|
||||||
import org.jivesoftware.smack.util.Objects;
|
import org.jivesoftware.smack.util.Objects;
|
||||||
|
@ -58,7 +60,8 @@ import org.jxmpp.stringprep.XmppStringprepException;
|
||||||
*
|
*
|
||||||
* @author Matt Tucker
|
* @author Matt Tucker
|
||||||
*/
|
*/
|
||||||
public final class Message extends Stanza implements 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";
|
||||||
|
@ -66,11 +69,12 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
private Type type;
|
private Type type;
|
||||||
private String thread = null;
|
private String thread = null;
|
||||||
|
|
||||||
private final Set<Subject> subjects = new HashSet<Subject>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new, "normal" message.
|
* Creates a new, "normal" message.
|
||||||
|
* @deprecated use {@link StanzaBuilder}, preferable via {@link StanzaFactory}, instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public Message() {
|
public Message() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +82,10 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* Creates a new "normal" message to the specified recipient.
|
* Creates a new "normal" message to the specified recipient.
|
||||||
*
|
*
|
||||||
* @param to the recipient of the message.
|
* @param to the recipient of the message.
|
||||||
|
* @deprecated use {@link StanzaBuilder}, preferable via {@link StanzaFactory}, instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public Message(Jid to) {
|
public Message(Jid to) {
|
||||||
setTo(to);
|
setTo(to);
|
||||||
}
|
}
|
||||||
|
@ -88,7 +95,10 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
*
|
*
|
||||||
* @param to the user to send the message to.
|
* @param to the user to send the message to.
|
||||||
* @param type the message type.
|
* @param type the message type.
|
||||||
|
* @deprecated use {@link StanzaBuilder}, preferable via {@link StanzaFactory}, instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public Message(Jid to, Type type) {
|
public Message(Jid to, Type type) {
|
||||||
this(to);
|
this(to);
|
||||||
setType(type);
|
setType(type);
|
||||||
|
@ -99,7 +109,10 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
*
|
*
|
||||||
* @param to the user to send the message to.
|
* @param to the user to send the message to.
|
||||||
* @param body the body of the message.
|
* @param body the body of the message.
|
||||||
|
* @deprecated use {@link StanzaBuilder}, preferable via {@link StanzaFactory}, instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public Message(Jid to, String body) {
|
public Message(Jid to, String body) {
|
||||||
this(to);
|
this(to);
|
||||||
setBody(body);
|
setBody(body);
|
||||||
|
@ -111,7 +124,10 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* @param to the user to send the message to.
|
* @param to the user to send the message to.
|
||||||
* @param body the body of the message.
|
* @param body the body of the message.
|
||||||
* @throws XmppStringprepException if 'to' is not a valid XMPP address.
|
* @throws XmppStringprepException if 'to' is not a valid XMPP address.
|
||||||
|
* @deprecated use {@link StanzaBuilder}, preferable via {@link StanzaFactory}, instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public Message(String to, String body) throws XmppStringprepException {
|
public Message(String to, String body) throws XmppStringprepException {
|
||||||
this(JidCreate.from(to), body);
|
this(JidCreate.from(to), body);
|
||||||
}
|
}
|
||||||
|
@ -122,12 +138,21 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* @param to TODO javadoc me please
|
* @param to TODO javadoc me please
|
||||||
* @param extensionElement TODO javadoc me please
|
* @param extensionElement TODO javadoc me please
|
||||||
* @since 4.2
|
* @since 4.2
|
||||||
|
* @deprecated use {@link StanzaBuilder}, preferable via {@link StanzaFactory}, instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public Message(Jid to, ExtensionElement extensionElement) {
|
public Message(Jid to, ExtensionElement extensionElement) {
|
||||||
this(to);
|
this(to);
|
||||||
addExtension(extensionElement);
|
addExtension(extensionElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Message(MessageBuilder messageBuilder) {
|
||||||
|
super(messageBuilder);
|
||||||
|
type = messageBuilder.type;
|
||||||
|
thread = messageBuilder.thread;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy constructor.
|
* Copy constructor.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -141,15 +166,9 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
super(other);
|
super(other);
|
||||||
this.type = other.type;
|
this.type = other.type;
|
||||||
this.thread = other.thread;
|
this.thread = other.thread;
|
||||||
this.subjects.addAll(other.subjects);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the type of the message. If no type has been set this method will return {@link
|
|
||||||
* org.jivesoftware.smack.packet.Message.Type#normal}.
|
|
||||||
*
|
|
||||||
* @return the type of the message.
|
|
||||||
*/
|
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
return Type.normal;
|
return Type.normal;
|
||||||
|
@ -161,7 +180,10 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* Sets the type of the message.
|
* Sets the type of the message.
|
||||||
*
|
*
|
||||||
* @param type the type of the message.
|
* @param type the type of the message.
|
||||||
|
* @deprecated use {@link StanzaBuilder} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public void setType(Type type) {
|
public void setType(Type type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
@ -195,8 +217,9 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
|
|
||||||
private Subject getMessageSubject(String language) {
|
private Subject getMessageSubject(String language) {
|
||||||
language = determineLanguage(language);
|
language = determineLanguage(language);
|
||||||
for (Subject subject : subjects) {
|
for (Subject subject : getSubjects()) {
|
||||||
if (Objects.equals(language, subject.language)) {
|
if (Objects.equals(language, subject.language)
|
||||||
|
|| (subject.language == null && Objects.equals(this.language, language))) {
|
||||||
return subject;
|
return subject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,7 +233,12 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* @return a collection of all subjects in this message.
|
* @return a collection of all subjects in this message.
|
||||||
*/
|
*/
|
||||||
public Set<Subject> getSubjects() {
|
public Set<Subject> getSubjects() {
|
||||||
return Collections.unmodifiableSet(subjects);
|
List<Subject> subjectList = getExtensions(Subject.class);
|
||||||
|
|
||||||
|
Set<Subject> subjects = new HashSet<>(subjectList.size());
|
||||||
|
subjects.addAll(subjectList);
|
||||||
|
|
||||||
|
return subjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -218,7 +246,10 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* message contents.
|
* message contents.
|
||||||
*
|
*
|
||||||
* @param subject the subject of the message.
|
* @param subject the subject of the message.
|
||||||
|
* @deprecated use {@link StanzaBuilder} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove when stanza builder is ready.
|
||||||
public void setSubject(String subject) {
|
public void setSubject(String subject) {
|
||||||
if (subject == null) {
|
if (subject == null) {
|
||||||
removeSubject(""); // use empty string because #removeSubject(null) is ambiguous
|
removeSubject(""); // use empty string because #removeSubject(null) is ambiguous
|
||||||
|
@ -235,10 +266,20 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* @return the new {@link org.jivesoftware.smack.packet.Message.Subject}
|
* @return the new {@link org.jivesoftware.smack.packet.Message.Subject}
|
||||||
* @throws NullPointerException if the subject is null, a null pointer exception is thrown
|
* @throws NullPointerException if the subject is null, a null pointer exception is thrown
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove when stanza builder is ready.
|
||||||
public Subject addSubject(String language, String subject) {
|
public Subject addSubject(String language, String subject) {
|
||||||
language = determineLanguage(language);
|
language = determineLanguage(language);
|
||||||
|
|
||||||
|
List<Subject> currentSubjects = getExtensions(Subject.class);
|
||||||
|
for (Subject currentSubject : currentSubjects) {
|
||||||
|
if (language.equals(currentSubject.getLanguage())) {
|
||||||
|
throw new IllegalArgumentException("Subject with the language " + language + " already exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Subject messageSubject = new Subject(language, subject);
|
Subject messageSubject = new Subject(language, subject);
|
||||||
subjects.add(messageSubject);
|
addExtension(messageSubject);
|
||||||
return messageSubject;
|
return messageSubject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,11 +289,13 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* @param language the language of the subject which is to be removed
|
* @param language the language of the subject which is to be removed
|
||||||
* @return true if a subject was removed and false if it was not.
|
* @return true if a subject was removed and false if it was not.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove when stanza builder is ready.
|
||||||
public boolean removeSubject(String language) {
|
public boolean removeSubject(String language) {
|
||||||
language = determineLanguage(language);
|
language = determineLanguage(language);
|
||||||
for (Subject subject : subjects) {
|
for (Subject subject : getExtensions(Subject.class)) {
|
||||||
if (language.equals(subject.language)) {
|
if (language.equals(subject.language)) {
|
||||||
return subjects.remove(subject);
|
return removeSubject(subject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -264,8 +307,10 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* @param subject the subject being removed from the message.
|
* @param subject the subject being removed from the message.
|
||||||
* @return true if the subject was successfully removed and false if it was not.
|
* @return true if the subject was successfully removed and false if it was not.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove when stanza builder is ready.
|
||||||
public boolean removeSubject(Subject subject) {
|
public boolean removeSubject(Subject subject) {
|
||||||
return subjects.remove(subject);
|
return removeExtension(subject) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -276,7 +321,7 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
public List<String> getSubjectLanguages() {
|
public List<String> getSubjectLanguages() {
|
||||||
Subject defaultSubject = getMessageSubject(null);
|
Subject defaultSubject = getMessageSubject(null);
|
||||||
List<String> languages = new ArrayList<String>();
|
List<String> languages = new ArrayList<String>();
|
||||||
for (Subject subject : subjects) {
|
for (Subject subject : getExtensions(Subject.class)) {
|
||||||
if (!subject.equals(defaultSubject)) {
|
if (!subject.equals(defaultSubject)) {
|
||||||
languages.add(subject.language);
|
languages.add(subject.language);
|
||||||
}
|
}
|
||||||
|
@ -345,7 +390,10 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* @param body the body of the message.
|
* @param body the body of the message.
|
||||||
* @see #setBody(String)
|
* @see #setBody(String)
|
||||||
* @since 4.2
|
* @since 4.2
|
||||||
|
* @deprecated use {@link StanzaBuilder} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove when stanza builder is ready.
|
||||||
public void setBody(CharSequence body) {
|
public void setBody(CharSequence body) {
|
||||||
String bodyString;
|
String bodyString;
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
|
@ -360,7 +408,10 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* Sets the body of the message. The body is the main message contents.
|
* Sets the body of the message. The body is the main message contents.
|
||||||
*
|
*
|
||||||
* @param body the body of the message.
|
* @param body the body of the message.
|
||||||
|
* @deprecated use {@link StanzaBuilder} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove when stanza builder is ready.
|
||||||
public void setBody(String body) {
|
public void setBody(String body) {
|
||||||
if (body == null) {
|
if (body == null) {
|
||||||
removeBody(""); // use empty string because #removeBody(null) is ambiguous
|
removeBody(""); // use empty string because #removeBody(null) is ambiguous
|
||||||
|
@ -377,7 +428,10 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* @return the new {@link org.jivesoftware.smack.packet.Message.Body}
|
* @return the new {@link org.jivesoftware.smack.packet.Message.Body}
|
||||||
* @throws NullPointerException if the body is null, a null pointer exception is thrown
|
* @throws NullPointerException if the body is null, a null pointer exception is thrown
|
||||||
* @since 3.0.2
|
* @since 3.0.2
|
||||||
|
* @deprecated use {@link StanzaBuilder} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove when stanza builder is ready.
|
||||||
public Body addBody(String language, String body) {
|
public Body addBody(String language, String body) {
|
||||||
language = determineLanguage(language);
|
language = determineLanguage(language);
|
||||||
|
|
||||||
|
@ -393,7 +447,10 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
*
|
*
|
||||||
* @param language the language of the body which is to be removed
|
* @param language the language of the body which is to be removed
|
||||||
* @return true if a body was removed and false if it was not.
|
* @return true if a body was removed and false if it was not.
|
||||||
|
* @deprecated use {@link StanzaBuilder} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove when stanza builder is ready.
|
||||||
public boolean removeBody(String language) {
|
public boolean removeBody(String language) {
|
||||||
language = determineLanguage(language);
|
language = determineLanguage(language);
|
||||||
for (Body body : getBodies()) {
|
for (Body body : getBodies()) {
|
||||||
|
@ -412,7 +469,10 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* @param body the body being removed from the message.
|
* @param body the body being removed from the message.
|
||||||
* @return true if the body was successfully removed and false if it was not.
|
* @return true if the body was successfully removed and false if it was not.
|
||||||
* @since 3.0.2
|
* @since 3.0.2
|
||||||
|
* @deprecated use {@link StanzaBuilder} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove when stanza builder is ready.
|
||||||
public boolean removeBody(Body body) {
|
public boolean removeBody(Body body) {
|
||||||
ExtensionElement removedElement = removeExtension(body);
|
ExtensionElement removedElement = removeExtension(body);
|
||||||
return removedElement != null;
|
return removedElement != null;
|
||||||
|
@ -450,7 +510,10 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
* of "chat" messages.
|
* of "chat" messages.
|
||||||
*
|
*
|
||||||
* @param thread the thread id of the message.
|
* @param thread the thread id of the message.
|
||||||
|
* @deprecated use {@link StanzaBuilder} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove when stanza builder is ready.
|
||||||
public void setThread(String thread) {
|
public void setThread(String thread) {
|
||||||
this.thread = thread;
|
this.thread = thread;
|
||||||
}
|
}
|
||||||
|
@ -472,6 +535,11 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
return ELEMENT;
|
return ELEMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MessageBuilder asBuilder() {
|
||||||
|
return StanzaBuilder.buildMessageFrom(this, getStanzaId());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
@ -491,18 +559,6 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
buf.optAttribute("type", type);
|
buf.optAttribute("type", type);
|
||||||
buf.rightAngleBracket();
|
buf.rightAngleBracket();
|
||||||
|
|
||||||
// Add the subject in the default language
|
|
||||||
Subject defaultSubject = getMessageSubject(null);
|
|
||||||
if (defaultSubject != null) {
|
|
||||||
buf.element("subject", defaultSubject.subject);
|
|
||||||
}
|
|
||||||
// Add the subject in other languages
|
|
||||||
for (Subject subject : getSubjects()) {
|
|
||||||
// Skip the default language
|
|
||||||
if (subject.equals(defaultSubject))
|
|
||||||
continue;
|
|
||||||
buf.append(subject);
|
|
||||||
}
|
|
||||||
buf.optElement("thread", thread);
|
buf.optElement("thread", thread);
|
||||||
// Append the error subpacket if the message type is an error.
|
// Append the error subpacket if the message type is an error.
|
||||||
if (type == Type.error) {
|
if (type == Type.error) {
|
||||||
|
@ -537,10 +593,12 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
public static final String ELEMENT = "subject";
|
public static final String ELEMENT = "subject";
|
||||||
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);
|
||||||
|
|
||||||
private final String subject;
|
private final String subject;
|
||||||
private final String language;
|
private final String language;
|
||||||
|
|
||||||
private Subject(String language, String subject) {
|
public Subject(String language, String subject) {
|
||||||
if (subject == null) {
|
if (subject == null) {
|
||||||
throw new NullPointerException("Subject cannot be null.");
|
throw new NullPointerException("Subject cannot be null.");
|
||||||
}
|
}
|
||||||
|
@ -608,6 +666,7 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
|
||||||
|
|
||||||
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),
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.Message.Body;
|
||||||
|
import org.jivesoftware.smack.packet.Message.Subject;
|
||||||
|
import org.jivesoftware.smack.packet.id.StanzaIdSource;
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
import org.jivesoftware.smack.util.ToStringUtil;
|
||||||
|
|
||||||
|
public final class MessageBuilder extends MessageOrPresenceBuilder<Message, MessageBuilder> implements MessageView {
|
||||||
|
static final MessageBuilder EMPTY = new MessageBuilder(() -> {
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
Message.Type type;
|
||||||
|
|
||||||
|
String thread;
|
||||||
|
|
||||||
|
MessageBuilder(Message message, String stanzaId) {
|
||||||
|
super(message, stanzaId);
|
||||||
|
copyFromMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageBuilder(Message message, StanzaIdSource stanzaIdSource) {
|
||||||
|
super(message, stanzaIdSource);
|
||||||
|
copyFromMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageBuilder(StanzaIdSource stanzaIdSource) {
|
||||||
|
super(stanzaIdSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageBuilder(String stanzaId) {
|
||||||
|
super(stanzaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyFromMessage(Message message) {
|
||||||
|
type = message.getType();
|
||||||
|
thread = message.getThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addStanzaSpecificAttributes(ToStringUtil.Builder builder) {
|
||||||
|
builder.addValue("type", type)
|
||||||
|
.addValue("thread", thread)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageBuilder ofType(Message.Type type) {
|
||||||
|
this.type = type;
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageBuilder setThread(String thread) {
|
||||||
|
this.thread = thread;
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the subject of the message. The subject is a short description of
|
||||||
|
* message contents.
|
||||||
|
*
|
||||||
|
* @param subject the subject of the message.
|
||||||
|
* @return a reference to this builder.
|
||||||
|
*/
|
||||||
|
public MessageBuilder setSubject(String subject) {
|
||||||
|
return addSubject(null, subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a subject with a corresponding language.
|
||||||
|
*
|
||||||
|
* @param language the language of the subject being added.
|
||||||
|
* @param subject the subject being added to the message.
|
||||||
|
* @return a reference to this builder.
|
||||||
|
* @throws NullPointerException if the subject is null.
|
||||||
|
*/
|
||||||
|
public MessageBuilder addSubject(String language, String subject) {
|
||||||
|
language = StringUtils.requireNullOrNotEmpty(language, "language must be null or not empty");
|
||||||
|
|
||||||
|
for (Subject currentSubject : getExtensions(Subject.class)) {
|
||||||
|
if (StringUtils.nullSafeCharSequenceEquals(language, currentSubject.getLanguage())) {
|
||||||
|
throw new IllegalArgumentException("Subject with the language " + language + " already exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Subject messageSubject = new Subject(language, subject);
|
||||||
|
addExtension(messageSubject);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the body of the message.
|
||||||
|
*
|
||||||
|
* @param body the body of the message.
|
||||||
|
* @return a reference to this builder.
|
||||||
|
* @see #setBody(String)
|
||||||
|
*/
|
||||||
|
public MessageBuilder setBody(CharSequence body) {
|
||||||
|
return setBody(body.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the body of the message. The body is the main message contents.
|
||||||
|
*
|
||||||
|
* @param body the body of the message.
|
||||||
|
* @return a reference to this builder.
|
||||||
|
*/
|
||||||
|
public MessageBuilder setBody(String body) {
|
||||||
|
return addBody(null, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a body with a corresponding language.
|
||||||
|
*
|
||||||
|
* @param language the language of the body being added.
|
||||||
|
* @param body the body being added to the message.
|
||||||
|
* @return a reference to this builder.
|
||||||
|
*/
|
||||||
|
public MessageBuilder addBody(String language, String body) {
|
||||||
|
language = StringUtils.requireNullOrNotEmpty(language, "language must be null or not empty");
|
||||||
|
|
||||||
|
for (Body currentBody : getExtensions(Body.class)) {
|
||||||
|
if (StringUtils.nullSafeCharSequenceEquals(language, currentBody.getLanguage())) {
|
||||||
|
throw new IllegalArgumentException("Bodyt with the language " + language + " already exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Body messageBody = new Body(language, body);
|
||||||
|
addExtension(messageBody);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MessageBuilder getThis() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message build() {
|
||||||
|
return new Message(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message.Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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 interface MessageView extends StanzaView {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of the message. If no type has been set this method will return {@link
|
||||||
|
* org.jivesoftware.smack.packet.Message.Type#normal}.
|
||||||
|
*
|
||||||
|
* @return the type of the message.
|
||||||
|
*/
|
||||||
|
Message.Type getType();
|
||||||
|
|
||||||
|
}
|
|
@ -19,7 +19,8 @@ package org.jivesoftware.smack.packet;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.id.StanzaIdUtil;
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import org.jivesoftware.smack.util.Objects;
|
import org.jivesoftware.smack.util.Objects;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
import org.jivesoftware.smack.util.TypedCloneable;
|
import org.jivesoftware.smack.util.TypedCloneable;
|
||||||
|
@ -60,7 +61,8 @@ import org.jxmpp.jid.Jid;
|
||||||
*
|
*
|
||||||
* @author Matt Tucker
|
* @author Matt Tucker
|
||||||
*/
|
*/
|
||||||
public final class Presence extends Stanza implements 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";
|
||||||
|
|
||||||
|
@ -81,7 +83,10 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
* Creates a new presence update. Status, priority, and mode are left un-set.
|
* Creates a new presence update. Status, priority, and mode are left un-set.
|
||||||
*
|
*
|
||||||
* @param type the type.
|
* @param type the type.
|
||||||
|
* @deprecated use {@link StanzaBuilder} or {@link SocketFactory} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public Presence(Type type) {
|
public Presence(Type type) {
|
||||||
// Ensure that the stanza ID is set by calling super().
|
// Ensure that the stanza ID is set by calling super().
|
||||||
super();
|
super();
|
||||||
|
@ -94,7 +99,10 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
* @param to the recipient.
|
* @param to the recipient.
|
||||||
* @param type the type.
|
* @param type the type.
|
||||||
* @since 4.2
|
* @since 4.2
|
||||||
|
* @deprecated use {@link StanzaBuilder} or {@link SocketFactory} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public Presence(Jid to, Type type) {
|
public Presence(Jid to, Type type) {
|
||||||
this(type);
|
this(type);
|
||||||
setTo(to);
|
setTo(to);
|
||||||
|
@ -107,7 +115,10 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
* @param status a text message describing the presence update.
|
* @param status a text message describing the presence update.
|
||||||
* @param priority the priority of this presence update.
|
* @param priority the priority of this presence update.
|
||||||
* @param mode the mode type for this presence update.
|
* @param mode the mode type for this presence update.
|
||||||
|
* @deprecated use {@link StanzaBuilder} or {@link SocketFactory} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public Presence(Type type, String status, int priority, Mode mode) {
|
public Presence(Type type, String status, int priority, Mode mode) {
|
||||||
// Ensure that the stanza ID is set by calling super().
|
// Ensure that the stanza ID is set by calling super().
|
||||||
super();
|
super();
|
||||||
|
@ -117,6 +128,14 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
setMode(mode);
|
setMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Presence(PresenceBuilder presenceBuilder) {
|
||||||
|
super(presenceBuilder);
|
||||||
|
type = presenceBuilder.type;
|
||||||
|
status = presenceBuilder.status;
|
||||||
|
priority = presenceBuilder.priority;
|
||||||
|
mode = presenceBuilder.mode;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy constructor.
|
* Copy constructor.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -163,11 +182,7 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
return type == Type.available && (mode == Mode.away || mode == Mode.xa || mode == Mode.dnd);
|
return type == Type.available && (mode == Mode.away || mode == Mode.xa || mode == Mode.dnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the type of this presence packet.
|
|
||||||
*
|
|
||||||
* @return the type of the presence packet.
|
|
||||||
*/
|
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
@ -176,18 +191,15 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
* Sets the type of the presence packet.
|
* Sets the type of the presence packet.
|
||||||
*
|
*
|
||||||
* @param type the type of the presence packet.
|
* @param type the type of the presence packet.
|
||||||
|
* @deprecated use {@link StanzaBuilder} or {@link SocketFactory} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public void setType(Type type) {
|
public void setType(Type type) {
|
||||||
this.type = Objects.requireNonNull(type, "Type cannot be null");
|
this.type = Objects.requireNonNull(type, "Type cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the status message of the presence update, or <code>null</code> if there
|
|
||||||
* is not a status. The status is free-form text describing a user's presence
|
|
||||||
* (i.e., "gone to lunch").
|
|
||||||
*
|
|
||||||
* @return the status message.
|
|
||||||
*/
|
|
||||||
public String getStatus() {
|
public String getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -197,18 +209,21 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
* describing a user's presence (i.e., "gone to lunch").
|
* describing a user's presence (i.e., "gone to lunch").
|
||||||
*
|
*
|
||||||
* @param status the status message.
|
* @param status the status message.
|
||||||
|
* @deprecated use {@link StanzaBuilder} or {@link SocketFactory} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public void setStatus(String status) {
|
public void setStatus(String status) {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the priority of the presence.
|
|
||||||
*
|
|
||||||
* @return the priority.
|
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc6121#section-4.7.2.3">RFC 6121 § 4.7.2.3. Priority Element</a>
|
|
||||||
*/
|
|
||||||
public int getPriority() {
|
public int getPriority() {
|
||||||
|
return getPriorityByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getPriorityByte() {
|
||||||
if (priority == null) {
|
if (priority == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -221,7 +236,10 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
* @param priority the priority of the presence.
|
* @param priority the priority of the presence.
|
||||||
* @throws IllegalArgumentException if the priority is outside the valid range.
|
* @throws IllegalArgumentException if the priority is outside the valid range.
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc6121#section-4.7.2.3">RFC 6121 § 4.7.2.3. Priority Element</a>
|
* @see <a href="https://tools.ietf.org/html/rfc6121#section-4.7.2.3">RFC 6121 § 4.7.2.3. Priority Element</a>
|
||||||
|
* @deprecated use {@link StanzaBuilder} or {@link SocketFactory} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public void setPriority(int priority) {
|
public void setPriority(int priority) {
|
||||||
if (priority < -128 || priority > 127) {
|
if (priority < -128 || priority > 127) {
|
||||||
throw new IllegalArgumentException("Priority value " + priority +
|
throw new IllegalArgumentException("Priority value " + priority +
|
||||||
|
@ -234,11 +252,7 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
this.priority = priority;
|
this.priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the mode of the presence update.
|
|
||||||
*
|
|
||||||
* @return the mode.
|
|
||||||
*/
|
|
||||||
public Mode getMode() {
|
public Mode getMode() {
|
||||||
if (mode == null) {
|
if (mode == null) {
|
||||||
return Mode.available;
|
return Mode.available;
|
||||||
|
@ -251,7 +265,10 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
* to be the same thing as {@link Presence.Mode#available}.
|
* to be the same thing as {@link Presence.Mode#available}.
|
||||||
*
|
*
|
||||||
* @param mode the mode.
|
* @param mode the mode.
|
||||||
|
* @deprecated use {@link StanzaBuilder} or {@link SocketFactory} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public void setMode(Mode mode) {
|
public void setMode(Mode mode) {
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
}
|
}
|
||||||
|
@ -261,6 +278,11 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
return ELEMENT;
|
return ELEMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PresenceBuilder asBuilder() {
|
||||||
|
return StanzaBuilder.buildPresenceFrom(this, getStanzaId());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
@ -326,7 +348,7 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
*/
|
*/
|
||||||
public Presence cloneWithNewId() {
|
public Presence cloneWithNewId() {
|
||||||
Presence clone = clone();
|
Presence clone = clone();
|
||||||
clone.setStanzaId(StanzaIdUtil.newStanzaId());
|
clone.setNewStanzaId();
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.Presence.Mode;
|
||||||
|
import org.jivesoftware.smack.packet.id.StanzaIdSource;
|
||||||
|
import org.jivesoftware.smack.util.Objects;
|
||||||
|
import org.jivesoftware.smack.util.ToStringUtil;
|
||||||
|
|
||||||
|
public final class PresenceBuilder extends MessageOrPresenceBuilder<Presence, PresenceBuilder> implements PresenceView {
|
||||||
|
static final PresenceBuilder EMPTY = new PresenceBuilder(() -> {
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
Presence.Type type = Presence.Type.available;
|
||||||
|
|
||||||
|
String status;
|
||||||
|
|
||||||
|
Byte priority;
|
||||||
|
|
||||||
|
Presence.Mode mode;
|
||||||
|
|
||||||
|
PresenceBuilder(Presence presence, String stanzaId) {
|
||||||
|
super(presence, stanzaId);
|
||||||
|
copyFromPresence(presence);
|
||||||
|
}
|
||||||
|
|
||||||
|
PresenceBuilder(Presence presence, StanzaIdSource stanzaIdSource) {
|
||||||
|
super(presence, stanzaIdSource);
|
||||||
|
copyFromPresence(presence);
|
||||||
|
}
|
||||||
|
|
||||||
|
PresenceBuilder(StanzaIdSource stanzaIdSource) {
|
||||||
|
super(stanzaIdSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
PresenceBuilder(String stanzaId) {
|
||||||
|
super(stanzaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyFromPresence(Presence presence) {
|
||||||
|
type = presence.getType();
|
||||||
|
status = presence.getStatus();
|
||||||
|
priority = presence.getPriorityByte();
|
||||||
|
mode = presence.getMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addStanzaSpecificAttributes(ToStringUtil.Builder builder) {
|
||||||
|
builder.addValue("type", type)
|
||||||
|
.addValue("mode", mode)
|
||||||
|
.addValue("priority", priority)
|
||||||
|
.addValue("status", status)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PresenceBuilder ofType(Presence.Type type) {
|
||||||
|
this.type = Objects.requireNonNull(type, "Type cannot be null");
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PresenceBuilder setStatus(String status) {
|
||||||
|
this.status = status;
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PresenceBuilder setPriority(int priority) {
|
||||||
|
if (priority < -128 || priority > 127) {
|
||||||
|
throw new IllegalArgumentException("Priority value " + priority +
|
||||||
|
" is not valid. Valid range is -128 through 127.");
|
||||||
|
}
|
||||||
|
Byte priorityByte = (byte) priority;
|
||||||
|
return setPriority(priorityByte);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PresenceBuilder setPriority(Byte priority) {
|
||||||
|
this.priority = priority;
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PresenceBuilder setMode(Presence.Mode mode) {
|
||||||
|
this.mode = mode;
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PresenceBuilder getThis() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Presence build() {
|
||||||
|
return new Presence(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Presence.Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPriority() {
|
||||||
|
return getPriorityByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getPriorityByte() {
|
||||||
|
if (priority == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Presence.Mode getMode() {
|
||||||
|
if (mode == null) {
|
||||||
|
return Mode.available;
|
||||||
|
}
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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 interface PresenceView extends StanzaView {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of this presence stanza.
|
||||||
|
*
|
||||||
|
* @return the type of the presence stanza.
|
||||||
|
*/
|
||||||
|
Presence.Type getType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the status message of the presence update, or <code>null</code> if there
|
||||||
|
* is not a status. The status is free-form text describing a user's presence
|
||||||
|
* (i.e., "gone to lunch").
|
||||||
|
*
|
||||||
|
* @return the status message.
|
||||||
|
*/
|
||||||
|
String getStatus();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the priority of the presence.
|
||||||
|
*
|
||||||
|
* @return the priority.
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6121#section-4.7.2.3">RFC 6121 § 4.7.2.3. Priority Element</a>
|
||||||
|
*/
|
||||||
|
int getPriority();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the priority of the presence.
|
||||||
|
*
|
||||||
|
* @return the priority.
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6121#section-4.7.2.3">RFC 6121 § 4.7.2.3. Priority Element</a>
|
||||||
|
*/
|
||||||
|
byte getPriorityByte();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mode of the presence update.
|
||||||
|
*
|
||||||
|
* @return the mode.
|
||||||
|
*/
|
||||||
|
Presence.Mode getMode();
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright © 2014 Florian Schmaus
|
* Copyright © 2014-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.
|
||||||
|
@ -29,6 +29,10 @@ public abstract class SimpleIQ extends IQ {
|
||||||
super(childElementName, childElementNamespace);
|
super(childElementName, childElementNamespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected SimpleIQ(IqData iqBuilder, String childElementName, String childElementNamespace) {
|
||||||
|
super(iqBuilder, childElementName, childElementNamespace);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
xml.setEmptyElement();
|
xml.setEmptyElement();
|
||||||
|
|
|
@ -20,15 +20,19 @@ package org.jivesoftware.smack.packet;
|
||||||
import static org.jivesoftware.smack.util.StringUtils.requireNotNullNorEmpty;
|
import static org.jivesoftware.smack.util.StringUtils.requireNotNullNorEmpty;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import javax.xml.namespace.QName;
|
import javax.xml.namespace.QName;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.id.StanzaIdUtil;
|
import org.jivesoftware.smack.packet.id.StandardStanzaIdSource;
|
||||||
|
import org.jivesoftware.smack.packet.id.StanzaIdSource;
|
||||||
import org.jivesoftware.smack.util.MultiMap;
|
import org.jivesoftware.smack.util.MultiMap;
|
||||||
import org.jivesoftware.smack.util.PacketUtil;
|
import org.jivesoftware.smack.util.PacketUtil;
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
import org.jivesoftware.smack.util.XmppElementUtil;
|
||||||
|
|
||||||
import org.jxmpp.jid.Jid;
|
import org.jxmpp.jid.Jid;
|
||||||
|
|
||||||
|
@ -43,12 +47,16 @@ import org.jxmpp.jid.Jid;
|
||||||
* XMPP Stanzas are {@link Message}, {@link IQ} and {@link Presence}. Which therefore subclass this
|
* XMPP Stanzas are {@link Message}, {@link IQ} and {@link Presence}. Which therefore subclass this
|
||||||
* class. <b>If you think you need to subclass this class, then you are doing something wrong.</b>
|
* class. <b>If you think you need to subclass this class, then you are doing something wrong.</b>
|
||||||
* </p>
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Use {@link StanzaBuilder} to construct a stanza instance. All instance mutating methods of this
|
||||||
|
* class are deprecated, although not all of them are currently marked as such, and must not be used.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @author Matt Tucker
|
* @author Matt Tucker
|
||||||
* @author Florian Schmaus
|
* @author Florian Schmaus
|
||||||
* @see <a href="http://xmpp.org/rfcs/rfc6120.html#stanzas">RFC 6120 § 8. XML Stanzas</a>
|
* @see <a href="http://xmpp.org/rfcs/rfc6120.html#stanzas">RFC 6120 § 8. XML Stanzas</a>
|
||||||
*/
|
*/
|
||||||
public abstract class Stanza implements TopLevelStreamElement {
|
public abstract class Stanza implements StanzaView, TopLevelStreamElement {
|
||||||
|
|
||||||
public static final String TEXT = "text";
|
public static final String TEXT = "text";
|
||||||
public static final String ITEM = "item";
|
public static final String ITEM = "item";
|
||||||
|
@ -56,12 +64,14 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
protected static final String DEFAULT_LANGUAGE =
|
protected static final String DEFAULT_LANGUAGE =
|
||||||
java.util.Locale.getDefault().getLanguage().toLowerCase(Locale.US);
|
java.util.Locale.getDefault().getLanguage().toLowerCase(Locale.US);
|
||||||
|
|
||||||
private final MultiMap<QName, ExtensionElement> extensionElements = new MultiMap<>();
|
private final MultiMap<QName, ExtensionElement> extensionElements;
|
||||||
|
|
||||||
// Assume that all stanzas Smack handles are in the client namespace, since Smack is an XMPP client library. We can
|
// Assume that all stanzas Smack handles are in the client namespace, since Smack is an XMPP client library. We can
|
||||||
// change this behavior later if it is required.
|
// change this behavior later if it is required.
|
||||||
private final String namespace = StreamOpen.CLIENT_NAMESPACE;
|
private final String namespace = StreamOpen.CLIENT_NAMESPACE;
|
||||||
|
|
||||||
|
private final StanzaIdSource usedStanzaIdSource;
|
||||||
|
|
||||||
private String id = null;
|
private String id = null;
|
||||||
private Jid to;
|
private Jid to;
|
||||||
private Jid from;
|
private Jid from;
|
||||||
|
@ -80,31 +90,47 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
protected String language;
|
protected String language;
|
||||||
|
|
||||||
protected Stanza() {
|
protected Stanza() {
|
||||||
this(StanzaIdUtil.newStanzaId());
|
extensionElements = new MultiMap<>();
|
||||||
|
usedStanzaIdSource = null;
|
||||||
|
id = StandardStanzaIdSource.DEFAULT.getNewStanzaId();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Stanza(String stanzaId) {
|
protected Stanza(StanzaBuilder<?> stanzaBuilder) {
|
||||||
setStanzaId(stanzaId);
|
if (stanzaBuilder.stanzaIdSource != null) {
|
||||||
|
id = stanzaBuilder.stanzaIdSource.getNewStanzaId();
|
||||||
|
// Note that some stanza ID sources, e.g. StanzaBuilder.PresenceBuilder.EMPTY return null here. Hence we
|
||||||
|
// only check that the returned string is not empty.
|
||||||
|
assert StringUtils.isNullOrNotEmpty(id);
|
||||||
|
usedStanzaIdSource = stanzaBuilder.stanzaIdSource;
|
||||||
|
} else {
|
||||||
|
// N.B. It is ok if stanzaId here is null.
|
||||||
|
id = stanzaBuilder.stanzaId;
|
||||||
|
usedStanzaIdSource = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
to = stanzaBuilder.to;
|
||||||
|
from = stanzaBuilder.from;
|
||||||
|
|
||||||
|
error = stanzaBuilder.stanzaError;
|
||||||
|
|
||||||
|
language = stanzaBuilder.language;
|
||||||
|
|
||||||
|
extensionElements = stanzaBuilder.extensionElements.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Stanza(Stanza p) {
|
protected Stanza(Stanza p) {
|
||||||
|
usedStanzaIdSource = p.usedStanzaIdSource;
|
||||||
|
|
||||||
id = p.getStanzaId();
|
id = p.getStanzaId();
|
||||||
to = p.getTo();
|
to = p.getTo();
|
||||||
from = p.getFrom();
|
from = p.getFrom();
|
||||||
error = p.error;
|
error = p.error;
|
||||||
|
|
||||||
// Copy extensions
|
extensionElements = p.extensionElements.clone();
|
||||||
for (ExtensionElement pe : p.getExtensions()) {
|
|
||||||
addExtension(pe);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the unique ID of the stanza. The returned value could be <code>null</code>.
|
public final String getStanzaId() {
|
||||||
*
|
|
||||||
* @return the packet's unique ID or <code>null</code> if the id is not available.
|
|
||||||
*/
|
|
||||||
public String getStanzaId() {
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +153,7 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
* @return true if the stanza ID is set, false otherwise.
|
* @return true if the stanza ID is set, false otherwise.
|
||||||
* @since 4.1
|
* @since 4.1
|
||||||
*/
|
*/
|
||||||
public boolean hasStanzaIdSet() {
|
public final boolean hasStanzaIdSet() {
|
||||||
// setStanzaId ensures that the id is either null or not empty,
|
// setStanzaId ensures that the id is either null or not empty,
|
||||||
// so we can assume that it is set if it's not null.
|
// so we can assume that it is set if it's not null.
|
||||||
return id != null;
|
return id != null;
|
||||||
|
@ -138,57 +164,51 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
*
|
*
|
||||||
* @return the stanza id.
|
* @return the stanza id.
|
||||||
* @since 4.2
|
* @since 4.2
|
||||||
* @deprecated use {@link #setNewStanzaId()} instead.
|
* @deprecated use {@link StanzaBuilder} instead.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
// TODO: Remove in Smack 4.5.
|
// TODO: Remove in Smack 4.5.
|
||||||
public String setStanzaId() {
|
public String setStanzaId() {
|
||||||
return ensureStanzaIdSet();
|
if (!hasStanzaIdSet()) {
|
||||||
}
|
setNewStanzaId();
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a new stanza ID even if there is already one set.
|
|
||||||
*
|
|
||||||
* @return the stanza id.
|
|
||||||
* @since 4.4
|
|
||||||
*/
|
|
||||||
public String setNewStanzaId() {
|
|
||||||
return ensureStanzaIdSet(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure a stanza id is set.
|
|
||||||
*
|
|
||||||
* @return the stanza id.
|
|
||||||
* @since 4.4
|
|
||||||
*/
|
|
||||||
public String ensureStanzaIdSet() {
|
|
||||||
return ensureStanzaIdSet(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure that a stanza ID is set.
|
|
||||||
*
|
|
||||||
* @param forceNew force a new ID even if there is already one set.
|
|
||||||
* @return the stanza ID.
|
|
||||||
* @since 4.4
|
|
||||||
*/
|
|
||||||
private String ensureStanzaIdSet(boolean forceNew) {
|
|
||||||
if (forceNew || !hasStanzaIdSet()) {
|
|
||||||
setStanzaId(StanzaIdUtil.newStanzaId());
|
|
||||||
}
|
}
|
||||||
return getStanzaId();
|
return getStanzaId();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns who the stanza is being sent "to", or <code>null</code> if
|
* Throws an {@link IllegalArgumentException} if this stanza has no stanza ID set.
|
||||||
* the value is not set. The XMPP protocol often makes the "to"
|
|
||||||
* attribute optional, so it does not always need to be set.<p>
|
|
||||||
*
|
*
|
||||||
* @return who the stanza is being sent to, or <code>null</code> if the
|
* @throws IllegalArgumentException if this stanza has no stanza ID set.
|
||||||
* value has not been set.
|
* @since 4.4.
|
||||||
*/
|
*/
|
||||||
public Jid getTo() {
|
public final void throwIfNoStanzaId() {
|
||||||
|
if (hasStanzaIdSet()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("The stanza has no RFC stanza ID set, although one is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure that a stanza ID is set.
|
||||||
|
*
|
||||||
|
* @return the stanza ID.
|
||||||
|
* @since 4.4
|
||||||
|
*/
|
||||||
|
// TODO: Remove this method once StanzaBuilder is ready.
|
||||||
|
protected String setNewStanzaId() {
|
||||||
|
if (usedStanzaIdSource != null) {
|
||||||
|
id = usedStanzaIdSource.getNewStanzaId();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
id = StandardStanzaIdSource.DEFAULT.getNewStanzaId();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getStanzaId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Jid getTo() {
|
||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,19 +218,13 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
*
|
*
|
||||||
* @param to who the packet is being sent to.
|
* @param to who the packet is being sent to.
|
||||||
*/
|
*/
|
||||||
|
// TODO: Mark this as deprecated once StanzaBuilder is ready and all call sites are gone.
|
||||||
public void setTo(Jid to) {
|
public void setTo(Jid to) {
|
||||||
this.to = to;
|
this.to = to;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns who the stanza is being sent "from" or <code>null</code> if
|
public final Jid getFrom() {
|
||||||
* the value is not set. The XMPP protocol often makes the "from"
|
|
||||||
* attribute optional, so it does not always need to be set.<p>
|
|
||||||
*
|
|
||||||
* @return who the stanza is being sent from, or <code>null</code> if the
|
|
||||||
* value has not been set.
|
|
||||||
*/
|
|
||||||
public Jid getFrom() {
|
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,35 +235,39 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
*
|
*
|
||||||
* @param from who the packet is being sent to.
|
* @param from who the packet is being sent to.
|
||||||
*/
|
*/
|
||||||
|
// TODO: Mark this as deprecated once StanzaBuilder is ready and all call sites are gone.
|
||||||
public void setFrom(Jid from) {
|
public void setFrom(Jid from) {
|
||||||
this.from = from;
|
this.from = from;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the error associated with this packet, or <code>null</code> if there are
|
public final StanzaError getError() {
|
||||||
* no errors.
|
|
||||||
*
|
|
||||||
* @return the error sub-packet or <code>null</code> if there isn't an error.
|
|
||||||
*/
|
|
||||||
public StanzaError getError() {
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the error for this stanza.
|
* Sets the error for this stanza.
|
||||||
*
|
*
|
||||||
* @param xmppErrorBuilder the error to associate with this stanza.
|
* @param stanzaError the error that this stanza carries and hence signals.
|
||||||
*/
|
*/
|
||||||
public void setError(StanzaError.Builder xmppErrorBuilder) {
|
// TODO: Mark this as deprecated once StanzaBuilder is ready and all call sites are gone.
|
||||||
if (xmppErrorBuilder == null) {
|
public void setError(StanzaError stanzaError) {
|
||||||
return;
|
error = stanzaError;
|
||||||
}
|
}
|
||||||
xmppErrorBuilder.setStanza(this);
|
|
||||||
error = xmppErrorBuilder.build();
|
/**
|
||||||
|
* Deprecated.
|
||||||
|
* @param stanzaError the stanza error.
|
||||||
|
* @deprecated use {@link StanzaBuilder} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
|
public void setError(StanzaError.Builder stanzaError) {
|
||||||
|
setError(stanzaError.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getLanguage() {
|
public final String getLanguage() {
|
||||||
return language;
|
return language;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,23 +275,32 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
* Sets the xml:lang of this Stanza.
|
* Sets the xml:lang of this Stanza.
|
||||||
*
|
*
|
||||||
* @param language the xml:lang of this Stanza.
|
* @param language the xml:lang of this Stanza.
|
||||||
|
* @deprecated use {@link StanzaBuilder#setLanguage(String)} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public void setLanguage(String language) {
|
public void setLanguage(String language) {
|
||||||
this.language = language;
|
this.language = language;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns a list of all extension elements of this stanza.
|
public final List<ExtensionElement> getExtensions() {
|
||||||
*
|
|
||||||
* @return a list of all extension elements of this stanza.
|
|
||||||
*/
|
|
||||||
public List<ExtensionElement> getExtensions() {
|
|
||||||
synchronized (extensionElements) {
|
synchronized (extensionElements) {
|
||||||
// No need to create a new list, values() will already create a new one for us
|
// No need to create a new list, values() will already create a new one for us
|
||||||
return extensionElements.values();
|
return extensionElements.values();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final MultiMap<QName, ExtensionElement> getExtensionsMap() {
|
||||||
|
return cloneExtensionsMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
final MultiMap<QName, ExtensionElement> cloneExtensionsMap() {
|
||||||
|
synchronized (extensionElements) {
|
||||||
|
return extensionElements.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a list of all extensions with the given element name <em>and</em> namespace.
|
* Return a list of all extensions with the given element name <em>and</em> namespace.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -285,11 +312,27 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
* @return a set of all matching extensions.
|
* @return a set of all matching extensions.
|
||||||
* @since 4.1
|
* @since 4.1
|
||||||
*/
|
*/
|
||||||
public List<ExtensionElement> getExtensions(String elementName, String namespace) {
|
public final List<ExtensionElement> getExtensions(String elementName, String namespace) {
|
||||||
requireNotNullNorEmpty(elementName, "elementName must not be null nor empty");
|
requireNotNullNorEmpty(elementName, "elementName must not be null nor empty");
|
||||||
requireNotNullNorEmpty(namespace, "namespace must not be null nor empty");
|
requireNotNullNorEmpty(namespace, "namespace must not be null nor empty");
|
||||||
QName key = new QName(namespace, elementName);
|
QName key = new QName(namespace, elementName);
|
||||||
return extensionElements.getAll(key);
|
return getExtensions(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final List<ExtensionElement> getExtensions(QName qname) {
|
||||||
|
List<ExtensionElement> res;
|
||||||
|
synchronized (extensionElements) {
|
||||||
|
res = extensionElements.getAll(qname);
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableList(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final <E extends ExtensionElement> List<E> getExtensions(Class<E> extensionElementClass) {
|
||||||
|
synchronized (extensionElements) {
|
||||||
|
return XmppElementUtil.getElementsFrom(extensionElements, extensionElementClass);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -301,7 +344,7 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
* @param namespace the namespace of the extension that is desired.
|
* @param namespace the namespace of the extension that is desired.
|
||||||
* @return the stanza extension with the given namespace.
|
* @return the stanza extension with the given namespace.
|
||||||
*/
|
*/
|
||||||
public ExtensionElement getExtension(String namespace) {
|
public final ExtensionElement getExtension(String namespace) {
|
||||||
return PacketUtil.extensionElementFrom(getExtensions(), null, namespace);
|
return PacketUtil.extensionElementFrom(getExtensions(), null, namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,27 +360,37 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
* @return the extension, or <code>null</code> if it doesn't exist.
|
* @return the extension, or <code>null</code> if it doesn't exist.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <PE extends ExtensionElement> PE getExtension(String elementName, String namespace) {
|
public final <PE extends ExtensionElement> PE getExtension(String elementName, String namespace) {
|
||||||
if (namespace == null) {
|
if (namespace == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
QName key = new QName(namespace, elementName);
|
QName key = new QName(namespace, elementName);
|
||||||
ExtensionElement packetExtension;
|
ExtensionElement packetExtension = getExtension(key);
|
||||||
synchronized (extensionElements) {
|
|
||||||
packetExtension = extensionElements.getFirst(key);
|
|
||||||
}
|
|
||||||
if (packetExtension == null) {
|
if (packetExtension == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (PE) packetExtension;
|
return (PE) packetExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public final <E extends ExtensionElement> E getExtension(QName qname) {
|
||||||
|
synchronized (extensionElements) {
|
||||||
|
return (E) extensionElements.getFirst(qname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a stanza extension to the packet. Does nothing if extension is null.
|
* Adds a stanza extension to the packet. Does nothing if extension is null.
|
||||||
|
* <p>
|
||||||
|
* Please note that although this method is not yet marked as deprecated, it is recommended to use
|
||||||
|
* {@link StanzaBuilder#addExtension(ExtensionElement)} instead.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @param extension a stanza extension.
|
* @param extension a stanza extension.
|
||||||
*/
|
*/
|
||||||
public void addExtension(ExtensionElement extension) {
|
// TODO: Mark this as deprecated once StanzaBuilder is ready and all call sites are gone.
|
||||||
|
public final void addExtension(ExtensionElement extension) {
|
||||||
if (extension == null) return;
|
if (extension == null) return;
|
||||||
QName key = extension.getQName();
|
QName key = extension.getQName();
|
||||||
synchronized (extensionElements) {
|
synchronized (extensionElements) {
|
||||||
|
@ -348,12 +401,17 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
/**
|
/**
|
||||||
* Add the given extension and override eventually existing extensions with the same name and
|
* Add the given extension and override eventually existing extensions with the same name and
|
||||||
* namespace.
|
* namespace.
|
||||||
|
* <p>
|
||||||
|
* Please note that although this method is not yet marked as deprecated, it is recommended to use
|
||||||
|
* {@link StanzaBuilder#overrideExtension(ExtensionElement)} instead.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @param extension the extension element to add.
|
* @param extension the extension element to add.
|
||||||
* @return one of the removed extensions or <code>null</code> if there are none.
|
* @return one of the removed extensions or <code>null</code> if there are none.
|
||||||
* @since 4.1.2
|
* @since 4.1.2
|
||||||
*/
|
*/
|
||||||
public ExtensionElement overrideExtension(ExtensionElement extension) {
|
// TODO: Mark this as deprecated once StanzaBuilder is ready and all call sites are gone.
|
||||||
|
public final ExtensionElement overrideExtension(ExtensionElement extension) {
|
||||||
if (extension == null) return null;
|
if (extension == null) return null;
|
||||||
synchronized (extensionElements) {
|
synchronized (extensionElements) {
|
||||||
// Note that we need to use removeExtension(String, String) here. If would use
|
// Note that we need to use removeExtension(String, String) here. If would use
|
||||||
|
@ -370,7 +428,8 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
*
|
*
|
||||||
* @param extensions a collection of stanza extensions
|
* @param extensions a collection of stanza extensions
|
||||||
*/
|
*/
|
||||||
public void addExtensions(Collection<ExtensionElement> extensions) {
|
// TODO: Mark this as deprecated once StanzaBuilder is ready and all call sites are gone.
|
||||||
|
public final void addExtensions(Collection<ExtensionElement> extensions) {
|
||||||
if (extensions == null) return;
|
if (extensions == null) return;
|
||||||
for (ExtensionElement packetExtension : extensions) {
|
for (ExtensionElement packetExtension : extensions) {
|
||||||
addExtension(packetExtension);
|
addExtension(packetExtension);
|
||||||
|
@ -387,7 +446,7 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
* @param namespace TODO javadoc me please
|
* @param namespace TODO javadoc me please
|
||||||
* @return true if a stanza extension exists, false otherwise.
|
* @return true if a stanza extension exists, false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean hasExtension(String elementName, String namespace) {
|
public final boolean hasExtension(String elementName, String namespace) {
|
||||||
if (elementName == null) {
|
if (elementName == null) {
|
||||||
return hasExtension(namespace);
|
return hasExtension(namespace);
|
||||||
}
|
}
|
||||||
|
@ -397,13 +456,9 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Overridden in order to avoid an extra copy.
|
||||||
* Check if a stanza extension with the given namespace exists.
|
@Override
|
||||||
*
|
public final boolean hasExtension(String namespace) {
|
||||||
* @param namespace TODO javadoc me please
|
|
||||||
* @return true if a stanza extension exists, false otherwise.
|
|
||||||
*/
|
|
||||||
public boolean hasExtension(String namespace) {
|
|
||||||
synchronized (extensionElements) {
|
synchronized (extensionElements) {
|
||||||
for (ExtensionElement packetExtension : extensionElements.values()) {
|
for (ExtensionElement packetExtension : extensionElements.values()) {
|
||||||
if (packetExtension.getNamespace().equals(namespace)) {
|
if (packetExtension.getNamespace().equals(namespace)) {
|
||||||
|
@ -421,7 +476,8 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
* @param namespace TODO javadoc me please
|
* @param namespace TODO javadoc me please
|
||||||
* @return the removed stanza extension or null.
|
* @return the removed stanza extension or null.
|
||||||
*/
|
*/
|
||||||
public ExtensionElement removeExtension(String elementName, String namespace) {
|
// TODO: Mark this as deprecated once StanzaBuilder is ready and all call sites are gone.
|
||||||
|
public final ExtensionElement removeExtension(String elementName, String namespace) {
|
||||||
QName key = new QName(namespace, elementName);
|
QName key = new QName(namespace, elementName);
|
||||||
synchronized (extensionElements) {
|
synchronized (extensionElements) {
|
||||||
return extensionElements.remove(key);
|
return extensionElements.remove(key);
|
||||||
|
@ -433,8 +489,11 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
*
|
*
|
||||||
* @param extension the stanza extension to remove.
|
* @param extension the stanza extension to remove.
|
||||||
* @return the removed stanza extension or null.
|
* @return the removed stanza extension or null.
|
||||||
|
* @deprecated use {@link StanzaBuilder} instead.
|
||||||
*/
|
*/
|
||||||
public ExtensionElement removeExtension(ExtensionElement extension) {
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
|
public final ExtensionElement removeExtension(ExtensionElement extension) {
|
||||||
QName key = extension.getQName();
|
QName key = extension.getQName();
|
||||||
synchronized (extensionElements) {
|
synchronized (extensionElements) {
|
||||||
List<ExtensionElement> list = extensionElements.getAll(key);
|
List<ExtensionElement> list = extensionElements.getAll(key);
|
||||||
|
@ -494,7 +553,7 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
*
|
*
|
||||||
* @param xml the XmlStringBuilder to append the error to.
|
* @param xml the XmlStringBuilder to append the error to.
|
||||||
*/
|
*/
|
||||||
protected void appendErrorIfExists(XmlStringBuilder xml) {
|
protected final void appendErrorIfExists(XmlStringBuilder xml) {
|
||||||
StanzaError error = getError();
|
StanzaError error = getError();
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
xml.append(error);
|
xml.append(error);
|
||||||
|
|
|
@ -0,0 +1,306 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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 java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.id.StanzaIdSource;
|
||||||
|
import org.jivesoftware.smack.util.Function;
|
||||||
|
import org.jivesoftware.smack.util.MultiMap;
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
import org.jivesoftware.smack.util.ToStringUtil;
|
||||||
|
import org.jivesoftware.smack.util.XmppElementUtil;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
|
import org.jxmpp.stringprep.XmppStringprepException;
|
||||||
|
|
||||||
|
public abstract class StanzaBuilder<B extends StanzaBuilder<B>> implements StanzaView {
|
||||||
|
|
||||||
|
final StanzaIdSource stanzaIdSource;
|
||||||
|
final String stanzaId;
|
||||||
|
|
||||||
|
Jid to;
|
||||||
|
Jid from;
|
||||||
|
|
||||||
|
StanzaError stanzaError;
|
||||||
|
|
||||||
|
String language;
|
||||||
|
|
||||||
|
MultiMap<QName, ExtensionElement> extensionElements = new MultiMap<>();
|
||||||
|
|
||||||
|
protected StanzaBuilder(StanzaBuilder<?> other) {
|
||||||
|
stanzaIdSource = other.stanzaIdSource;
|
||||||
|
stanzaId = other.stanzaId;
|
||||||
|
|
||||||
|
to = other.to;
|
||||||
|
from = other.from;
|
||||||
|
stanzaError = other.stanzaError;
|
||||||
|
language = other.language;
|
||||||
|
extensionElements = other.extensionElements.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected StanzaBuilder(StanzaIdSource stanzaIdSource) {
|
||||||
|
this.stanzaIdSource = stanzaIdSource;
|
||||||
|
this.stanzaId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected StanzaBuilder(String stanzaId) {
|
||||||
|
this.stanzaIdSource = null;
|
||||||
|
this.stanzaId = StringUtils.requireNullOrNotEmpty(stanzaId, "Stanza ID must not be the empty String");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected StanzaBuilder(Stanza message, String stanzaId) {
|
||||||
|
this(stanzaId);
|
||||||
|
copyFromStanza(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected StanzaBuilder(Stanza message, StanzaIdSource stanzaIdSource) {
|
||||||
|
this(stanzaIdSource);
|
||||||
|
copyFromStanza(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyFromStanza(Stanza stanza) {
|
||||||
|
to = stanza.getTo();
|
||||||
|
from = stanza.getFrom();
|
||||||
|
stanzaError = stanza.getError();
|
||||||
|
language = stanza.getLanguage();
|
||||||
|
|
||||||
|
extensionElements = stanza.cloneExtensionsMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the recipent address of the stanza.
|
||||||
|
*
|
||||||
|
* @param to whoe the stanza is being sent to.
|
||||||
|
* @return a reference to this builder.
|
||||||
|
* @throws XmppStringprepException if the provided character sequence is not a valid XMPP address.
|
||||||
|
* @see #to(Jid)
|
||||||
|
*/
|
||||||
|
public final B to(CharSequence to) throws XmppStringprepException {
|
||||||
|
return to(JidCreate.from(to));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets who the stanza is being sent "to". The XMPP protocol often makes the "to" attribute optional, so it does not
|
||||||
|
* always need to be set.
|
||||||
|
*
|
||||||
|
* @param to who the stanza is being sent to.
|
||||||
|
* @return a reference to this builder.
|
||||||
|
*/
|
||||||
|
public final B to(Jid to) {
|
||||||
|
this.to = to;
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets who the the stanza is being sent "from".
|
||||||
|
*
|
||||||
|
* @param from who the stanza is being sent from.
|
||||||
|
* @return a reference to this builder.
|
||||||
|
* @throws XmppStringprepException if the provided character sequence is not a valid XMPP address.
|
||||||
|
* @see #from(Jid)
|
||||||
|
*/
|
||||||
|
public final B from(CharSequence from) throws XmppStringprepException {
|
||||||
|
return from(JidCreate.from(from));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets who the stanza is being sent "from". The XMPP protocol often makes the "from" attribute optional, so it does
|
||||||
|
* not always need to be set.
|
||||||
|
*
|
||||||
|
* @param from who the stanza is being sent from.
|
||||||
|
* @return a reference to this builder.
|
||||||
|
*/
|
||||||
|
public final B from(Jid from) {
|
||||||
|
this.from = from;
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the error for this stanza.
|
||||||
|
*
|
||||||
|
* @param stanzaError the error to associate with this stanza.
|
||||||
|
* @return a reference to this builder.
|
||||||
|
*/
|
||||||
|
public final B setError(StanzaError stanzaError) {
|
||||||
|
this.stanzaError = stanzaError;
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the xml:lang for this stanza.
|
||||||
|
*
|
||||||
|
* @param language the xml:lang of this stanza.
|
||||||
|
* @return a reference to this builder.
|
||||||
|
*/
|
||||||
|
public final B setLanguage(String language) {
|
||||||
|
this.language = language;
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final B addExtension(ExtensionElement extensionElement) {
|
||||||
|
QName key = extensionElement.getQName();
|
||||||
|
extensionElements.put(key, extensionElement);
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final B addExtensions(Collection<? extends ExtensionElement> extensionElements) {
|
||||||
|
for (ExtensionElement extensionElement : extensionElements) {
|
||||||
|
addExtension(extensionElement);
|
||||||
|
}
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final B overrideExtension(ExtensionElement extensionElement) {
|
||||||
|
QName key = extensionElement.getQName();
|
||||||
|
extensionElements.remove(key);
|
||||||
|
extensionElements.put(key, extensionElement);
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract B getThis();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String getStanzaId() {
|
||||||
|
return stanzaId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Jid getTo() {
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Jid getFrom() {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String getLanguage() {
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final StanzaError getError() {
|
||||||
|
return stanzaError;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public final <E extends ExtensionElement> E getExtension(QName qname) {
|
||||||
|
return (E) extensionElements.getFirst(qname);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final List<ExtensionElement> getExtensions() {
|
||||||
|
return extensionElements.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final List<ExtensionElement> getExtensions(QName qname) {
|
||||||
|
return extensionElements.getAll(qname);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final <E extends ExtensionElement> List<E> getExtensions(Class<E> extensionElementClass) {
|
||||||
|
return XmppElementUtil.getElementsFrom(extensionElements, extensionElementClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean willBuildStanzaWithId() {
|
||||||
|
return stanzaIdSource != null || StringUtils.isNotEmpty(stanzaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void throwIfNoStanzaId() {
|
||||||
|
if (willBuildStanzaWithId()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The builder will not build a stanza with an ID set, although it is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void addStanzaSpecificAttributes(ToStringUtil.Builder builder);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
ToStringUtil.Builder builder = ToStringUtil.builderFor(getClass())
|
||||||
|
.addValue("id", stanzaId)
|
||||||
|
.addValue("from", from)
|
||||||
|
.addValue("to", to)
|
||||||
|
.addValue("language", language)
|
||||||
|
.addValue("error", stanzaError)
|
||||||
|
;
|
||||||
|
|
||||||
|
addStanzaSpecificAttributes(builder);
|
||||||
|
|
||||||
|
builder.add("Extension Elements", extensionElements.values(), e -> {
|
||||||
|
return e.getQName();
|
||||||
|
});
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MessageBuilder buildMessage() {
|
||||||
|
return buildMessage(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MessageBuilder buildMessage(String stanzaId) {
|
||||||
|
return new MessageBuilder(stanzaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MessageBuilder buildMessageFrom(Message message, String stanzaId) {
|
||||||
|
return new MessageBuilder(message, stanzaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MessageBuilder buildMessageFrom(Message message, StanzaIdSource stanzaIdSource) {
|
||||||
|
return new MessageBuilder(message, stanzaIdSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PresenceBuilder buildPresence() {
|
||||||
|
return buildPresence(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PresenceBuilder buildPresence(String stanzaId) {
|
||||||
|
return new PresenceBuilder(stanzaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PresenceBuilder buildPresenceFrom(Presence presence, String stanzaId) {
|
||||||
|
return new PresenceBuilder(presence, stanzaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PresenceBuilder buildPresenceFrom(Presence presence, StanzaIdSource stanzaIdSource) {
|
||||||
|
return new PresenceBuilder(presence, stanzaIdSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IqData buildIqData(String stanzaId) {
|
||||||
|
return new IqData(stanzaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <SB extends StanzaBuilder<?>> SB buildResponse(StanzaView request, Function<SB, String> builderFromStanzaId) {
|
||||||
|
SB responseBuilder = builderFromStanzaId.apply(request.getStanzaId());
|
||||||
|
|
||||||
|
responseBuilder.to(request.getFrom())
|
||||||
|
.from(request.getTo())
|
||||||
|
;
|
||||||
|
|
||||||
|
return responseBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -106,7 +106,6 @@ public class StanzaError extends AbstractError implements ExtensionElement {
|
||||||
private final String conditionText;
|
private final String conditionText;
|
||||||
private final String errorGenerator;
|
private final String errorGenerator;
|
||||||
private final Type type;
|
private final Type type;
|
||||||
private final Stanza stanza;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new error with the specified type, condition and message.
|
* Creates a new error with the specified type, condition and message.
|
||||||
|
@ -120,13 +119,11 @@ public class StanzaError extends AbstractError implements ExtensionElement {
|
||||||
* @param errorGenerator TODO javadoc me please
|
* @param errorGenerator TODO javadoc me please
|
||||||
* @param descriptiveTexts TODO javadoc me please
|
* @param descriptiveTexts TODO javadoc me please
|
||||||
* @param extensions list of stanza extensions
|
* @param extensions list of stanza extensions
|
||||||
* @param stanza the stanza carrying this XMPP error.
|
|
||||||
*/
|
*/
|
||||||
public StanzaError(Condition condition, String conditionText, String errorGenerator, Type type, Map<String, String> descriptiveTexts,
|
public StanzaError(Condition condition, String conditionText, String errorGenerator, Type type, Map<String, String> descriptiveTexts,
|
||||||
List<ExtensionElement> extensions, Stanza stanza) {
|
List<ExtensionElement> extensions) {
|
||||||
super(descriptiveTexts, ERROR_CONDITION_AND_TEXT_NAMESPACE, extensions);
|
super(descriptiveTexts, ERROR_CONDITION_AND_TEXT_NAMESPACE, extensions);
|
||||||
this.condition = Objects.requireNonNull(condition, "condition must not be null");
|
this.condition = Objects.requireNonNull(condition, "condition must not be null");
|
||||||
this.stanza = stanza;
|
|
||||||
// Some implementations may send the condition as non-empty element containing the empty string, that is
|
// Some implementations may send the condition as non-empty element containing the empty string, that is
|
||||||
// <condition xmlns='foo'></condition>, in this case the parser may calls this constructor with the empty string
|
// <condition xmlns='foo'></condition>, in this case the parser may calls this constructor with the empty string
|
||||||
// as conditionText, therefore reset it to null if it's the empty string
|
// as conditionText, therefore reset it to null if it's the empty string
|
||||||
|
@ -184,16 +181,6 @@ public class StanzaError extends AbstractError implements ExtensionElement {
|
||||||
return conditionText;
|
return conditionText;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the stanza carrying the XMPP error.
|
|
||||||
*
|
|
||||||
* @return the stanza carrying the XMPP error.
|
|
||||||
* @since 4.2
|
|
||||||
*/
|
|
||||||
public Stanza getStanza() {
|
|
||||||
return stanza;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder("XMPPError: ");
|
StringBuilder sb = new StringBuilder("XMPPError: ");
|
||||||
|
@ -271,7 +258,6 @@ public class StanzaError extends AbstractError implements ExtensionElement {
|
||||||
private String conditionText;
|
private String conditionText;
|
||||||
private String errorGenerator;
|
private String errorGenerator;
|
||||||
private Type type;
|
private Type type;
|
||||||
private Stanza stanza;
|
|
||||||
|
|
||||||
private Builder() {
|
private Builder() {
|
||||||
}
|
}
|
||||||
|
@ -296,17 +282,11 @@ public class StanzaError extends AbstractError implements ExtensionElement {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setStanza(Stanza stanza) {
|
|
||||||
this.stanza = stanza;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder copyFrom(StanzaError xmppError) {
|
public Builder copyFrom(StanzaError xmppError) {
|
||||||
setCondition(xmppError.getCondition());
|
setCondition(xmppError.getCondition());
|
||||||
setType(xmppError.getType());
|
setType(xmppError.getType());
|
||||||
setConditionText(xmppError.getConditionText());
|
setConditionText(xmppError.getConditionText());
|
||||||
setErrorGenerator(xmppError.getErrorGenerator());
|
setErrorGenerator(xmppError.getErrorGenerator());
|
||||||
setStanza(xmppError.getStanza());
|
|
||||||
setDescriptiveTexts(xmppError.descriptiveTexts);
|
setDescriptiveTexts(xmppError.descriptiveTexts);
|
||||||
setTextNamespace(xmppError.textNamespace);
|
setTextNamespace(xmppError.textNamespace);
|
||||||
setExtensions(xmppError.extensions);
|
setExtensions(xmppError.extensions);
|
||||||
|
@ -315,7 +295,7 @@ public class StanzaError extends AbstractError implements ExtensionElement {
|
||||||
|
|
||||||
public StanzaError build() {
|
public StanzaError build() {
|
||||||
return new StanzaError(condition, conditionText, errorGenerator, type, descriptiveTexts,
|
return new StanzaError(condition, conditionText, errorGenerator, type, descriptiveTexts,
|
||||||
extensions, stanza);
|
extensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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 final class StanzaFactory {
|
||||||
|
|
||||||
|
private final StanzaIdSource stanzaIdSource;
|
||||||
|
|
||||||
|
StanzaIdSource getStanzaIdSource() {
|
||||||
|
return stanzaIdSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StanzaFactory(StanzaIdSource stanzaIdSource) {
|
||||||
|
this.stanzaIdSource = stanzaIdSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageBuilder buildMessageStanza() {
|
||||||
|
return new MessageBuilder(stanzaIdSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageBuilder buildMessageStanzaFrom(Message message) {
|
||||||
|
return new MessageBuilder(message, stanzaIdSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PresenceBuilder buildPresenceStanza() {
|
||||||
|
return new PresenceBuilder(stanzaIdSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PresenceBuilder buildPresenceStanzaFrom(Presence presence) {
|
||||||
|
return new PresenceBuilder(presence, stanzaIdSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IqData buildIqData() {
|
||||||
|
return new IqData(stanzaIdSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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 java.util.List;
|
||||||
|
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.XmppElementUtil;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
|
||||||
|
public interface StanzaView extends XmlLangElement {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unique ID of the stanza. The returned value could be <code>null</code>.
|
||||||
|
*
|
||||||
|
* @return the packet's unique ID or <code>null</code> if the id is not available.
|
||||||
|
*/
|
||||||
|
String getStanzaId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns who the stanza is being sent "to", or <code>null</code> if
|
||||||
|
* the value is not set. The XMPP protocol often makes the "to"
|
||||||
|
* attribute optional, so it does not always need to be set.<p>
|
||||||
|
*
|
||||||
|
* @return who the stanza is being sent to, or <code>null</code> if the
|
||||||
|
* value has not been set.
|
||||||
|
*/
|
||||||
|
Jid getTo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns who the stanza is being sent "from" or <code>null</code> if
|
||||||
|
* the value is not set. The XMPP protocol often makes the "from"
|
||||||
|
* attribute optional, so it does not always need to be set.<p>
|
||||||
|
*
|
||||||
|
* @return who the stanza is being sent from, or <code>null</code> if the
|
||||||
|
* value has not been set.
|
||||||
|
*/
|
||||||
|
Jid getFrom();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the error associated with this packet, or <code>null</code> if there are
|
||||||
|
* no errors.
|
||||||
|
*
|
||||||
|
* @return the error sub-packet or <code>null</code> if there isn't an error.
|
||||||
|
*/
|
||||||
|
StanzaError getError();
|
||||||
|
|
||||||
|
<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);
|
||||||
|
return (E) getExtension(qname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all extension elements of this stanza.
|
||||||
|
*
|
||||||
|
* @return a list of all extension elements of this stanza.
|
||||||
|
*/
|
||||||
|
List<ExtensionElement> getExtensions();
|
||||||
|
|
||||||
|
List<ExtensionElement> getExtensions(QName qname);
|
||||||
|
|
||||||
|
<E extends ExtensionElement> List<E> getExtensions(Class<E> extensionElementClass);
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright © 2014-2018 Florian Schmaus
|
* Copyright © 2014-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.
|
||||||
|
@ -52,9 +52,15 @@ public class StartTls implements Nonza {
|
||||||
@Override
|
@Override
|
||||||
public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
|
public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
|
||||||
XmlStringBuilder xml = new XmlStringBuilder(this, enclosingNamespace);
|
XmlStringBuilder xml = new XmlStringBuilder(this, enclosingNamespace);
|
||||||
|
|
||||||
|
if (required) {
|
||||||
xml.rightAngleBracket();
|
xml.rightAngleBracket();
|
||||||
xml.condEmptyElement(required, "required");
|
xml.emptyElement("required");
|
||||||
xml.closeElement(this);
|
xml.closeElement(this);
|
||||||
|
} else {
|
||||||
|
xml.closeEmptyElement();
|
||||||
|
}
|
||||||
|
|
||||||
return xml;
|
return xml;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.jivesoftware.smack.packet;
|
||||||
|
|
||||||
import org.jivesoftware.smack.util.ParserUtils;
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
|
||||||
public class XmlEnvironment {
|
public class XmlEnvironment {
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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 interface XmlLangElement {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the xml:lang of this XML element, or null if one has not been set.
|
||||||
|
*
|
||||||
|
* @return the xml:lang of this XML element, or null.
|
||||||
|
*/
|
||||||
|
String getLanguage();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.id;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
|
||||||
|
public final class RandomStringStanzaIdSource {
|
||||||
|
|
||||||
|
public static class Factory implements StanzaIdSourceFactory {
|
||||||
|
|
||||||
|
private static final int REQUIRED_MIN_LENGTH = 10;
|
||||||
|
|
||||||
|
private final int length;
|
||||||
|
private final boolean verySecure;
|
||||||
|
|
||||||
|
public static final Factory VERY_SECURE = new Factory(10, true);
|
||||||
|
public static final Factory MEDIUM_SECURE = new Factory(10, false);
|
||||||
|
|
||||||
|
public Factory(int length, boolean verySecure) {
|
||||||
|
if (length < REQUIRED_MIN_LENGTH) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Insufficient length " + length + ", must be at least " + REQUIRED_MIN_LENGTH);
|
||||||
|
}
|
||||||
|
this.length = length;
|
||||||
|
this.verySecure = verySecure;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StanzaIdSource constructStanzaIdSource() {
|
||||||
|
StanzaIdSource stanzaIdSource;
|
||||||
|
if (verySecure) {
|
||||||
|
stanzaIdSource = () -> StringUtils.randomString(length);
|
||||||
|
} else {
|
||||||
|
stanzaIdSource = () -> StringUtils.insecureRandomString(length);
|
||||||
|
}
|
||||||
|
return stanzaIdSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software, 2015 Florian Schmaus
|
* Copyright 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.
|
||||||
|
@ -20,20 +20,32 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
|
||||||
public class StanzaIdUtil {
|
public class StandardStanzaIdSource implements StanzaIdSource {
|
||||||
|
|
||||||
|
public static final StandardStanzaIdSource DEFAULT = new StandardStanzaIdSource();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A prefix helps to make sure that ID's are unique across multiple instances.
|
* A prefix helps to make sure that ID's are unique across multiple instances.
|
||||||
*/
|
*/
|
||||||
private static final String PREFIX = StringUtils.randomString(5) + "-";
|
private final String prefix = StringUtils.randomString(5) + "-";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps track of the current increment, which is appended to the prefix to
|
* Keeps track of the current increment, which is appended to the prefix to
|
||||||
* forum a unique ID.
|
* forum a unique ID.
|
||||||
*/
|
*/
|
||||||
private static final AtomicLong ID = new AtomicLong();
|
private final AtomicLong id = new AtomicLong();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNewStanzaId() {
|
||||||
|
return prefix + Long.toString(id.incrementAndGet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Factory implements StanzaIdSourceFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StandardStanzaIdSource constructStanzaIdSource() {
|
||||||
|
return new StandardStanzaIdSource();
|
||||||
|
}
|
||||||
|
|
||||||
public static String newStanzaId() {
|
|
||||||
return PREFIX + Long.toString(ID.incrementAndGet());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.id;
|
||||||
|
|
||||||
|
public interface StanzaIdSource {
|
||||||
|
String getNewStanzaId();
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.id;
|
||||||
|
|
||||||
|
public interface StanzaIdSourceFactory {
|
||||||
|
StanzaIdSource constructStanzaIdSource();
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.id;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public final class UuidStanzaIdSource implements StanzaIdSource {
|
||||||
|
|
||||||
|
public static final UuidStanzaIdSource INSTANCE = new UuidStanzaIdSource();
|
||||||
|
|
||||||
|
private UuidStanzaIdSource() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNewStanzaId() {
|
||||||
|
return UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Factory implements StanzaIdSourceFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UuidStanzaIdSource constructStanzaIdSource() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,7 +39,7 @@ public interface ParsingExceptionCallback {
|
||||||
* Called when parsing a stanza caused an exception.
|
* Called when parsing a stanza caused an exception.
|
||||||
*
|
*
|
||||||
* @param stanzaData the raw stanza data that caused the exception
|
* @param stanzaData the raw stanza data that caused the exception
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
*/
|
*/
|
||||||
void handleUnparsableStanza(UnparseableStanza stanzaData) throws IOException;
|
void handleUnparsableStanza(UnparseableStanza stanzaData) throws IOException;
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||||
import org.jivesoftware.smack.util.ParserUtils;
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParserException;
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.provider;
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.Element;
|
||||||
|
|
||||||
|
public class AbstractProvider<E extends Element> {
|
||||||
|
|
||||||
|
private final Class<E> elementClass;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected AbstractProvider() {
|
||||||
|
Type currentType = getClass().getGenericSuperclass();
|
||||||
|
while (!(currentType instanceof ParameterizedType)) {
|
||||||
|
Class<?> currentClass = (Class<?>) currentType;
|
||||||
|
currentType = currentClass.getGenericSuperclass();
|
||||||
|
}
|
||||||
|
ParameterizedType parameterizedGenericSuperclass = (ParameterizedType) currentType;
|
||||||
|
Type[] actualTypeArguments = parameterizedGenericSuperclass.getActualTypeArguments();
|
||||||
|
Type elementType = actualTypeArguments[0];
|
||||||
|
|
||||||
|
elementClass = (Class<E>) elementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Class<E> getElementClass() {
|
||||||
|
return elementClass;
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,7 +23,6 @@ import java.io.IOException;
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import org.jivesoftware.smack.packet.Message;
|
||||||
import org.jivesoftware.smack.packet.XmlEnvironment;
|
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
import org.jivesoftware.smack.util.ParserUtils;
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParserException;
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ import org.jivesoftware.smack.packet.ExtensionElement;
|
||||||
import org.jivesoftware.smack.packet.XmlEnvironment;
|
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
import org.jivesoftware.smack.parsing.SmackParsingException;
|
import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
|
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParserException;
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
|
|
||||||
|
|
|
@ -17,15 +17,53 @@
|
||||||
|
|
||||||
package org.jivesoftware.smack.provider;
|
package org.jivesoftware.smack.provider;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smack.packet.IqData;
|
||||||
|
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
|
import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* <p>
|
||||||
|
* <b>Deprecation Notice:</b> This class is deprecated, use {@link IQProvider} instead.
|
||||||
|
* </p>
|
||||||
* An abstract class for parsing custom IQ packets. Each IQProvider must be registered with
|
* An abstract class for parsing custom IQ packets. Each IQProvider must be registered with
|
||||||
* the ProviderManager class for it to be used. Every implementation of this
|
* the ProviderManager class for it to be used. Every implementation of this
|
||||||
* abstract class <b>must</b> have a public, no-argument constructor.
|
* abstract class <b>must</b> have a public, no-argument constructor.
|
||||||
*
|
*
|
||||||
* @author Matt Tucker
|
* @author Matt Tucker
|
||||||
*/
|
*/
|
||||||
public abstract class IQProvider<I extends IQ> extends Provider<I> {
|
public abstract class IQProvider<I extends IQ> extends IqProvider<I> {
|
||||||
|
|
||||||
|
public final I parse(XmlPullParser parser) throws IOException, XmlPullParserException, SmackParsingException {
|
||||||
|
return parse(parser, (XmlEnvironment) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final I parse(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws IOException, XmlPullParserException, SmackParsingException {
|
||||||
|
// XPP3 calling convention assert: Parser should be at start tag
|
||||||
|
ParserUtils.assertAtStartTag(parser);
|
||||||
|
|
||||||
|
final int initialDepth = parser.getDepth();
|
||||||
|
final XmlEnvironment xmlEnvironment = XmlEnvironment.from(parser, outerXmlEnvironment);
|
||||||
|
|
||||||
|
I e = parse(parser, initialDepth, xmlEnvironment);
|
||||||
|
|
||||||
|
// XPP3 calling convention assert: Parser should be at end tag of the consumed/parsed element
|
||||||
|
ParserUtils.forwardToEndTagOfDepth(parser, initialDepth);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final I parse(XmlPullParser parser, int initialDepth, IqData iqData, XmlEnvironment xmlEnvironment)
|
||||||
|
throws XmlPullParserException, IOException, SmackParsingException {
|
||||||
|
// Old-style IQ parsers do not need IqData.
|
||||||
|
return parse(parser, initialDepth, xmlEnvironment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract I parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ public final class IQProviderInfo extends AbstractProviderInfo {
|
||||||
* @param namespace Namespace that provider parses.
|
* @param namespace Namespace that provider parses.
|
||||||
* @param iqProvider The provider implementation.
|
* @param iqProvider The provider implementation.
|
||||||
*/
|
*/
|
||||||
public IQProviderInfo(String elementName, String namespace, IQProvider<IQ> iqProvider) {
|
public IQProviderInfo(String elementName, String namespace, IqProvider<IQ> iqProvider) {
|
||||||
super(elementName, namespace, iqProvider);
|
super(elementName, namespace, iqProvider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import org.jivesoftware.smack.packet.ExtensionElement;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smack.packet.XmlEnvironment;
|
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
import org.jivesoftware.smack.util.ParserUtils;
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParserException;
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.provider;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smack.packet.IqData;
|
||||||
|
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
|
import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||||
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
|
|
||||||
|
public abstract class IqProvider<I extends IQ> extends AbstractProvider<I> {
|
||||||
|
|
||||||
|
public final I parse(XmlPullParser parser, IqData iqCommon)
|
||||||
|
throws XmlPullParserException, IOException, SmackParsingException {
|
||||||
|
return parse(parser, iqCommon, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final I parse(XmlPullParser parser, IqData iqData, XmlEnvironment outerXmlEnvironment)
|
||||||
|
throws XmlPullParserException, IOException, SmackParsingException {
|
||||||
|
final int initialDepth = parser.getDepth();
|
||||||
|
final XmlEnvironment xmlEnvironment = XmlEnvironment.from(parser, outerXmlEnvironment);
|
||||||
|
|
||||||
|
return parse(parser, initialDepth, iqData, xmlEnvironment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract I parse(XmlPullParser parser, int initialDepth, IqData iqData, XmlEnvironment xmlEnvironment)
|
||||||
|
throws XmlPullParserException, IOException, SmackParsingException;
|
||||||
|
|
||||||
|
}
|
|
@ -18,14 +18,11 @@
|
||||||
package org.jivesoftware.smack.provider;
|
package org.jivesoftware.smack.provider;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.Element;
|
import org.jivesoftware.smack.packet.Element;
|
||||||
import org.jivesoftware.smack.packet.XmlEnvironment;
|
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
import org.jivesoftware.smack.parsing.SmackParsingException;
|
import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||||
import org.jivesoftware.smack.util.ParserUtils;
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParserException;
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
|
|
||||||
|
@ -40,27 +37,7 @@ import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
* @author Florian Schmaus
|
* @author Florian Schmaus
|
||||||
* @param <E> the type of the resulting element.
|
* @param <E> the type of the resulting element.
|
||||||
*/
|
*/
|
||||||
public abstract class Provider<E extends Element> {
|
public abstract class Provider<E extends Element> extends AbstractProvider<E> {
|
||||||
|
|
||||||
private final Class<E> elementClass;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected Provider() {
|
|
||||||
Type currentType = getClass().getGenericSuperclass();
|
|
||||||
while (!(currentType instanceof ParameterizedType)) {
|
|
||||||
Class<?> currentClass = (Class<?>) currentType;
|
|
||||||
currentType = currentClass.getGenericSuperclass();
|
|
||||||
}
|
|
||||||
ParameterizedType parameterizedGenericSuperclass = (ParameterizedType) currentType;
|
|
||||||
Type[] actualTypeArguments = parameterizedGenericSuperclass.getActualTypeArguments();
|
|
||||||
Type elementType = actualTypeArguments[0];
|
|
||||||
|
|
||||||
elementClass = (Class<E>) elementType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final Class<E> getElementClass() {
|
|
||||||
return elementClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final E parse(XmlPullParser parser) throws IOException, XmlPullParserException, SmackParsingException {
|
public final E parse(XmlPullParser parser) throws IOException, XmlPullParserException, SmackParsingException {
|
||||||
return parse(parser, null);
|
return parse(parser, null);
|
||||||
|
|
|
@ -80,8 +80,8 @@ public class ProviderFileLoader implements ProviderLoader {
|
||||||
// an IQ class, add the class object itself, then we'll use
|
// an IQ class, add the class object itself, then we'll use
|
||||||
// reflection later to create instances of the class.
|
// reflection later to create instances of the class.
|
||||||
// Add the provider to the map.
|
// Add the provider to the map.
|
||||||
if (IQProvider.class.isAssignableFrom(provider)) {
|
if (IqProvider.class.isAssignableFrom(provider)) {
|
||||||
IQProvider<IQ> iqProvider = (IQProvider<IQ>) provider.getConstructor().newInstance();
|
IqProvider<IQ> iqProvider = (IqProvider<IQ>) provider.getConstructor().newInstance();
|
||||||
iqProviders.add(new IQProviderInfo(elementName, namespace, iqProvider));
|
iqProviders.add(new IQProviderInfo(elementName, namespace, iqProvider));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -113,7 +113,7 @@ import org.jivesoftware.smack.util.XmppElementUtil;
|
||||||
public final class ProviderManager {
|
public final class ProviderManager {
|
||||||
|
|
||||||
private static final Map<QName, ExtensionElementProvider<ExtensionElement>> extensionProviders = new ConcurrentHashMap<>();
|
private static final Map<QName, ExtensionElementProvider<ExtensionElement>> extensionProviders = new ConcurrentHashMap<>();
|
||||||
private static final Map<QName, IQProvider<IQ>> iqProviders = new ConcurrentHashMap<>();
|
private static final Map<QName, IqProvider<IQ>> iqProviders = new ConcurrentHashMap<>();
|
||||||
private static final Map<QName, ExtensionElementProvider<ExtensionElement>> streamFeatureProviders = new ConcurrentHashMap<>();
|
private static final Map<QName, ExtensionElementProvider<ExtensionElement>> streamFeatureProviders = new ConcurrentHashMap<>();
|
||||||
private static final Map<QName, NonzaProvider<? extends Nonza>> nonzaProviders = new ConcurrentHashMap<>();
|
private static final Map<QName, NonzaProvider<? extends Nonza>> nonzaProviders = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ public final class ProviderManager {
|
||||||
* @param namespace the XML namespace.
|
* @param namespace the XML namespace.
|
||||||
* @return the IQ provider.
|
* @return the IQ provider.
|
||||||
*/
|
*/
|
||||||
public static IQProvider<IQ> getIQProvider(String elementName, String namespace) {
|
public static IqProvider<IQ> getIQProvider(String elementName, String namespace) {
|
||||||
QName key = getQName(elementName, namespace);
|
QName key = getQName(elementName, namespace);
|
||||||
return iqProviders.get(key);
|
return iqProviders.get(key);
|
||||||
}
|
}
|
||||||
|
@ -179,8 +179,8 @@ public final class ProviderManager {
|
||||||
*
|
*
|
||||||
* @return all IQProvider instances.
|
* @return all IQProvider instances.
|
||||||
*/
|
*/
|
||||||
public static List<IQProvider<IQ>> getIQProviders() {
|
public static List<IqProvider<IQ>> getIQProviders() {
|
||||||
List<IQProvider<IQ>> providers = new ArrayList<>(iqProviders.size());
|
List<IqProvider<IQ>> providers = new ArrayList<>(iqProviders.size());
|
||||||
providers.addAll(iqProviders.values());
|
providers.addAll(iqProviders.values());
|
||||||
return providers;
|
return providers;
|
||||||
}
|
}
|
||||||
|
@ -200,10 +200,10 @@ public final class ProviderManager {
|
||||||
validate(elementName, namespace);
|
validate(elementName, namespace);
|
||||||
// First remove existing providers
|
// First remove existing providers
|
||||||
QName key = removeIQProvider(elementName, namespace);
|
QName key = removeIQProvider(elementName, namespace);
|
||||||
if (provider instanceof IQProvider) {
|
if (provider instanceof IqProvider) {
|
||||||
iqProviders.put(key, (IQProvider<IQ>) provider);
|
iqProviders.put(key, (IqProvider<IQ>) provider);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Provider must be an IQProvider");
|
throw new IllegalArgumentException("Provider must be an instance of IqProvider");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.jivesoftware.smack.provider;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.TlsProceed;
|
import org.jivesoftware.smack.packet.TlsProceed;
|
||||||
import org.jivesoftware.smack.packet.XmlEnvironment;
|
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
|
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
|
||||||
public final class TlsFailureProvider extends NonzaProvider<TlsProceed> {
|
public final class TlsFailureProvider extends NonzaProvider<TlsProceed> {
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.jivesoftware.smack.provider;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.TlsFailure;
|
import org.jivesoftware.smack.packet.TlsFailure;
|
||||||
import org.jivesoftware.smack.packet.XmlEnvironment;
|
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
|
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
|
||||||
public final class TlsProceedProvider extends NonzaProvider<TlsFailure> {
|
public final class TlsProceedProvider extends NonzaProvider<TlsFailure> {
|
||||||
|
|
|
@ -222,7 +222,7 @@ public abstract class SASLMechanism implements Comparable<SASLMechanism> {
|
||||||
* empty array here.
|
* empty array here.
|
||||||
*
|
*
|
||||||
* @return the initial response or null
|
* @return the initial response or null
|
||||||
* @throws SmackSaslException if a SASL specific error occured.
|
* @throws SmackSaslException if a SASL specific error occurred.
|
||||||
*/
|
*/
|
||||||
protected abstract byte[] getAuthenticationText() throws SmackSaslException;
|
protected abstract byte[] getAuthenticationText() throws SmackSaslException;
|
||||||
|
|
||||||
|
|
|
@ -259,7 +259,7 @@ public abstract class ScramMechanism extends SASLMechanism {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return the Channel Binding data.
|
* @return the Channel Binding data.
|
||||||
* @throws SmackSaslException if a SASL specific error occured.
|
* @throws SmackSaslException if a SASL specific error occurred.
|
||||||
*/
|
*/
|
||||||
protected byte[] getChannelBindingData() throws SmackSaslException {
|
protected byte[] getChannelBindingData() throws SmackSaslException {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -110,7 +110,7 @@ public final class FileUtils {
|
||||||
*
|
*
|
||||||
* @param file TODO javadoc me please
|
* @param file TODO javadoc me please
|
||||||
* @return the content of file or null in case of an error
|
* @return the content of file or null in case of an error
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("DefaultCharset")
|
@SuppressWarnings("DefaultCharset")
|
||||||
public static String readFileOrThrow(File file) throws IOException {
|
public static String readFileOrThrow(File file) throws IOException {
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
public interface Function<R, T> {
|
||||||
|
|
||||||
|
R apply(T t);
|
||||||
|
|
||||||
|
}
|
|
@ -34,7 +34,7 @@ import java.util.Set;
|
||||||
* @param <K> the type of the keys the map uses.
|
* @param <K> the type of the keys the map uses.
|
||||||
* @param <V> the type of the values the map uses.
|
* @param <V> the type of the values the map uses.
|
||||||
*/
|
*/
|
||||||
public class MultiMap<K, V> {
|
public class MultiMap<K, V> implements TypedCloneable<MultiMap<K, V>> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The constant value {@value}.
|
* The constant value {@value}.
|
||||||
|
@ -252,6 +252,19 @@ public class MultiMap<K, V> {
|
||||||
return new MultiMap<K, V>(Collections.unmodifiableMap(mapCopy));
|
return new MultiMap<K, V>(Collections.unmodifiableMap(mapCopy));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultiMap<K, V> clone() {
|
||||||
|
Map<K, List<V>> clonedMap = new LinkedHashMap<>(map.size());
|
||||||
|
|
||||||
|
// TODO: Use Map.forEach() once Smack's minimum Android API is 24 or higher.
|
||||||
|
for (Entry<K, List<V>> entry : map.entrySet()) {
|
||||||
|
List<V> clonedList = CollectionUtil.newListWith(entry.getValue());
|
||||||
|
clonedMap.put(entry.getKey(), clonedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MultiMap<>(clonedMap);
|
||||||
|
}
|
||||||
|
|
||||||
private static final class SimpleMapEntry<K, V> implements Map.Entry<K, V> {
|
private static final class SimpleMapEntry<K, V> implements Map.Entry<K, V> {
|
||||||
|
|
||||||
private final K key;
|
private final K key;
|
||||||
|
|
|
@ -28,6 +28,7 @@ import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.jivesoftware.smack.compress.packet.Compress;
|
import org.jivesoftware.smack.compress.packet.Compress;
|
||||||
|
@ -35,10 +36,14 @@ import org.jivesoftware.smack.packet.EmptyResultIQ;
|
||||||
import org.jivesoftware.smack.packet.ErrorIQ;
|
import org.jivesoftware.smack.packet.ErrorIQ;
|
||||||
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.IqData;
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.packet.MessageBuilder;
|
||||||
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.StanzaBuilder;
|
||||||
import org.jivesoftware.smack.packet.StanzaError;
|
import org.jivesoftware.smack.packet.StanzaError;
|
||||||
import org.jivesoftware.smack.packet.StartTls;
|
import org.jivesoftware.smack.packet.StartTls;
|
||||||
import org.jivesoftware.smack.packet.StreamError;
|
import org.jivesoftware.smack.packet.StreamError;
|
||||||
|
@ -47,7 +52,7 @@ import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
import org.jivesoftware.smack.parsing.SmackParsingException;
|
import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||||
import org.jivesoftware.smack.parsing.StandardExtensionElementProvider;
|
import org.jivesoftware.smack.parsing.StandardExtensionElementProvider;
|
||||||
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||||
import org.jivesoftware.smack.provider.IQProvider;
|
import org.jivesoftware.smack.provider.IqProvider;
|
||||||
import org.jivesoftware.smack.provider.ProviderManager;
|
import org.jivesoftware.smack.provider.ProviderManager;
|
||||||
import org.jivesoftware.smack.xml.SmackXmlParser;
|
import org.jivesoftware.smack.xml.SmackXmlParser;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
@ -101,9 +106,9 @@ public class PacketParserUtils {
|
||||||
* @param parser TODO javadoc me please
|
* @param parser TODO javadoc me please
|
||||||
* @param outerXmlEnvironment the outer XML environment (optional).
|
* @param outerXmlEnvironment the outer XML environment (optional).
|
||||||
* @return a stanza which is either a Message, IQ or Presence.
|
* @return a stanza which is either a Message, IQ or Presence.
|
||||||
* @throws XmlPullParserException if an error in the XML parser occured.
|
* @throws XmlPullParserException if an error in the XML parser occurred.
|
||||||
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
*/
|
*/
|
||||||
public static Stanza parseStanza(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, SmackParsingException, IOException {
|
public static Stanza parseStanza(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, SmackParsingException, IOException {
|
||||||
ParserUtils.assertAtStartTag(parser);
|
ParserUtils.assertAtStartTag(parser);
|
||||||
|
@ -120,18 +125,25 @@ public class PacketParserUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void parseCommonStanzaAttributes(Stanza stanza, XmlPullParser parser, XmlEnvironment xmlEnvironment) throws XmppStringprepException {
|
private interface StanzaBuilderSupplier<SB extends StanzaBuilder<?>> {
|
||||||
|
SB get(String stanzaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <SB extends StanzaBuilder<?>> SB parseCommonStanzaAttributes(StanzaBuilderSupplier<SB> stanzaBuilderSupplier, XmlPullParser parser, XmlEnvironment xmlEnvironment) throws XmppStringprepException {
|
||||||
String id = parser.getAttributeValue("id");
|
String id = parser.getAttributeValue("id");
|
||||||
stanza.setStanzaId(id);
|
|
||||||
|
SB stanzaBuilder = stanzaBuilderSupplier.get(id);
|
||||||
|
|
||||||
Jid to = ParserUtils.getJidAttribute(parser, "to");
|
Jid to = ParserUtils.getJidAttribute(parser, "to");
|
||||||
stanza.setTo(to);
|
stanzaBuilder.to(to);
|
||||||
|
|
||||||
Jid from = ParserUtils.getJidAttribute(parser, "from");
|
Jid from = ParserUtils.getJidAttribute(parser, "from");
|
||||||
stanza.setFrom(from);
|
stanzaBuilder.from(from);
|
||||||
|
|
||||||
String language = ParserUtils.getXmlLang(parser, xmlEnvironment);
|
String language = ParserUtils.getXmlLang(parser, xmlEnvironment);
|
||||||
stanza.setLanguage(language);
|
stanzaBuilder.setLanguage(language);
|
||||||
|
|
||||||
|
return stanzaBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message parseMessage(XmlPullParser parser) throws XmlPullParserException, IOException, SmackParsingException {
|
public static Message parseMessage(XmlPullParser parser) throws XmlPullParserException, IOException, SmackParsingException {
|
||||||
|
@ -144,8 +156,8 @@ public class PacketParserUtils {
|
||||||
* @param parser the XML parser, positioned at the start of a message packet.
|
* @param parser the XML parser, positioned at the start of a message packet.
|
||||||
* @param outerXmlEnvironment the outer XML environment (optional).
|
* @param outerXmlEnvironment the outer XML environment (optional).
|
||||||
* @return a Message packet.
|
* @return a Message packet.
|
||||||
* @throws XmlPullParserException if an error in the XML parser occured.
|
* @throws XmlPullParserException if an error in the XML parser occurred.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
||||||
*/
|
*/
|
||||||
public static Message parseMessage(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException {
|
public static Message parseMessage(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException {
|
||||||
|
@ -154,11 +166,14 @@ public class PacketParserUtils {
|
||||||
|
|
||||||
XmlEnvironment messageXmlEnvironment = XmlEnvironment.from(parser, outerXmlEnvironment);
|
XmlEnvironment messageXmlEnvironment = XmlEnvironment.from(parser, outerXmlEnvironment);
|
||||||
final int initialDepth = parser.getDepth();
|
final int initialDepth = parser.getDepth();
|
||||||
Message message = new Message();
|
|
||||||
parseCommonStanzaAttributes(message, parser, outerXmlEnvironment);
|
MessageBuilder message = parseCommonStanzaAttributes(id -> {
|
||||||
|
return StanzaBuilder.buildMessage(id);
|
||||||
|
}, parser, outerXmlEnvironment);
|
||||||
|
|
||||||
String typeString = parser.getAttributeValue("", "type");
|
String typeString = parser.getAttributeValue("", "type");
|
||||||
if (typeString != null) {
|
if (typeString != null) {
|
||||||
message.setType(Message.Type.fromString(typeString));
|
message.ofType(Message.Type.fromString(typeString));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse sub-elements. We include extra logic to make sure the values
|
// Parse sub-elements. We include extra logic to make sure the values
|
||||||
|
@ -176,9 +191,8 @@ public class PacketParserUtils {
|
||||||
String xmlLangSubject = ParserUtils.getXmlLang(parser);
|
String xmlLangSubject = ParserUtils.getXmlLang(parser);
|
||||||
String subject = parseElementText(parser);
|
String subject = parseElementText(parser);
|
||||||
|
|
||||||
if (message.getSubject(xmlLangSubject) == null) {
|
Message.Subject subjectExtensionElement = new Message.Subject(xmlLangSubject, subject);
|
||||||
message.addSubject(xmlLangSubject, subject);
|
message.addExtension(subjectExtensionElement);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "thread":
|
case "thread":
|
||||||
if (thread == null) {
|
if (thread == null) {
|
||||||
|
@ -189,7 +203,8 @@ public class PacketParserUtils {
|
||||||
message.setError(parseError(parser, messageXmlEnvironment));
|
message.setError(parseError(parser, messageXmlEnvironment));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PacketParserUtils.addExtensionElement(message, parser, elementName, namespace, messageXmlEnvironment);
|
ExtensionElement extensionElement = parseExtensionElement(elementName, namespace, parser, messageXmlEnvironment);
|
||||||
|
message.addExtension(extensionElement);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -208,7 +223,7 @@ public class PacketParserUtils {
|
||||||
// situations where we have a body element with an explicit xml lang set and once where the value is inherited
|
// situations where we have a body element with an explicit xml lang set and once where the value is inherited
|
||||||
// and both values are equal.
|
// and both values are equal.
|
||||||
|
|
||||||
return message;
|
return message.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -223,8 +238,8 @@ public class PacketParserUtils {
|
||||||
*
|
*
|
||||||
* @param parser TODO javadoc me please
|
* @param parser TODO javadoc me please
|
||||||
* @return the textual content of the element as String
|
* @return the textual content of the element as String
|
||||||
* @throws XmlPullParserException if an error in the XML parser occured.
|
* @throws XmlPullParserException if an error in the XML parser occurred.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
*/
|
*/
|
||||||
public static String parseElementText(XmlPullParser parser) throws XmlPullParserException, IOException {
|
public static String parseElementText(XmlPullParser parser) throws XmlPullParserException, IOException {
|
||||||
assert parser.getEventType() == XmlPullParser.Event.START_ELEMENT;
|
assert parser.getEventType() == XmlPullParser.Event.START_ELEMENT;
|
||||||
|
@ -262,8 +277,8 @@ public class PacketParserUtils {
|
||||||
*
|
*
|
||||||
* @param parser the XML pull parser
|
* @param parser the XML pull parser
|
||||||
* @return the element as string
|
* @return the element as string
|
||||||
* @throws XmlPullParserException if an error in the XML parser occured.
|
* @throws XmlPullParserException if an error in the XML parser occurred.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
*/
|
*/
|
||||||
public static CharSequence parseElement(XmlPullParser parser) throws XmlPullParserException, IOException {
|
public static CharSequence parseElement(XmlPullParser parser) throws XmlPullParserException, IOException {
|
||||||
return parseElement(parser, false);
|
return parseElement(parser, false);
|
||||||
|
@ -301,8 +316,8 @@ public class PacketParserUtils {
|
||||||
* @param depth TODO javadoc me please
|
* @param depth TODO javadoc me please
|
||||||
* @param fullNamespaces TODO javadoc me please
|
* @param fullNamespaces TODO javadoc me please
|
||||||
* @return the content of the current depth
|
* @return the content of the current depth
|
||||||
* @throws XmlPullParserException if an error in the XML parser occured.
|
* @throws XmlPullParserException if an error in the XML parser occurred.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
*/
|
*/
|
||||||
public static CharSequence parseContentDepth(XmlPullParser parser, int depth, boolean fullNamespaces) throws XmlPullParserException, IOException {
|
public static CharSequence parseContentDepth(XmlPullParser parser, int depth, boolean fullNamespaces) throws XmlPullParserException, IOException {
|
||||||
if (parser.supportsRoundtrip()) {
|
if (parser.supportsRoundtrip()) {
|
||||||
|
@ -427,8 +442,8 @@ public class PacketParserUtils {
|
||||||
* @param parser the XML parser, positioned at the start of a presence packet.
|
* @param parser the XML parser, positioned at the start of a presence packet.
|
||||||
* @param outerXmlEnvironment the outer XML environment (optional).
|
* @param outerXmlEnvironment the outer XML environment (optional).
|
||||||
* @return a Presence packet.
|
* @return a Presence packet.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws XmlPullParserException if an error in the XML parser occured.
|
* @throws XmlPullParserException if an error in the XML parser occurred.
|
||||||
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
||||||
*/
|
*/
|
||||||
public static Presence parsePresence(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException {
|
public static Presence parsePresence(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException {
|
||||||
|
@ -436,13 +451,16 @@ public class PacketParserUtils {
|
||||||
final int initialDepth = parser.getDepth();
|
final int initialDepth = parser.getDepth();
|
||||||
XmlEnvironment presenceXmlEnvironment = XmlEnvironment.from(parser, outerXmlEnvironment);
|
XmlEnvironment presenceXmlEnvironment = XmlEnvironment.from(parser, outerXmlEnvironment);
|
||||||
|
|
||||||
|
PresenceBuilder presence = parseCommonStanzaAttributes(
|
||||||
|
stanzaId -> StanzaBuilder.buildPresence(stanzaId), parser, outerXmlEnvironment);
|
||||||
|
|
||||||
Presence.Type type = Presence.Type.available;
|
Presence.Type type = Presence.Type.available;
|
||||||
String typeString = parser.getAttributeValue("", "type");
|
String typeString = parser.getAttributeValue("", "type");
|
||||||
if (typeString != null && !typeString.equals("")) {
|
if (typeString != null && !typeString.equals("")) {
|
||||||
type = Presence.Type.fromString(typeString);
|
type = Presence.Type.fromString(typeString);
|
||||||
}
|
}
|
||||||
Presence presence = new Presence(type);
|
|
||||||
parseCommonStanzaAttributes(presence, parser, outerXmlEnvironment);
|
presence.ofType(type);
|
||||||
|
|
||||||
// Parse sub-elements
|
// Parse sub-elements
|
||||||
outerloop: while (true) {
|
outerloop: while (true) {
|
||||||
|
@ -468,9 +486,7 @@ public class PacketParserUtils {
|
||||||
// '<show />' element, which is a invalid XMPP presence
|
// '<show />' element, which is a invalid XMPP presence
|
||||||
// stanza according to RFC 6121 4.7.2.1
|
// stanza according to RFC 6121 4.7.2.1
|
||||||
LOGGER.warning("Empty or null mode text in presence show element form "
|
LOGGER.warning("Empty or null mode text in presence show element form "
|
||||||
+ presence.getFrom()
|
+ presence
|
||||||
+ " with id '"
|
|
||||||
+ presence.getStanzaId()
|
|
||||||
+ "' which is invalid according to RFC6121 4.7.2.1");
|
+ "' which is invalid according to RFC6121 4.7.2.1");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -482,10 +498,10 @@ public class PacketParserUtils {
|
||||||
// Be extra robust: Skip PacketExtensions that cause Exceptions, instead of
|
// Be extra robust: Skip PacketExtensions that cause Exceptions, instead of
|
||||||
// failing completely here. See SMACK-390 for more information.
|
// failing completely here. See SMACK-390 for more information.
|
||||||
try {
|
try {
|
||||||
PacketParserUtils.addExtensionElement(presence, parser, elementName, namespace, presenceXmlEnvironment);
|
ExtensionElement extensionElement = parseExtensionElement(elementName, namespace, parser, presenceXmlEnvironment);
|
||||||
|
presence.addExtension(extensionElement);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.warning("Failed to parse extension element in Presence stanza: \"" + e + "\" from: '"
|
LOGGER.log(Level.WARNING, "Failed to parse extension element in Presence stanza: " + presence, e);
|
||||||
+ presence.getFrom() + " id: '" + presence.getStanzaId() + "'");
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -500,7 +516,8 @@ public class PacketParserUtils {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return presence;
|
|
||||||
|
return presence.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IQ parseIQ(XmlPullParser parser) throws Exception {
|
public static IQ parseIQ(XmlPullParser parser) throws Exception {
|
||||||
|
@ -513,9 +530,9 @@ public class PacketParserUtils {
|
||||||
* @param parser the XML parser, positioned at the start of an IQ packet.
|
* @param parser the XML parser, positioned at the start of an IQ packet.
|
||||||
* @param outerXmlEnvironment the outer XML environment (optional).
|
* @param outerXmlEnvironment the outer XML environment (optional).
|
||||||
* @return an IQ object.
|
* @return an IQ object.
|
||||||
* @throws XmlPullParserException if an error in the XML parser occured.
|
* @throws XmlPullParserException if an error in the XML parser occurred.
|
||||||
* @throws XmppStringprepException if the provided string is invalid.
|
* @throws XmppStringprepException if the provided string is invalid.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
||||||
*/
|
*/
|
||||||
public static IQ parseIQ(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, XmppStringprepException, IOException, SmackParsingException {
|
public static IQ parseIQ(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, XmppStringprepException, IOException, SmackParsingException {
|
||||||
|
@ -523,12 +540,19 @@ public class PacketParserUtils {
|
||||||
final int initialDepth = parser.getDepth();
|
final int initialDepth = parser.getDepth();
|
||||||
XmlEnvironment iqXmlEnvironment = XmlEnvironment.from(parser, outerXmlEnvironment);
|
XmlEnvironment iqXmlEnvironment = XmlEnvironment.from(parser, outerXmlEnvironment);
|
||||||
IQ iqPacket = null;
|
IQ iqPacket = null;
|
||||||
StanzaError.Builder error = null;
|
StanzaError error = null;
|
||||||
|
|
||||||
final String id = parser.getAttributeValue("", "id");
|
final String id = parser.getAttributeValue("", "id");
|
||||||
|
IqData iqData = StanzaBuilder.buildIqData(id);
|
||||||
|
|
||||||
final Jid to = ParserUtils.getJidAttribute(parser, "to");
|
final Jid to = ParserUtils.getJidAttribute(parser, "to");
|
||||||
|
iqData.to(to);
|
||||||
|
|
||||||
final Jid from = ParserUtils.getJidAttribute(parser, "from");
|
final Jid from = ParserUtils.getJidAttribute(parser, "from");
|
||||||
|
iqData.from(from);
|
||||||
|
|
||||||
final IQ.Type type = IQ.Type.fromString(parser.getAttributeValue("", "type"));
|
final IQ.Type type = IQ.Type.fromString(parser.getAttributeValue("", "type"));
|
||||||
|
iqData.ofType(type);
|
||||||
|
|
||||||
outerloop: while (true) {
|
outerloop: while (true) {
|
||||||
XmlPullParser.Event eventType = parser.next();
|
XmlPullParser.Event eventType = parser.next();
|
||||||
|
@ -544,9 +568,9 @@ public class PacketParserUtils {
|
||||||
// Otherwise, see if there is a registered provider for
|
// Otherwise, see if there is a registered provider for
|
||||||
// this element name and namespace.
|
// this element name and namespace.
|
||||||
default:
|
default:
|
||||||
IQProvider<IQ> provider = ProviderManager.getIQProvider(elementName, namespace);
|
IqProvider<IQ> provider = ProviderManager.getIQProvider(elementName, namespace);
|
||||||
if (provider != null) {
|
if (provider != null) {
|
||||||
iqPacket = provider.parse(parser, outerXmlEnvironment);
|
iqPacket = provider.parse(parser, iqData, outerXmlEnvironment);
|
||||||
}
|
}
|
||||||
// Note that if we reach this code, it is guranteed that the result IQ contained a child element
|
// Note that if we reach this code, it is guranteed that the result IQ contained a child element
|
||||||
// (RFC 6120 § 8.2.3 6) because otherwhise we would have reached the END_ELEMENT first.
|
// (RFC 6120 § 8.2.3 6) because otherwhise we would have reached the END_ELEMENT first.
|
||||||
|
@ -598,8 +622,8 @@ public class PacketParserUtils {
|
||||||
*
|
*
|
||||||
* @param parser the XML parser, positioned at the start of the mechanisms stanza.
|
* @param parser the XML parser, positioned at the start of the mechanisms stanza.
|
||||||
* @return a collection of Stings with the mechanisms included in the mechanisms stanza.
|
* @return a collection of Stings with the mechanisms included in the mechanisms stanza.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws XmlPullParserException if an error in the XML parser occured.
|
* @throws XmlPullParserException if an error in the XML parser occurred.
|
||||||
*/
|
*/
|
||||||
public static Collection<String> parseMechanisms(XmlPullParser parser)
|
public static Collection<String> parseMechanisms(XmlPullParser parser)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
|
@ -628,7 +652,7 @@ public class PacketParserUtils {
|
||||||
*
|
*
|
||||||
* @param parser the XML parser, positioned at the start of the compression stanza.
|
* @param parser the XML parser, positioned at the start of the compression stanza.
|
||||||
* @return The CompressionFeature stream element
|
* @return The CompressionFeature stream element
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws XmlPullParserException if an exception occurs while parsing the stanza.
|
* @throws XmlPullParserException if an exception occurs while parsing the stanza.
|
||||||
*/
|
*/
|
||||||
public static Compress.Feature parseCompressionFeature(XmlPullParser parser)
|
public static Compress.Feature parseCompressionFeature(XmlPullParser parser)
|
||||||
|
@ -695,8 +719,8 @@ public class PacketParserUtils {
|
||||||
* @param parser the XML parser.
|
* @param parser the XML parser.
|
||||||
* @param outerXmlEnvironment the outer XML environment (optional).
|
* @param outerXmlEnvironment the outer XML environment (optional).
|
||||||
* @return an stream error packet.
|
* @return an stream error packet.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws XmlPullParserException if an error in the XML parser occured.
|
* @throws XmlPullParserException if an error in the XML parser occurred.
|
||||||
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
||||||
*/
|
*/
|
||||||
public static StreamError parseStreamError(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException {
|
public static StreamError parseStreamError(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException {
|
||||||
|
@ -747,7 +771,7 @@ public class PacketParserUtils {
|
||||||
return new StreamError(condition, conditionText, descriptiveTexts, extensions);
|
return new StreamError(condition, conditionText, descriptiveTexts, extensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StanzaError.Builder parseError(XmlPullParser parser) throws XmlPullParserException, IOException, SmackParsingException {
|
public static StanzaError parseError(XmlPullParser parser) throws XmlPullParserException, IOException, SmackParsingException {
|
||||||
return parseError(parser, null);
|
return parseError(parser, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -757,11 +781,11 @@ public class PacketParserUtils {
|
||||||
* @param parser the XML parser.
|
* @param parser the XML parser.
|
||||||
* @param outerXmlEnvironment the outer XML environment (optional).
|
* @param outerXmlEnvironment the outer XML environment (optional).
|
||||||
* @return an error sub-packet.
|
* @return an error sub-packet.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws XmlPullParserException if an error in the XML parser occured.
|
* @throws XmlPullParserException if an error in the XML parser occurred.
|
||||||
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
||||||
*/
|
*/
|
||||||
public static StanzaError.Builder parseError(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException {
|
public static StanzaError parseError(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException {
|
||||||
final int initialDepth = parser.getDepth();
|
final int initialDepth = parser.getDepth();
|
||||||
Map<String, String> descriptiveTexts = null;
|
Map<String, String> descriptiveTexts = null;
|
||||||
XmlEnvironment stanzaErrorXmlEnvironment = XmlEnvironment.from(parser, outerXmlEnvironment);
|
XmlEnvironment stanzaErrorXmlEnvironment = XmlEnvironment.from(parser, outerXmlEnvironment);
|
||||||
|
@ -808,7 +832,8 @@ public class PacketParserUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.setExtensions(extensions).setDescriptiveTexts(descriptiveTexts);
|
builder.setExtensions(extensions).setDescriptiveTexts(descriptiveTexts);
|
||||||
return builder;
|
|
||||||
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -820,8 +845,8 @@ public class PacketParserUtils {
|
||||||
* @param outerXmlEnvironment the outer XML environment (optional).
|
* @param outerXmlEnvironment the outer XML environment (optional).
|
||||||
*
|
*
|
||||||
* @return an extension element.
|
* @return an extension element.
|
||||||
* @throws XmlPullParserException if an error in the XML parser occured.
|
* @throws XmlPullParserException if an error in the XML parser occurred.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
||||||
*/
|
*/
|
||||||
public static ExtensionElement parseExtensionElement(String elementName, String namespace,
|
public static ExtensionElement parseExtensionElement(String elementName, String namespace,
|
||||||
|
@ -898,6 +923,18 @@ public class PacketParserUtils {
|
||||||
return new Session.Feature(optional);
|
return new Session.Feature(optional);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void addExtensionElement(StanzaBuilder<?> stanzaBuilder, XmlPullParser parser, XmlEnvironment outerXmlEnvironment)
|
||||||
|
throws XmlPullParserException, IOException, SmackParsingException {
|
||||||
|
ParserUtils.assertAtStartTag(parser);
|
||||||
|
addExtensionElement(stanzaBuilder, parser, parser.getName(), parser.getNamespace(), outerXmlEnvironment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addExtensionElement(StanzaBuilder<?> stanzaBuilder, XmlPullParser parser, String elementName,
|
||||||
|
String namespace, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException {
|
||||||
|
ExtensionElement extensionElement = parseExtensionElement(elementName, namespace, parser, outerXmlEnvironment);
|
||||||
|
stanzaBuilder.addExtension(extensionElement);
|
||||||
|
}
|
||||||
|
|
||||||
public static void addExtensionElement(Stanza packet, XmlPullParser parser, XmlEnvironment outerXmlEnvironment)
|
public static void addExtensionElement(Stanza packet, XmlPullParser parser, XmlEnvironment outerXmlEnvironment)
|
||||||
throws XmlPullParserException, IOException, SmackParsingException {
|
throws XmlPullParserException, IOException, SmackParsingException {
|
||||||
ParserUtils.assertAtStartTag(parser);
|
ParserUtils.assertAtStartTag(parser);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -427,6 +427,13 @@ public class StringUtils {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isNullOrNotEmpty(CharSequence cs) {
|
||||||
|
if (cs == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !cs.toString().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given CharSequence is empty.
|
* Returns true if the given CharSequence is empty.
|
||||||
*
|
*
|
||||||
|
@ -456,6 +463,11 @@ public class StringUtils {
|
||||||
*/
|
*/
|
||||||
public static StringBuilder toStringBuilder(Collection<? extends Object> collection, String delimiter) {
|
public static StringBuilder toStringBuilder(Collection<? extends Object> collection, String delimiter) {
|
||||||
StringBuilder sb = new StringBuilder(collection.size() * 20);
|
StringBuilder sb = new StringBuilder(collection.size() * 20);
|
||||||
|
appendTo(collection, delimiter, sb);
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void appendTo(Collection<? extends Object> collection, String delimiter, StringBuilder sb) {
|
||||||
for (Iterator<? extends Object> it = collection.iterator(); it.hasNext();) {
|
for (Iterator<? extends Object> it = collection.iterator(); it.hasNext();) {
|
||||||
Object cs = it.next();
|
Object cs = it.next();
|
||||||
sb.append(cs);
|
sb.append(cs);
|
||||||
|
@ -463,7 +475,6 @@ public class StringUtils {
|
||||||
sb.append(delimiter);
|
sb.append(delimiter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String returnIfNotEmptyTrimmed(String string) {
|
public static String returnIfNotEmptyTrimmed(String string) {
|
||||||
|
@ -524,7 +535,7 @@ public class StringUtils {
|
||||||
if (cs == null) {
|
if (cs == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (cs.toString().isEmpty()) {
|
if (isEmpty(cs)) {
|
||||||
throw new IllegalArgumentException(message);
|
throw new IllegalArgumentException(message);
|
||||||
}
|
}
|
||||||
return cs;
|
return cs;
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ToStringUtil {
|
||||||
|
|
||||||
|
public static Builder builderFor(Class<?> clazz) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(clazz.getSimpleName()).append('(');
|
||||||
|
return new Builder(sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Builder {
|
||||||
|
private final StringBuilder sb;
|
||||||
|
|
||||||
|
private Builder(StringBuilder sb) {
|
||||||
|
this.sb = sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder addValue(String name, Object value) {
|
||||||
|
if (value == null) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
if (sb.charAt(sb.length() - 1) != '(') {
|
||||||
|
sb.append(' ');
|
||||||
|
}
|
||||||
|
sb.append(name).append("='").append(value).append('\'');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <V> Builder add(String name, Collection<? extends V> values, Function<?, V> toStringFunction) {
|
||||||
|
if (values.isEmpty()) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append(' ').append(name).append('[');
|
||||||
|
|
||||||
|
List<String> stringValues = new ArrayList<>(values.size());
|
||||||
|
for (V value : values) {
|
||||||
|
String valueString = toStringFunction.apply(value).toString();
|
||||||
|
stringValues.add(valueString);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringUtils.appendTo(stringValues, ", ", sb);
|
||||||
|
|
||||||
|
sb.append(']');
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String build() {
|
||||||
|
sb.append(')');
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -628,7 +628,7 @@ public class XmlStringBuilder implements Appendable, CharSequence, Element {
|
||||||
*
|
*
|
||||||
* @param writer TODO javadoc me please
|
* @param writer TODO javadoc me please
|
||||||
* @param enclosingXmlEnvironment the enclosing XML environment.
|
* @param enclosingXmlEnvironment the enclosing XML environment.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
*/
|
*/
|
||||||
public void write(Writer writer, XmlEnvironment enclosingXmlEnvironment) throws IOException {
|
public void write(Writer writer, XmlEnvironment enclosingXmlEnvironment) throws IOException {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smack.util;
|
package org.jivesoftware.smack.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.xml.namespace.QName;
|
import javax.xml.namespace.QName;
|
||||||
|
@ -52,4 +55,21 @@ public class XmppElementUtil {
|
||||||
return new QName(namespace, element);
|
return new QName(namespace, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <E extends FullyQualifiedElement, R extends FullyQualifiedElement> List<R> getElementsFrom(
|
||||||
|
MultiMap<QName, E> elementMap, Class<R> extensionElementClass) {
|
||||||
|
QName qname = XmppElementUtil.getQNameFor(extensionElementClass);
|
||||||
|
|
||||||
|
List<E> extensionElements = elementMap.getAll(qname);
|
||||||
|
|
||||||
|
if (extensionElements.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<R> res = new ArrayList<>(extensionElements.size());
|
||||||
|
for (E extensionElement : extensionElements) {
|
||||||
|
R e = extensionElementClass.cast(extensionElement);
|
||||||
|
res.add(e);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,8 @@ package org.jivesoftware.smack.filter;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.Message;
|
|
||||||
import org.jivesoftware.smack.packet.Stanza;
|
import org.jivesoftware.smack.packet.Stanza;
|
||||||
|
import org.jivesoftware.smack.packet.StanzaBuilder;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.jxmpp.jid.EntityFullJid;
|
import org.jxmpp.jid.EntityFullJid;
|
||||||
|
@ -47,7 +47,7 @@ public class FromMatchesFilterTest {
|
||||||
@Test
|
@Test
|
||||||
public void autoCompareMatchingEntityFullJid() {
|
public void autoCompareMatchingEntityFullJid() {
|
||||||
FromMatchesFilter filter = FromMatchesFilter.create(FULL_JID1_R1);
|
FromMatchesFilter filter = FromMatchesFilter.create(FULL_JID1_R1);
|
||||||
Stanza packet = new Message();
|
Stanza packet = StanzaBuilder.buildMessage().build();
|
||||||
|
|
||||||
packet.setFrom(FULL_JID1_R1);
|
packet.setFrom(FULL_JID1_R1);
|
||||||
assertTrue(filter.accept(packet));
|
assertTrue(filter.accept(packet));
|
||||||
|
@ -71,7 +71,7 @@ public class FromMatchesFilterTest {
|
||||||
@Test
|
@Test
|
||||||
public void autoCompareMatchingBaseJid() {
|
public void autoCompareMatchingBaseJid() {
|
||||||
FromMatchesFilter filter = FromMatchesFilter.create(BASE_JID1);
|
FromMatchesFilter filter = FromMatchesFilter.create(BASE_JID1);
|
||||||
Stanza packet = new Message();
|
Stanza packet = StanzaBuilder.buildMessage().build();
|
||||||
|
|
||||||
packet.setFrom(BASE_JID1);
|
packet.setFrom(BASE_JID1);
|
||||||
assertTrue(filter.accept(packet));
|
assertTrue(filter.accept(packet));
|
||||||
|
@ -95,7 +95,7 @@ public class FromMatchesFilterTest {
|
||||||
@Test
|
@Test
|
||||||
public void autoCompareMatchingServiceJid() {
|
public void autoCompareMatchingServiceJid() {
|
||||||
FromMatchesFilter filter = FromMatchesFilter.create(SERVICE_JID1);
|
FromMatchesFilter filter = FromMatchesFilter.create(SERVICE_JID1);
|
||||||
Stanza packet = new Message();
|
Stanza packet = StanzaBuilder.buildMessage().build();
|
||||||
|
|
||||||
packet.setFrom(SERVICE_JID1);
|
packet.setFrom(SERVICE_JID1);
|
||||||
assertTrue(filter.accept(packet));
|
assertTrue(filter.accept(packet));
|
||||||
|
@ -116,7 +116,7 @@ public class FromMatchesFilterTest {
|
||||||
@Test
|
@Test
|
||||||
public void bareCompareMatchingEntityFullJid() {
|
public void bareCompareMatchingEntityFullJid() {
|
||||||
FromMatchesFilter filter = FromMatchesFilter.createBare(FULL_JID1_R1);
|
FromMatchesFilter filter = FromMatchesFilter.createBare(FULL_JID1_R1);
|
||||||
Stanza packet = new Message();
|
Stanza packet = StanzaBuilder.buildMessage().build();
|
||||||
|
|
||||||
packet.setFrom(BASE_JID1);
|
packet.setFrom(BASE_JID1);
|
||||||
assertTrue(filter.accept(packet));
|
assertTrue(filter.accept(packet));
|
||||||
|
@ -140,7 +140,7 @@ public class FromMatchesFilterTest {
|
||||||
@Test
|
@Test
|
||||||
public void bareCompareMatchingBaseJid() {
|
public void bareCompareMatchingBaseJid() {
|
||||||
FromMatchesFilter filter = FromMatchesFilter.createBare(BASE_JID1);
|
FromMatchesFilter filter = FromMatchesFilter.createBare(BASE_JID1);
|
||||||
Stanza packet = new Message();
|
Stanza packet = StanzaBuilder.buildMessage().build();
|
||||||
|
|
||||||
packet.setFrom(BASE_JID1);
|
packet.setFrom(BASE_JID1);
|
||||||
assertTrue(filter.accept(packet));
|
assertTrue(filter.accept(packet));
|
||||||
|
@ -164,7 +164,7 @@ public class FromMatchesFilterTest {
|
||||||
@Test
|
@Test
|
||||||
public void bareCompareMatchingServiceJid() {
|
public void bareCompareMatchingServiceJid() {
|
||||||
FromMatchesFilter filter = FromMatchesFilter.createBare(SERVICE_JID1);
|
FromMatchesFilter filter = FromMatchesFilter.createBare(SERVICE_JID1);
|
||||||
Stanza packet = new Message();
|
Stanza packet = StanzaBuilder.buildMessage().build();
|
||||||
|
|
||||||
packet.setFrom(SERVICE_JID1);
|
packet.setFrom(SERVICE_JID1);
|
||||||
assertTrue(filter.accept(packet));
|
assertTrue(filter.accept(packet));
|
||||||
|
@ -185,7 +185,7 @@ public class FromMatchesFilterTest {
|
||||||
@Test
|
@Test
|
||||||
public void fullCompareMatchingEntityFullJid() {
|
public void fullCompareMatchingEntityFullJid() {
|
||||||
FromMatchesFilter filter = FromMatchesFilter.createFull(FULL_JID1_R1);
|
FromMatchesFilter filter = FromMatchesFilter.createFull(FULL_JID1_R1);
|
||||||
Stanza packet = new Message();
|
Stanza packet = StanzaBuilder.buildMessage().build();
|
||||||
|
|
||||||
packet.setFrom(FULL_JID1_R1);
|
packet.setFrom(FULL_JID1_R1);
|
||||||
assertTrue(filter.accept(packet));
|
assertTrue(filter.accept(packet));
|
||||||
|
@ -209,7 +209,7 @@ public class FromMatchesFilterTest {
|
||||||
@Test
|
@Test
|
||||||
public void fullCompareMatchingBaseJid() {
|
public void fullCompareMatchingBaseJid() {
|
||||||
FromMatchesFilter filter = FromMatchesFilter.createFull(BASE_JID1);
|
FromMatchesFilter filter = FromMatchesFilter.createFull(BASE_JID1);
|
||||||
Stanza packet = new Message();
|
Stanza packet = StanzaBuilder.buildMessage().build();
|
||||||
|
|
||||||
packet.setFrom(BASE_JID1);
|
packet.setFrom(BASE_JID1);
|
||||||
assertTrue(filter.accept(packet));
|
assertTrue(filter.accept(packet));
|
||||||
|
@ -233,7 +233,7 @@ public class FromMatchesFilterTest {
|
||||||
@Test
|
@Test
|
||||||
public void fullCompareMatchingServiceJid() {
|
public void fullCompareMatchingServiceJid() {
|
||||||
FromMatchesFilter filter = FromMatchesFilter.createFull(SERVICE_JID1);
|
FromMatchesFilter filter = FromMatchesFilter.createFull(SERVICE_JID1);
|
||||||
Stanza packet = new Message();
|
Stanza packet = StanzaBuilder.buildMessage().build();
|
||||||
|
|
||||||
packet.setFrom(SERVICE_JID1);
|
packet.setFrom(SERVICE_JID1);
|
||||||
assertTrue(filter.accept(packet));
|
assertTrue(filter.accept(packet));
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class IQResponseTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGeneratingValidErrorResponse() throws XmppStringprepException {
|
public void testGeneratingValidErrorResponse() throws XmppStringprepException {
|
||||||
final StanzaError.Builder error = StanzaError.getBuilder(StanzaError.Condition.bad_request);
|
final StanzaError error = StanzaError.getBuilder(StanzaError.Condition.bad_request).build();
|
||||||
final IQ request = new TestIQ(ELEMENT, NAMESPACE);
|
final IQ request = new TestIQ(ELEMENT, NAMESPACE);
|
||||||
|
|
||||||
request.setType(IQ.Type.set);
|
request.setType(IQ.Type.set);
|
||||||
|
@ -75,7 +75,7 @@ public class IQResponseTest {
|
||||||
assertNotNull(result.getStanzaId());
|
assertNotNull(result.getStanzaId());
|
||||||
assertEquals(request.getStanzaId(), result.getStanzaId());
|
assertEquals(request.getStanzaId(), result.getStanzaId());
|
||||||
assertEquals(request.getFrom(), result.getTo());
|
assertEquals(request.getFrom(), result.getTo());
|
||||||
assertEquals(error.build().toXML().toString(), result.getError().toXML().toString());
|
assertEquals(error.toXML().toString(), result.getError().toXML().toString());
|
||||||
// TODO this test was never valid
|
// TODO this test was never valid
|
||||||
// assertEquals(CHILD_ELEMENT, result.getChildElementXML());
|
// assertEquals(CHILD_ELEMENT, result.getChildElementXML());
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ public class IQResponseTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGeneratingErrorBasedOnError() throws XmppStringprepException {
|
public void testGeneratingErrorBasedOnError() throws XmppStringprepException {
|
||||||
final StanzaError.Builder error = StanzaError.getBuilder(StanzaError.Condition.bad_request);
|
final StanzaError error = StanzaError.getBuilder(StanzaError.Condition.bad_request).build();
|
||||||
final IQ request = new TestIQ(ELEMENT, NAMESPACE);
|
final IQ request = new TestIQ(ELEMENT, NAMESPACE);
|
||||||
|
|
||||||
request.setType(IQ.Type.error);
|
request.setType(IQ.Type.error);
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.jivesoftware.smack.packet;
|
||||||
|
|
||||||
import static org.jivesoftware.smack.test.util.XmlUnitUtils.assertXmlSimilar;
|
import static org.jivesoftware.smack.test.util.XmlUnitUtils.assertXmlSimilar;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -44,10 +43,12 @@ public class MessageTest {
|
||||||
.append("</message>");
|
.append("</message>");
|
||||||
String control = controlBuilder.toString();
|
String control = controlBuilder.toString();
|
||||||
|
|
||||||
Message messageTypeInConstructor = new Message(null, Message.Type.chat);
|
Message messageBuildWithBuilder = StanzaBuilder.buildMessage()
|
||||||
messageTypeInConstructor.setStanzaId(null);
|
.ofType(Message.Type.chat)
|
||||||
assertEquals(type, messageTypeInConstructor.getType());
|
.build();
|
||||||
assertXmlSimilar(control, messageTypeInConstructor.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
|
||||||
|
assertEquals(type, messageBuildWithBuilder.getType());
|
||||||
|
assertXmlSimilar(control, messageBuildWithBuilder.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
|
|
||||||
controlBuilder = new StringBuilder();
|
controlBuilder = new StringBuilder();
|
||||||
controlBuilder.append("<message")
|
controlBuilder.append("<message")
|
||||||
|
@ -57,16 +58,18 @@ public class MessageTest {
|
||||||
.append("</message>");
|
.append("</message>");
|
||||||
control = controlBuilder.toString();
|
control = controlBuilder.toString();
|
||||||
|
|
||||||
Message messageTypeSet = getNewMessage();
|
Message messageTypeSet = StanzaBuilder.buildMessage()
|
||||||
messageTypeSet.setType(type2);
|
.ofType(type2)
|
||||||
|
.build();
|
||||||
assertEquals(type2, messageTypeSet.getType());
|
assertEquals(type2, messageTypeSet.getType());
|
||||||
assertXmlSimilar(control, messageTypeSet.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertXmlSimilar(control, messageTypeSet.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = NullPointerException.class)
|
@Test(expected = NullPointerException.class)
|
||||||
public void setNullMessageBodyTest() {
|
public void setNullMessageBodyTest() {
|
||||||
Message message = getNewMessage();
|
StanzaBuilder.buildMessage()
|
||||||
message.addBody(null, null);
|
.addBody(null, null)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -81,9 +84,9 @@ public class MessageTest {
|
||||||
.append("</message>");
|
.append("</message>");
|
||||||
String control = controlBuilder.toString();
|
String control = controlBuilder.toString();
|
||||||
|
|
||||||
Message message = getNewMessage();
|
Message message = StanzaBuilder.buildMessage()
|
||||||
message.setSubject(messageSubject);
|
.setSubject(messageSubject)
|
||||||
|
.build();
|
||||||
assertEquals(messageSubject, message.getSubject());
|
assertEquals(messageSubject, message.getSubject());
|
||||||
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
}
|
}
|
||||||
|
@ -100,9 +103,9 @@ public class MessageTest {
|
||||||
.append("</message>");
|
.append("</message>");
|
||||||
String control = controlBuilder.toString();
|
String control = controlBuilder.toString();
|
||||||
|
|
||||||
Message message = getNewMessage();
|
Message message = StanzaBuilder.buildMessage()
|
||||||
message.setBody(messageBody);
|
.setBody(messageBody)
|
||||||
|
.build();
|
||||||
assertEquals(messageBody, message.getBody());
|
assertEquals(messageBody, message.getBody());
|
||||||
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
}
|
}
|
||||||
|
@ -133,10 +136,11 @@ public class MessageTest {
|
||||||
.append("</message>");
|
.append("</message>");
|
||||||
String control = controlBuilder.toString();
|
String control = controlBuilder.toString();
|
||||||
|
|
||||||
Message message = getNewMessage();
|
Message message = StanzaBuilder.buildMessage()
|
||||||
message.addBody(null, messageBody1);
|
.addBody(null, messageBody1)
|
||||||
message.addBody(lang2, messageBody2);
|
.addBody(lang2, messageBody2)
|
||||||
message.addBody(lang3, messageBody3);
|
.addBody(lang3, messageBody3)
|
||||||
|
.build();
|
||||||
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE));
|
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE));
|
||||||
|
|
||||||
Collection<String> languages = message.getBodyLanguages();
|
Collection<String> languages = message.getBodyLanguages();
|
||||||
|
@ -148,21 +152,20 @@ public class MessageTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void removeMessageBodyTest() {
|
public void simpleMessageBodyTest() {
|
||||||
Message message = getNewMessage();
|
Message message = StanzaBuilder.buildMessage()
|
||||||
message.setBody("test");
|
.setBody("test")
|
||||||
|
.build();
|
||||||
assertTrue(message.getBodies().size() == 1);
|
assertTrue(message.getBodies().size() == 1);
|
||||||
|
|
||||||
message.setBody(null);
|
message = StanzaBuilder.buildMessage().build();
|
||||||
assertTrue(message.getBodies().size() == 0);
|
assertTrue(message.getBodies().size() == 0);
|
||||||
|
|
||||||
assertFalse(message.removeBody("sp"));
|
|
||||||
|
|
||||||
Message.Body body = message.addBody("es", "test");
|
message = StanzaBuilder.buildMessage()
|
||||||
|
.addBody("es", "test")
|
||||||
|
.build();
|
||||||
assertTrue(message.getBodies().size() == 1);
|
assertTrue(message.getBodies().size() == 1);
|
||||||
|
|
||||||
message.removeBody(body);
|
|
||||||
assertTrue(message.getBodies().size() == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -177,8 +180,9 @@ public class MessageTest {
|
||||||
.append("</message>");
|
.append("</message>");
|
||||||
String control = controlBuilder.toString();
|
String control = controlBuilder.toString();
|
||||||
|
|
||||||
Message message = getNewMessage();
|
Message message = StanzaBuilder.buildMessage()
|
||||||
message.setThread(messageThread);
|
.setThread(messageThread)
|
||||||
|
.build();
|
||||||
|
|
||||||
assertEquals(messageThread, message.getThread());
|
assertEquals(messageThread, message.getThread());
|
||||||
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
|
@ -196,15 +200,10 @@ public class MessageTest {
|
||||||
.append("</message>");
|
.append("</message>");
|
||||||
String control = controlBuilder.toString();
|
String control = controlBuilder.toString();
|
||||||
|
|
||||||
Message message = getNewMessage();
|
Message message = StanzaBuilder.buildMessage()
|
||||||
message.setLanguage(lang);
|
.setLanguage(lang)
|
||||||
|
.build();
|
||||||
|
|
||||||
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Message getNewMessage() {
|
|
||||||
Message message = new Message();
|
|
||||||
message.setStanzaId(null);
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,9 @@ public class PresenceTest {
|
||||||
.append("</presence>");
|
.append("</presence>");
|
||||||
String control = controlBuilder.toString();
|
String control = controlBuilder.toString();
|
||||||
|
|
||||||
Presence presenceTypeInConstructor = new Presence(type);
|
Presence presenceTypeInConstructor = StanzaBuilder.buildPresence()
|
||||||
presenceTypeInConstructor.setStanzaId(null);
|
.ofType(type)
|
||||||
|
.build();
|
||||||
assertEquals(type, presenceTypeInConstructor.getType());
|
assertEquals(type, presenceTypeInConstructor.getType());
|
||||||
assertXmlSimilar(control, presenceTypeInConstructor.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertXmlSimilar(control, presenceTypeInConstructor.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
|
|
||||||
|
@ -54,27 +55,27 @@ public class PresenceTest {
|
||||||
.append("</presence>");
|
.append("</presence>");
|
||||||
control = controlBuilder.toString();
|
control = controlBuilder.toString();
|
||||||
|
|
||||||
Presence presenceTypeSet = getNewPresence();
|
PresenceBuilder presenceTypeSet = getNewPresence();
|
||||||
presenceTypeSet.setType(type2);
|
presenceTypeSet.ofType(type2);
|
||||||
assertEquals(type2, presenceTypeSet.getType());
|
assertEquals(type2, presenceTypeSet.getType());
|
||||||
assertXmlSimilar(control, presenceTypeSet.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertXmlSimilar(control, presenceTypeSet.build().toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setNullPresenceTypeTest() {
|
public void setNullPresenceTypeTest() {
|
||||||
assertThrows(IllegalArgumentException.class, () ->
|
assertThrows(IllegalArgumentException.class, () ->
|
||||||
getNewPresence().setType(null)
|
getNewPresence().ofType(null)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isPresenceAvailableTest() {
|
public void isPresenceAvailableTest() {
|
||||||
Presence presence = getNewPresence();
|
PresenceBuilder presence = getNewPresence();
|
||||||
presence.setType(Presence.Type.available);
|
presence.ofType(Presence.Type.available);
|
||||||
assertTrue(presence.isAvailable());
|
assertTrue(presence.build().isAvailable());
|
||||||
|
|
||||||
presence.setType(Presence.Type.unavailable);
|
presence.ofType(Presence.Type.unavailable);
|
||||||
assertFalse(presence.isAvailable());
|
assertFalse(presence.build().isAvailable());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -89,11 +90,11 @@ public class PresenceTest {
|
||||||
.append("</presence>");
|
.append("</presence>");
|
||||||
String control = controlBuilder.toString();
|
String control = controlBuilder.toString();
|
||||||
|
|
||||||
Presence presence = getNewPresence();
|
PresenceBuilder presence = getNewPresence();
|
||||||
presence.setStatus(status);
|
presence.setStatus(status);
|
||||||
|
|
||||||
assertEquals(status, presence.getStatus());
|
assertEquals(status, presence.getStatus());
|
||||||
assertXmlSimilar(control, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertXmlSimilar(control, presence.build().toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -108,11 +109,11 @@ public class PresenceTest {
|
||||||
.append("</presence>");
|
.append("</presence>");
|
||||||
String control = controlBuilder.toString();
|
String control = controlBuilder.toString();
|
||||||
|
|
||||||
Presence presence = getNewPresence();
|
PresenceBuilder presence = getNewPresence();
|
||||||
presence.setPriority(priority);
|
presence.setPriority(priority);
|
||||||
|
|
||||||
assertEquals(priority, presence.getPriority());
|
assertEquals(priority, presence.getPriority());
|
||||||
assertXmlSimilar(control, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertXmlSimilar(control, presence.build().toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -143,11 +144,14 @@ public class PresenceTest {
|
||||||
.append("</presence>");
|
.append("</presence>");
|
||||||
String control = controlBuilder.toString();
|
String control = controlBuilder.toString();
|
||||||
|
|
||||||
Presence presenceModeInConstructor = new Presence(Presence.Type.available, status, priority,
|
Presence presenceBuildWithBuilder = StanzaBuilder.buildPresence()
|
||||||
mode1);
|
.ofType(Presence.Type.available)
|
||||||
presenceModeInConstructor.setStanzaId(null);
|
.setStatus(status)
|
||||||
assertEquals(mode1, presenceModeInConstructor.getMode());
|
.setPriority(priority)
|
||||||
assertXmlSimilar(control, presenceModeInConstructor.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
.setMode(mode1)
|
||||||
|
.build();
|
||||||
|
assertEquals(mode1, presenceBuildWithBuilder.getMode());
|
||||||
|
assertXmlSimilar(control, presenceBuildWithBuilder.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
|
|
||||||
controlBuilder = new StringBuilder();
|
controlBuilder = new StringBuilder();
|
||||||
controlBuilder.append("<presence>")
|
controlBuilder.append("<presence>")
|
||||||
|
@ -157,20 +161,20 @@ public class PresenceTest {
|
||||||
.append("</presence>");
|
.append("</presence>");
|
||||||
control = controlBuilder.toString();
|
control = controlBuilder.toString();
|
||||||
|
|
||||||
Presence presenceModeSet = getNewPresence();
|
PresenceBuilder presenceModeSet = getNewPresence();
|
||||||
presenceModeSet.setMode(mode2);
|
presenceModeSet.setMode(mode2);
|
||||||
assertEquals(mode2, presenceModeSet.getMode());
|
assertEquals(mode2, presenceModeSet.getMode());
|
||||||
assertXmlSimilar(control, presenceModeSet.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertXmlSimilar(control, presenceModeSet.build().toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isModeAwayTest() {
|
public void isModeAwayTest() {
|
||||||
Presence presence = getNewPresence();
|
PresenceBuilder presence = getNewPresence();
|
||||||
presence.setMode(Presence.Mode.away);
|
presence.setMode(Presence.Mode.away);
|
||||||
assertTrue(presence.isAway());
|
assertTrue(presence.build().isAway());
|
||||||
|
|
||||||
presence.setMode(Presence.Mode.chat);
|
presence.setMode(Presence.Mode.chat);
|
||||||
assertFalse(presence.isAway());
|
assertFalse(presence.build().isAway());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -185,15 +189,14 @@ public class PresenceTest {
|
||||||
.append("</presence>");
|
.append("</presence>");
|
||||||
String control = controlBuilder.toString();
|
String control = controlBuilder.toString();
|
||||||
|
|
||||||
Presence presence = getNewPresence();
|
PresenceBuilder presence = getNewPresence();
|
||||||
presence.setLanguage(lang);
|
presence.setLanguage(lang);
|
||||||
|
|
||||||
assertXmlSimilar(control, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertXmlSimilar(control, presence.build().toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Presence getNewPresence() {
|
private static PresenceBuilder getNewPresence() {
|
||||||
Presence presence = new Presence(Presence.Type.available);
|
PresenceBuilder presence = StanzaBuilder.buildPresence().ofType(Presence.Type.available);
|
||||||
presence.setStanzaId(null);
|
|
||||||
return presence;
|
return presence;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright © 2016-2017 Florian Schmaus
|
* Copyright © 2016-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.
|
||||||
|
@ -18,8 +18,6 @@ package org.jivesoftware.smack.packet;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.Presence.Mode;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.jxmpp.jid.JidTestUtil;
|
import org.jxmpp.jid.JidTestUtil;
|
||||||
|
|
||||||
|
@ -27,15 +25,21 @@ public class ToStringTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void messageTest() {
|
public void messageTest() {
|
||||||
Message message = new Message(JidTestUtil.BARE_JID_1, Message.Type.headline);
|
Message message = StanzaBuilder.buildMessage("message-id")
|
||||||
message.setStanzaId("message-id");
|
.ofType(Message.Type.headline)
|
||||||
|
.to(JidTestUtil.BARE_JID_1)
|
||||||
|
.build();
|
||||||
String string = message.toString();
|
String string = message.toString();
|
||||||
assertEquals("Message Stanza [to=one@exampleone.org,id=message-id,type=headline,]", string);
|
assertEquals("Message Stanza [to=one@exampleone.org,id=message-id,type=headline,]", string);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void presenceTest() {
|
public void presenceTest() {
|
||||||
Presence presence = new Presence(Presence.Type.subscribe, null, 0, Mode.away);
|
Presence presence = StanzaBuilder.buildPresence()
|
||||||
|
.ofType(Presence.Type.subscribe)
|
||||||
|
.setPriority(0)
|
||||||
|
.setMode(Presence.Mode.away)
|
||||||
|
.build();
|
||||||
presence.setStanzaId("presence-id");
|
presence.setStanzaId("presence-id");
|
||||||
String string = presence.toString();
|
String string = presence.toString();
|
||||||
assertEquals("Presence Stanza [id=presence-id,type=subscribe,mode=away,prio=0,]", string);
|
assertEquals("Presence Stanza [id=presence-id,type=subscribe,mode=away,prio=0,]", string);
|
||||||
|
|
|
@ -16,12 +16,13 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smack.packet;
|
package org.jivesoftware.smack.packet;
|
||||||
|
|
||||||
import static org.jivesoftware.smack.packet.StanzaError.Condition;
|
|
||||||
import static org.jivesoftware.smack.packet.StanzaError.Type;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.StanzaError.Condition;
|
||||||
|
import org.jivesoftware.smack.packet.StanzaError.Type;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class XMPPErrorTest {
|
public class XMPPErrorTest {
|
||||||
|
|
|
@ -45,7 +45,6 @@ import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParserException;
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
|
|
||||||
import com.jamesmurty.utils.XMLBuilder;
|
import com.jamesmurty.utils.XMLBuilder;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
@ -547,30 +546,6 @@ public class PacketParserUtilsTest {
|
||||||
assertTrue(message.getSubjectLanguages().contains(otherLanguage));
|
assertTrue(message.getSubjectLanguages().contains(otherLanguage));
|
||||||
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
|
|
||||||
// message has default language, first subject no language, second subject default language
|
|
||||||
control = XMLBuilder.create("message")
|
|
||||||
.a("from", "romeo@montague.lit/orchard")
|
|
||||||
.a("to", "juliet@capulet.lit/balcony")
|
|
||||||
.a("id", "zid615d9")
|
|
||||||
.a("type", "chat")
|
|
||||||
.a("xml:lang", defaultLanguage)
|
|
||||||
.e("subject")
|
|
||||||
.t(defaultLanguage)
|
|
||||||
.up()
|
|
||||||
.e("subject")
|
|
||||||
.a("xml:lang", defaultLanguage)
|
|
||||||
.t(defaultLanguage + "2")
|
|
||||||
.asString(outputProperties);
|
|
||||||
|
|
||||||
message = PacketParserUtils
|
|
||||||
.parseMessage(PacketParserUtils.getParserFor(control));
|
|
||||||
|
|
||||||
assertEquals(defaultLanguage, message.getSubject());
|
|
||||||
assertEquals(defaultLanguage, message.getSubject(defaultLanguage));
|
|
||||||
assertEquals(1, message.getSubjects().size());
|
|
||||||
assertEquals(0, message.getSubjectLanguages().size());
|
|
||||||
assertXmlNotSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
|
||||||
|
|
||||||
// message has non-default language, first subject no language, second subject default language
|
// message has non-default language, first subject no language, second subject default language
|
||||||
control = XMLBuilder.create("message")
|
control = XMLBuilder.create("message")
|
||||||
.a("from", "romeo@montague.lit/orchard")
|
.a("from", "romeo@montague.lit/orchard")
|
||||||
|
@ -867,7 +842,7 @@ public class PacketParserUtilsTest {
|
||||||
.element("text", StanzaError.ERROR_CONDITION_AND_TEXT_NAMESPACE).t(text).up()
|
.element("text", StanzaError.ERROR_CONDITION_AND_TEXT_NAMESPACE).t(text).up()
|
||||||
.asString();
|
.asString();
|
||||||
XmlPullParser parser = TestUtils.getParser(errorXml);
|
XmlPullParser parser = TestUtils.getParser(errorXml);
|
||||||
StanzaError error = PacketParserUtils.parseError(parser).build();
|
StanzaError error = PacketParserUtils.parseError(parser);
|
||||||
assertEquals(text, error.getDescriptiveText());
|
assertEquals(text, error.getDescriptiveText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -88,10 +88,11 @@ public final class DnsOverXmppManager extends Manager {
|
||||||
try {
|
try {
|
||||||
response = resolver.resolve(query);
|
response = resolver.resolve(query);
|
||||||
} catch (IOException exception) {
|
} catch (IOException exception) {
|
||||||
StanzaError.Builder errorBuilder = StanzaError.getBuilder()
|
StanzaError errorBuilder = StanzaError.getBuilder()
|
||||||
.setType(Type.CANCEL)
|
.setType(Type.CANCEL)
|
||||||
.setCondition(Condition.internal_server_error)
|
.setCondition(Condition.internal_server_error)
|
||||||
.setDescriptiveEnText("Exception while resolving your DNS query", exception)
|
.setDescriptiveEnText("Exception while resolving your DNS query", exception)
|
||||||
|
.build()
|
||||||
;
|
;
|
||||||
|
|
||||||
IQ errorResponse = IQ.createErrorResponse(iqRequest, errorBuilder);
|
IQ errorResponse = IQ.createErrorResponse(iqRequest, errorBuilder);
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -20,8 +20,12 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
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.Message;
|
||||||
|
import org.jivesoftware.smack.packet.MessageBuilder;
|
||||||
|
import org.jivesoftware.smack.packet.MessageView;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
@ -33,6 +37,8 @@ public class ExplicitMessageEncryptionElement implements ExtensionElement {
|
||||||
|
|
||||||
public static final String NAMESPACE = "urn:xmpp:eme:0";
|
public static final String NAMESPACE = "urn:xmpp:eme:0";
|
||||||
|
|
||||||
|
public static final QName QNAME = new QName(NAMESPACE, ELEMENT);
|
||||||
|
|
||||||
public enum ExplicitMessageEncryptionProtocol {
|
public enum ExplicitMessageEncryptionProtocol {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,14 +160,12 @@ public class ExplicitMessageEncryptionElement implements ExtensionElement {
|
||||||
* @param protocolNamespace namespace
|
* @param protocolNamespace namespace
|
||||||
* @return true if message has EME element for that namespace, otherwise false
|
* @return true if message has EME element for that namespace, otherwise false
|
||||||
*/
|
*/
|
||||||
public static boolean hasProtocol(Message message, String protocolNamespace) {
|
public static boolean hasProtocol(MessageView message, String protocolNamespace) {
|
||||||
List<ExtensionElement> extensionElements = message.getExtensions(
|
List<ExplicitMessageEncryptionElement> emeElements = message
|
||||||
ExplicitMessageEncryptionElement.ELEMENT,
|
.getExtensions(ExplicitMessageEncryptionElement.class);
|
||||||
ExplicitMessageEncryptionElement.NAMESPACE);
|
|
||||||
|
|
||||||
for (ExtensionElement extensionElement : extensionElements) {
|
for (ExplicitMessageEncryptionElement emeElement : emeElements) {
|
||||||
ExplicitMessageEncryptionElement e = (ExplicitMessageEncryptionElement) extensionElement;
|
if (emeElement.getEncryptionNamespace().equals(protocolNamespace)) {
|
||||||
if (e.getEncryptionNamespace().equals(protocolNamespace)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,7 +180,7 @@ public class ExplicitMessageEncryptionElement implements ExtensionElement {
|
||||||
* @param protocol protocol
|
* @param protocol protocol
|
||||||
* @return true if message has EME element for that namespace, otherwise false
|
* @return true if message has EME element for that namespace, otherwise false
|
||||||
*/
|
*/
|
||||||
public static boolean hasProtocol(Message message, ExplicitMessageEncryptionProtocol protocol) {
|
public static boolean hasProtocol(MessageView message, ExplicitMessageEncryptionProtocol protocol) {
|
||||||
return hasProtocol(message, protocol.namespace);
|
return hasProtocol(message, protocol.namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,10 +188,10 @@ public class ExplicitMessageEncryptionElement implements ExtensionElement {
|
||||||
* Add an EME element containing the specified {@code protocol} namespace to the message.
|
* Add an EME element containing the specified {@code protocol} namespace to the message.
|
||||||
* In case there is already an element with that protocol, we do nothing.
|
* In case there is already an element with that protocol, we do nothing.
|
||||||
*
|
*
|
||||||
* @param message message
|
* @param message a message builder.
|
||||||
* @param protocol encryption protocol
|
* @param protocol encryption protocol
|
||||||
*/
|
*/
|
||||||
public static void set(Message message, ExplicitMessageEncryptionProtocol protocol) {
|
public static void set(MessageBuilder message, ExplicitMessageEncryptionProtocol protocol) {
|
||||||
if (!hasProtocol(message, protocol.namespace)) {
|
if (!hasProtocol(message, protocol.namespace)) {
|
||||||
message.addExtension(new ExplicitMessageEncryptionElement(protocol));
|
message.addExtension(new ExplicitMessageEncryptionElement(protocol));
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ import java.util.WeakHashMap;
|
||||||
import org.jivesoftware.smack.Manager;
|
import org.jivesoftware.smack.Manager;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smack.util.SecurityUtil;
|
import org.jivesoftware.smack.util.SecurityUtil;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
import org.jivesoftware.smackx.hashes.element.HashElement;
|
import org.jivesoftware.smackx.hashes.element.HashElement;
|
||||||
|
|
||||||
|
|
|
@ -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,7 +16,10 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.hints.element;
|
package org.jivesoftware.smackx.hints.element;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import javax.xml.namespace.QName;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.MessageBuilder;
|
||||||
|
import org.jivesoftware.smack.packet.MessageView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A "store" hint. Messages with this hint should be stored in permanent stores or archives.
|
* A "store" hint. Messages with this hint should be stored in permanent stores or archives.
|
||||||
|
@ -29,6 +32,8 @@ public final class StoreHint extends MessageProcessingHint {
|
||||||
|
|
||||||
public static final String ELEMENT = "store";
|
public static final String ELEMENT = "store";
|
||||||
|
|
||||||
|
public static final QName QNAME = new QName(NAMESPACE, ELEMENT);
|
||||||
|
|
||||||
private StoreHint() {
|
private StoreHint() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,15 +52,15 @@ public final class StoreHint extends MessageProcessingHint {
|
||||||
return MessageProcessingHintType.store;
|
return MessageProcessingHintType.store;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StoreHint from(Message message) {
|
public static StoreHint from(MessageView message) {
|
||||||
return message.getExtension(ELEMENT, NAMESPACE);
|
return message.getExtension(QNAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasHint(Message message) {
|
public static boolean hasHint(MessageView message) {
|
||||||
return from(message) != null;
|
return from(message) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void set(Message message) {
|
public static void set(MessageBuilder message) {
|
||||||
message.overrideExtension(INSTANCE);
|
message.overrideExtension(INSTANCE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,8 +55,8 @@ public abstract class AbstractHttpOverXmppProvider<H extends AbstractHttpOverXmp
|
||||||
*
|
*
|
||||||
* @param parser parser
|
* @param parser parser
|
||||||
* @return HeadersExtension or null if no headers
|
* @return HeadersExtension or null if no headers
|
||||||
* @throws XmlPullParserException if an error in the XML parser occured.
|
* @throws XmlPullParserException if an error in the XML parser occurred.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
* @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
|
||||||
*/
|
*/
|
||||||
protected HeadersExtension parseHeaders(XmlPullParser parser) throws IOException, XmlPullParserException, SmackParsingException {
|
protected HeadersExtension parseHeaders(XmlPullParser parser) throws IOException, XmlPullParserException, SmackParsingException {
|
||||||
|
@ -76,8 +76,8 @@ public abstract class AbstractHttpOverXmppProvider<H extends AbstractHttpOverXmp
|
||||||
* @param parser parser
|
* @param parser parser
|
||||||
* @return Data or null if no data
|
* @return Data or null if no data
|
||||||
*
|
*
|
||||||
* @throws XmlPullParserException if an error in the XML parser occured.
|
* @throws XmlPullParserException if an error in the XML parser occurred.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
*/
|
*/
|
||||||
protected AbstractHttpOverXmpp.Data parseData(XmlPullParser parser) throws XmlPullParserException, IOException {
|
protected AbstractHttpOverXmpp.Data parseData(XmlPullParser parser) throws XmlPullParserException, IOException {
|
||||||
NamedElement child = null;
|
NamedElement child = null;
|
||||||
|
|
|
@ -251,7 +251,7 @@ public final class HttpFileUploadManager extends Manager {
|
||||||
* @throws InterruptedException if the calling thread was interrupted.
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
* @throws XMPPException.XMPPErrorException if there was an XMPP error returned.
|
* @throws XMPPException.XMPPErrorException if there was an XMPP error returned.
|
||||||
* @throws SmackException if Smack detected an exceptional situation.
|
* @throws SmackException if Smack detected an exceptional situation.
|
||||||
* @throws IOException if an I/O error occured.
|
* @throws IOException if an I/O error occurred.
|
||||||
*/
|
*/
|
||||||
public URL uploadFile(File file, UploadProgressListener listener) throws InterruptedException,
|
public URL uploadFile(File file, UploadProgressListener listener) throws InterruptedException,
|
||||||
XMPPException.XMPPErrorException, SmackException, IOException {
|
XMPPException.XMPPErrorException, SmackException, IOException {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright © 2016 Florian Schmaus
|
* Copyright © 2016-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,20 +16,26 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.iot.control.element;
|
package org.jivesoftware.smackx.iot.control.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.AbstractIqBuilder;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smack.packet.IqData;
|
||||||
|
|
||||||
public class IoTSetResponse extends IQ {
|
public class IoTSetResponse extends IQ {
|
||||||
|
|
||||||
public static final String ELEMENT = "setResponse";
|
public static final String ELEMENT = "setResponse";
|
||||||
public static final String NAMESPACE = Constants.IOT_CONTROL_NAMESPACE;
|
public static final String NAMESPACE = Constants.IOT_CONTROL_NAMESPACE;
|
||||||
|
|
||||||
|
public IoTSetResponse(IqData iqBuilder) {
|
||||||
|
super(iqBuilder, ELEMENT, NAMESPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Deprecate when stanza build is ready.
|
||||||
public IoTSetResponse() {
|
public IoTSetResponse() {
|
||||||
super(ELEMENT, NAMESPACE);
|
super(ELEMENT, NAMESPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IoTSetResponse(IoTSetRequest iotSetRequest) {
|
public IoTSetResponse(IoTSetRequest iotSetRequest) {
|
||||||
this();
|
this(AbstractIqBuilder.createResponse(iotSetRequest));
|
||||||
initializeAsResultFor(iotSetRequest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -125,10 +125,14 @@ public final class IoTDataManager extends IoTManager {
|
||||||
@Override
|
@Override
|
||||||
public void momentaryReadOut(List<? extends IoTDataField> results) {
|
public void momentaryReadOut(List<? extends IoTDataField> results) {
|
||||||
IoTFieldsExtension iotFieldsExtension = IoTFieldsExtension.buildFor(dataRequest.getSequenceNr(), true, thing.getNodeInfo(), results);
|
IoTFieldsExtension iotFieldsExtension = IoTFieldsExtension.buildFor(dataRequest.getSequenceNr(), true, thing.getNodeInfo(), results);
|
||||||
Message message = new Message(dataRequest.getFrom());
|
|
||||||
message.addExtension(iotFieldsExtension);
|
XMPPConnection connection = connection();
|
||||||
|
Message message = connection.getStanzaFactory().buildMessageStanza()
|
||||||
|
.to(dataRequest.getFrom())
|
||||||
|
.addExtension(iotFieldsExtension)
|
||||||
|
.build();
|
||||||
try {
|
try {
|
||||||
connection().sendStanza(message);
|
connection.sendStanza(message);
|
||||||
}
|
}
|
||||||
catch (NotConnectedException | InterruptedException e) {
|
catch (NotConnectedException | InterruptedException e) {
|
||||||
LOGGER.log(Level.SEVERE, "Could not send read-out response " + message, e);
|
LOGGER.log(Level.SEVERE, "Could not send read-out response " + message, e);
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
|
||||||
public class NodeElement extends IoTDataExtensionElement {
|
public class NodeElement extends IoTDataExtensionElement {
|
||||||
|
|
|
@ -140,8 +140,10 @@ public final class IoTProvisioningManager extends Manager {
|
||||||
+ " is already not subscribed to our presence.");
|
+ " is already not subscribed to our presence.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Presence unsubscribed = new Presence(Presence.Type.unsubscribed);
|
Presence unsubscribed = connection.getStanzaFactory().buildPresenceStanza()
|
||||||
unsubscribed.setTo(unfriendJid);
|
.ofType(Presence.Type.unsubscribed)
|
||||||
|
.to(unfriendJid)
|
||||||
|
.build();
|
||||||
connection.sendStanza(unsubscribed);
|
connection.sendStanza(unsubscribed);
|
||||||
}
|
}
|
||||||
}, UNFRIEND_MESSAGE);
|
}, UNFRIEND_MESSAGE);
|
||||||
|
@ -162,7 +164,10 @@ public final class IoTProvisioningManager extends Manager {
|
||||||
// friendship requests.
|
// friendship requests.
|
||||||
final XMPPConnection connection = connection();
|
final XMPPConnection connection = connection();
|
||||||
Friend friendNotification = new Friend(connection.getUser().asBareJid());
|
Friend friendNotification = new Friend(connection.getUser().asBareJid());
|
||||||
Message notificationMessage = new Message(friendJid, friendNotification);
|
Message notificationMessage = connection.getStanzaFactory().buildMessageStanza()
|
||||||
|
.to(friendJid)
|
||||||
|
.addExtension(friendNotification)
|
||||||
|
.build();
|
||||||
connection.sendStanza(notificationMessage);
|
connection.sendStanza(notificationMessage);
|
||||||
} else {
|
} else {
|
||||||
// Check is the message was send from a thing we previously
|
// Check is the message was send from a thing we previously
|
||||||
|
@ -359,8 +364,11 @@ public final class IoTProvisioningManager extends Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendFriendshipRequest(BareJid bareJid) throws NotConnectedException, InterruptedException {
|
public void sendFriendshipRequest(BareJid bareJid) throws NotConnectedException, InterruptedException {
|
||||||
Presence presence = new Presence(Presence.Type.subscribe);
|
XMPPConnection connection = connection();
|
||||||
presence.setTo(bareJid);
|
Presence presence = connection.getStanzaFactory().buildPresenceStanza()
|
||||||
|
.ofType(Presence.Type.subscribe)
|
||||||
|
.to(bareJid)
|
||||||
|
.build();
|
||||||
|
|
||||||
friendshipRequestedCache.put(bareJid, null);
|
friendshipRequestedCache.put(bareJid, null);
|
||||||
|
|
||||||
|
@ -379,9 +387,12 @@ public final class IoTProvisioningManager extends Manager {
|
||||||
|
|
||||||
public void unfriend(Jid friend) throws NotConnectedException, InterruptedException {
|
public void unfriend(Jid friend) throws NotConnectedException, InterruptedException {
|
||||||
if (isMyFriend(friend)) {
|
if (isMyFriend(friend)) {
|
||||||
Presence presence = new Presence(Presence.Type.unsubscribed);
|
XMPPConnection connection = connection();
|
||||||
presence.setTo(friend);
|
Presence presence = connection.getStanzaFactory().buildPresenceStanza()
|
||||||
connection().sendStanza(presence);
|
.ofType(Presence.Type.unsubscribed)
|
||||||
|
.to(friend)
|
||||||
|
.build();
|
||||||
|
connection.sendStanza(presence);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||||
import org.jivesoftware.smack.provider.IQProvider;
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParserException;
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.jid_prep.element.JidPrepIq;
|
import org.jivesoftware.smackx.jid_prep.element.JidPrepIq;
|
||||||
|
|
||||||
public class JidPrepIqProvider extends IQProvider<JidPrepIq> {
|
public class JidPrepIqProvider extends IQProvider<JidPrepIq> {
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.jivesoftware.smack.filter.MessageTypeFilter;
|
||||||
import org.jivesoftware.smack.filter.StanzaFilter;
|
import org.jivesoftware.smack.filter.StanzaFilter;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
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.smackx.muclight.element.MUCLightAffiliationsIQ;
|
import org.jivesoftware.smackx.muclight.element.MUCLightAffiliationsIQ;
|
||||||
|
@ -126,9 +127,9 @@ public class MultiUserChatLight {
|
||||||
* @throws InterruptedException if the calling thread was interrupted.
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
*/
|
*/
|
||||||
public void sendMessage(String text) throws NotConnectedException, InterruptedException {
|
public void sendMessage(String text) throws NotConnectedException, InterruptedException {
|
||||||
Message message = createMessage();
|
MessageBuilder message = buildMessage();
|
||||||
message.setBody(text);
|
message.setBody(text);
|
||||||
connection.sendStanza(message);
|
connection.sendStanza(message.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -157,9 +158,28 @@ public class MultiUserChatLight {
|
||||||
* Creates a new Message to send to the chat room.
|
* Creates a new Message to send to the chat room.
|
||||||
*
|
*
|
||||||
* @return a new Message addressed to the chat room.
|
* @return a new Message addressed to the chat room.
|
||||||
|
* @deprecated use {@link #buildMessage()} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove when stanza builder is ready.
|
||||||
public Message createMessage() {
|
public Message createMessage() {
|
||||||
return new Message(room, Message.Type.groupchat);
|
return connection.getStanzaFactory().buildMessageStanza()
|
||||||
|
.ofType(Message.Type.groupchat)
|
||||||
|
.to(room)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new message builder for messages send to this MUC room.
|
||||||
|
*
|
||||||
|
* @return a new message builder.
|
||||||
|
*/
|
||||||
|
public MessageBuilder buildMessage() {
|
||||||
|
return connection.getStanzaFactory()
|
||||||
|
.buildMessageStanza()
|
||||||
|
.ofType(Message.Type.groupchat)
|
||||||
|
.to(room)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,10 +189,23 @@ public class MultiUserChatLight {
|
||||||
* the message.
|
* the message.
|
||||||
* @throws NotConnectedException if the XMPP connection is not connected.
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
||||||
* @throws InterruptedException if the calling thread was interrupted.
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
|
* @deprecated use {@link #sendMessage(MessageBuilder)} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO: Remove in Smack 4.5.
|
||||||
public void sendMessage(Message message) throws NotConnectedException, InterruptedException {
|
public void sendMessage(Message message) throws NotConnectedException, InterruptedException {
|
||||||
message.setTo(room);
|
sendMessage(message.asBuilder());
|
||||||
message.setType(Message.Type.groupchat);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a Message to the chat room.
|
||||||
|
*
|
||||||
|
* @param messageBuilder the message.
|
||||||
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
||||||
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
|
*/
|
||||||
|
public void sendMessage(MessageBuilder messageBuilder) throws NotConnectedException, InterruptedException {
|
||||||
|
Message message = messageBuilder.to(room).ofType(Message.Type.groupchat).build();
|
||||||
connection.sendStanza(message);
|
connection.sendStanza(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,9 @@ public class RemoteDisablingProvider extends ExtensionElementProvider<RemoteDisa
|
||||||
|
|
||||||
String affiliation = parser.getAttributeValue("", "affiliation");
|
String affiliation = parser.getAttributeValue("", "affiliation");
|
||||||
if (affiliation == null || !affiliation.equals("none")) {
|
if (affiliation == null || !affiliation.equals("none")) {
|
||||||
return null;
|
// TODO: Is this correct? We previously returned null here, but was certainly wrong, as
|
||||||
|
// providers should always return an element or throw.
|
||||||
|
throw new IOException("Invalid affiliation: " + affiliation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (eventType == XmlPullParser.Event.END_ELEMENT) {
|
} else if (eventType == XmlPullParser.Event.END_ELEMENT) {
|
||||||
|
|
|
@ -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,7 +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 +63,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 +113,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 +122,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
@ -21,6 +21,7 @@ import javax.xml.namespace.QName;
|
||||||
import org.jivesoftware.smack.packet.StandardExtensionElement;
|
import org.jivesoftware.smack.packet.StandardExtensionElement;
|
||||||
import org.jivesoftware.smack.packet.XmlEnvironment;
|
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.xdata.FormField;
|
import org.jivesoftware.smackx.xdata.FormField;
|
||||||
import org.jivesoftware.smackx.xdata.FormFieldChildElement;
|
import org.jivesoftware.smackx.xdata.FormFieldChildElement;
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||||
import org.jivesoftware.smack.parsing.StandardExtensionElementProvider;
|
import org.jivesoftware.smack.parsing.StandardExtensionElementProvider;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParserException;
|
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.xdata.provider.FormFieldChildElementProvider;
|
import org.jivesoftware.smackx.xdata.provider.FormFieldChildElementProvider;
|
||||||
import org.jivesoftware.smackx.xmlelement.element.DataFormsXmlElement;
|
import org.jivesoftware.smackx.xmlelement.element.DataFormsXmlElement;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.jivesoftware.smackx.chat_markers;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.packet.StanzaBuilder;
|
||||||
import org.jivesoftware.smack.packet.StreamOpen;
|
import org.jivesoftware.smack.packet.StreamOpen;
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
@ -28,7 +29,6 @@ import org.jivesoftware.smackx.chat_markers.element.ChatMarkersElements.Acknowle
|
||||||
import org.jivesoftware.smackx.chat_markers.provider.AcknowledgedProvider;
|
import org.jivesoftware.smackx.chat_markers.provider.AcknowledgedProvider;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
|
||||||
|
|
||||||
public class AcknowledgedExtensionTest {
|
public class AcknowledgedExtensionTest {
|
||||||
|
|
||||||
|
@ -39,9 +39,10 @@ public class AcknowledgedExtensionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkDisplayedExtension() throws Exception {
|
public void checkDisplayedExtension() throws Exception {
|
||||||
Message message = new Message(JidCreate.from("northumberland@shakespeare.lit/westminster"));
|
Message message = StanzaBuilder.buildMessage("message-2")
|
||||||
message.setStanzaId("message-2");
|
.to("northumberland@shakespeare.lit/westminster")
|
||||||
message.addExtension(new ChatMarkersElements.AcknowledgedExtension("message-1"));
|
.addExtension(new ChatMarkersElements.AcknowledgedExtension("message-1"))
|
||||||
|
.build();
|
||||||
assertEquals(acknowledgedMessageStanza, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertEquals(acknowledgedMessageStanza, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.jivesoftware.smackx.chat_markers;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.packet.StanzaBuilder;
|
||||||
import org.jivesoftware.smack.packet.StreamOpen;
|
import org.jivesoftware.smack.packet.StreamOpen;
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
@ -28,7 +29,6 @@ import org.jivesoftware.smackx.chat_markers.element.ChatMarkersElements.Displaye
|
||||||
import org.jivesoftware.smackx.chat_markers.provider.DisplayedProvider;
|
import org.jivesoftware.smackx.chat_markers.provider.DisplayedProvider;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
|
||||||
|
|
||||||
public class DisplayedExtensionTest {
|
public class DisplayedExtensionTest {
|
||||||
|
|
||||||
|
@ -39,9 +39,10 @@ public class DisplayedExtensionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkDisplayedExtension() throws Exception {
|
public void checkDisplayedExtension() throws Exception {
|
||||||
Message message = new Message(JidCreate.from("northumberland@shakespeare.lit/westminster"));
|
Message message = StanzaBuilder.buildMessage("message-2")
|
||||||
message.setStanzaId("message-2");
|
.to("northumberland@shakespeare.lit/westminster")
|
||||||
message.addExtension(new ChatMarkersElements.DisplayedExtension("message-1"));
|
.addExtension(new ChatMarkersElements.DisplayedExtension("message-1"))
|
||||||
|
.build();
|
||||||
assertEquals(displayedMessageStanza, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertEquals(displayedMessageStanza, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.jivesoftware.smackx.chat_markers;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.packet.StanzaBuilder;
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
|
||||||
|
@ -39,10 +40,12 @@ public class MarkableExtensionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkMarkableExtension() throws Exception {
|
public void checkMarkableExtension() throws Exception {
|
||||||
Message message = new Message(JidCreate.from("ingrichard@royalty.england.lit/throne"));
|
Message message = StanzaBuilder.buildMessage("message-1")
|
||||||
message.setStanzaId("message-1");
|
.to(JidCreate.from("ingrichard@royalty.england.lit/throne"))
|
||||||
message.setBody("My lord, dispatch; read o'er these articles.");
|
.setBody("My lord, dispatch; read o'er these articles.")
|
||||||
message.addExtension(ChatMarkersElements.MarkableExtension.INSTANCE);
|
.addExtension(ChatMarkersElements.MarkableExtension.INSTANCE)
|
||||||
|
.build();
|
||||||
|
|
||||||
assertEquals(markableMessageStanza, message.toXML().toString());
|
assertEquals(markableMessageStanza, message.toXML().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.jivesoftware.smackx.chat_markers;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.packet.StanzaBuilder;
|
||||||
import org.jivesoftware.smack.packet.StreamOpen;
|
import org.jivesoftware.smack.packet.StreamOpen;
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
@ -28,7 +29,6 @@ import org.jivesoftware.smackx.chat_markers.element.ChatMarkersElements.Received
|
||||||
import org.jivesoftware.smackx.chat_markers.provider.ReceivedProvider;
|
import org.jivesoftware.smackx.chat_markers.provider.ReceivedProvider;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
|
||||||
|
|
||||||
public class ReceivedExtensionTest {
|
public class ReceivedExtensionTest {
|
||||||
|
|
||||||
|
@ -39,9 +39,10 @@ public class ReceivedExtensionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkReceivedExtension() throws Exception {
|
public void checkReceivedExtension() throws Exception {
|
||||||
Message message = new Message(JidCreate.from("northumberland@shakespeare.lit/westminster"));
|
Message message = StanzaBuilder.buildMessage("message-2")
|
||||||
message.setStanzaId("message-2");
|
.to("northumberland@shakespeare.lit/westminster")
|
||||||
message.addExtension(new ChatMarkersElements.ReceivedExtension("message-1"));
|
.addExtension(new ChatMarkersElements.ReceivedExtension("message-1"))
|
||||||
|
.build();
|
||||||
assertEquals(receivedMessageStanza, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
assertEquals(receivedMessageStanza, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.jivesoftware.smackx.colors;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.colors.ConsistentColor.Deficiency;
|
import org.jivesoftware.smackx.colors.ConsistentColor.Deficiency;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
|
@ -25,6 +25,8 @@ import java.util.List;
|
||||||
|
|
||||||
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.StanzaBuilder;
|
||||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement;
|
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement;
|
||||||
|
@ -35,7 +37,7 @@ public class ExplicitMessageEncryptionElementTest extends SmackTestSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void addToMessageTest() {
|
public void addToMessageTest() {
|
||||||
Message message = new Message();
|
Message message = StanzaBuilder.buildMessage().build();
|
||||||
|
|
||||||
// Check inital state (no elements)
|
// Check inital state (no elements)
|
||||||
assertNull(ExplicitMessageEncryptionElement.from(message));
|
assertNull(ExplicitMessageEncryptionElement.from(message));
|
||||||
|
@ -45,9 +47,12 @@ public class ExplicitMessageEncryptionElementTest extends SmackTestSuite {
|
||||||
List<ExtensionElement> extensions = message.getExtensions();
|
List<ExtensionElement> extensions = message.getExtensions();
|
||||||
assertEquals(0, extensions.size());
|
assertEquals(0, extensions.size());
|
||||||
|
|
||||||
|
MessageBuilder messageBuilder = StanzaBuilder.buildMessage();
|
||||||
// Add OMEMO
|
// Add OMEMO
|
||||||
ExplicitMessageEncryptionElement.set(message,
|
ExplicitMessageEncryptionElement.set(messageBuilder,
|
||||||
ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.omemoVAxolotl);
|
ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.omemoVAxolotl);
|
||||||
|
|
||||||
|
message = messageBuilder.build();
|
||||||
extensions = message.getExtensions();
|
extensions = message.getExtensions();
|
||||||
assertEquals(1, extensions.size());
|
assertEquals(1, extensions.size());
|
||||||
assertTrue(ExplicitMessageEncryptionElement.hasProtocol(message,
|
assertTrue(ExplicitMessageEncryptionElement.hasProtocol(message,
|
||||||
|
@ -59,8 +64,10 @@ public class ExplicitMessageEncryptionElementTest extends SmackTestSuite {
|
||||||
assertFalse(ExplicitMessageEncryptionElement.hasProtocol(message,
|
assertFalse(ExplicitMessageEncryptionElement.hasProtocol(message,
|
||||||
ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.openpgpV0.getNamespace()));
|
ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.openpgpV0.getNamespace()));
|
||||||
|
|
||||||
ExplicitMessageEncryptionElement.set(message,
|
ExplicitMessageEncryptionElement.set(messageBuilder,
|
||||||
ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.openpgpV0);
|
ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.openpgpV0);
|
||||||
|
|
||||||
|
message = messageBuilder.build();
|
||||||
extensions = message.getExtensions();
|
extensions = message.getExtensions();
|
||||||
assertEquals(2, extensions.size());
|
assertEquals(2, extensions.size());
|
||||||
assertTrue(ExplicitMessageEncryptionElement.hasProtocol(message,
|
assertTrue(ExplicitMessageEncryptionElement.hasProtocol(message,
|
||||||
|
@ -69,9 +76,10 @@ public class ExplicitMessageEncryptionElementTest extends SmackTestSuite {
|
||||||
ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.omemoVAxolotl));
|
ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.omemoVAxolotl));
|
||||||
|
|
||||||
// Check, if adding additional OMEMO wont add another element
|
// Check, if adding additional OMEMO wont add another element
|
||||||
ExplicitMessageEncryptionElement.set(message,
|
ExplicitMessageEncryptionElement.set(messageBuilder,
|
||||||
ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.omemoVAxolotl);
|
ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.omemoVAxolotl);
|
||||||
|
|
||||||
|
message = messageBuilder.build();
|
||||||
extensions = message.getExtensions();
|
extensions = message.getExtensions();
|
||||||
assertEquals(2, extensions.size());
|
assertEquals(2, extensions.size());
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import java.util.TimeZone;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import org.jivesoftware.smack.packet.Message;
|
||||||
import org.jivesoftware.smack.packet.Message.Type;
|
import org.jivesoftware.smack.packet.Message.Type;
|
||||||
|
import org.jivesoftware.smack.packet.StanzaBuilder;
|
||||||
import org.jivesoftware.smack.packet.StreamOpen;
|
import org.jivesoftware.smack.packet.StreamOpen;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.delay.packet.DelayInformation;
|
import org.jivesoftware.smackx.delay.packet.DelayInformation;
|
||||||
|
@ -62,21 +63,21 @@ public class QueryArchiveTest extends MamTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkMamQueryResults() throws Exception {
|
public void checkMamQueryResults() throws Exception {
|
||||||
Message message = new Message();
|
Message message = StanzaBuilder.buildMessage("iasd207")
|
||||||
message.setStanzaId("iasd207");
|
.from("coven@chat.shakespeare.lit")
|
||||||
message.setFrom(JidCreate.from("coven@chat.shakespeare.lit"));
|
.to("hag66@shakespeare.lit/pda")
|
||||||
message.setTo(JidCreate.from("hag66@shakespeare.lit/pda"));
|
.build();
|
||||||
|
|
||||||
GregorianCalendar calendar = new GregorianCalendar(2002, 10 - 1, 13, 23, 58, 37);
|
GregorianCalendar calendar = new GregorianCalendar(2002, 10 - 1, 13, 23, 58, 37);
|
||||||
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
|
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
Date date = calendar.getTime();
|
Date date = calendar.getTime();
|
||||||
|
|
||||||
DelayInformation delay = new DelayInformation(date);
|
DelayInformation delay = new DelayInformation(date);
|
||||||
Message forwardedMessage = new Message();
|
Message forwardedMessage = StanzaBuilder.buildMessage("162BEBB1-F6DB-4D9A-9BD8-CFDCC801A0B2")
|
||||||
forwardedMessage.setFrom(JidCreate.from("coven@chat.shakespeare.lit/firstwitch"));
|
.from(JidCreate.from("coven@chat.shakespeare.lit/firstwitch"))
|
||||||
forwardedMessage.setStanzaId("162BEBB1-F6DB-4D9A-9BD8-CFDCC801A0B2");
|
.ofType(Type.chat)
|
||||||
forwardedMessage.setType(Type.chat);
|
.setBody("Thrice the brinded cat hath mew.")
|
||||||
forwardedMessage.setBody("Thrice the brinded cat hath mew.");
|
.build();
|
||||||
|
|
||||||
Forwarded forwarded = new Forwarded(delay, forwardedMessage);
|
Forwarded forwarded = new Forwarded(delay, forwardedMessage);
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue