mirror of
https://github.com/vanitasvitae/Smack.git
synced 2025-09-13 02:59:39 +02:00
Compare commits
No commits in common. "12e20c2d6c127fa746ed3e846a077d769e09691f" and "4dd3800d82c59c1a28c03d00f120ea2e8bdf9e50" have entirely different histories.
12e20c2d6c
...
4dd3800d82
153 changed files with 4745 additions and 7439 deletions
|
@ -18,7 +18,7 @@ Getting started
|
|||
|
||||
Start with having a look at the **[Documentation]** and the **[Javadoc]**.
|
||||
|
||||
Instructions on how to use Smack in your Java or Android project are provided in the [Smack Readme and Upgrade Guide](https://igniterealtime.org/projects/smack/readme).
|
||||
Instructions how to use Smack in your Java or Android project are provided in the [Smack Readme and Upgrade Guide](https://igniterealtime.org/projects/smack/readme).
|
||||
|
||||
Professional Services
|
||||
---------------------
|
||||
|
|
60
build.gradle
60
build.gradle
|
@ -14,8 +14,6 @@ buildscript {
|
|||
plugins {
|
||||
id 'ru.vyarus.animalsniffer' version '1.5.0'
|
||||
id 'net.ltgt.errorprone' version '1.1.1'
|
||||
// Use e.g. "gradle <task> taskTree" to show its dependency tree.
|
||||
id 'com.dorongold.task-tree' version '1.5'
|
||||
}
|
||||
|
||||
apply plugin: 'org.kordamp.gradle.markdown'
|
||||
|
@ -290,7 +288,14 @@ configure (junit4Projects) {
|
|||
}
|
||||
}
|
||||
|
||||
task javadocAll(type: Javadoc) {
|
||||
task copyAllJavadocDocFiles(type: Copy) {
|
||||
from javadocAllProjects.collect { project ->
|
||||
"${project.projectDir}/src/javadoc" }
|
||||
into javadocAllDir
|
||||
include '**/doc-files/*.*'
|
||||
}
|
||||
|
||||
task javadocAll(type: Javadoc, dependsOn: copyAllJavadocDocFiles) {
|
||||
source javadocAllProjects.collect {project ->
|
||||
project.sourceSets.main.allJava.findAll {
|
||||
// Filter out symbolic links to avoid
|
||||
|
@ -320,25 +325,6 @@ task javadocAll(type: Javadoc) {
|
|||
] as String[]
|
||||
overview = "$projectDir/resources/javadoc-overview.html"
|
||||
}
|
||||
|
||||
// Finally copy the javadoc doc-files from the subprojects, which
|
||||
// are potentially generated, to the javadocAll directory. Note
|
||||
// that we use a copy *method* and not a *task* because the inputs
|
||||
// of copy tasks is determined within the configuration phase. And
|
||||
// since some of the inputs are generated, they will not get
|
||||
// picked up if we used a copy method. See also
|
||||
// https://stackoverflow.com/a/40518516/194894
|
||||
doLast {
|
||||
copy {
|
||||
javadocAllProjects.each {
|
||||
from ("${it.projectDir}/src/javadoc") {
|
||||
include '**/doc-files/*.*'
|
||||
}
|
||||
}
|
||||
|
||||
into javadocAllDir
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
@ -508,25 +494,31 @@ subprojects {
|
|||
}
|
||||
|
||||
// Work around https://github.com/gradle/gradle/issues/4046
|
||||
javadoc.dependsOn('copyJavadocDocFiles')
|
||||
task copyJavadocDocFiles(type: Copy) {
|
||||
from('src/javadoc')
|
||||
into 'build/docs/javadoc'
|
||||
include '**/doc-files/*.*'
|
||||
}
|
||||
javadoc.dependsOn copyJavadocDocFiles
|
||||
|
||||
// Make sure root projects 'javadocAll' depends on the
|
||||
// subproject's javadoc, to ensure that all all doc-files/ are
|
||||
// generated and up-to-date. Obviously this means that the
|
||||
// javadocAll task will also create the individual javadoc's of the
|
||||
// subprojects.
|
||||
javadocAll.dependsOn javadoc
|
||||
}
|
||||
// If this subproject has a Makefile then make copyJavadocDocFiles
|
||||
// and the root project's javadocAll task dependend on
|
||||
// generateFiles.
|
||||
if (file("$projectDir/Makefile").exists()) {
|
||||
copyJavadocDocFiles.dependsOn('generateFiles')
|
||||
rootProject.copyAllJavadocDocFiles.dependsOn("${project.name}:generateFiles")
|
||||
task generateFiles(type: Exec) {
|
||||
workingDir projectDir
|
||||
commandLine 'make'
|
||||
}
|
||||
|
||||
// The smack-java8-full project generates the dot and png files of the
|
||||
// current state graph. Ensure they are generated before copied.
|
||||
configure (project(':smack-java8-full')) {
|
||||
copyJavadocDocFiles.dependsOn convertModularXmppClientToServerConnectionStateGraphDotToPng
|
||||
clean.dependsOn('cleanGeneratedFiles')
|
||||
rootProject.clean.dependsOn("${project.name}:cleanGeneratedFiles")
|
||||
task cleanGeneratedFiles(type: Exec) {
|
||||
workingDir projectDir
|
||||
commandLine 'make', 'clean'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configure (androidProjects + androidBootClasspathProjects) {
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
Smack's Modular Connection Architecture
|
||||
======================================
|
||||
|
||||
[Back](index.md)
|
||||
|
||||
**Note: Everything related to the modular connection architecture is currently considered experimental and should not be used in production. Use the mature `XMPPTCPConnection` if you do not feel adventurous.
|
||||
|
||||
Smack's modular connection architecture allows to extend a XMPP c2s (client-to-server) connection with additional functionalty by adding modules.
|
||||
Those modules extend the Finite State Machine (FSM) within the `ModularXmppClientToServerConnection` with new states.
|
||||
|
||||
Connection modules can either be
|
||||
- Transports
|
||||
- Extensions
|
||||
|
||||
Transports bind the XMPP XML stream to an underlying transport like TCP, WebSockets, BOSH, and allow for the different particularities of transports like DirectTLS ([XEP-0368](https://xmpp.org/extensions/xep-0368.html)).
|
||||
This eventually means that a single transport module can implement multiple transport mechanisms.
|
||||
For example the TCP transport module implements the RFC6120 TCP and the XEP-0368 direct TLS TCP transport bindings.
|
||||
|
||||
Extensions allow for a richer functionality of the connection. Those include
|
||||
- Compression
|
||||
- zlib ([XEP-0138](https://xmpp.org/extensions/xep-0138.html))
|
||||
- [Efficient XML Interchange (EXI)](https://www.w3.org/TR/exi/)
|
||||
- Instant Stream Resumption ([XEP-0397](https://xmpp.org/extensions/xep-0397.html)
|
||||
- Bind2
|
||||
- Stream Management
|
||||
|
||||
Note that not all extensions work with every transport.
|
||||
For example compression only works with TCP-based transport bindings.
|
||||
|
||||
|
||||
Connection modules are plugged into the the modular connection via their constructor. and they usually declare backwards edges to some common, generic connection state of the FSM.
|
||||
|
||||
Modules and states always have an accompanying *descriptor* type.
|
||||
`ModuleDescriptor` and `StateDescriptor` exist without an connection instance.
|
||||
They describe the module and state metadata, while their modules are states are instanciated once a modular connection is instanciated.
|
|
@ -58,28 +58,24 @@ debugger=console
|
|||
|
||||
### Framework properties
|
||||
|
||||
| Name | Description |
|
||||
|----------------------|-----------------------------------------------------------------------------|
|
||||
| service | XMPP service to run the tests on |
|
||||
| serviceTlsPin | TLS Pin (used by [java-pinning](https://github.com/Flowdalic/java-pinning)) |
|
||||
| securityMode | Either 'required' or 'disabled' |
|
||||
| replyTimeout | In milliseconds |
|
||||
| adminAccountUsername | Username of the XEP-0133 Admin account |
|
||||
| adminAccountPassword | Password of the XEP-0133 Admin account |
|
||||
| accountOneUsername | Username of the first XMPP account |
|
||||
| accountOnePassword | Password of the first XMPP account |
|
||||
| accountTwoUsername | Username of the second XMPP account |
|
||||
| accountTwoPassword | Password of the second XMPP account |
|
||||
| accountThreeUsername | Username of the third XMPP account |
|
||||
| accountThreePassword | Password of the third XMPP account |
|
||||
| debugger | 'console' for console debugger, 'enhanced' for the enhanced debugger |
|
||||
| enabledTests | List of enabled tests |
|
||||
| disabledTests | List of disabled tests |
|
||||
| defaultConnection | Nickname of the default connection |
|
||||
| enabledConnections | List of enabled connection's nicknames |
|
||||
| disabledConnections | List of disabled connection's nicknames |
|
||||
| testPackages | List of packages with tests |
|
||||
| verbose | If `true` set output to verbose |
|
||||
| Name | |
|
||||
|----------------------|-------------------------------------------|
|
||||
| service | XMPP service to run the tests on |
|
||||
| serviceTlsPin | TLS Pin (used by [java-pinning](https://github.com/Flowdalic/java-pinning)) |
|
||||
| securityMode | Either 'required' or 'disabled' |
|
||||
| replyTimeout | In milliseconds |
|
||||
| adminAccountUsername | Username of the XEP-0133 Admin account |
|
||||
| adminAccountPassword | Password of the XEP-0133 Admin account |
|
||||
| accountOneUsername | Username of the first XMPP account |
|
||||
| accountOnePassword | Password of the first XMPP account |
|
||||
| accountTwoUsername | Username of the second XMPP account |
|
||||
| accountTwoPassword | Password of the second XMPP account |
|
||||
| accountThreeUsername | Username of the third XMPP account |
|
||||
| accountThreePassword | Password of the third XMPP account |
|
||||
| debugger | 'console' for console debugger, 'enhanced' for the enhanced debugger |
|
||||
| enabledTests | List of enabled tests |
|
||||
| disabledTests | List of disabled tests |
|
||||
| testPackages | List of packages with tests |
|
||||
|
||||
### Where to place the properties file
|
||||
|
||||
|
@ -103,10 +99,6 @@ The base class that integration tests need to subclass.
|
|||
|
||||
Allows low level integration test, i.e. ever test method will have its on exclusive XMPPTCPConnection instances.
|
||||
|
||||
### `AbstractSmackSpecificLowLevelIntegrationTest`
|
||||
|
||||
Operates, like `AbstractSmackLowLevelIntegrationTest` on its own `XMPPConnection` instances, but is limited to a particular type of `XMPPConnection`.
|
||||
|
||||
### `IntegrationTestEnvironment`
|
||||
|
||||
The environment, e.g. the `XMPPConnections` provided to the integration tests by the framework. Note that for convenience `AbstractSmackIntegrationTest` contains some of those as protected members.
|
||||
|
|
|
@ -23,13 +23,6 @@ Currently supported XEPs of smack-tcp
|
|||
|---------------------------------------------|--------------------------------------------------------|-----------|----------------------------------------------------------------------------------------------------------|
|
||||
| [Stream Management](streammanagement.md) | [XEP-0198](https://xmpp.org/extensions/xep-0198.html) | n/a | Allows active management of an XML Stream between two XMPP entities (stanza acknowledgement, stream resumption). |
|
||||
|
||||
Currently supported XEPs of smack-im
|
||||
------------------------------------
|
||||
|
||||
| Name | XEP | Version | Description |
|
||||
|---------------------------------------------|--------------------------------------------------------|-----------|-----------------------------------|--
|
||||
| Roster Versioning | [XEP-0237](https://xmpp.org/extensions/xep-0237.html) | n/a | Efficient roster synchronization. |
|
||||
|
||||
Smack Extensions and currently supported XEPs of smack-extensions
|
||||
-----------------------------------------------------------------
|
||||
|
||||
|
@ -59,19 +52,17 @@ Smack Extensions and currently supported XEPs of smack-extensions
|
|||
| Chat State Notifications | [XEP-0085](https://xmpp.org/extensions/xep-0085.html) | n/a | Communicating the status of a user in a chat session. |
|
||||
| [Time Exchange](time.md) | [XEP-0090](https://xmpp.org/extensions/xep-0090.html) | n/a | Allows local time information to be shared between users. |
|
||||
| Software Version | [XEP-0092](https://xmpp.org/extensions/xep-0092.html) | n/a | Retrieve and announce the software application of an XMPP entity. |
|
||||
| Stream Initiation | [XEP-0095](https://xmpp.org/extensions/xep-0095.html) | n/a | Initiating a data stream between any two XMPP entities. |
|
||||
| Stream Initation | [XEP-0095](https://xmpp.org/extensions/xep-0095.html) | n/a | Initiating a data stream between any two XMPP entities. |
|
||||
| [SI File Transfer](filetransfer.md) | [XEP-0096](https://xmpp.org/extensions/xep-0096.html) | n/a | Transfer files between two users over XMPP. |
|
||||
| User Mood | [XEP-0107](https://xmpp.org/extensions/xep-0107.html) | 1.2.1 | Communicate the users current mood. |
|
||||
| [Entity Capabilities](caps.md) | [XEP-0115](https://xmpp.org/extensions/xep-0115.html) | n/a | Broadcasting and dynamic discovery of entity capabilities. |
|
||||
| User Tune | [XEP-0118](https://xmpp.org/extensions/xep-0118.html) | n/a | Defines a payload format for communicating information about music to which a user is listening. |
|
||||
| Data Forms Validation | [XEP-0122](https://xmpp.org/extensions/xep-0122.html) | n/a | Enables an application to specify additional validation guidelines . |
|
||||
| Stanza Headers and Internet Metadata (SHIM) | [XEP-0131](https://xmpp.org/extensions/xep-0131.html) | 1.2 | Add Metadata Headers to Stanzas. |
|
||||
| Service Administration | [XEP-0133](https://xmpp.org/extensions/xep-0133.html) | n/a | Recommended best practices for service-level administration of servers and components using Ad-Hoc Commands. |
|
||||
| Stream Compression | [XEP-0138](https://xmpp.org/extensions/xep-0138.html) | n/a | Support for optional compression of the XMPP stream.
|
||||
| Data Forms Layout | [XEP-0141](https://xmpp.org/extensions/xep-0141.html) | n/a | Enables an application to specify form layouts. |
|
||||
| Personal Eventing Protocol | [XEP-0163](https://xmpp.org/extensions/xep-0163.html) | n/a | Using the XMPP publish-subscribe protocol to broadcast state change events associated with an XMPP account. |
|
||||
| [Jingle](jingle.html) | [XEP-0166](https://xmpp.org/extensions/xep-0166.html) | n/a | Initiate and manage sessions between two XMPP entities. |
|
||||
| User Nickname | [XEP-0172](https://xmpp.org/extensions/xep-0172.html) | n/a | Communicate user nicknames. |
|
||||
| Message Delivery Receipts | [XEP-0184](https://xmpp.org/extensions/xep-0184.html) | n/a | Extension for message delivery receipts. The sender can request notification that the message has been delivered. |
|
||||
| [Blocking Command](blockingcommand.md) | [XEP-0191](https://xmpp.org/extensions/xep-0191.html) | n/a | Communications blocking that is intended to be simpler than privacy lists (XEP-0016). |
|
||||
| XMPP Ping | [XEP-0199](https://xmpp.org/extensions/xep-0199.html) | n/a | Sending application-level pings over XML streams.
|
||||
|
@ -82,7 +73,6 @@ Smack Extensions and currently supported XEPs of smack-extensions
|
|||
| Attention | [XEP-0224](https://xmpp.org/extensions/xep-0224.html) | n/a | Getting attention of another user. |
|
||||
| Bits of Binary | [XEP-0231](https://xmpp.org/extensions/xep-0231.html) | n/a | Including or referring to small bits of binary data in an XML stanza. |
|
||||
| Best Practices for Resource Locking | [XEP-0296](https://xmpp.org/extensions/xep-0296.html) | n/a | Specifies best practices to be followed by Jabber/XMPP clients about when to lock into, and unlock away from, resources. |
|
||||
| Stanza Forwarding | [XEP-0297](https://xmpp.org/extensions/xep-0297.html) | n/a | Allows forwarding of Stanzas. |
|
||||
| Last Message Correction | [XEP-0308](https://xmpp.org/extensions/xep-0308.html) | n/a | Provides a method for indicating that a message is a correction of the last sent message. |
|
||||
| Last User Interaction in Presence | [XEP-0319](https://xmpp.org/extensions/xep-0319.html) | n/a | Communicate time of last user interaction via XMPP presence notifications. |
|
||||
| Data Forms Geolocation Element | [XEP-0350](https://xmpp.org/extensions/xep-0350.html) | n/a | Allows to include XEP-0080 gelocation data in XEP-0004 data forms. |
|
||||
|
@ -112,7 +102,6 @@ Experimental Smack Extensions and currently supported XEPs of smack-experimental
|
|||
| Stable and Unique Stanza IDs | [XEP-0359](https://xmpp.org/extensions/xep-0359.html) | 0.5.0 | This specification describes unique and stable IDs for messages. |
|
||||
| HTTP File Upload | [XEP-0363](https://xmpp.org/extensions/xep-0363.html) | 0.3.1 | Protocol to request permissions to upload a file to an HTTP server and get a shareable URL. |
|
||||
| References | [XEP-0372](https://xmpp.org/extensions/xep-0363.html) | 0.2.0 | Add references like mentions or external data to stanzas. |
|
||||
| Explicit Message Encryption | [XEP-0380](https://xmpp.org/extensions/xep-0380.html) | 0.3.0 | Mark a message as explicitly encrypted. |
|
||||
| [OpenPGP for XMPP](ox.md) | [XEP-0373](https://xmpp.org/extensions/xep-0373.html) | 0.3.2 | Utilize OpenPGP to exchange encrypted and signed content. |
|
||||
| [OpenPGP for XMPP: Instant Messaging](ox-im.md) | [XEP-0374](https://xmpp.org/extensions/xep-0374.html) | 0.2.0 | OpenPGP encrypted Instant Messaging. |
|
||||
| [Spoiler Messages](spoiler.md) | [XEP-0382](https://xmpp.org/extensions/xep-0382.html) | 0.2.0 | Indicate that the body of a message should be treated as a spoiler. |
|
||||
|
|
|
@ -13,4 +13,3 @@
|
|||
* [Debugging with Smack](debugging.md)
|
||||
|
||||
* [Smack Extensions Manual](extensions/index.md)
|
||||
* [Smack's Modular Connection Architecture](connection-modules.md)
|
||||
|
|
|
@ -67,7 +67,6 @@ SMACK_EXCEPTIONS[CorruptedOmemoKeyException]="if the OMEMO key is corrupted."
|
|||
SMACK_EXCEPTIONS[CryptoFailedException]="if the OMEMO cryptography failed."
|
||||
SMACK_EXCEPTIONS[CannotEstablishOmemoSessionException]="if no OMEMO session could be established."
|
||||
SMACK_EXCEPTIONS[UntrustedOmemoIdentityException]="if the OMEMO identity is not trusted."
|
||||
SMACK_EXCEPTIONS[FailedNonzaException]="if an XMPP protocol failure was received."
|
||||
|
||||
MODE=""
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ include 'smack-core',
|
|||
'smack-android',
|
||||
'smack-android-extensions',
|
||||
'smack-java7',
|
||||
'smack-java8-full',
|
||||
'smack-integration-test',
|
||||
'smack-omemo',
|
||||
'smack-omemo-signal',
|
||||
|
|
|
@ -27,7 +27,7 @@ import java.util.logging.Logger;
|
|||
|
||||
import org.jivesoftware.smack.AbstractXMPPConnection;
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.SmackException.GenericConnectionException;
|
||||
import org.jivesoftware.smack.SmackException.ConnectionException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.SmackException.SmackWrappedException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
|
@ -136,7 +136,6 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
|
|||
this.config = config;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected void connectInternal() throws SmackException, InterruptedException {
|
||||
done = false;
|
||||
|
@ -178,7 +177,7 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
|
|||
.setAttribute(BodyQName.createWithPrefix(XMPP_BOSH_NS, "version", "xmpp"), "1.0")
|
||||
.build());
|
||||
} catch (Exception e) {
|
||||
throw new GenericConnectionException(e);
|
||||
throw new ConnectionException(e);
|
||||
}
|
||||
|
||||
// Wait for the response from the server
|
||||
|
|
|
@ -25,8 +25,6 @@ dependencies {
|
|||
testCompile "org.xmlunit:xmlunit-assertj:$xmlUnitVersion"
|
||||
testCompile 'com.jamesmurty.utils:java-xmlbuilder:1.2'
|
||||
testCompile 'org.bouncycastle:bcprov-jdk15on:1.64'
|
||||
testCompile 'com.google.guava:guava:28.2-jre'
|
||||
testCompile 'org.jgrapht:jgrapht-io:1.3.1'
|
||||
}
|
||||
|
||||
class CreateFileTask extends DefaultTask {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2009 Jive Software, 2018-2020 Florian Schmaus.
|
||||
* Copyright 2009 Jive Software, 2018-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.
|
||||
|
@ -34,6 +34,7 @@ import java.security.SecureRandom;
|
|||
import java.security.Security;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
@ -86,7 +87,6 @@ import org.jivesoftware.smack.XMPPException.StreamErrorException;
|
|||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.compress.packet.Compress;
|
||||
import org.jivesoftware.smack.compression.XMPPInputOutputStream;
|
||||
import org.jivesoftware.smack.datatypes.UInt16;
|
||||
import org.jivesoftware.smack.debugger.SmackDebugger;
|
||||
import org.jivesoftware.smack.debugger.SmackDebuggerFactory;
|
||||
import org.jivesoftware.smack.filter.IQReplyFilter;
|
||||
|
@ -136,6 +136,7 @@ import org.jivesoftware.smack.util.ParserUtils;
|
|||
import org.jivesoftware.smack.util.Predicate;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smack.util.TLSUtils;
|
||||
import org.jivesoftware.smack.util.dns.HostAddress;
|
||||
import org.jivesoftware.smack.util.dns.SmackDaneProvider;
|
||||
import org.jivesoftware.smack.util.dns.SmackDaneVerifier;
|
||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||
|
@ -149,6 +150,8 @@ import org.jxmpp.jid.impl.JidCreate;
|
|||
import org.jxmpp.jid.parts.Resourcepart;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
import org.jxmpp.util.XmppStringUtils;
|
||||
import org.minidns.dnsname.DnsName;
|
||||
|
||||
|
||||
/**
|
||||
* This abstract class is commonly used as super class for XMPP connection mechanisms like TCP and BOSH. Hence it
|
||||
|
@ -391,7 +394,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
/**
|
||||
* The used port to establish the connection to
|
||||
*/
|
||||
protected UInt16 port;
|
||||
protected int port;
|
||||
|
||||
/**
|
||||
* Flag that indicates if the user is currently authenticated with the server.
|
||||
|
@ -481,12 +484,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
|
||||
@Override
|
||||
public int getPort() {
|
||||
final UInt16 port = this.port;
|
||||
if (port == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return port.intValue();
|
||||
return port;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -527,7 +525,6 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
saslFeatureReceived.init();
|
||||
lastFeaturesReceived.init();
|
||||
tlsHandled.init();
|
||||
closingStreamReceived.init();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -781,6 +778,38 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
|
||||
private DomainBareJid xmppServiceDomain;
|
||||
|
||||
protected List<HostAddress> hostAddresses;
|
||||
|
||||
/**
|
||||
* Populates {@link #hostAddresses} with the resolved addresses or with the configured host address. If no host
|
||||
* address was configured and all lookups failed, for example with NX_DOMAIN, then {@link #hostAddresses} will be
|
||||
* populated with the empty list.
|
||||
*
|
||||
* @return a list of host addresses where DNS (SRV) RR resolution failed.
|
||||
*/
|
||||
protected List<HostAddress> populateHostAddresses() {
|
||||
List<HostAddress> failedAddresses = new LinkedList<>();
|
||||
if (config.hostAddress != null) {
|
||||
hostAddresses = new ArrayList<>(1);
|
||||
HostAddress hostAddress = new HostAddress(config.port, config.hostAddress);
|
||||
hostAddresses.add(hostAddress);
|
||||
}
|
||||
else if (config.host != null) {
|
||||
hostAddresses = new ArrayList<>(1);
|
||||
HostAddress hostAddress = DNSUtil.getDNSResolver().lookupHostAddress(config.host, config.port, failedAddresses, config.getDnssecMode());
|
||||
if (hostAddress != null) {
|
||||
hostAddresses.add(hostAddress);
|
||||
}
|
||||
} else {
|
||||
// N.B.: Important to use config.serviceName and not AbstractXMPPConnection.serviceName
|
||||
DnsName dnsName = DnsName.from(config.getXMPPServiceDomain());
|
||||
hostAddresses = DNSUtil.resolveXMPPServiceDomain(dnsName, failedAddresses, config.getDnssecMode());
|
||||
}
|
||||
// Either the populated host addresses are not empty *or* there must be at least one failed address.
|
||||
assert !hostAddresses.isEmpty() || !failedAddresses.isEmpty();
|
||||
return failedAddresses;
|
||||
}
|
||||
|
||||
protected Lock getConnectionLock() {
|
||||
return connectionLock;
|
||||
}
|
||||
|
@ -951,7 +980,6 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
tlsHandled.reportGenericFailure(smackWrappedException);
|
||||
saslFeatureReceived.reportGenericFailure(smackWrappedException);
|
||||
lastFeaturesReceived.reportGenericFailure(smackWrappedException);
|
||||
closingStreamReceived.reportFailure(smackWrappedException);
|
||||
// TODO From XMPPTCPConnection. Was called in Smack 4.3 where notifyConnectionError() was part of
|
||||
// XMPPTCPConnection. Create delegation method?
|
||||
// maybeCompressFeaturesReceived.reportGenericFailure(smackWrappedException);
|
||||
|
@ -2154,10 +2182,6 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
CACHED_EXECUTOR_SERVICE.execute(runnable);
|
||||
}
|
||||
|
||||
protected final SmackReactor getReactor() {
|
||||
return SMACK_REACTOR;
|
||||
}
|
||||
|
||||
protected static ScheduledAction schedule(Runnable runnable, long delay, TimeUnit unit) {
|
||||
return SMACK_REACTOR.schedule(runnable, delay, unit);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 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;
|
||||
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
|
||||
import org.jivesoftware.smack.SmackReactor.ChannelSelectedCallback;
|
||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptor;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptorGraph.GraphVertex;
|
||||
|
||||
public abstract class AbstractXmppNioConnection extends AbstractXmppStateMachineConnection {
|
||||
|
||||
protected AbstractXmppNioConnection(ConnectionConfiguration configuration, GraphVertex<StateDescriptor> initialStateDescriptorVertex) {
|
||||
super(configuration, initialStateDescriptorVertex);
|
||||
}
|
||||
|
||||
protected SelectionKey registerWithSelector(SelectableChannel channel, int ops, ChannelSelectedCallback callback)
|
||||
throws ClosedChannelException {
|
||||
return SMACK_REACTOR.registerWithSelector(channel, ops, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the interest Ops of a SelectionKey. Since Java's NIO interestOps(int) can block at any time, we use a queue
|
||||
* to perform the actual operation in the reactor where we can perform this operation non-blocking.
|
||||
*
|
||||
* @param selectionKey TODO javadoc me please
|
||||
* @param interestOps TODO javadoc me please
|
||||
*/
|
||||
protected void setInterestOps(SelectionKey selectionKey, int interestOps) {
|
||||
SMACK_REACTOR.setInterestOps(selectionKey, interestOps);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software, 2017-2020 Florian Schmaus.
|
||||
* Copyright 2003-2007 Jive Software, 2017-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.
|
||||
|
@ -229,18 +229,14 @@ public abstract class ConnectionConfiguration {
|
|||
|
||||
}
|
||||
|
||||
public DnsName getHost() {
|
||||
DnsName getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public InetAddress getHostAddress() {
|
||||
InetAddress getHostAddress() {
|
||||
return hostAddress;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server name of the target server.
|
||||
*
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software, 2018-2020 Florian Schmaus.
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -28,8 +28,6 @@ import java.util.Set;
|
|||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionConfiguration;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionModuleDescriptor;
|
||||
import org.jivesoftware.smack.compression.XMPPInputOutputStream;
|
||||
import org.jivesoftware.smack.debugger.ReflectionDebuggerFactory;
|
||||
import org.jivesoftware.smack.debugger.SmackDebuggerFactory;
|
||||
|
@ -240,6 +238,18 @@ public final class SmackConfiguration {
|
|||
compressionHandlers.add(xmppInputOutputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get compression handlers.
|
||||
*
|
||||
* @return a list of compression handlers.
|
||||
* @deprecated use {@link #getCompressionHandlers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
// TODO: Remove in Smack 4.4.
|
||||
public static List<XMPPInputOutputStream> getCompresionHandlers() {
|
||||
return getCompressionHandlers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get compression handlers.
|
||||
*
|
||||
|
@ -369,19 +379,4 @@ public final class SmackConfiguration {
|
|||
return defaultConcurrencyLevelLimit;
|
||||
}
|
||||
|
||||
private static final Set<Class<? extends ModularXmppClientToServerConnectionModuleDescriptor>> KNOWN_MODULES = new HashSet<>();
|
||||
|
||||
public static boolean addModule(Class<? extends ModularXmppClientToServerConnectionModuleDescriptor> moduleDescriptor) {
|
||||
synchronized (KNOWN_MODULES) {
|
||||
return KNOWN_MODULES.add(moduleDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addAllKnownModulesTo(ModularXmppClientToServerConnectionConfiguration.Builder builder) {
|
||||
synchronized (KNOWN_MODULES) {
|
||||
for (Class<? extends ModularXmppClientToServerConnectionModuleDescriptor> moduleDescriptor : KNOWN_MODULES) {
|
||||
builder.addModule(moduleDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2014-2020 Florian Schmaus
|
||||
* Copyright 2014-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.
|
||||
|
@ -16,15 +16,11 @@
|
|||
*/
|
||||
package org.jivesoftware.smack;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jivesoftware.smack.c2s.XmppClientToServerTransport.LookupConnectionEndpointsFailed;
|
||||
import org.jivesoftware.smack.filter.StanzaFilter;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smack.util.rce.RemoteConnectionEndpoint;
|
||||
import org.jivesoftware.smack.util.rce.RemoteConnectionEndpointLookupFailure;
|
||||
import org.jivesoftware.smack.util.rce.RemoteConnectionException;
|
||||
import org.jivesoftware.smack.util.dns.HostAddress;
|
||||
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
||||
|
@ -94,10 +90,16 @@ public abstract class SmackException extends Exception {
|
|||
public static NoResponseException newWith(XMPPConnection connection, String waitingFor) {
|
||||
final StringBuilder sb = getWaitingFor(connection);
|
||||
sb.append(" While waiting for ").append(waitingFor);
|
||||
sb.append(" [").append(connection).append(']');
|
||||
return new NoResponseException(sb.toString());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
// TODO: Remove in Smack 4.4.
|
||||
public static NoResponseException newWith(long timeout,
|
||||
StanzaCollector collector) {
|
||||
return newWith(timeout, collector.getStanzaFilter(), false);
|
||||
}
|
||||
|
||||
public static NoResponseException newWith(long timeout,
|
||||
StanzaCollector collector, boolean stanzaCollectorCancelled) {
|
||||
return newWith(timeout, collector.getStanzaFilter(), stanzaCollectorCancelled);
|
||||
|
@ -262,112 +264,45 @@ public abstract class SmackException extends Exception {
|
|||
}
|
||||
}
|
||||
|
||||
public abstract static class ConnectionException extends SmackException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected ConnectionException(Throwable wrappedThrowable) {
|
||||
super(wrappedThrowable);
|
||||
}
|
||||
|
||||
protected ConnectionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final class GenericConnectionException extends ConnectionException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Deprecated, do not use.
|
||||
*
|
||||
* @param wrappedThrowable the wrapped throwable.
|
||||
*/
|
||||
@Deprecated
|
||||
public GenericConnectionException(Throwable wrappedThrowable) {
|
||||
super(wrappedThrowable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This exception is thrown if Smack is unable to connect to all hosts of a given XMPP
|
||||
* service. The connection exceptions can be retrieved with
|
||||
* {@link EndpointConnectionException#getConnectionExceptions()}, which will have the exception causing the
|
||||
* connection failure set and retrievable with {@link RemoteConnectionException#getException()}.
|
||||
* ConnectionException is thrown if Smack is unable to connect to all hosts of a given XMPP
|
||||
* service. The failed hosts can be retrieved with
|
||||
* {@link ConnectionException#getFailedAddresses()}, which will have the exception causing the
|
||||
* connection failure set and retrievable with {@link HostAddress#getExceptions()}.
|
||||
*/
|
||||
public static final class EndpointConnectionException extends ConnectionException {
|
||||
public static class ConnectionException extends SmackException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1;
|
||||
private static final long serialVersionUID = 1686944201672697996L;
|
||||
|
||||
private final List<RemoteConnectionEndpointLookupFailure> lookupFailures;
|
||||
private final List<? extends RemoteConnectionException<?>> connectionExceptions;
|
||||
private final List<HostAddress> failedAddresses;
|
||||
|
||||
private EndpointConnectionException(String message, List<RemoteConnectionEndpointLookupFailure> lookupFailures,
|
||||
List<? extends RemoteConnectionException<?>> connectionExceptions) {
|
||||
public ConnectionException(Throwable wrappedThrowable) {
|
||||
super(wrappedThrowable);
|
||||
failedAddresses = new ArrayList<>(0);
|
||||
}
|
||||
|
||||
private ConnectionException(String message, List<HostAddress> failedAddresses) {
|
||||
super(message);
|
||||
// At least one list must contain an entry.
|
||||
assert !lookupFailures.isEmpty() || !connectionExceptions.isEmpty();
|
||||
this.lookupFailures = lookupFailures;
|
||||
this.connectionExceptions = connectionExceptions;
|
||||
this.failedAddresses = failedAddresses;
|
||||
}
|
||||
|
||||
public static EndpointConnectionException from(List<RemoteConnectionEndpointLookupFailure> lookupFailures,
|
||||
List<? extends RemoteConnectionException<?>> connectionExceptions) {
|
||||
StringBuilder sb = new StringBuilder(256);
|
||||
|
||||
if (!lookupFailures.isEmpty()) {
|
||||
sb.append("Could not lookup the following endpoints: ");
|
||||
StringUtils.appendTo(lookupFailures, sb);
|
||||
public static ConnectionException from(List<HostAddress> failedAddresses) {
|
||||
final String DELIMITER = ", ";
|
||||
StringBuilder sb = new StringBuilder("The following addresses failed: ");
|
||||
for (HostAddress hostAddress : failedAddresses) {
|
||||
sb.append(hostAddress.getErrorMessage());
|
||||
sb.append(DELIMITER);
|
||||
}
|
||||
|
||||
if (!connectionExceptions.isEmpty()) {
|
||||
sb.append("The following addresses failed: ");
|
||||
StringUtils.appendTo(connectionExceptions, sb, rce -> sb.append(rce.getErrorMessage()));
|
||||
}
|
||||
|
||||
return new EndpointConnectionException(sb.toString(), lookupFailures, connectionExceptions);
|
||||
// Remove the last delimiter
|
||||
sb.setLength(sb.length() - DELIMITER.length());
|
||||
return new ConnectionException(sb.toString(), failedAddresses);
|
||||
}
|
||||
|
||||
public List<RemoteConnectionEndpointLookupFailure> getLookupFailures() {
|
||||
return lookupFailures;
|
||||
}
|
||||
|
||||
public List<? extends RemoteConnectionException<? extends RemoteConnectionEndpoint>> getConnectionExceptions() {
|
||||
return connectionExceptions;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class NoEndpointsDiscoveredException extends ConnectionException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final List<LookupConnectionEndpointsFailed> lookupFailures;
|
||||
|
||||
private NoEndpointsDiscoveredException(String message, List<LookupConnectionEndpointsFailed> lookupFailures) {
|
||||
super(message);
|
||||
this.lookupFailures = Collections.unmodifiableList(lookupFailures);
|
||||
}
|
||||
|
||||
public List<LookupConnectionEndpointsFailed> getLookupFailures() {
|
||||
return lookupFailures;
|
||||
}
|
||||
|
||||
public static NoEndpointsDiscoveredException from(List<LookupConnectionEndpointsFailed> lookupFailures) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (lookupFailures.isEmpty()) {
|
||||
sb.append("No endpoint lookup finished within the timeout");
|
||||
} else {
|
||||
sb.append("Not endpoints could be discovered due the following lookup failures: ");
|
||||
StringUtils.appendTo(lookupFailures, sb);
|
||||
}
|
||||
|
||||
return new NoEndpointsDiscoveredException(sb.toString(), lookupFailures);
|
||||
public List<HostAddress> getFailedAddresses() {
|
||||
return failedAddresses;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017-2020 Florian Schmaus
|
||||
* Copyright 2017-2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -19,9 +19,7 @@ package org.jivesoftware.smack;
|
|||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -33,7 +31,6 @@ import javax.net.SocketFactory;
|
|||
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smack.util.CallbackRecipient;
|
||||
import org.jivesoftware.smack.util.Consumer;
|
||||
import org.jivesoftware.smack.util.ExceptionCallback;
|
||||
import org.jivesoftware.smack.util.SuccessCallback;
|
||||
|
||||
|
@ -51,8 +48,6 @@ public abstract class SmackFuture<V, E extends Exception> implements Future<V>,
|
|||
|
||||
private ExceptionCallback<E> exceptionCallback;
|
||||
|
||||
private Consumer<SmackFuture<V, E>> completionCallback;
|
||||
|
||||
@Override
|
||||
public final synchronized boolean cancel(boolean mayInterruptIfRunning) {
|
||||
if (isDone()) {
|
||||
|
@ -92,11 +87,6 @@ public abstract class SmackFuture<V, E extends Exception> implements Future<V>,
|
|||
return this;
|
||||
}
|
||||
|
||||
public void onCompletion(Consumer<SmackFuture<V, E>> completionCallback) {
|
||||
this.completionCallback = completionCallback;
|
||||
maybeInvokeCallbacks();
|
||||
}
|
||||
|
||||
private V getOrThrowExecutionException() throws ExecutionException {
|
||||
assert result != null || exception != null || cancelled;
|
||||
if (result != null) {
|
||||
|
@ -158,19 +148,11 @@ public abstract class SmackFuture<V, E extends Exception> implements Future<V>,
|
|||
return getOrThrowExecutionException();
|
||||
}
|
||||
|
||||
public V getIfAvailable() {
|
||||
return result;
|
||||
}
|
||||
|
||||
protected final synchronized void maybeInvokeCallbacks() {
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((result != null || exception != null) && completionCallback != null) {
|
||||
completionCallback.accept(this);
|
||||
}
|
||||
|
||||
if (result != null && successCallback != null) {
|
||||
AbstractXMPPConnection.asyncGo(new Runnable() {
|
||||
@Override
|
||||
|
@ -326,12 +308,4 @@ public abstract class SmackFuture<V, E extends Exception> implements Future<V>,
|
|||
return future;
|
||||
}
|
||||
|
||||
public static boolean await(Collection<? extends SmackFuture<?, ?>> futures, long timeout, TimeUnit unit) throws InterruptedException {
|
||||
CountDownLatch latch = new CountDownLatch(futures.size());
|
||||
for (SmackFuture<?, ?> future : futures) {
|
||||
future.onCompletion(f -> latch.countDown());
|
||||
}
|
||||
|
||||
return latch.await(timeout, unit);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,15 +26,12 @@ import java.util.List;
|
|||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smack.bind2.Bind2ModuleDescriptor;
|
||||
import org.jivesoftware.smack.compress.provider.CompressedProvider;
|
||||
import org.jivesoftware.smack.compress.provider.FailureProvider;
|
||||
import org.jivesoftware.smack.compression.CompressionModuleDescriptor;
|
||||
import org.jivesoftware.smack.compression.Java7ZlibInputOutputStream;
|
||||
import org.jivesoftware.smack.compression.XmppCompressionManager;
|
||||
import org.jivesoftware.smack.compression.zlib.ZlibXmppCompressionFactory;
|
||||
import org.jivesoftware.smack.initializer.SmackInitializer;
|
||||
import org.jivesoftware.smack.isr.InstantStreamResumptionModuleDescriptor;
|
||||
import org.jivesoftware.smack.packet.Bind;
|
||||
import org.jivesoftware.smack.packet.Message.Body;
|
||||
import org.jivesoftware.smack.provider.BindIQProvider;
|
||||
|
@ -139,10 +136,6 @@ public final class SmackInitialization {
|
|||
ProviderManager.addNonzaProvider(CompressedProvider.INSTANCE);
|
||||
ProviderManager.addNonzaProvider(FailureProvider.INSTANCE);
|
||||
|
||||
SmackConfiguration.addModule(Bind2ModuleDescriptor.class);
|
||||
SmackConfiguration.addModule(CompressionModuleDescriptor.class);
|
||||
SmackConfiguration.addModule(InstantStreamResumptionModuleDescriptor.class);
|
||||
|
||||
SmackConfiguration.smackInitialized = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018-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.
|
||||
|
@ -116,7 +116,7 @@ public class SmackReactor {
|
|||
setReactorThreadCount(DEFAULT_REACTOR_THREAD_COUNT);
|
||||
}
|
||||
|
||||
public SelectionKey registerWithSelector(SelectableChannel channel, int ops, ChannelSelectedCallback callback)
|
||||
SelectionKey registerWithSelector(SelectableChannel channel, int ops, ChannelSelectedCallback callback)
|
||||
throws ClosedChannelException {
|
||||
SelectionKeyAttachment selectionKeyAttachment = new SelectionKeyAttachment(callback);
|
||||
|
||||
|
@ -129,7 +129,7 @@ public class SmackReactor {
|
|||
}
|
||||
}
|
||||
|
||||
public void setInterestOps(SelectionKey selectionKey, int interestOps) {
|
||||
void setInterestOps(SelectionKey selectionKey, int interestOps) {
|
||||
SetInterestOps setInterestOps = new SetInterestOps(selectionKey, interestOps);
|
||||
pendingSetInterestOps.add(setInterestOps);
|
||||
selector.wakeup();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -70,7 +70,7 @@ public interface XmppInputOutputFilter {
|
|||
default void waitUntilInputOutputClosed() throws IOException, NoResponseException, CertificateException, InterruptedException, SmackException {
|
||||
}
|
||||
|
||||
Object getStats();
|
||||
|
||||
String getFilterName();
|
||||
default Object getStats() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019-2020 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.bind2;
|
||||
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.AuthenticatedAndResourceBoundStateDescriptor;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.ConnectedButUnauthenticatedStateDescriptor;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.SaslAuthenticationStateDescriptor;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionModule;
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
import org.jivesoftware.smack.c2s.internal.WalkStateGraphContext;
|
||||
import org.jivesoftware.smack.fsm.State;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptor;
|
||||
import org.jivesoftware.smack.fsm.StateTransitionResult;
|
||||
|
||||
public class Bind2Module extends ModularXmppClientToServerConnectionModule<Bind2ModuleDescriptor> {
|
||||
|
||||
protected Bind2Module(Bind2ModuleDescriptor moduleDescriptor,
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
super(moduleDescriptor, connectionInternal);
|
||||
}
|
||||
|
||||
public static final class Bind2StateDescriptor extends StateDescriptor {
|
||||
private Bind2StateDescriptor() {
|
||||
super(Bind2State.class, 386, StateDescriptor.Property.notImplemented);
|
||||
|
||||
addPredeccessor(ConnectedButUnauthenticatedStateDescriptor.class);
|
||||
addSuccessor(AuthenticatedAndResourceBoundStateDescriptor.class);
|
||||
declarePrecedenceOver(SaslAuthenticationStateDescriptor.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bind2Module.Bind2State constructState(ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
// This is the trick: the module is constructed prior the states, so we get the actual state out of the module by fetching the module from the connection.
|
||||
Bind2Module bind2Module = connectionInternal.connection.getConnectionModuleFor(Bind2ModuleDescriptor.class);
|
||||
return bind2Module.constructBind2State(this, connectionInternal);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Bind2State extends State {
|
||||
|
||||
private Bind2State(Bind2StateDescriptor bind2StateDescriptor,
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
super(bind2StateDescriptor, connectionInternal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateTransitionResult.TransitionImpossible isTransitionToPossible(WalkStateGraphContext walkStateGraphContext) {
|
||||
return new StateTransitionResult.TransitionImpossibleBecauseNotImplemented(stateDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateTransitionResult.AttemptResult transitionInto(WalkStateGraphContext walkStateGraphContext) {
|
||||
throw new IllegalStateException("Bind2 not implemented");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Bind2State constructBind2State(Bind2StateDescriptor bind2StateDescriptor,
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
return new Bind2State(bind2StateDescriptor, connectionInternal);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019-2020 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.bind2;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionConfiguration;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionModuleDescriptor;
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptor;
|
||||
|
||||
public class Bind2ModuleDescriptor extends ModularXmppClientToServerConnectionModuleDescriptor {
|
||||
|
||||
private static final Bind2ModuleDescriptor INSTANCE = new Bind2ModuleDescriptor();
|
||||
|
||||
@Override
|
||||
protected Set<Class<? extends StateDescriptor>> getStateDescriptors() {
|
||||
return Collections.singleton(Bind2Module.Bind2StateDescriptor.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bind2Module constructXmppConnectionModule(
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
return new Bind2Module(this, connectionInternal);
|
||||
}
|
||||
|
||||
public static class Builder extends ModularXmppClientToServerConnectionModuleDescriptor.Builder {
|
||||
|
||||
protected Builder(ModularXmppClientToServerConnectionConfiguration.Builder connectionConfigurationBuilder) {
|
||||
super(connectionConfigurationBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bind2ModuleDescriptor build() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes and interfaces for Bind 2.0 (XEP-0386).
|
||||
*/
|
||||
package org.jivesoftware.smack.bind2;
|
File diff suppressed because it is too large
Load diff
|
@ -1,167 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019-2020 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.c2s;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jivesoftware.smack.ConnectionConfiguration;
|
||||
import org.jivesoftware.smack.SmackConfiguration;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptor;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptorGraph;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptorGraph.GraphVertex;
|
||||
import org.jivesoftware.smack.util.CollectionUtil;
|
||||
|
||||
public final class ModularXmppClientToServerConnectionConfiguration extends ConnectionConfiguration {
|
||||
|
||||
final Set<ModularXmppClientToServerConnectionModuleDescriptor> moduleDescriptors;
|
||||
|
||||
final GraphVertex<StateDescriptor> initialStateDescriptorVertex;
|
||||
|
||||
private ModularXmppClientToServerConnectionConfiguration(Builder builder) {
|
||||
super(builder);
|
||||
|
||||
moduleDescriptors = Collections.unmodifiableSet(CollectionUtil.newSetWith(builder.modulesDescriptors.values()));
|
||||
|
||||
Set<Class<? extends StateDescriptor>> backwardEdgeStateDescriptors = new HashSet<>();
|
||||
// Add backward edges from configured connection modules. Note that all state descriptors from module
|
||||
// descriptors are backwards edges.
|
||||
for (ModularXmppClientToServerConnectionModuleDescriptor moduleDescriptor : moduleDescriptors) {
|
||||
Set<Class<? extends StateDescriptor>> moduleStateDescriptors = moduleDescriptor.getStateDescriptors();
|
||||
backwardEdgeStateDescriptors.addAll(moduleStateDescriptors);
|
||||
}
|
||||
|
||||
try {
|
||||
initialStateDescriptorVertex = StateDescriptorGraph.constructStateDescriptorGraph(backwardEdgeStateDescriptors);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
|
||||
| NoSuchMethodException | SecurityException e) {
|
||||
// TODO: Depending on the exact exception thrown, this potentially indicates an invalid connection
|
||||
// configuration, e.g. there is no edge from disconnected to connected.
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void printStateGraphInDotFormat(PrintWriter pw, boolean breakStateName) {
|
||||
StateDescriptorGraph.stateDescriptorGraphToDot(Collections.singleton(initialStateDescriptorVertex), pw,
|
||||
breakStateName);
|
||||
}
|
||||
|
||||
public String getStateGraphInDotFormat() {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
|
||||
printStateGraphInDotFormat(pw, true);
|
||||
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static final class Builder
|
||||
extends ConnectionConfiguration.Builder<Builder, ModularXmppClientToServerConnectionConfiguration> {
|
||||
|
||||
private final Map<Class<? extends ModularXmppClientToServerConnectionModuleDescriptor>, ModularXmppClientToServerConnectionModuleDescriptor> modulesDescriptors = new HashMap<>();
|
||||
|
||||
private Builder() {
|
||||
SmackConfiguration.addAllKnownModulesTo(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModularXmppClientToServerConnectionConfiguration build() {
|
||||
return new ModularXmppClientToServerConnectionConfiguration(this);
|
||||
}
|
||||
|
||||
void addModule(ModularXmppClientToServerConnectionModuleDescriptor connectionModule) {
|
||||
Class<? extends ModularXmppClientToServerConnectionModuleDescriptor> moduleDescriptorClass = connectionModule.getClass();
|
||||
if (modulesDescriptors.containsKey(moduleDescriptorClass)) {
|
||||
throw new IllegalArgumentException("A connection module for " + moduleDescriptorClass + " is already configured");
|
||||
}
|
||||
modulesDescriptors.put(moduleDescriptorClass, connectionModule);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Builder addModule(Class<? extends ModularXmppClientToServerConnectionModuleDescriptor> moduleClass) {
|
||||
Class<?>[] declaredClasses = moduleClass.getDeclaredClasses();
|
||||
|
||||
Class<? extends ModularXmppClientToServerConnectionModuleDescriptor.Builder> builderClass = null;
|
||||
for (Class<?> declaredClass : declaredClasses) {
|
||||
if (!ModularXmppClientToServerConnectionModuleDescriptor.Builder.class.isAssignableFrom(declaredClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
builderClass = (Class<? extends ModularXmppClientToServerConnectionModuleDescriptor.Builder>) declaredClass;
|
||||
break;
|
||||
}
|
||||
|
||||
if (builderClass == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Found no builder for " + moduleClass + ". Delcared classes: " + Arrays.toString(declaredClasses));
|
||||
}
|
||||
|
||||
return with(builderClass).buildModule();
|
||||
}
|
||||
|
||||
public <B extends ModularXmppClientToServerConnectionModuleDescriptor.Builder> B with(
|
||||
Class<? extends B> moduleDescriptorBuilderClass) {
|
||||
Constructor<? extends B> moduleDescriptorBuilderCosntructor;
|
||||
try {
|
||||
moduleDescriptorBuilderCosntructor = moduleDescriptorBuilderClass.getDeclaredConstructor(
|
||||
ModularXmppClientToServerConnectionConfiguration.Builder.class);
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
|
||||
moduleDescriptorBuilderCosntructor.setAccessible(true);
|
||||
|
||||
B moduleDescriptorBuilder;
|
||||
try {
|
||||
moduleDescriptorBuilder = moduleDescriptorBuilderCosntructor.newInstance(this);
|
||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
||||
| InvocationTargetException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
|
||||
return moduleDescriptorBuilder;
|
||||
}
|
||||
|
||||
public Builder removeModule(Class<? extends ModularXmppClientToServerConnectionModuleDescriptor> moduleClass) {
|
||||
modulesDescriptors.remove(moduleClass);
|
||||
return getThis();
|
||||
}
|
||||
|
||||
public Builder removeAllModules() {
|
||||
modulesDescriptors.clear();
|
||||
return getThis();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Builder getThis() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 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.c2s;
|
||||
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
|
||||
public abstract class ModularXmppClientToServerConnectionModule<MD extends ModularXmppClientToServerConnectionModuleDescriptor> {
|
||||
|
||||
protected final MD moduleDescriptor;
|
||||
|
||||
protected final ModularXmppClientToServerConnectionInternal connectionInternal;
|
||||
|
||||
protected ModularXmppClientToServerConnectionModule(MD moduleDescriptor,
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
this.moduleDescriptor = moduleDescriptor;
|
||||
this.connectionInternal = connectionInternal;
|
||||
}
|
||||
|
||||
public MD getModuleDescriptor() {
|
||||
return moduleDescriptor;
|
||||
}
|
||||
|
||||
protected XmppClientToServerTransport getTransport() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019-2020 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.c2s;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptor;
|
||||
|
||||
public abstract class ModularXmppClientToServerConnectionModuleDescriptor {
|
||||
|
||||
protected abstract Set<Class<? extends StateDescriptor>> getStateDescriptors();
|
||||
|
||||
protected abstract ModularXmppClientToServerConnectionModule<? extends ModularXmppClientToServerConnectionModuleDescriptor> constructXmppConnectionModule(
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal);
|
||||
|
||||
public abstract static class Builder {
|
||||
private final ModularXmppClientToServerConnectionConfiguration.Builder connectionConfigurationBuilder;
|
||||
|
||||
protected Builder(ModularXmppClientToServerConnectionConfiguration.Builder connectionConfigurationBuilder) {
|
||||
this.connectionConfigurationBuilder = connectionConfigurationBuilder;
|
||||
}
|
||||
|
||||
protected abstract ModularXmppClientToServerConnectionModuleDescriptor build();
|
||||
|
||||
public ModularXmppClientToServerConnectionConfiguration.Builder buildModule() {
|
||||
ModularXmppClientToServerConnectionModuleDescriptor moduleDescriptor = build();
|
||||
connectionConfigurationBuilder.addModule(moduleDescriptor);
|
||||
return connectionConfigurationBuilder;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019-2020 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.c2s;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.jivesoftware.smack.SmackFuture;
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
|
||||
public abstract class XmppClientToServerTransport {
|
||||
|
||||
protected final ModularXmppClientToServerConnectionInternal connectionInternal;
|
||||
|
||||
protected XmppClientToServerTransport(ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
this.connectionInternal = connectionInternal;
|
||||
}
|
||||
|
||||
protected abstract void resetDiscoveredConnectionEndpoints();
|
||||
|
||||
protected abstract List<SmackFuture<LookupConnectionEndpointsResult, Exception>> lookupConnectionEndpoints();
|
||||
|
||||
protected abstract void loadConnectionEndpoints(LookupConnectionEndpointsSuccess lookupConnectionEndpointsSuccess);
|
||||
|
||||
/**
|
||||
* Notify the transport that new outgoing data is available. Usually this method does not need to be called
|
||||
* explicitly, only if the filters are modified so that they potentially produced new data.
|
||||
*/
|
||||
protected abstract void afterFiltersClosed();
|
||||
|
||||
/**
|
||||
* Called by the CloseConnection state.
|
||||
*/
|
||||
protected abstract void disconnect();
|
||||
|
||||
protected abstract void notifyAboutNewOutgoingElements();
|
||||
|
||||
public abstract SSLSession getSslSession();
|
||||
|
||||
public abstract boolean isConnected();
|
||||
|
||||
public boolean isTransportSecured() {
|
||||
return getSslSession() != null;
|
||||
}
|
||||
|
||||
public abstract Stats getStats();
|
||||
|
||||
public abstract static class Stats {
|
||||
}
|
||||
|
||||
protected interface LookupConnectionEndpointsResult {
|
||||
}
|
||||
|
||||
protected interface LookupConnectionEndpointsSuccess extends LookupConnectionEndpointsResult {
|
||||
}
|
||||
|
||||
public interface LookupConnectionEndpointsFailed extends LookupConnectionEndpointsResult {
|
||||
// TODO: Add something like getExceptions() or getConnectionExceptions()?
|
||||
}
|
||||
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 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.c2s.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Queue;
|
||||
|
||||
import org.jivesoftware.smack.AbstractXMPPConnection.SmackTlsContext;
|
||||
import org.jivesoftware.smack.SmackException.ConnectionUnexpectedTerminatedException;
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.SmackReactor;
|
||||
import org.jivesoftware.smack.SmackReactor.ChannelSelectedCallback;
|
||||
import org.jivesoftware.smack.XMPPException.FailedNonzaException;
|
||||
import org.jivesoftware.smack.XmppInputOutputFilter;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection;
|
||||
import org.jivesoftware.smack.c2s.XmppClientToServerTransport;
|
||||
import org.jivesoftware.smack.debugger.SmackDebugger;
|
||||
import org.jivesoftware.smack.fsm.ConnectionStateEvent;
|
||||
import org.jivesoftware.smack.packet.Nonza;
|
||||
import org.jivesoftware.smack.packet.TopLevelStreamElement;
|
||||
import org.jivesoftware.smack.packet.XmlEnvironment;
|
||||
import org.jivesoftware.smack.util.Consumer;
|
||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||
|
||||
public abstract class ModularXmppClientToServerConnectionInternal {
|
||||
|
||||
private final SmackReactor reactor;
|
||||
|
||||
public final ModularXmppClientToServerConnection connection;
|
||||
|
||||
public final SmackDebugger smackDebugger;
|
||||
|
||||
public final Queue<TopLevelStreamElement> outgoingElementsQueue;
|
||||
|
||||
public ModularXmppClientToServerConnectionInternal(ModularXmppClientToServerConnection connection, SmackReactor reactor,
|
||||
SmackDebugger smackDebugger, Queue<TopLevelStreamElement> outgoingElementsQueue) {
|
||||
this.connection = connection;
|
||||
this.reactor = reactor;
|
||||
this.smackDebugger = smackDebugger;
|
||||
this.outgoingElementsQueue = outgoingElementsQueue;
|
||||
}
|
||||
|
||||
public SelectionKey registerWithSelector(SelectableChannel channel, int ops, ChannelSelectedCallback callback)
|
||||
throws ClosedChannelException {
|
||||
return reactor.registerWithSelector(channel, ops, callback);
|
||||
}
|
||||
|
||||
public void setInterestOps(SelectionKey selectionKey, int interestOps) {
|
||||
reactor.setInterestOps(selectionKey, interestOps);
|
||||
}
|
||||
|
||||
public final void withSmackDebugger(Consumer<SmackDebugger> smackDebuggerConsumer) {
|
||||
if (smackDebugger == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
smackDebuggerConsumer.accept(smackDebugger);
|
||||
}
|
||||
|
||||
public abstract XmlEnvironment getOutgoingStreamXmlEnvironment();
|
||||
|
||||
// TODO: The incomingElement parameter was previously of type TopLevelStreamElement, but I believe it has to be
|
||||
// of type string. But would this also work for BOSH or WebSocket?
|
||||
public abstract void parseAndProcessElement(String wrappedCompleteIncomingElement);
|
||||
|
||||
public abstract void notifyConnectionError(Exception e);
|
||||
|
||||
public abstract void onStreamOpen(XmlPullParser parser);
|
||||
|
||||
public abstract void onStreamClosed();
|
||||
|
||||
public abstract void fireFirstLevelElementSendListeners(TopLevelStreamElement element);
|
||||
|
||||
public abstract void invokeConnectionStateMachineListener(ConnectionStateEvent connectionStateEvent);
|
||||
|
||||
public abstract void addXmppInputOutputFilter(XmppInputOutputFilter xmppInputOutputFilter);
|
||||
|
||||
public abstract ListIterator<XmppInputOutputFilter> getXmppInputOutputFilterBeginIterator();
|
||||
|
||||
public abstract ListIterator<XmppInputOutputFilter> getXmppInputOutputFilterEndIterator();
|
||||
|
||||
public abstract void newStreamOpenWaitForFeaturesSequence(String waitFor) throws InterruptedException,
|
||||
ConnectionUnexpectedTerminatedException, NoResponseException, NotConnectedException;
|
||||
|
||||
public abstract SmackTlsContext getSmackTlsContext()
|
||||
throws KeyManagementException, NoSuchAlgorithmException, CertificateException, IOException,
|
||||
UnrecoverableKeyException, KeyStoreException, NoSuchProviderException;
|
||||
|
||||
public abstract <SN extends Nonza, FN extends Nonza> SN sendAndWaitForResponse(Nonza nonza,
|
||||
Class<SN> successNonzaClass, Class<FN> failedNonzaClass)
|
||||
throws NoResponseException, NotConnectedException, FailedNonzaException, InterruptedException;
|
||||
|
||||
public abstract void asyncGo(Runnable runnable);
|
||||
|
||||
public abstract Exception getCurrentConnectionException();
|
||||
|
||||
public abstract void setCompressionEnabled(boolean compressionEnabled);
|
||||
|
||||
public abstract void setTransport(XmppClientToServerTransport xmppTransport);
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 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.c2s.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.AuthenticatedAndResourceBoundStateDescriptor;
|
||||
import org.jivesoftware.smack.fsm.LoginContext;
|
||||
import org.jivesoftware.smack.fsm.State;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptor;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptorGraph.GraphVertex;
|
||||
import org.jivesoftware.smack.fsm.StateTransitionResult;
|
||||
import org.jivesoftware.smack.util.CollectionUtil;
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
|
||||
import org.jxmpp.jid.parts.Resourcepart;
|
||||
|
||||
public final class WalkStateGraphContext {
|
||||
private final Class<? extends StateDescriptor> initialStateClass;
|
||||
private final Class<? extends StateDescriptor> finalStateClass;
|
||||
private final Class<? extends StateDescriptor> mandatoryIntermediateState;
|
||||
private final LoginContext loginContext;
|
||||
|
||||
private final List<State> walkedStateGraphPath = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* A linked Map of failed States with their reason as value.
|
||||
*/
|
||||
final Map<State, StateTransitionResult> failedStates = new LinkedHashMap<>();
|
||||
|
||||
boolean mandatoryIntermediateStateHandled;
|
||||
|
||||
WalkStateGraphContext(Builder builder) {
|
||||
initialStateClass = builder.initialStateClass;
|
||||
finalStateClass = builder.finalStateClass;
|
||||
mandatoryIntermediateState = builder.mandatoryIntermediateState;
|
||||
loginContext = builder.loginContext;
|
||||
}
|
||||
|
||||
public void recordWalkTo(State state) {
|
||||
walkedStateGraphPath.add(state);
|
||||
}
|
||||
|
||||
public boolean isWalksFinalState(StateDescriptor stateDescriptor) {
|
||||
return stateDescriptor.getClass() == finalStateClass;
|
||||
}
|
||||
|
||||
public boolean isFinalStateAuthenticatedAndResourceBound() {
|
||||
return finalStateClass == AuthenticatedAndResourceBoundStateDescriptor.class;
|
||||
}
|
||||
|
||||
public GraphVertex<State> maybeReturnMandatoryImmediateState(List<GraphVertex<State>> outgoingStateEdges) {
|
||||
for (GraphVertex<State> outgoingStateVertex : outgoingStateEdges) {
|
||||
if (outgoingStateVertex.getElement().getStateDescriptor().getClass() == mandatoryIntermediateState) {
|
||||
mandatoryIntermediateStateHandled = true;
|
||||
return outgoingStateVertex;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<State> getWalk() {
|
||||
return CollectionUtil.newListWith(walkedStateGraphPath);
|
||||
}
|
||||
|
||||
public int getWalkLength() {
|
||||
return walkedStateGraphPath.size();
|
||||
}
|
||||
|
||||
public void appendWalkTo(List<State> walk) {
|
||||
walk.addAll(walkedStateGraphPath);
|
||||
}
|
||||
|
||||
public LoginContext getLoginContext() {
|
||||
return loginContext;
|
||||
}
|
||||
|
||||
public boolean stateAlreadyVisited(State state) {
|
||||
return walkedStateGraphPath.contains(state);
|
||||
}
|
||||
|
||||
public void recordFailedState(State state, StateTransitionResult stateTransitionResult) {
|
||||
failedStates.put(state, stateTransitionResult);
|
||||
}
|
||||
|
||||
public Map<State, StateTransitionResult> getFailedStates() {
|
||||
return new HashMap<>(failedStates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the way to the final state via the given successor state that would loop, i.e., lead over the initial state and
|
||||
* thus from a cycle.
|
||||
*
|
||||
* @param successorStateVertex the successor state to use on the way.
|
||||
* @return <code>true</code> if it would loop, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean wouldCauseCycle(GraphVertex<State> successorStateVertex) {
|
||||
Set<Class<? extends StateDescriptor>> visited = new HashSet<>();
|
||||
return wouldCycleRecursive(successorStateVertex, visited);
|
||||
}
|
||||
|
||||
private boolean wouldCycleRecursive(GraphVertex<State> stateVertex, Set<Class<? extends StateDescriptor>> visited) {
|
||||
Class<? extends StateDescriptor> stateVertexClass = stateVertex.getElement().getStateDescriptor().getClass();
|
||||
|
||||
if (stateVertexClass == initialStateClass) {
|
||||
return true;
|
||||
}
|
||||
if (finalStateClass == stateVertexClass || visited.contains(stateVertexClass)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
visited.add(stateVertexClass);
|
||||
|
||||
for (GraphVertex<State> successorStateVertex : stateVertex.getOutgoingEdges()) {
|
||||
boolean cycle = wouldCycleRecursive(successorStateVertex, visited);
|
||||
if (cycle) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Builder builder(Class<? extends StateDescriptor> initialStateClass, Class<? extends StateDescriptor> finalStateClass) {
|
||||
return new Builder(initialStateClass, finalStateClass);
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private final Class<? extends StateDescriptor> initialStateClass;
|
||||
private final Class<? extends StateDescriptor> finalStateClass;
|
||||
private Class<? extends StateDescriptor> mandatoryIntermediateState;
|
||||
private LoginContext loginContext;
|
||||
|
||||
private Builder(Class<? extends StateDescriptor> initialStateClass, Class<? extends StateDescriptor> finalStateClass) {
|
||||
this.initialStateClass = Objects.requireNonNull(initialStateClass);
|
||||
this.finalStateClass = Objects.requireNonNull(finalStateClass);
|
||||
}
|
||||
|
||||
public Builder withMandatoryIntermediateState(Class<? extends StateDescriptor> mandatoryIntermedidateState) {
|
||||
this.mandatoryIntermediateState = mandatoryIntermedidateState;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withLoginContext(String username, String password, Resourcepart resource) {
|
||||
LoginContext loginContext = new LoginContext(username, password, resource);
|
||||
return withLoginContext(loginContext);
|
||||
}
|
||||
|
||||
public Builder withLoginContext(LoginContext loginContext) {
|
||||
this.loginContext = loginContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
public WalkStateGraphContext build() {
|
||||
return new WalkStateGraphContext(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smack's internal API for client-to-server (c2s) connections.
|
||||
*/
|
||||
package org.jivesoftware.smack.c2s.internal;
|
|
@ -1,21 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smack's (new) API for client-to-server (c2s) connections.
|
||||
*/
|
||||
package org.jivesoftware.smack.c2s;
|
|
@ -1,132 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 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.compression;
|
||||
|
||||
import org.jivesoftware.smack.ConnectionConfiguration;
|
||||
import org.jivesoftware.smack.SmackException.ConnectionUnexpectedTerminatedException;
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPException.FailedNonzaException;
|
||||
import org.jivesoftware.smack.XmppInputOutputFilter;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.AuthenticatedButUnboundStateDescriptor;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.ResourceBindingStateDescriptor;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionModule;
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
import org.jivesoftware.smack.c2s.internal.WalkStateGraphContext;
|
||||
import org.jivesoftware.smack.compress.packet.Compress;
|
||||
import org.jivesoftware.smack.compress.packet.Compressed;
|
||||
import org.jivesoftware.smack.compress.packet.Failure;
|
||||
import org.jivesoftware.smack.fsm.State;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptor;
|
||||
import org.jivesoftware.smack.fsm.StateTransitionResult;
|
||||
|
||||
public class CompressionModule extends ModularXmppClientToServerConnectionModule<CompressionModuleDescriptor> {
|
||||
|
||||
protected CompressionModule(CompressionModuleDescriptor moduleDescriptor,
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
super(moduleDescriptor, connectionInternal);
|
||||
}
|
||||
|
||||
public static final class CompressionStateDescriptor extends StateDescriptor {
|
||||
private CompressionStateDescriptor() {
|
||||
super(CompressionModule.CompressionState.class, 138);
|
||||
addPredeccessor(AuthenticatedButUnboundStateDescriptor.class);
|
||||
addSuccessor(AuthenticatedButUnboundStateDescriptor.class);
|
||||
declarePrecedenceOver(ResourceBindingStateDescriptor.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompressionModule.CompressionState constructState(ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
CompressionModule compressionModule = connectionInternal.connection.getConnectionModuleFor(CompressionModuleDescriptor.class);
|
||||
return compressionModule.constructCompressionState(this, connectionInternal);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CompressionState extends State {
|
||||
private XmppCompressionFactory selectedCompressionFactory;
|
||||
private XmppInputOutputFilter usedXmppInputOutputCompressionFitler;
|
||||
|
||||
private CompressionState(StateDescriptor stateDescriptor, ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
super(stateDescriptor, connectionInternal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateTransitionResult.TransitionImpossible isTransitionToPossible(
|
||||
WalkStateGraphContext walkStateGraphContext) {
|
||||
final ConnectionConfiguration config = connectionInternal.connection.getConfiguration();
|
||||
if (!config.isCompressionEnabled()) {
|
||||
return new StateTransitionResult.TransitionImpossibleReason("Stream compression disabled by connection configuration");
|
||||
}
|
||||
|
||||
Compress.Feature compressFeature = connectionInternal.connection.getFeature(Compress.Feature.ELEMENT, Compress.NAMESPACE);
|
||||
if (compressFeature == null) {
|
||||
return new StateTransitionResult.TransitionImpossibleReason("Stream compression not supported or enabled by service");
|
||||
}
|
||||
|
||||
selectedCompressionFactory = XmppCompressionManager.getBestFactory(compressFeature);
|
||||
if (selectedCompressionFactory == null) {
|
||||
return new StateTransitionResult.TransitionImpossibleReason(
|
||||
"No matching compression factory for " + compressFeature.getMethods());
|
||||
}
|
||||
|
||||
usedXmppInputOutputCompressionFitler = selectedCompressionFactory.fabricate(config);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateTransitionResult.AttemptResult transitionInto(WalkStateGraphContext walkStateGraphContext)
|
||||
throws NoResponseException, NotConnectedException, FailedNonzaException, InterruptedException,
|
||||
ConnectionUnexpectedTerminatedException {
|
||||
final String compressionMethod = selectedCompressionFactory.getCompressionMethod();
|
||||
connectionInternal.sendAndWaitForResponse(new Compress(compressionMethod), Compressed.class, Failure.class);
|
||||
|
||||
connectionInternal.addXmppInputOutputFilter(usedXmppInputOutputCompressionFitler);
|
||||
|
||||
connectionInternal.newStreamOpenWaitForFeaturesSequence("server stream features after compression enabled");
|
||||
|
||||
connectionInternal.setCompressionEnabled(true);
|
||||
|
||||
return new CompressionTransitionSuccessResult(compressionMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetState() {
|
||||
selectedCompressionFactory = null;
|
||||
usedXmppInputOutputCompressionFitler = null;
|
||||
connectionInternal.setCompressionEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class CompressionTransitionSuccessResult extends StateTransitionResult.Success {
|
||||
private final String compressionMethod;
|
||||
|
||||
private CompressionTransitionSuccessResult(String compressionMethod) {
|
||||
super(compressionMethod + " compression enabled");
|
||||
this.compressionMethod = compressionMethod;
|
||||
}
|
||||
|
||||
public String getCompressionMethod() {
|
||||
return compressionMethod;
|
||||
}
|
||||
}
|
||||
|
||||
public CompressionState constructCompressionState(CompressionStateDescriptor compressionStateDescriptor,
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
return new CompressionState(compressionStateDescriptor, connectionInternal);
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 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.compression;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionConfiguration;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionModuleDescriptor;
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptor;
|
||||
|
||||
public class CompressionModuleDescriptor extends ModularXmppClientToServerConnectionModuleDescriptor {
|
||||
|
||||
private static final CompressionModuleDescriptor INSTANCE = new CompressionModuleDescriptor();
|
||||
|
||||
@Override
|
||||
protected Set<Class<? extends StateDescriptor>> getStateDescriptors() {
|
||||
return Collections.singleton(CompressionModule.CompressionStateDescriptor.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompressionModule constructXmppConnectionModule(
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
return new CompressionModule(this, connectionInternal);
|
||||
}
|
||||
|
||||
public static final class Builder extends ModularXmppClientToServerConnectionModuleDescriptor.Builder {
|
||||
|
||||
private Builder(ModularXmppClientToServerConnectionConfiguration.Builder connectionConfigurationBuilder) {
|
||||
super(connectionConfigurationBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ModularXmppClientToServerConnectionModuleDescriptor build() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -230,11 +230,6 @@ public final class ZlibXmppCompressionFactory extends XmppCompressionFactory {
|
|||
public Stats getStats() {
|
||||
return new Stats(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilterName() {
|
||||
return "Compression (zlib)";
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Stats {
|
||||
|
|
|
@ -0,0 +1,806 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-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.fsm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.jivesoftware.smack.AbstractXMPPConnection;
|
||||
import org.jivesoftware.smack.ConnectionConfiguration;
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.SmackException.ConnectionUnexpectedTerminatedException;
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.XMPPException.FailedNonzaException;
|
||||
import org.jivesoftware.smack.XMPPException.StreamErrorException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.XmppInputOutputFilter;
|
||||
import org.jivesoftware.smack.compress.packet.Compress;
|
||||
import org.jivesoftware.smack.compress.packet.Compressed;
|
||||
import org.jivesoftware.smack.compress.packet.Failure;
|
||||
import org.jivesoftware.smack.compression.XmppCompressionFactory;
|
||||
import org.jivesoftware.smack.compression.XmppCompressionManager;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptorGraph.GraphVertex;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.packet.Presence;
|
||||
import org.jivesoftware.smack.packet.StreamError;
|
||||
import org.jivesoftware.smack.parsing.SmackParsingException;
|
||||
import org.jivesoftware.smack.sasl.SASLErrorException;
|
||||
import org.jivesoftware.smack.sasl.SASLMechanism;
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||
import org.jivesoftware.smack.xml.XmlPullParserException;
|
||||
|
||||
import org.jxmpp.jid.parts.Resourcepart;
|
||||
|
||||
public abstract class AbstractXmppStateMachineConnection extends AbstractXMPPConnection {
|
||||
|
||||
private final List<ConnectionStateMachineListener> connectionStateMachineListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
private boolean featuresReceived;
|
||||
|
||||
protected boolean streamResumed;
|
||||
|
||||
private GraphVertex<State> currentStateVertex;
|
||||
|
||||
private List<State> walkFromDisconnectToAuthenticated;
|
||||
|
||||
private final List<XmppInputOutputFilter> inputOutputFilters = new CopyOnWriteArrayList<>();
|
||||
private List<XmppInputOutputFilter> previousInputOutputFilters;
|
||||
|
||||
protected AbstractXmppStateMachineConnection(ConnectionConfiguration configuration, GraphVertex<StateDescriptor> initialStateDescriptorVertex) {
|
||||
super(configuration);
|
||||
currentStateVertex = StateDescriptorGraph.convertToStateGraph(initialStateDescriptorVertex, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loginInternal(String username, String password, Resourcepart resource)
|
||||
throws XMPPException, SmackException, IOException, InterruptedException {
|
||||
WalkStateGraphContext walkStateGraphContext = buildNewWalkTo(AuthenticatedAndResourceBoundStateDescriptor.class)
|
||||
.withLoginContext(username, password, resource)
|
||||
.build();
|
||||
walkStateGraph(walkStateGraphContext);
|
||||
}
|
||||
|
||||
protected static WalkStateGraphContextBuilder buildNewWalkTo(Class<? extends StateDescriptor> finalStateClass) {
|
||||
return new WalkStateGraphContextBuilder(finalStateClass);
|
||||
}
|
||||
|
||||
protected static final class WalkStateGraphContext {
|
||||
private final Class<? extends StateDescriptor> finalStateClass;
|
||||
private final Class<? extends StateDescriptor> mandatoryIntermediateState;
|
||||
private final LoginContext loginContext;
|
||||
|
||||
private final List<State> walkedStateGraphPath = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* A linked Map of failed States with their reason as value.
|
||||
*/
|
||||
private final Map<State, TransitionReason> failedStates = new LinkedHashMap<>();
|
||||
|
||||
private boolean mandatoryIntermediateStateHandled;
|
||||
|
||||
private WalkStateGraphContext(Class<? extends StateDescriptor> finalStateClass, Class<? extends StateDescriptor> mandatoryIntermedidateState, LoginContext loginContext) {
|
||||
this.finalStateClass = Objects.requireNonNull(finalStateClass);
|
||||
this.mandatoryIntermediateState = mandatoryIntermedidateState;
|
||||
this.loginContext = loginContext;
|
||||
}
|
||||
|
||||
public boolean isFinalStateAuthenticatedAndResourceBound() {
|
||||
return finalStateClass == AuthenticatedAndResourceBoundStateDescriptor.class;
|
||||
}
|
||||
}
|
||||
|
||||
protected static final class WalkStateGraphContextBuilder {
|
||||
private final Class<? extends StateDescriptor> finalStateClass;
|
||||
private Class<? extends StateDescriptor> mandatoryIntermedidateState;
|
||||
private LoginContext loginContext;
|
||||
|
||||
private WalkStateGraphContextBuilder(Class<? extends StateDescriptor> finalStateClass) {
|
||||
this.finalStateClass = finalStateClass;
|
||||
}
|
||||
|
||||
public WalkStateGraphContextBuilder withMandatoryIntermediateState(Class<? extends StateDescriptor> mandatoryIntermedidateState) {
|
||||
this.mandatoryIntermedidateState = mandatoryIntermedidateState;
|
||||
return this;
|
||||
}
|
||||
|
||||
public WalkStateGraphContextBuilder withLoginContext(String username, String password, Resourcepart resource) {
|
||||
LoginContext loginContext = new LoginContext(username, password, resource);
|
||||
return withLoginContext(loginContext);
|
||||
}
|
||||
|
||||
public WalkStateGraphContextBuilder withLoginContext(LoginContext loginContext) {
|
||||
this.loginContext = loginContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
public WalkStateGraphContext build() {
|
||||
return new WalkStateGraphContext(finalStateClass, mandatoryIntermedidateState, loginContext);
|
||||
}
|
||||
}
|
||||
|
||||
protected final void walkStateGraph(WalkStateGraphContext walkStateGraphContext) throws XMPPErrorException, SASLErrorException,
|
||||
FailedNonzaException, IOException, SmackException, InterruptedException {
|
||||
// Save a copy of the current state
|
||||
GraphVertex<State> previousStateVertex = currentStateVertex;
|
||||
try {
|
||||
walkStateGraphInternal(walkStateGraphContext);
|
||||
}
|
||||
catch (XMPPErrorException | SASLErrorException | FailedNonzaException | IOException | SmackException
|
||||
| InterruptedException e) {
|
||||
currentStateVertex = previousStateVertex;
|
||||
// Reset that state.
|
||||
State revertedState = currentStateVertex.getElement();
|
||||
invokeConnectionStateMachineListener(new ConnectionStateEvent.StateRevertBackwardsWalk(revertedState));
|
||||
revertedState.resetState();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void walkStateGraphInternal(WalkStateGraphContext walkStateGraphContext)
|
||||
throws XMPPErrorException, SASLErrorException, IOException, SmackException, InterruptedException, FailedNonzaException {
|
||||
// Save a copy of the current state
|
||||
final GraphVertex<State> initialStateVertex = currentStateVertex;
|
||||
final State initialState = initialStateVertex.getElement();
|
||||
final StateDescriptor initialStateDescriptor = initialState.getStateDescriptor();
|
||||
|
||||
walkStateGraphContext.walkedStateGraphPath.add(initialState);
|
||||
|
||||
if (initialStateDescriptor.getClass() == walkStateGraphContext.finalStateClass) {
|
||||
// If this is used as final state, then it should be marked as such.
|
||||
assert initialStateDescriptor.isFinalState();
|
||||
|
||||
// We reached the final state.
|
||||
invokeConnectionStateMachineListener(new ConnectionStateEvent.FinalStateReached(initialState));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
List<GraphVertex<State>> outgoingStateEdges = currentStateVertex.getOutgoingEdges();
|
||||
|
||||
// See if we need to handle mandatory intermediate states.
|
||||
if (walkStateGraphContext.mandatoryIntermediateState != null && !walkStateGraphContext.mandatoryIntermediateStateHandled) {
|
||||
// Check if outgoingStateEdges contains the mandatory intermediate state.
|
||||
GraphVertex<State> mandatoryIntermediateStateVertex = null;
|
||||
for (GraphVertex<State> outgoingStateVertex : outgoingStateEdges) {
|
||||
if (outgoingStateVertex.getElement().getStateDescriptor().getClass() == walkStateGraphContext.mandatoryIntermediateState) {
|
||||
mandatoryIntermediateStateVertex = outgoingStateVertex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mandatoryIntermediateStateVertex != null) {
|
||||
walkStateGraphContext.mandatoryIntermediateStateHandled = true;
|
||||
TransitionReason reason = attemptEnterState(mandatoryIntermediateStateVertex, walkStateGraphContext);
|
||||
if (reason instanceof TransitionSuccessResult) {
|
||||
walkStateGraph(walkStateGraphContext);
|
||||
return;
|
||||
}
|
||||
|
||||
// We could not enter a mandatory intermediate state. Throw here.
|
||||
throw new StateMachineException.SmackMandatoryStateFailedException(
|
||||
mandatoryIntermediateStateVertex.getElement(), reason);
|
||||
}
|
||||
}
|
||||
|
||||
for (Iterator<GraphVertex<State>> it = outgoingStateEdges.iterator(); it.hasNext();) {
|
||||
GraphVertex<State> successorStateVertex = it.next();
|
||||
State successorState = successorStateVertex.getElement();
|
||||
TransitionReason reason = attemptEnterState(successorStateVertex, walkStateGraphContext);
|
||||
if (reason instanceof TransitionSuccessResult) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If attemptEnterState did not throw and did not return a value of type TransitionSuccessResult, then we
|
||||
// just record this value and go on from there. Note that reason may be null, which is returned by
|
||||
// attemptEnterState in case the state was already successfully handled. If this is the case, then we don't
|
||||
// record it.
|
||||
if (reason != null) {
|
||||
walkStateGraphContext.failedStates.put(successorState, reason);
|
||||
}
|
||||
|
||||
if (!it.hasNext()) {
|
||||
throw new StateMachineException.SmackStateGraphDeadEndException(walkStateGraphContext.walkedStateGraphPath, walkStateGraphContext.failedStates);
|
||||
}
|
||||
}
|
||||
|
||||
// Walk the state graph by recursion.
|
||||
walkStateGraph(walkStateGraphContext);
|
||||
}
|
||||
|
||||
private TransitionReason attemptEnterState(GraphVertex<State> successorStateVertex,
|
||||
WalkStateGraphContext walkStateGraphContext)
|
||||
throws SmackException, XMPPErrorException, SASLErrorException, IOException, InterruptedException, FailedNonzaException {
|
||||
final State successorState = successorStateVertex.getElement();
|
||||
final StateDescriptor successorStateDescriptor = successorState.getStateDescriptor();
|
||||
|
||||
if (!successorStateDescriptor.isMultiVisitState() && walkStateGraphContext.walkedStateGraphPath.contains(successorState)) {
|
||||
// This can happen if a state leads back to the state where it originated from. See for example the
|
||||
// 'Compression' state. We return 'null' here to signal that the state can safely be ignored.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (successorStateDescriptor.isNotImplemented()) {
|
||||
TransitionImpossibleBecauseNotImplemented transtionImpossibleBecauseNotImplemented = new TransitionImpossibleBecauseNotImplemented(
|
||||
successorStateDescriptor);
|
||||
invokeConnectionStateMachineListener(new ConnectionStateEvent.TransitionNotPossible(successorState,
|
||||
transtionImpossibleBecauseNotImplemented));
|
||||
return transtionImpossibleBecauseNotImplemented;
|
||||
}
|
||||
|
||||
final TransitionIntoResult transitionIntoResult;
|
||||
try {
|
||||
TransitionImpossibleReason transitionImpossibleReason = successorState.isTransitionToPossible(walkStateGraphContext);
|
||||
if (transitionImpossibleReason != null) {
|
||||
invokeConnectionStateMachineListener(new ConnectionStateEvent.TransitionNotPossible(successorState,
|
||||
transitionImpossibleReason));
|
||||
return transitionImpossibleReason;
|
||||
}
|
||||
|
||||
invokeConnectionStateMachineListener(new ConnectionStateEvent.AboutToTransitionInto(successorState));
|
||||
transitionIntoResult = successorState.transitionInto(walkStateGraphContext);
|
||||
} catch (SmackException | XMPPErrorException | SASLErrorException | IOException | InterruptedException
|
||||
| FailedNonzaException e) {
|
||||
// TODO Document why this is required given that there is another call site of resetState().
|
||||
invokeConnectionStateMachineListener(new ConnectionStateEvent.StateRevertBackwardsWalk(successorState));
|
||||
successorState.resetState();
|
||||
throw e;
|
||||
}
|
||||
if (transitionIntoResult instanceof TransitionFailureResult) {
|
||||
TransitionFailureResult transitionFailureResult = (TransitionFailureResult) transitionIntoResult;
|
||||
invokeConnectionStateMachineListener(new ConnectionStateEvent.TransitionFailed(successorState, transitionFailureResult));
|
||||
return transitionIntoResult;
|
||||
}
|
||||
|
||||
// If transitionIntoResult is not an instance of TransitionFailureResult, then it has to be of type
|
||||
// TransitionSuccessResult.
|
||||
TransitionSuccessResult transitionSuccessResult = (TransitionSuccessResult) transitionIntoResult;
|
||||
|
||||
currentStateVertex = successorStateVertex;
|
||||
invokeConnectionStateMachineListener(new ConnectionStateEvent.SuccessfullyTransitionedInto(successorState,
|
||||
transitionSuccessResult));
|
||||
|
||||
return transitionSuccessResult;
|
||||
}
|
||||
|
||||
protected abstract SSLSession getSSLSession();
|
||||
|
||||
@Override
|
||||
protected void afterFeaturesReceived() {
|
||||
featuresReceived = true;
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected final void parseAndProcessElement(String element) throws XmlPullParserException, IOException,
|
||||
InterruptedException, StreamErrorException, SmackException, SmackParsingException {
|
||||
XmlPullParser parser = PacketParserUtils.getParserFor(element);
|
||||
|
||||
// Skip the enclosing stream open what is guaranteed to be there.
|
||||
parser.next();
|
||||
|
||||
XmlPullParser.Event event = parser.getEventType();
|
||||
outerloop: while (true) {
|
||||
switch (event) {
|
||||
case START_ELEMENT:
|
||||
final String name = parser.getName();
|
||||
// Note that we don't handle "stream" here as it's done in the splitter.
|
||||
switch (name) {
|
||||
case Message.ELEMENT:
|
||||
case IQ.IQ_ELEMENT:
|
||||
case Presence.ELEMENT:
|
||||
try {
|
||||
parseAndProcessStanza(parser);
|
||||
} finally {
|
||||
// TODO: Here would be the following stream management code.
|
||||
// clientHandledStanzasCount = SMUtils.incrementHeight(clientHandledStanzasCount);
|
||||
}
|
||||
break;
|
||||
case "error":
|
||||
StreamError streamError = PacketParserUtils.parseStreamError(parser, null);
|
||||
saslFeatureReceived.reportFailure(new StreamErrorException(streamError));
|
||||
throw new StreamErrorException(streamError);
|
||||
case "features":
|
||||
parseFeatures(parser);
|
||||
afterFeaturesReceived();
|
||||
break;
|
||||
default:
|
||||
parseAndProcessNonza(parser);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case END_DOCUMENT:
|
||||
break outerloop;
|
||||
default: // fall out
|
||||
}
|
||||
event = parser.next();
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void prepareToWaitForFeaturesReceived() {
|
||||
featuresReceived = false;
|
||||
}
|
||||
|
||||
protected void waitForFeaturesReceived(String waitFor)
|
||||
throws InterruptedException, ConnectionUnexpectedTerminatedException, NoResponseException {
|
||||
long waitStartMs = System.currentTimeMillis();
|
||||
long timeoutMs = getReplyTimeout();
|
||||
synchronized (this) {
|
||||
while (!featuresReceived && currentConnectionException == null) {
|
||||
long remainingWaitMs = timeoutMs - (System.currentTimeMillis() - waitStartMs);
|
||||
if (remainingWaitMs <= 0) {
|
||||
throw NoResponseException.newWith(this, waitFor);
|
||||
}
|
||||
wait(remainingWaitMs);
|
||||
}
|
||||
if (currentConnectionException != null) {
|
||||
throw new SmackException.ConnectionUnexpectedTerminatedException(currentConnectionException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void newStreamOpenWaitForFeaturesSequence(String waitFor) throws InterruptedException,
|
||||
ConnectionUnexpectedTerminatedException, NoResponseException, NotConnectedException {
|
||||
prepareToWaitForFeaturesReceived();
|
||||
sendStreamOpen();
|
||||
waitForFeaturesReceived(waitFor);
|
||||
}
|
||||
|
||||
protected final void addXmppInputOutputFilter(XmppInputOutputFilter xmppInputOutputFilter) {
|
||||
inputOutputFilters.add(0, xmppInputOutputFilter);
|
||||
}
|
||||
|
||||
protected final ListIterator<XmppInputOutputFilter> getXmppInputOutputFilterBeginIterator() {
|
||||
return inputOutputFilters.listIterator();
|
||||
}
|
||||
|
||||
protected final ListIterator<XmppInputOutputFilter> getXmppInputOutputFilterEndIterator() {
|
||||
return inputOutputFilters.listIterator(inputOutputFilters.size());
|
||||
}
|
||||
|
||||
protected final synchronized List<Object> getFilterStats() {
|
||||
Collection<XmppInputOutputFilter> filters;
|
||||
if (inputOutputFilters.isEmpty() && previousInputOutputFilters != null) {
|
||||
filters = previousInputOutputFilters;
|
||||
} else {
|
||||
filters = inputOutputFilters;
|
||||
}
|
||||
|
||||
List<Object> filterStats = new ArrayList<>(filters.size());
|
||||
for (XmppInputOutputFilter xmppInputOutputFilter : filters) {
|
||||
Object stats = xmppInputOutputFilter.getStats();
|
||||
if (stats != null) {
|
||||
filterStats.add(stats);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(filterStats);
|
||||
}
|
||||
|
||||
protected abstract class State {
|
||||
private final StateDescriptor stateDescriptor;
|
||||
|
||||
protected State(StateDescriptor stateDescriptor) {
|
||||
this.stateDescriptor = stateDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the state should be activated.
|
||||
*
|
||||
* @param walkStateGraphContext the context of the current state graph walk.
|
||||
* @return <code>null</code> if the state should be activated.
|
||||
* @throws SmackException in case a Smack exception occurs.
|
||||
*/
|
||||
protected TransitionImpossibleReason isTransitionToPossible(WalkStateGraphContext walkStateGraphContext) throws SmackException {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract TransitionIntoResult transitionInto(WalkStateGraphContext walkStateGraphContext)
|
||||
throws XMPPErrorException, SASLErrorException, IOException, SmackException, InterruptedException, FailedNonzaException;
|
||||
|
||||
StateDescriptor getStateDescriptor() {
|
||||
return stateDescriptor;
|
||||
}
|
||||
|
||||
protected void resetState() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "State " + stateDescriptor + ' ' + AbstractXmppStateMachineConnection.this;
|
||||
}
|
||||
|
||||
protected final void ensureNotOnOurWayToAuthenticatedAndResourceBound(WalkStateGraphContext walkStateGraphContext) {
|
||||
if (walkStateGraphContext.isFinalStateAuthenticatedAndResourceBound()) {
|
||||
throw new IllegalStateException(
|
||||
"Smack should never attempt to reach the authenticated and resource bound state over " + this
|
||||
+ ". This is probably a programming error within Smack, please report it to the develoeprs.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract static class TransitionReason {
|
||||
public final String reason;
|
||||
private TransitionReason(String reason) {
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return reason;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class TransitionImpossibleReason extends TransitionReason {
|
||||
public TransitionImpossibleReason(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class TransitionImpossibleBecauseNotImplemented extends TransitionImpossibleReason {
|
||||
public TransitionImpossibleBecauseNotImplemented(StateDescriptor stateDescriptor) {
|
||||
super(stateDescriptor.getFullStateName(false) + " is not implemented (yet)");
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract static class TransitionIntoResult extends TransitionReason {
|
||||
public TransitionIntoResult(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TransitionSuccessResult extends TransitionIntoResult {
|
||||
|
||||
public static final TransitionSuccessResult EMPTY_INSTANCE = new TransitionSuccessResult();
|
||||
|
||||
private TransitionSuccessResult() {
|
||||
super("");
|
||||
}
|
||||
|
||||
public TransitionSuccessResult(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TransitionFailureResult extends TransitionIntoResult {
|
||||
private TransitionFailureResult(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
}
|
||||
|
||||
protected final class NoOpState extends State {
|
||||
|
||||
private NoOpState(StateDescriptor stateDescriptor) {
|
||||
super(stateDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransitionImpossibleReason isTransitionToPossible(WalkStateGraphContext walkStateGraphContext) {
|
||||
// Transition into a NoOpState is always possible.
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransitionIntoResult transitionInto(WalkStateGraphContext walkStateGraphContext) {
|
||||
// Transition into a NoOpState always succeeds.
|
||||
return TransitionSuccessResult.EMPTY_INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class DisconnectedStateDescriptor extends StateDescriptor {
|
||||
protected DisconnectedStateDescriptor() {
|
||||
super(DisconnectedState.class, StateDescriptor.Property.finalState);
|
||||
}
|
||||
}
|
||||
|
||||
private final class DisconnectedState extends State {
|
||||
|
||||
private DisconnectedState(StateDescriptor stateDescriptor) {
|
||||
super(stateDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransitionIntoResult transitionInto(WalkStateGraphContext walkStateGraphContext) {
|
||||
if (inputOutputFilters.isEmpty()) {
|
||||
previousInputOutputFilters = null;
|
||||
} else {
|
||||
previousInputOutputFilters = new ArrayList<>(inputOutputFilters.size());
|
||||
previousInputOutputFilters.addAll(inputOutputFilters);
|
||||
inputOutputFilters.clear();
|
||||
}
|
||||
|
||||
ListIterator<State> it = walkFromDisconnectToAuthenticated.listIterator(
|
||||
walkFromDisconnectToAuthenticated.size());
|
||||
while (it.hasPrevious()) {
|
||||
State stateToReset = it.previous();
|
||||
stateToReset.resetState();
|
||||
}
|
||||
walkFromDisconnectToAuthenticated = null;
|
||||
|
||||
return TransitionSuccessResult.EMPTY_INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
protected static final class ConnectedButUnauthenticatedStateDescriptor extends StateDescriptor {
|
||||
private ConnectedButUnauthenticatedStateDescriptor() {
|
||||
super(ConnectedButUnauthenticatedState.class, StateDescriptor.Property.finalState);
|
||||
addSuccessor(SaslAuthenticationStateDescriptor.class);
|
||||
}
|
||||
}
|
||||
|
||||
private final class ConnectedButUnauthenticatedState extends State {
|
||||
private ConnectedButUnauthenticatedState(StateDescriptor stateDescriptor) {
|
||||
super(stateDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransitionIntoResult transitionInto(WalkStateGraphContext walkStateGraphContext) {
|
||||
assert walkFromDisconnectToAuthenticated == null;
|
||||
if (getStateDescriptor().getClass() == walkStateGraphContext.finalStateClass) {
|
||||
// If this is the final state, then record the walk so far.
|
||||
walkFromDisconnectToAuthenticated = new ArrayList<>(walkStateGraphContext.walkedStateGraphPath);
|
||||
}
|
||||
|
||||
connected = true;
|
||||
return TransitionSuccessResult.EMPTY_INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetState() {
|
||||
connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected static final class SaslAuthenticationStateDescriptor extends StateDescriptor {
|
||||
private SaslAuthenticationStateDescriptor() {
|
||||
super(SaslAuthenticationState.class, "RFC 6120 § 6");
|
||||
addSuccessor(AuthenticatedButUnboundStateDescriptor.class);
|
||||
}
|
||||
}
|
||||
|
||||
private final class SaslAuthenticationState extends State {
|
||||
private SaslAuthenticationState(StateDescriptor stateDescriptor) {
|
||||
super(stateDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransitionIntoResult transitionInto(WalkStateGraphContext walkStateGraphContext) throws XMPPErrorException,
|
||||
SASLErrorException, IOException, SmackException, InterruptedException {
|
||||
prepareToWaitForFeaturesReceived();
|
||||
|
||||
LoginContext loginContext = walkStateGraphContext.loginContext;
|
||||
SASLMechanism usedSaslMechanism = authenticate(loginContext.username, loginContext.password, config.getAuthzid(), getSSLSession());
|
||||
// authenticate() will only return if the SASL authentication was successful, but we also need to wait for the next round of stream features.
|
||||
|
||||
waitForFeaturesReceived("server stream features after SASL authentication");
|
||||
|
||||
return new SaslAuthenticationSuccessResult(usedSaslMechanism);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SaslAuthenticationSuccessResult extends TransitionSuccessResult {
|
||||
private final String saslMechanismName;
|
||||
|
||||
private SaslAuthenticationSuccessResult(SASLMechanism usedSaslMechanism) {
|
||||
super("SASL authentication successfull using " + usedSaslMechanism.getName());
|
||||
this.saslMechanismName = usedSaslMechanism.getName();
|
||||
}
|
||||
|
||||
public String getSaslMechanismName() {
|
||||
return saslMechanismName;
|
||||
}
|
||||
}
|
||||
|
||||
protected static final class AuthenticatedButUnboundStateDescriptor extends StateDescriptor {
|
||||
private AuthenticatedButUnboundStateDescriptor() {
|
||||
super(StateDescriptor.Property.multiVisitState);
|
||||
addSuccessor(ResourceBindingStateDescriptor.class);
|
||||
addSuccessor(CompressionStateDescriptor.class);
|
||||
}
|
||||
}
|
||||
|
||||
protected static final class ResourceBindingStateDescriptor extends StateDescriptor {
|
||||
private ResourceBindingStateDescriptor() {
|
||||
super(ResourceBindingState.class, "RFC 6120 § 7");
|
||||
addSuccessor(AuthenticatedAndResourceBoundStateDescriptor.class);
|
||||
}
|
||||
}
|
||||
|
||||
private final class ResourceBindingState extends State {
|
||||
private ResourceBindingState(StateDescriptor stateDescriptor) {
|
||||
super(stateDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransitionIntoResult transitionInto(WalkStateGraphContext walkStateGraphContext) throws XMPPErrorException,
|
||||
SASLErrorException, IOException, SmackException, InterruptedException {
|
||||
// TODO: The reportSuccess() is just a quick fix until there is a variant of the
|
||||
// bindResourceAndEstablishSession() method which does not require this.
|
||||
lastFeaturesReceived.reportSuccess();
|
||||
|
||||
LoginContext loginContext = walkStateGraphContext.loginContext;
|
||||
Resourcepart resource = bindResourceAndEstablishSession(loginContext.resource);
|
||||
streamResumed = false;
|
||||
|
||||
return new ResourceBoundResult(resource, loginContext.resource);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ResourceBoundResult extends TransitionSuccessResult {
|
||||
private final Resourcepart resource;
|
||||
|
||||
private ResourceBoundResult(Resourcepart boundResource, Resourcepart requestedResource) {
|
||||
super("Resource '" + boundResource + "' bound (requested: '" + requestedResource + "'");
|
||||
this.resource = boundResource;
|
||||
}
|
||||
|
||||
public Resourcepart getResource() {
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
protected static final class CompressionStateDescriptor extends StateDescriptor {
|
||||
private CompressionStateDescriptor() {
|
||||
super(CompressionState.class, 138);
|
||||
addSuccessor(AuthenticatedButUnboundStateDescriptor.class);
|
||||
declarePrecedenceOver(ResourceBindingStateDescriptor.class);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean compressionEnabled;
|
||||
|
||||
private class CompressionState extends State {
|
||||
private XmppCompressionFactory selectedCompressionFactory;
|
||||
private XmppInputOutputFilter usedXmppInputOutputCompressionFitler;
|
||||
|
||||
protected CompressionState(StateDescriptor stateDescriptor) {
|
||||
super(stateDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransitionImpossibleReason isTransitionToPossible(WalkStateGraphContext walkStateGraphContext) {
|
||||
if (!config.isCompressionEnabled()) {
|
||||
return new TransitionImpossibleReason("Stream compression disabled");
|
||||
}
|
||||
|
||||
Compress.Feature compressFeature = getFeature(Compress.Feature.ELEMENT, Compress.NAMESPACE);
|
||||
if (compressFeature == null) {
|
||||
return new TransitionImpossibleReason("Stream compression not supported");
|
||||
}
|
||||
|
||||
selectedCompressionFactory = XmppCompressionManager.getBestFactory(compressFeature);
|
||||
if (selectedCompressionFactory == null) {
|
||||
return new TransitionImpossibleReason("No matching compression factory");
|
||||
}
|
||||
|
||||
usedXmppInputOutputCompressionFitler = selectedCompressionFactory.fabricate(config);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransitionIntoResult transitionInto(WalkStateGraphContext walkStateGraphContext)
|
||||
throws NoResponseException, NotConnectedException, FailedNonzaException, InterruptedException,
|
||||
ConnectionUnexpectedTerminatedException {
|
||||
final String compressionMethod = selectedCompressionFactory.getCompressionMethod();
|
||||
sendAndWaitForResponse(new Compress(compressionMethod), Compressed.class, Failure.class);
|
||||
|
||||
addXmppInputOutputFilter(usedXmppInputOutputCompressionFitler);
|
||||
|
||||
newStreamOpenWaitForFeaturesSequence("server stream features after compression enabled");
|
||||
|
||||
compressionEnabled = true;
|
||||
|
||||
return new CompressionTransitionSuccessResult(compressionMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetState() {
|
||||
selectedCompressionFactory = null;
|
||||
usedXmppInputOutputCompressionFitler = null;
|
||||
compressionEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class CompressionTransitionSuccessResult extends TransitionSuccessResult {
|
||||
private final String compressionMethod;
|
||||
|
||||
private CompressionTransitionSuccessResult(String compressionMethod) {
|
||||
super(compressionMethod + " compression enabled");
|
||||
this.compressionMethod = compressionMethod;
|
||||
}
|
||||
|
||||
public String getCompressionMethod() {
|
||||
return compressionMethod;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isUsingCompression() {
|
||||
return compressionEnabled;
|
||||
}
|
||||
|
||||
protected static final class AuthenticatedAndResourceBoundStateDescriptor extends StateDescriptor {
|
||||
private AuthenticatedAndResourceBoundStateDescriptor() {
|
||||
super(AuthenticatedAndResourceBoundState.class, StateDescriptor.Property.finalState);
|
||||
}
|
||||
}
|
||||
|
||||
private final class AuthenticatedAndResourceBoundState extends State {
|
||||
private AuthenticatedAndResourceBoundState(StateDescriptor stateDescriptor) {
|
||||
super(stateDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransitionIntoResult transitionInto(WalkStateGraphContext walkStateGraphContext)
|
||||
throws NotConnectedException, InterruptedException {
|
||||
if (walkFromDisconnectToAuthenticated != null) {
|
||||
// If there was already a previous walk to ConnectedButUnauthenticated, then the context of the current
|
||||
// walk must not start from the 'Disconnected' state.
|
||||
assert walkStateGraphContext.walkedStateGraphPath.get(0).stateDescriptor.getClass() != DisconnectedStateDescriptor.class;
|
||||
walkFromDisconnectToAuthenticated.addAll(walkStateGraphContext.walkedStateGraphPath);
|
||||
} else {
|
||||
walkFromDisconnectToAuthenticated = new ArrayList<>(walkStateGraphContext.walkedStateGraphPath.size() + 1);
|
||||
walkFromDisconnectToAuthenticated.addAll(walkStateGraphContext.walkedStateGraphPath);
|
||||
}
|
||||
walkFromDisconnectToAuthenticated.add(this);
|
||||
|
||||
afterSuccessfulLogin(streamResumed);
|
||||
return TransitionSuccessResult.EMPTY_INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetState() {
|
||||
authenticated = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void addConnectionStateMachineListener(ConnectionStateMachineListener connectionStateMachineListener) {
|
||||
connectionStateMachineListeners.add(connectionStateMachineListener);
|
||||
}
|
||||
|
||||
public boolean removeConnectionStateMachineListener(ConnectionStateMachineListener connectionStateMachineListener) {
|
||||
return connectionStateMachineListeners.remove(connectionStateMachineListener);
|
||||
}
|
||||
|
||||
protected void invokeConnectionStateMachineListener(ConnectionStateEvent connectionStateEvent) {
|
||||
if (connectionStateMachineListeners.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASYNC_BUT_ORDERED.performAsyncButOrdered(this, () -> {
|
||||
for (ConnectionStateMachineListener connectionStateMachineListener : connectionStateMachineListeners) {
|
||||
connectionStateMachineListener.onConnectionStateEvent(connectionStateEvent, this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,37 +16,29 @@
|
|||
*/
|
||||
package org.jivesoftware.smack.fsm;
|
||||
|
||||
import org.jivesoftware.smack.fsm.StateDescriptorGraph.GraphVertex;
|
||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.State;
|
||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.TransitionFailureResult;
|
||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.TransitionImpossibleReason;
|
||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.TransitionSuccessResult;
|
||||
|
||||
public class ConnectionStateEvent {
|
||||
|
||||
private final StateDescriptor currentStateDescriptor;
|
||||
private final StateDescriptor successorStateDescriptor;
|
||||
private final StateDescriptor stateDescriptor;
|
||||
|
||||
private final long timestamp;
|
||||
|
||||
public ConnectionStateEvent(StateDescriptor currentStateDescriptor) {
|
||||
this(currentStateDescriptor, null);
|
||||
}
|
||||
|
||||
public ConnectionStateEvent(StateDescriptor currentStateDescriptor, StateDescriptor successorStateDescriptor) {
|
||||
this.currentStateDescriptor = currentStateDescriptor;
|
||||
this.successorStateDescriptor = successorStateDescriptor;
|
||||
protected ConnectionStateEvent(StateDescriptor stateDescriptor) {
|
||||
this.stateDescriptor = stateDescriptor;
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public StateDescriptor getStateDescriptor() {
|
||||
return currentStateDescriptor;
|
||||
return stateDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (successorStateDescriptor == null) {
|
||||
return getClass().getSimpleName() + ": " + currentStateDescriptor.getStateName();
|
||||
} else {
|
||||
return currentStateDescriptor.getStateName() + ' ' + getClass().getSimpleName() + ' '
|
||||
+ successorStateDescriptor.getStateName();
|
||||
}
|
||||
return stateDescriptor.getStateName() + ' ' + getClass().getSimpleName();
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
|
@ -54,22 +46,22 @@ public class ConnectionStateEvent {
|
|||
}
|
||||
|
||||
public static class StateRevertBackwardsWalk extends ConnectionStateEvent {
|
||||
public StateRevertBackwardsWalk(State state) {
|
||||
StateRevertBackwardsWalk(State state) {
|
||||
super(state.getStateDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
public static class FinalStateReached extends ConnectionStateEvent {
|
||||
public FinalStateReached(State state) {
|
||||
FinalStateReached(State state) {
|
||||
super(state.getStateDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
public static class TransitionNotPossible extends ConnectionStateEvent {
|
||||
private final StateTransitionResult.TransitionImpossible transitionImpossibleReason;
|
||||
private final TransitionImpossibleReason transitionImpossibleReason;
|
||||
|
||||
public TransitionNotPossible(State currentState, State successorState, StateTransitionResult.TransitionImpossible reason) {
|
||||
super(currentState.getStateDescriptor(), successorState.getStateDescriptor());
|
||||
TransitionNotPossible(State state, TransitionImpossibleReason reason) {
|
||||
super(state.getStateDescriptor());
|
||||
this.transitionImpossibleReason = reason;
|
||||
}
|
||||
|
||||
|
@ -80,16 +72,16 @@ public class ConnectionStateEvent {
|
|||
}
|
||||
|
||||
public static class AboutToTransitionInto extends ConnectionStateEvent {
|
||||
public AboutToTransitionInto(State currentState, State successorState) {
|
||||
super(currentState.getStateDescriptor(), successorState.getStateDescriptor());
|
||||
AboutToTransitionInto(State state) {
|
||||
super(state.getStateDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
public static class TransitionFailed extends ConnectionStateEvent {
|
||||
private final StateTransitionResult.Failure transitionFailedReason;
|
||||
private final TransitionFailureResult transitionFailedReason;
|
||||
|
||||
public TransitionFailed(State currentState, State failedSuccessorState, StateTransitionResult.Failure transitionFailedReason) {
|
||||
super(currentState.getStateDescriptor(), failedSuccessorState.getStateDescriptor());
|
||||
TransitionFailed(State state, TransitionFailureResult transitionFailedReason) {
|
||||
super(state.getStateDescriptor());
|
||||
this.transitionFailedReason = transitionFailedReason;
|
||||
}
|
||||
|
||||
|
@ -99,16 +91,10 @@ public class ConnectionStateEvent {
|
|||
}
|
||||
}
|
||||
|
||||
public static class TransitionIgnoredDueCycle extends ConnectionStateEvent {
|
||||
public TransitionIgnoredDueCycle(GraphVertex<State> currentStateVertex, GraphVertex<State> successorStateVertexCausingCycle) {
|
||||
super(currentStateVertex.getElement().getStateDescriptor(), successorStateVertexCausingCycle.getElement().getStateDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
public static class SuccessfullyTransitionedInto extends ConnectionStateEvent {
|
||||
private final StateTransitionResult.Success transitionSuccessResult;
|
||||
private final TransitionSuccessResult transitionSuccessResult;
|
||||
|
||||
public SuccessfullyTransitionedInto(State state, StateTransitionResult.Success transitionSuccessResult) {
|
||||
SuccessfullyTransitionedInto(State state, TransitionSuccessResult transitionSuccessResult) {
|
||||
super(state.getStateDescriptor());
|
||||
this.transitionSuccessResult = transitionSuccessResult;
|
||||
}
|
||||
|
|
|
@ -16,11 +16,9 @@
|
|||
*/
|
||||
package org.jivesoftware.smack.fsm;
|
||||
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection;
|
||||
|
||||
// TODO: Mark as java.lang.FunctionalInterface once Smack's minimum Android API level is 24 or higher.
|
||||
public interface ConnectionStateMachineListener {
|
||||
|
||||
void onConnectionStateEvent(ConnectionStateEvent connectionStateEvent, ModularXmppClientToServerConnection connection);
|
||||
void onConnectionStateEvent(ConnectionStateEvent connectionStateEvent, AbstractXmppStateMachineConnection connection);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -20,11 +20,11 @@ import org.jxmpp.jid.parts.Resourcepart;
|
|||
|
||||
// TODO: At one point SASL authzid should be part of this.
|
||||
public class LoginContext {
|
||||
public final String username;
|
||||
public final String password;
|
||||
public final Resourcepart resource;
|
||||
final String username;
|
||||
final String password;
|
||||
final Resourcepart resource;
|
||||
|
||||
public LoginContext(String username, String password, Resourcepart resource) {
|
||||
LoginContext(String username, String password, Resourcepart resource) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.resource = resource;
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 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.fsm;
|
||||
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection;
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
import org.jivesoftware.smack.c2s.internal.WalkStateGraphContext;
|
||||
|
||||
public class NoOpState extends State {
|
||||
|
||||
/**
|
||||
* Constructs a NoOpState. Note that the signature of this constructor is designed so that it mimics States which
|
||||
* are non-static inner classes of ModularXmppClientToServerConnection. That is why the first argument is not used.
|
||||
*
|
||||
* @param connection the connection.
|
||||
* @param stateDescriptor the related state descriptor
|
||||
* @param connectionInternal the internal connection API.
|
||||
*/
|
||||
@SuppressWarnings("UnusedVariable")
|
||||
protected NoOpState(ModularXmppClientToServerConnection connection, StateDescriptor stateDescriptor, ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
super(stateDescriptor, connectionInternal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateTransitionResult.Success transitionInto(WalkStateGraphContext walkStateGraphContext) {
|
||||
// Transition into a NoOpState always succeeds.
|
||||
return StateTransitionResult.Success.EMPTY_INSTANCE;
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 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.fsm;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPException.FailedNonzaException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
import org.jivesoftware.smack.c2s.internal.WalkStateGraphContext;
|
||||
import org.jivesoftware.smack.sasl.SASLErrorException;
|
||||
|
||||
/**
|
||||
* Note that this is an non-static inner class of XmppClientToServerConnection so that states can inspect and modify
|
||||
* the connection.
|
||||
*/
|
||||
public abstract class State {
|
||||
|
||||
protected final StateDescriptor stateDescriptor;
|
||||
|
||||
protected final ModularXmppClientToServerConnectionInternal connectionInternal;
|
||||
|
||||
protected State(StateDescriptor stateDescriptor, ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
this.stateDescriptor = stateDescriptor;
|
||||
this.connectionInternal = connectionInternal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the state should be activated.
|
||||
*
|
||||
* @param walkStateGraphContext the context of the current state graph walk.
|
||||
* @return <code>null</code> if the state should be activated.
|
||||
* @throws SmackException in case a Smack exception occurs.
|
||||
*/
|
||||
public StateTransitionResult.TransitionImpossible isTransitionToPossible(WalkStateGraphContext walkStateGraphContext)
|
||||
throws SmackException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract StateTransitionResult.AttemptResult transitionInto(WalkStateGraphContext walkStateGraphContext)
|
||||
throws XMPPErrorException, SASLErrorException, IOException, SmackException,
|
||||
InterruptedException, FailedNonzaException;
|
||||
|
||||
public StateDescriptor getStateDescriptor() {
|
||||
return stateDescriptor;
|
||||
}
|
||||
|
||||
public void resetState() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "State " + stateDescriptor + ' ' + connectionInternal.connection;
|
||||
}
|
||||
|
||||
protected final void ensureNotOnOurWayToAuthenticatedAndResourceBound(
|
||||
WalkStateGraphContext walkStateGraphContext) {
|
||||
if (walkStateGraphContext.isFinalStateAuthenticatedAndResourceBound()) {
|
||||
throw new IllegalStateException(
|
||||
"Smack should never attempt to reach the authenticated and resource bound state over "
|
||||
+ this
|
||||
+ ". This is probably a programming error within Smack, please report it to the develoeprs.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -22,9 +22,9 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection;
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.State;
|
||||
|
||||
public abstract class StateDescriptor {
|
||||
|
||||
|
@ -34,13 +34,15 @@ public abstract class StateDescriptor {
|
|||
notImplemented,
|
||||
}
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(StateDescriptor.class.getName());
|
||||
|
||||
private final String stateName;
|
||||
private final int xepNum;
|
||||
private final String rfcSection;
|
||||
private final Set<Property> properties;
|
||||
|
||||
private final Class<? extends State> stateClass;
|
||||
private final Constructor<? extends State> stateClassConstructor;
|
||||
private final Class<? extends AbstractXmppStateMachineConnection.State> stateClass;
|
||||
private final Constructor<? extends AbstractXmppStateMachineConnection.State> stateClassConstructor;
|
||||
|
||||
private final Set<Class<? extends StateDescriptor>> successors = new HashSet<>();
|
||||
|
||||
|
@ -51,36 +53,36 @@ public abstract class StateDescriptor {
|
|||
private final Set<Class<? extends StateDescriptor>> inferiorTo = new HashSet<>();
|
||||
|
||||
protected StateDescriptor() {
|
||||
this(NoOpState.class, (Property) null);
|
||||
this(AbstractXmppStateMachineConnection.NoOpState.class, (Property) null);
|
||||
}
|
||||
|
||||
protected StateDescriptor(Property... properties) {
|
||||
this(NoOpState.class, properties);
|
||||
this(AbstractXmppStateMachineConnection.NoOpState.class, properties);
|
||||
}
|
||||
|
||||
protected StateDescriptor(Class<? extends State> stateClass) {
|
||||
protected StateDescriptor(Class<? extends AbstractXmppStateMachineConnection.State> stateClass) {
|
||||
this(stateClass, -1, null, Collections.emptySet());
|
||||
}
|
||||
|
||||
protected StateDescriptor(Class<? extends State> stateClass, Property... properties) {
|
||||
protected StateDescriptor(Class<? extends AbstractXmppStateMachineConnection.State> stateClass, Property... properties) {
|
||||
this(stateClass, -1, null, new HashSet<>(Arrays.asList(properties)));
|
||||
}
|
||||
|
||||
protected StateDescriptor(Class<? extends State> stateClass, int xepNum) {
|
||||
protected StateDescriptor(Class<? extends AbstractXmppStateMachineConnection.State> stateClass, int xepNum) {
|
||||
this(stateClass, xepNum, null, Collections.emptySet());
|
||||
}
|
||||
|
||||
protected StateDescriptor(Class<? extends State> stateClass, int xepNum,
|
||||
protected StateDescriptor(Class<? extends AbstractXmppStateMachineConnection.State> stateClass, int xepNum,
|
||||
Property... properties) {
|
||||
this(stateClass, xepNum, null, new HashSet<>(Arrays.asList(properties)));
|
||||
}
|
||||
|
||||
protected StateDescriptor(Class<? extends State> stateClass, String rfcSection) {
|
||||
protected StateDescriptor(Class<? extends AbstractXmppStateMachineConnection.State> stateClass, String rfcSection) {
|
||||
this(stateClass, -1, rfcSection, Collections.emptySet());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private StateDescriptor(Class<? extends State> stateClass, int xepNum,
|
||||
private StateDescriptor(Class<? extends AbstractXmppStateMachineConnection.State> stateClass, int xepNum,
|
||||
String rfcSection, Set<Property> properties) {
|
||||
this.stateClass = stateClass;
|
||||
if (rfcSection != null && xepNum > 0) {
|
||||
|
@ -90,32 +92,26 @@ public abstract class StateDescriptor {
|
|||
this.rfcSection = rfcSection;
|
||||
this.properties = properties;
|
||||
|
||||
Constructor<? extends State> selectedConstructor = null;
|
||||
Constructor<? extends AbstractXmppStateMachineConnection.State> selectedConstructor = null;
|
||||
Constructor<?>[] constructors = stateClass.getDeclaredConstructors();
|
||||
for (Constructor<?> constructor : constructors) {
|
||||
Class<?>[] parameterTypes = constructor.getParameterTypes();
|
||||
if (parameterTypes.length != 3) {
|
||||
if (parameterTypes.length != 2) {
|
||||
LOGGER.warning("Invalid State class constructor: " + constructor);
|
||||
continue;
|
||||
}
|
||||
if (!ModularXmppClientToServerConnection.class.isAssignableFrom(parameterTypes[0])) {
|
||||
continue;
|
||||
}
|
||||
if (!StateDescriptor.class.isAssignableFrom(parameterTypes[1])) {
|
||||
continue;
|
||||
}
|
||||
if (!ModularXmppClientToServerConnectionInternal.class.isAssignableFrom(parameterTypes[2])) {
|
||||
if (!AbstractXmppStateMachineConnection.class.isAssignableFrom(parameterTypes[0])) {
|
||||
continue;
|
||||
}
|
||||
selectedConstructor = (Constructor<? extends State>) constructor;
|
||||
break;
|
||||
}
|
||||
|
||||
stateClassConstructor = selectedConstructor;
|
||||
if (stateClassConstructor != null) {
|
||||
stateClassConstructor.setAccessible(true);
|
||||
} else {
|
||||
// TODO: Add validation check that if stateClassConstructor is 'null' the cosntructState() method is overriden.
|
||||
if (selectedConstructor == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
stateClassConstructor = selectedConstructor;
|
||||
stateClassConstructor.setAccessible(true);
|
||||
|
||||
String className = getClass().getSimpleName();
|
||||
stateName = className.replaceFirst("StateDescriptor", "");
|
||||
|
@ -125,7 +121,7 @@ public abstract class StateDescriptor {
|
|||
addAndCheckNonExistent(successors, successor);
|
||||
}
|
||||
|
||||
public void addPredeccessor(Class<? extends StateDescriptor> predeccessor) {
|
||||
protected void addPredeccessor(Class<? extends StateDescriptor> predeccessor) {
|
||||
addAndCheckNonExistent(predecessors, predeccessor);
|
||||
}
|
||||
|
||||
|
@ -193,7 +189,7 @@ public abstract class StateDescriptor {
|
|||
return referenceCache;
|
||||
}
|
||||
|
||||
public Class<? extends State> getStateClass() {
|
||||
public Class<? extends AbstractXmppStateMachineConnection.State> getStateClass() {
|
||||
return stateClass;
|
||||
}
|
||||
|
||||
|
@ -209,12 +205,9 @@ public abstract class StateDescriptor {
|
|||
return properties.contains(Property.finalState);
|
||||
}
|
||||
|
||||
protected State constructState(ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
ModularXmppClientToServerConnection connection = connectionInternal.connection;
|
||||
protected final AbstractXmppStateMachineConnection.State constructState(AbstractXmppStateMachineConnection connection) {
|
||||
try {
|
||||
// If stateClassConstructor is null here, then you probably forgot to override the the
|
||||
// StateDescriptor.constructState() method?
|
||||
return stateClassConstructor.newInstance(connection, this, connectionInternal);
|
||||
return stateClassConstructor.newInstance(connection, this);
|
||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
||||
| InvocationTargetException e) {
|
||||
throw new IllegalStateException(e);
|
||||
|
|
|
@ -30,8 +30,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.DisconnectedStateDescriptor;
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.DisconnectedStateDescriptor;
|
||||
import org.jivesoftware.smack.util.Consumer;
|
||||
import org.jivesoftware.smack.util.MultiMap;
|
||||
|
||||
|
@ -135,7 +134,7 @@ public class StateDescriptorGraph {
|
|||
|
||||
// The preference graph is the graph where the precedence information of all successors is stored, which we will
|
||||
// topologically sort to find out which successor we should try first. It is a further new graph we use solely in
|
||||
// this step for every node. The graph is represented as map. There is no special marker for the initial node
|
||||
// this step for every node. The graph is representent as map. There is no special marker for the initial node
|
||||
// as it is not required for the topological sort performed later.
|
||||
Map<Class<? extends StateDescriptor>, GraphVertex<Class<? extends StateDescriptor>>> preferenceGraph = new HashMap<>(numSuccessors);
|
||||
|
||||
|
@ -172,8 +171,7 @@ public class StateDescriptorGraph {
|
|||
}
|
||||
}
|
||||
|
||||
// Perform a topological sort which returns the state descriptor classes sorted by their priority. Highest
|
||||
// priority state descriptors first.
|
||||
// Perform a topological sort which returns the state descriptor classes in their priority.
|
||||
List<GraphVertex<Class<? extends StateDescriptor>>> sortedSuccessors = topologicalSort(preferenceGraph.values());
|
||||
|
||||
// Handle the successor nodes which have not preference information available. Simply append them to the end of
|
||||
|
@ -224,19 +222,19 @@ public class StateDescriptorGraph {
|
|||
return initialNode;
|
||||
}
|
||||
|
||||
private static GraphVertex<State> convertToStateGraph(GraphVertex<StateDescriptor> stateDescriptorVertex,
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal, Map<StateDescriptor, GraphVertex<State>> handledStateDescriptors) {
|
||||
private static GraphVertex<AbstractXmppStateMachineConnection.State> convertToStateGraph(GraphVertex<StateDescriptor> stateDescriptorVertex,
|
||||
AbstractXmppStateMachineConnection connection, Map<StateDescriptor, GraphVertex<AbstractXmppStateMachineConnection.State>> handledStateDescriptors) {
|
||||
StateDescriptor stateDescriptor = stateDescriptorVertex.getElement();
|
||||
GraphVertex<State> stateVertex = handledStateDescriptors.get(stateDescriptor);
|
||||
GraphVertex<AbstractXmppStateMachineConnection.State> stateVertex = handledStateDescriptors.get(stateDescriptor);
|
||||
if (stateVertex != null) {
|
||||
return stateVertex;
|
||||
}
|
||||
|
||||
State state = stateDescriptor.constructState(connectionInternal);
|
||||
AbstractXmppStateMachineConnection.State state = stateDescriptor.constructState(connection);
|
||||
stateVertex = new GraphVertex<>(state);
|
||||
handledStateDescriptors.put(stateDescriptor, stateVertex);
|
||||
for (GraphVertex<StateDescriptor> successorStateDescriptorVertex : stateDescriptorVertex.getOutgoingEdges()) {
|
||||
GraphVertex<State> successorStateVertex = convertToStateGraph(successorStateDescriptorVertex, connectionInternal, handledStateDescriptors);
|
||||
GraphVertex<AbstractXmppStateMachineConnection.State> successorStateVertex = convertToStateGraph(successorStateDescriptorVertex, connection, handledStateDescriptors);
|
||||
// It is important that we keep the order of the edges. This should do it.
|
||||
stateVertex.addOutgoingEdge(successorStateVertex);
|
||||
}
|
||||
|
@ -244,10 +242,10 @@ public class StateDescriptorGraph {
|
|||
return stateVertex;
|
||||
}
|
||||
|
||||
public static GraphVertex<State> convertToStateGraph(GraphVertex<StateDescriptor> initialStateDescriptor,
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
Map<StateDescriptor, GraphVertex<State>> handledStateDescriptors = new HashMap<>();
|
||||
GraphVertex<State> initialState = convertToStateGraph(initialStateDescriptor, connectionInternal,
|
||||
static GraphVertex<AbstractXmppStateMachineConnection.State> convertToStateGraph(GraphVertex<StateDescriptor> initialStateDescriptor,
|
||||
AbstractXmppStateMachineConnection connection) {
|
||||
Map<StateDescriptor, GraphVertex<AbstractXmppStateMachineConnection.State>> handledStateDescriptors = new HashMap<>();
|
||||
GraphVertex<AbstractXmppStateMachineConnection.State> initialState = convertToStateGraph(initialStateDescriptor, connection,
|
||||
handledStateDescriptors);
|
||||
return initialState;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018-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.
|
||||
|
@ -21,26 +21,18 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.c2s.internal.WalkStateGraphContext;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptorGraph.GraphVertex;
|
||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.State;
|
||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.TransitionReason;
|
||||
|
||||
public abstract class StateMachineException extends SmackException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected StateMachineException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
protected StateMachineException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static class SmackMandatoryStateFailedException extends StateMachineException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SmackMandatoryStateFailedException(State state, StateTransitionResult failureReason) {
|
||||
SmackMandatoryStateFailedException(State state, TransitionReason failureReason) {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,36 +40,21 @@ public abstract class StateMachineException extends SmackException {
|
|||
|
||||
private final List<State> walkedStateGraphPath;
|
||||
|
||||
private final Map<State, StateTransitionResult> failedStates;
|
||||
|
||||
private final StateDescriptor deadEndState;
|
||||
private final Map<State, TransitionReason> failedStates;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private SmackStateGraphDeadEndException(String message, WalkStateGraphContext walkStateGraphContext, GraphVertex<State> stateVertex) {
|
||||
super(message);
|
||||
this.walkedStateGraphPath = Collections.unmodifiableList(walkStateGraphContext.getWalk());
|
||||
this.failedStates = Collections.unmodifiableMap(walkStateGraphContext.getFailedStates());
|
||||
|
||||
deadEndState = stateVertex.getElement().getStateDescriptor();
|
||||
SmackStateGraphDeadEndException(List<State> walkedStateGraphPath, Map<State, TransitionReason> failedStates) {
|
||||
this.walkedStateGraphPath = Collections.unmodifiableList(walkedStateGraphPath);
|
||||
this.failedStates = Collections.unmodifiableMap(failedStates);
|
||||
}
|
||||
|
||||
public List<State> getWalkedStateGraph() {
|
||||
return walkedStateGraphPath;
|
||||
}
|
||||
|
||||
public Map<State, StateTransitionResult> getFailedStates() {
|
||||
public Map<State, TransitionReason> getFailedStates() {
|
||||
return failedStates;
|
||||
}
|
||||
|
||||
public StateDescriptor getDeadEndState() {
|
||||
return deadEndState;
|
||||
}
|
||||
|
||||
public static SmackStateGraphDeadEndException from(WalkStateGraphContext walkStateGraphContext, GraphVertex<State> stateVertex) {
|
||||
String message = stateVertex + " has no successor vertexes";
|
||||
|
||||
return new SmackStateGraphDeadEndException(message, walkStateGraphContext, stateVertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 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.fsm;
|
||||
|
||||
public abstract class StateTransitionResult {
|
||||
|
||||
private final String message;
|
||||
|
||||
protected StateTransitionResult(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public abstract static class AttemptResult extends StateTransitionResult {
|
||||
protected AttemptResult(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Success extends AttemptResult {
|
||||
|
||||
public static final Success EMPTY_INSTANCE = new Success();
|
||||
|
||||
private Success() {
|
||||
super("");
|
||||
}
|
||||
|
||||
public Success(String successMessage) {
|
||||
super(successMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Failure extends AttemptResult {
|
||||
public Failure(String failureMessage) {
|
||||
super(failureMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class FailureCausedByException<E extends Exception> extends Failure {
|
||||
private final E exception;
|
||||
|
||||
public FailureCausedByException(E exception) {
|
||||
super(exception.getMessage());
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
public E getException() {
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class TransitionImpossible extends StateTransitionResult {
|
||||
protected TransitionImpossible(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TransitionImpossibleReason extends TransitionImpossible {
|
||||
public TransitionImpossibleReason(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TransitionImpossibleBecauseNotImplemented extends TransitionImpossibleReason {
|
||||
public TransitionImpossibleBecauseNotImplemented(StateDescriptor stateDescriptor) {
|
||||
super(stateDescriptor.getFullStateName(false) + " is not implemented (yet)");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019-2020 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.isr;
|
||||
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.AuthenticatedAndResourceBoundStateDescriptor;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.ConnectedButUnauthenticatedStateDescriptor;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.SaslAuthenticationStateDescriptor;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionModule;
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
import org.jivesoftware.smack.c2s.internal.WalkStateGraphContext;
|
||||
import org.jivesoftware.smack.fsm.State;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptor;
|
||||
import org.jivesoftware.smack.fsm.StateTransitionResult;
|
||||
|
||||
public class InstantStreamResumptionModule extends ModularXmppClientToServerConnectionModule<InstantStreamResumptionModuleDescriptor> {
|
||||
|
||||
protected InstantStreamResumptionModule(InstantStreamResumptionModuleDescriptor instantStreamResumptionModuleDescriptor,
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
super(instantStreamResumptionModuleDescriptor, connectionInternal);
|
||||
}
|
||||
|
||||
public static final class InstantStreamResumptionStateDescriptor extends StateDescriptor {
|
||||
private InstantStreamResumptionStateDescriptor() {
|
||||
super(InstantStreamResumptionState.class, 397, StateDescriptor.Property.notImplemented);
|
||||
|
||||
addSuccessor(AuthenticatedAndResourceBoundStateDescriptor.class);
|
||||
addPredeccessor(ConnectedButUnauthenticatedStateDescriptor.class);
|
||||
declarePrecedenceOver(SaslAuthenticationStateDescriptor.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstantStreamResumptionModule.InstantStreamResumptionState constructState(ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
// This is the trick: the module is constructed prior the states, so we get the actual state out of the module by fetching the module from the connection.
|
||||
InstantStreamResumptionModule isrModule = connectionInternal.connection.getConnectionModuleFor(InstantStreamResumptionModuleDescriptor.class);
|
||||
return isrModule.constructInstantStreamResumptionState(this, connectionInternal);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean useIsr = true;
|
||||
|
||||
private final class InstantStreamResumptionState extends State {
|
||||
private InstantStreamResumptionState(InstantStreamResumptionStateDescriptor instantStreamResumptionStateDescriptor,
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
super(instantStreamResumptionStateDescriptor, connectionInternal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateTransitionResult.TransitionImpossible isTransitionToPossible(WalkStateGraphContext walkStateGraphContext) {
|
||||
if (!useIsr) {
|
||||
return new StateTransitionResult.TransitionImpossibleReason("Instant stream resumption not enabled nor implemented");
|
||||
}
|
||||
|
||||
return new StateTransitionResult.TransitionImpossibleBecauseNotImplemented(stateDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateTransitionResult.AttemptResult transitionInto(WalkStateGraphContext walkStateGraphContext) {
|
||||
throw new IllegalStateException("Instant stream resumption not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
public void setInstantStreamResumptionEnabled(boolean useIsr) {
|
||||
this.useIsr = useIsr;
|
||||
}
|
||||
|
||||
public InstantStreamResumptionState constructInstantStreamResumptionState(
|
||||
InstantStreamResumptionStateDescriptor instantStreamResumptionStateDescriptor,
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
return new InstantStreamResumptionState(instantStreamResumptionStateDescriptor, connectionInternal);
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019-2020 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.isr;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionConfiguration;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionModuleDescriptor;
|
||||
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||
import org.jivesoftware.smack.fsm.StateDescriptor;
|
||||
|
||||
public class InstantStreamResumptionModuleDescriptor extends ModularXmppClientToServerConnectionModuleDescriptor {
|
||||
|
||||
private static final InstantStreamResumptionModuleDescriptor INSTANCE = new InstantStreamResumptionModuleDescriptor();
|
||||
|
||||
@Override
|
||||
protected Set<Class<? extends StateDescriptor>> getStateDescriptors() {
|
||||
return Collections.singleton(InstantStreamResumptionModule.InstantStreamResumptionStateDescriptor.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstantStreamResumptionModule constructXmppConnectionModule(
|
||||
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||
return new InstantStreamResumptionModule(this, connectionInternal);
|
||||
}
|
||||
|
||||
public static final class Builder extends ModularXmppClientToServerConnectionModuleDescriptor.Builder {
|
||||
|
||||
private Builder(ModularXmppClientToServerConnectionConfiguration.Builder connectionConfigurationBuilder) {
|
||||
super(connectionConfigurationBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ModularXmppClientToServerConnectionModuleDescriptor build() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes and interfaces for Instant Stream Resumption (ISR) (XEP-0397).
|
||||
*
|
||||
* @see <a href="https://xmpp.org/extensions/xep-0397.html">XEP-0397: Instant Stream Resumption</a>
|
||||
*/
|
||||
package org.jivesoftware.smack.isr;
|
|
@ -163,20 +163,15 @@ public class ArrayBlockingQueueWithShutdown<E> extends AbstractQueue<E> implemen
|
|||
/**
|
||||
* Start the queue. Newly created instances will be started automatically, thus this only needs
|
||||
* to be called after {@link #shutdown()}.
|
||||
*
|
||||
* @return <code>true</code> if the queues was shutdown before, <code>false</code> if not.
|
||||
*/
|
||||
public boolean start() {
|
||||
boolean previousIsShutdown;
|
||||
public void start() {
|
||||
lock.lock();
|
||||
try {
|
||||
previousIsShutdown = isShutdown;
|
||||
isShutdown = false;
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return previousIsShutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-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.
|
||||
|
@ -18,10 +18,8 @@ package org.jivesoftware.smack.util;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class CollectionUtil {
|
||||
|
||||
|
@ -58,11 +56,4 @@ public class CollectionUtil {
|
|||
}
|
||||
return new ArrayList<>(collection);
|
||||
}
|
||||
|
||||
public static <T> Set<T> newSetWith(Collection<? extends T> collection) {
|
||||
if (collection == null) {
|
||||
return null;
|
||||
}
|
||||
return new HashSet<>(collection);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2005 Jive Software, 2016-2020 Florian Schmaus.
|
||||
* Copyright 2003-2005 Jive Software, 2016-2018 Florian Schmaus.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,9 +16,23 @@
|
|||
*/
|
||||
package org.jivesoftware.smack.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smack.ConnectionConfiguration.DnssecMode;
|
||||
import org.jivesoftware.smack.util.dns.DNSResolver;
|
||||
import org.jivesoftware.smack.util.dns.HostAddress;
|
||||
import org.jivesoftware.smack.util.dns.SRVRecord;
|
||||
import org.jivesoftware.smack.util.dns.SmackDaneProvider;
|
||||
|
||||
import org.minidns.dnsname.DnsName;
|
||||
|
||||
/**
|
||||
* Utility class to perform DNS lookups for XMPP services.
|
||||
*
|
||||
|
@ -27,6 +41,10 @@ import org.jivesoftware.smack.util.dns.SmackDaneProvider;
|
|||
*/
|
||||
public class DNSUtil {
|
||||
|
||||
public static final String XMPP_CLIENT_DNS_SRV_PREFIX = "_xmpp-client._tcp";
|
||||
public static final String XMPP_SERVER_DNS_SRV_PREFIX = "_xmpp-server._tcp";
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(DNSUtil.class.getName());
|
||||
private static DNSResolver dnsResolver = null;
|
||||
private static SmackDaneProvider daneProvider;
|
||||
|
||||
|
@ -66,4 +84,188 @@ public class DNSUtil {
|
|||
return daneProvider;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ImmutableEnumChecker")
|
||||
enum DomainType {
|
||||
server(XMPP_SERVER_DNS_SRV_PREFIX),
|
||||
client(XMPP_CLIENT_DNS_SRV_PREFIX),
|
||||
;
|
||||
public final DnsName srvPrefix;
|
||||
|
||||
DomainType(String srvPrefixString) {
|
||||
srvPrefix = DnsName.from(srvPrefixString);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of HostAddresses under which the specified XMPP server can be reached at for client-to-server
|
||||
* communication. A DNS lookup for a SRV record in the form "_xmpp-client._tcp.example.com" is attempted, according
|
||||
* to section 3.2.1 of RFC 6120. If that lookup fails, it's assumed that the XMPP server lives at the host resolved
|
||||
* by a DNS lookup at the specified domain on the default port of 5222.
|
||||
* <p>
|
||||
* As an example, a lookup for "example.com" may return "im.example.com:5269".
|
||||
* </p>
|
||||
*
|
||||
* @param domain the domain.
|
||||
* @param failedAddresses on optional list that will be populated with host addresses that failed to resolve.
|
||||
* @param dnssecMode DNSSec mode.
|
||||
* @return List of HostAddress, which encompasses the hostname and port that the
|
||||
* XMPP server can be reached at for the specified domain.
|
||||
*/
|
||||
public static List<HostAddress> resolveXMPPServiceDomain(DnsName domain, List<HostAddress> failedAddresses, DnssecMode dnssecMode) {
|
||||
return resolveDomain(domain, DomainType.client, failedAddresses, dnssecMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of HostAddresses under which the specified XMPP server can be reached at for server-to-server
|
||||
* communication. A DNS lookup for a SRV record in the form "_xmpp-server._tcp.example.com" is attempted, according
|
||||
* to section 3.2.1 of RFC 6120. If that lookup fails , it's assumed that the XMPP server lives at the host resolved
|
||||
* by a DNS lookup at the specified domain on the default port of 5269.
|
||||
* <p>
|
||||
* As an example, a lookup for "example.com" may return "im.example.com:5269".
|
||||
* </p>
|
||||
*
|
||||
* @param domain the domain.
|
||||
* @param failedAddresses on optional list that will be populated with host addresses that failed to resolve.
|
||||
* @param dnssecMode DNSSec mode.
|
||||
* @return List of HostAddress, which encompasses the hostname and port that the
|
||||
* XMPP server can be reached at for the specified domain.
|
||||
*/
|
||||
public static List<HostAddress> resolveXMPPServerDomain(DnsName domain, List<HostAddress> failedAddresses, DnssecMode dnssecMode) {
|
||||
return resolveDomain(domain, DomainType.server, failedAddresses, dnssecMode);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param domain the domain.
|
||||
* @param domainType the XMPP domain type, server or client.
|
||||
* @param failedAddresses a list that will be populated with host addresses that failed to resolve.
|
||||
* @return a list of resolver host addresses for this domain.
|
||||
*/
|
||||
private static List<HostAddress> resolveDomain(DnsName domain, DomainType domainType,
|
||||
List<HostAddress> failedAddresses, DnssecMode dnssecMode) {
|
||||
if (dnsResolver == null) {
|
||||
throw new IllegalStateException("No DNS Resolver active in Smack");
|
||||
}
|
||||
|
||||
List<HostAddress> addresses = new ArrayList<HostAddress>();
|
||||
|
||||
// Step one: Do SRV lookups
|
||||
DnsName srvDomain = DnsName.from(domainType.srvPrefix, domain);
|
||||
|
||||
List<SRVRecord> srvRecords = dnsResolver.lookupSRVRecords(srvDomain, failedAddresses, dnssecMode);
|
||||
if (srvRecords != null && !srvRecords.isEmpty()) {
|
||||
if (LOGGER.isLoggable(Level.FINE)) {
|
||||
String logMessage = "Resolved SRV RR for " + srvDomain + ":";
|
||||
for (SRVRecord r : srvRecords)
|
||||
logMessage += " " + r;
|
||||
LOGGER.fine(logMessage);
|
||||
}
|
||||
List<HostAddress> sortedRecords = sortSRVRecords(srvRecords);
|
||||
addresses.addAll(sortedRecords);
|
||||
} else {
|
||||
LOGGER.info("Could not resolve DNS SRV resource records for " + srvDomain + ". Consider adding those.");
|
||||
}
|
||||
|
||||
int defaultPort = -1;
|
||||
switch (domainType) {
|
||||
case client:
|
||||
defaultPort = 5222;
|
||||
break;
|
||||
case server:
|
||||
defaultPort = 5269;
|
||||
break;
|
||||
}
|
||||
// Step two: Add the hostname to the end of the list
|
||||
HostAddress hostAddress = dnsResolver.lookupHostAddress(domain, defaultPort, failedAddresses, dnssecMode);
|
||||
if (hostAddress != null) {
|
||||
addresses.add(hostAddress);
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort a given list of SRVRecords as described in RFC 2782
|
||||
* Note that we follow the RFC with one exception. In a group of the same priority, only the first entry
|
||||
* is calculated by random. The others are ore simply ordered by their priority.
|
||||
*
|
||||
* @param records TODO javadoc me please
|
||||
* @return the list of resolved HostAddresses
|
||||
*/
|
||||
private static List<HostAddress> sortSRVRecords(List<SRVRecord> records) {
|
||||
// RFC 2782, Usage rules: "If there is precisely one SRV RR, and its Target is "."
|
||||
// (the root domain), abort."
|
||||
if (records.size() == 1 && records.get(0).getFQDN().isRootLabel())
|
||||
return Collections.emptyList();
|
||||
|
||||
// sorting the records improves the performance of the bisection later
|
||||
Collections.sort(records);
|
||||
|
||||
// create the priority buckets
|
||||
SortedMap<Integer, List<SRVRecord>> buckets = new TreeMap<Integer, List<SRVRecord>>();
|
||||
for (SRVRecord r : records) {
|
||||
Integer priority = r.getPriority();
|
||||
List<SRVRecord> bucket = buckets.get(priority);
|
||||
// create the list of SRVRecords if it doesn't exist
|
||||
if (bucket == null) {
|
||||
bucket = new LinkedList<SRVRecord>();
|
||||
buckets.put(priority, bucket);
|
||||
}
|
||||
bucket.add(r);
|
||||
}
|
||||
|
||||
List<HostAddress> res = new ArrayList<HostAddress>(records.size());
|
||||
|
||||
for (Integer priority : buckets.keySet()) {
|
||||
List<SRVRecord> bucket = buckets.get(priority);
|
||||
int bucketSize;
|
||||
while ((bucketSize = bucket.size()) > 0) {
|
||||
int[] totals = new int[bucketSize];
|
||||
int running_total = 0;
|
||||
int count = 0;
|
||||
int zeroWeight = 1;
|
||||
|
||||
for (SRVRecord r : bucket) {
|
||||
if (r.getWeight() > 0) {
|
||||
zeroWeight = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (SRVRecord r : bucket) {
|
||||
running_total += r.getWeight() + zeroWeight;
|
||||
totals[count] = running_total;
|
||||
count++;
|
||||
}
|
||||
int selectedPos;
|
||||
if (running_total == 0) {
|
||||
// If running total is 0, then all weights in this priority
|
||||
// group are 0. So we simply select one of the weights randomly
|
||||
// as the other 'normal' algorithm is unable to handle this case
|
||||
selectedPos = (int) (Math.random() * bucketSize);
|
||||
} else {
|
||||
double rnd = Math.random() * running_total;
|
||||
selectedPos = bisect(totals, rnd);
|
||||
}
|
||||
// add the SRVRecord that was randomly chosen on it's weight
|
||||
// to the start of the result list
|
||||
SRVRecord chosenSRVRecord = bucket.remove(selectedPos);
|
||||
res.add(chosenSRVRecord);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// TODO this is not yet really bisection just a stupid linear search
|
||||
private static int bisect(int[] array, double value) {
|
||||
int pos = 0;
|
||||
for (int element : array) {
|
||||
if (value < element)
|
||||
break;
|
||||
pos++;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019-2020 Florian Schmaus
|
||||
* 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.
|
||||
|
@ -20,7 +20,4 @@ public interface Function<R, T> {
|
|||
|
||||
R apply(T t);
|
||||
|
||||
static <T> Function<T, T> identity() {
|
||||
return t -> t;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,26 +123,17 @@ public class MultiMap<K, V> implements TypedCloneable<MultiMap<K, V>> {
|
|||
}
|
||||
|
||||
public boolean put(K key, V value) {
|
||||
return putInternal(key, list -> list.add(value));
|
||||
}
|
||||
|
||||
public boolean putFirst(K key, V value) {
|
||||
return putInternal(key, list -> list.add(0, value));
|
||||
}
|
||||
|
||||
private boolean putInternal(K key, Consumer<List<V>> valueListConsumer) {
|
||||
boolean keyExisted;
|
||||
List<V> list = map.get(key);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>(ENTRY_LIST_SIZE);
|
||||
list.add(value);
|
||||
map.put(key, list);
|
||||
keyExisted = false;
|
||||
} else {
|
||||
list.add(value);
|
||||
keyExisted = true;
|
||||
}
|
||||
|
||||
valueListConsumer.accept(list);
|
||||
|
||||
return keyExisted;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software, 2016-2020 Florian Schmaus.
|
||||
* Copyright 2003-2007 Jive Software, 2016-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.
|
||||
|
@ -467,24 +467,10 @@ public class StringUtils {
|
|||
return sb;
|
||||
}
|
||||
|
||||
public static void appendTo(Collection<? extends Object> collection, StringBuilder sb) {
|
||||
appendTo(collection, ", ", sb);
|
||||
}
|
||||
|
||||
public static <O extends Object> void appendTo(Collection<O> collection, StringBuilder sb,
|
||||
Consumer<O> appendFunction) {
|
||||
appendTo(collection, ", ", sb, appendFunction);
|
||||
}
|
||||
|
||||
public static void appendTo(Collection<? extends Object> collection, String delimiter, StringBuilder sb) {
|
||||
appendTo(collection, delimiter, sb, o -> sb.append(o));
|
||||
}
|
||||
|
||||
public static <O extends Object> void appendTo(Collection<O> collection, String delimiter, StringBuilder sb,
|
||||
Consumer<O> appendFunction) {
|
||||
for (Iterator<O> it = collection.iterator(); it.hasNext();) {
|
||||
O cs = it.next();
|
||||
appendFunction.accept(cs);
|
||||
for (Iterator<? extends Object> it = collection.iterator(); it.hasNext();) {
|
||||
Object cs = it.next();
|
||||
sb.append(cs);
|
||||
if (it.hasNext()) {
|
||||
sb.append(delimiter);
|
||||
}
|
||||
|
@ -579,16 +565,4 @@ public class StringUtils {
|
|||
public static String deleteXmlWhitespace(String string) {
|
||||
return XML_WHITESPACE.matcher(string).replaceAll("");
|
||||
}
|
||||
|
||||
public static Appendable appendHeading(Appendable appendable, String heading) throws IOException {
|
||||
return appendHeading(appendable, heading, '-');
|
||||
}
|
||||
|
||||
public static Appendable appendHeading(Appendable appendable, String heading, char underlineChar) throws IOException {
|
||||
appendable.append(heading).append('\n');
|
||||
for (int i = 0; i < heading.length(); i++) {
|
||||
appendable.append(underlineChar);
|
||||
}
|
||||
return appendable.append('\n');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2013-2020 Florian Schmaus
|
||||
* Copyright 2013-2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -19,16 +19,13 @@ package org.jivesoftware.smack.util.dns;
|
|||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smack.ConnectionConfiguration.DnssecMode;
|
||||
import org.jivesoftware.smack.util.rce.RemoteConnectionEndpointLookupFailure;
|
||||
|
||||
import org.minidns.dnsname.DnsName;
|
||||
import org.minidns.record.SRV;
|
||||
|
||||
/**
|
||||
* Implementations of this interface define a class that is capable of resolving DNS addresses.
|
||||
|
@ -46,25 +43,25 @@ public abstract class DNSResolver {
|
|||
|
||||
/**
|
||||
* Gets a list of service records for the specified service.
|
||||
*
|
||||
* @param name The symbolic name of the service.
|
||||
* @param lookupFailures list of exceptions that occurred during lookup.
|
||||
* @param failedAddresses list of failed addresses.
|
||||
* @param dnssecMode security mode.
|
||||
* @return The list of SRV records mapped to the service name.
|
||||
*/
|
||||
public final Collection<SRV> lookupSrvRecords(DnsName name,
|
||||
List<RemoteConnectionEndpointLookupFailure> lookupFailures, DnssecMode dnssecMode) {
|
||||
public final List<SRVRecord> lookupSRVRecords(DnsName name, List<HostAddress> failedAddresses, DnssecMode dnssecMode) {
|
||||
checkIfDnssecRequestedAndSupported(dnssecMode);
|
||||
return lookupSrvRecords0(name, lookupFailures, dnssecMode);
|
||||
return lookupSRVRecords0(name, failedAddresses, dnssecMode);
|
||||
}
|
||||
|
||||
protected abstract Collection<SRV> lookupSrvRecords0(DnsName name,
|
||||
List<RemoteConnectionEndpointLookupFailure> lookupFailures, DnssecMode dnssecMode);
|
||||
protected abstract List<SRVRecord> lookupSRVRecords0(DnsName name, List<HostAddress> failedAddresses, DnssecMode dnssecMode);
|
||||
|
||||
public final List<InetAddress> lookupHostAddress(DnsName name,
|
||||
List<RemoteConnectionEndpointLookupFailure> lookupFailures, DnssecMode dnssecMode) {
|
||||
public final HostAddress lookupHostAddress(DnsName name, int port, List<HostAddress> failedAddresses, DnssecMode dnssecMode) {
|
||||
checkIfDnssecRequestedAndSupported(dnssecMode);
|
||||
return lookupHostAddress0(name, lookupFailures, dnssecMode);
|
||||
List<InetAddress> inetAddresses = lookupHostAddress0(name, failedAddresses, dnssecMode);
|
||||
if (inetAddresses == null || inetAddresses.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return new HostAddress(name, port, inetAddresses);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,11 +74,11 @@ public abstract class DNSResolver {
|
|||
* </p>
|
||||
*
|
||||
* @param name the DNS name to lookup
|
||||
* @param lookupFailures list of exceptions that occurred during lookup.
|
||||
* @param failedAddresses a list with the failed addresses
|
||||
* @param dnssecMode the selected DNSSEC mode
|
||||
* @return A list, either empty or non-empty, or <code>null</code>
|
||||
*/
|
||||
protected List<InetAddress> lookupHostAddress0(DnsName name, List<RemoteConnectionEndpointLookupFailure> lookupFailures, DnssecMode dnssecMode) {
|
||||
protected List<InetAddress> lookupHostAddress0(DnsName name, List<HostAddress> failedAddresses, DnssecMode dnssecMode) {
|
||||
// Default implementation of a DNS name lookup for A/AAAA records. It is assumed that this method does never
|
||||
// support DNSSEC. Subclasses are free to override this method.
|
||||
if (dnssecMode != DnssecMode.disabled) {
|
||||
|
@ -92,14 +89,14 @@ public abstract class DNSResolver {
|
|||
try {
|
||||
inetAddressArray = InetAddress.getAllByName(name.toString());
|
||||
} catch (UnknownHostException e) {
|
||||
lookupFailures.add(new RemoteConnectionEndpointLookupFailure.DnsLookupFailure(name, e));
|
||||
failedAddresses.add(new HostAddress(name, e));
|
||||
return null;
|
||||
}
|
||||
|
||||
return Arrays.asList(inetAddressArray);
|
||||
}
|
||||
|
||||
protected static boolean shouldContinue(CharSequence name, CharSequence hostname, List<InetAddress> hostAddresses) {
|
||||
protected final boolean shouldContinue(CharSequence name, CharSequence hostname, List<InetAddress> hostAddresses) {
|
||||
if (hostAddresses == null) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
/**
|
||||
*
|
||||
* Copyright © 2013-2018 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.dns;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.jivesoftware.smack.SmackException.ConnectionException;
|
||||
|
||||
import org.minidns.dnsname.DnsName;
|
||||
|
||||
public class HostAddress {
|
||||
private final DnsName fqdn;
|
||||
private final int port;
|
||||
private final Map<InetAddress, Exception> exceptions = new LinkedHashMap<>();
|
||||
private final List<InetAddress> inetAddresses;
|
||||
|
||||
/**
|
||||
* Creates a new HostAddress with the given FQDN.
|
||||
*
|
||||
* @param fqdn the optional fully qualified domain name (FQDN).
|
||||
* @param port The port to connect on.
|
||||
* @param inetAddresses list of addresses.
|
||||
* @throws IllegalArgumentException If the port is out of valid range (0 - 65535).
|
||||
*/
|
||||
public HostAddress(DnsName fqdn, int port, List<InetAddress> inetAddresses) {
|
||||
if (port < 0 || port > 65535)
|
||||
throw new IllegalArgumentException(
|
||||
"Port must be a 16-bit unsigned integer (i.e. between 0-65535. Port was: " + port);
|
||||
this.fqdn = fqdn;
|
||||
this.port = port;
|
||||
if (inetAddresses.isEmpty()) {
|
||||
throw new IllegalArgumentException("Must provide at least one InetAddress");
|
||||
}
|
||||
this.inetAddresses = inetAddresses;
|
||||
}
|
||||
|
||||
public HostAddress(int port, InetAddress hostAddress) {
|
||||
this(null, port, Collections.singletonList(hostAddress));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new failed HostAddress. This constructor is usually used when the DNS resolution of the domain name
|
||||
* failed for some reason.
|
||||
*
|
||||
* @param fqdn the domain name of the host.
|
||||
* @param e the exception causing the failure.
|
||||
*/
|
||||
public HostAddress(DnsName fqdn, Exception e) {
|
||||
this.fqdn = fqdn;
|
||||
this.port = 5222;
|
||||
inetAddresses = Collections.emptyList();
|
||||
setException(e);
|
||||
}
|
||||
|
||||
public HostAddress(InetSocketAddress inetSocketAddress, Exception exception) {
|
||||
String hostString = inetSocketAddress.getHostString();
|
||||
this.fqdn = DnsName.from(hostString);
|
||||
this.port = inetSocketAddress.getPort();
|
||||
inetAddresses = Collections.emptyList();
|
||||
setException(exception);
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
if (fqdn != null) {
|
||||
return fqdn.toString();
|
||||
}
|
||||
|
||||
// In this case, the HostAddress(int, InetAddress) constructor must been used. We have no FQDN. And
|
||||
// inetAddresses.size() must be exactly one.
|
||||
assert inetAddresses.size() == 1;
|
||||
return inetAddresses.get(0).getHostAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fully qualified domain name. This may return <code>null</code> in case there host address is only numeric, i.e. an IP address.
|
||||
*
|
||||
* @return the fully qualified domain name or <code>null</code>
|
||||
*/
|
||||
public DnsName getFQDN() {
|
||||
return fqdn;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setException(Exception exception) {
|
||||
setException(null, exception);
|
||||
}
|
||||
|
||||
public void setException(InetAddress inetAddress, Exception exception) {
|
||||
Exception old = exceptions.put(inetAddress, exception);
|
||||
assert old == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Exception that caused a connection failure to this HostAddress. Every
|
||||
* HostAddress found in {@link ConnectionException} will have an Exception set,
|
||||
* which can be retrieved with this method.
|
||||
*
|
||||
* @return the Exception causing this HostAddress to fail
|
||||
*/
|
||||
public Map<InetAddress, Exception> getExceptions() {
|
||||
return Collections.unmodifiableMap(exceptions);
|
||||
}
|
||||
|
||||
public List<InetAddress> getInetAddresses() {
|
||||
return Collections.unmodifiableList(inetAddresses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getHost() + ":" + port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof HostAddress)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final HostAddress address = (HostAddress) o;
|
||||
|
||||
if (!getHost().equals(address.getHost())) {
|
||||
return false;
|
||||
}
|
||||
return port == address.port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 1;
|
||||
result = 37 * result + getHost().hashCode();
|
||||
return result * 37 + port;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
if (exceptions.isEmpty()) {
|
||||
return "No error logged";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('\'').append(toString()).append("' failed because: ");
|
||||
Iterator<Entry<InetAddress, Exception>> iterator = exceptions.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Entry<InetAddress, Exception> entry = iterator.next();
|
||||
InetAddress inetAddress = entry.getKey();
|
||||
if (inetAddress != null) {
|
||||
sb.append(entry.getKey()).append(" exception: ");
|
||||
}
|
||||
sb.append(entry.getValue());
|
||||
if (iterator.hasNext()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2013-2018 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.dns;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.List;
|
||||
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
|
||||
import org.minidns.dnsname.DnsName;
|
||||
|
||||
/**
|
||||
* A DNS SRV RR.
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc2782">RFC 2782: A DNS RR for specifying the location of services (DNS
|
||||
* SRV)</a>
|
||||
* @author Florian Schmaus
|
||||
*
|
||||
*/
|
||||
public class SRVRecord extends HostAddress implements Comparable<SRVRecord> {
|
||||
|
||||
private int weight;
|
||||
private int priority;
|
||||
|
||||
/**
|
||||
* SRV Record constructor.
|
||||
*
|
||||
* @param fqdn Fully qualified domain name
|
||||
* @param port The connection port
|
||||
* @param priority Priority of the target host
|
||||
* @param weight Relative weight for records with same priority
|
||||
* @param inetAddresses list of addresses.
|
||||
* @throws IllegalArgumentException fqdn is null or any other field is not in valid range (0-65535).
|
||||
*/
|
||||
public SRVRecord(DnsName fqdn, int port, int priority, int weight, List<InetAddress> inetAddresses) {
|
||||
super(fqdn, port, inetAddresses);
|
||||
StringUtils.requireNotNullNorEmpty(fqdn, "The FQDN must not be null");
|
||||
if (weight < 0 || weight > 65535)
|
||||
throw new IllegalArgumentException(
|
||||
"DNS SRV records weight must be a 16-bit unsigned integer (i.e. between 0-65535. Weight was: "
|
||||
+ weight);
|
||||
|
||||
if (priority < 0 || priority > 65535)
|
||||
throw new IllegalArgumentException(
|
||||
"DNS SRV records priority must be a 16-bit unsigned integer (i.e. between 0-65535. Priority was: "
|
||||
+ priority);
|
||||
|
||||
this.priority = priority;
|
||||
this.weight = weight;
|
||||
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(SRVRecord other) {
|
||||
// According to RFC2782,
|
||||
// "[a] client MUST attempt to contact the target host with the lowest-numbered priority it can reach".
|
||||
// This means that a SRV record with a higher priority is 'less' then one with a lower.
|
||||
int res = other.priority - this.priority;
|
||||
if (res == 0) {
|
||||
res = this.weight - other.weight;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " prio:" + priority + ":w:" + weight;
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 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.rce;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jivesoftware.smack.datatypes.UInt16;
|
||||
|
||||
public interface RemoteConnectionEndpoint {
|
||||
|
||||
CharSequence getHost();
|
||||
|
||||
UInt16 getPort();
|
||||
|
||||
Collection<? extends InetAddress> getInetAddresses();
|
||||
|
||||
String getDescription();
|
||||
|
||||
class InetSocketAddressCoupling<RCE extends RemoteConnectionEndpoint> {
|
||||
private final RCE connectionEndpoint;
|
||||
private final InetSocketAddress inetSocketAddress;
|
||||
|
||||
public InetSocketAddressCoupling(RCE connectionEndpoint, InetAddress inetAddress) {
|
||||
this.connectionEndpoint = connectionEndpoint;
|
||||
|
||||
UInt16 port = connectionEndpoint.getPort();
|
||||
inetSocketAddress = new InetSocketAddress(inetAddress, port.intValue());
|
||||
}
|
||||
|
||||
public RCE getRemoteConnectionEndpoint() {
|
||||
return connectionEndpoint;
|
||||
}
|
||||
|
||||
public InetSocketAddress getInetSocketAddress() {
|
||||
return inetSocketAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return connectionEndpoint.getDescription() + " (" + inetSocketAddress + ')';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 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.rce;
|
||||
|
||||
import org.jivesoftware.smack.util.ToStringUtil;
|
||||
|
||||
import org.minidns.dnsname.DnsName;
|
||||
|
||||
public abstract class RemoteConnectionEndpointLookupFailure {
|
||||
|
||||
private final String description;
|
||||
private final Exception exception;
|
||||
|
||||
public RemoteConnectionEndpointLookupFailure(String description, Exception exception) {
|
||||
this.description = description;
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
public final String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public final Exception getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return description + " because: " + exception;
|
||||
}
|
||||
|
||||
private transient String toStringCache;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (toStringCache == null) {
|
||||
toStringCache = ToStringUtil.builderFor(RemoteConnectionEndpointLookupFailure.class)
|
||||
.addValue("description", description)
|
||||
.addValue("exception", exception)
|
||||
.build();
|
||||
}
|
||||
return toStringCache;
|
||||
}
|
||||
|
||||
public static class DnsLookupFailure extends RemoteConnectionEndpointLookupFailure {
|
||||
private final DnsName dnsName;
|
||||
|
||||
public DnsLookupFailure(DnsName dnsName, Exception exception) {
|
||||
super("DNS lookup exception for " + dnsName, exception);
|
||||
this.dnsName = dnsName;
|
||||
}
|
||||
|
||||
public DnsName getDnsName() {
|
||||
return dnsName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 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.rce;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import org.jivesoftware.smack.util.ToStringUtil;
|
||||
|
||||
public final class RemoteConnectionException<RCE extends RemoteConnectionEndpoint> {
|
||||
|
||||
private final RemoteConnectionEndpoint.InetSocketAddressCoupling<RCE> address;
|
||||
private final Exception exception;
|
||||
|
||||
public RemoteConnectionException(RCE remoteConnectionEndpoint, InetAddress inetAddress,
|
||||
Exception exception) {
|
||||
this(new RemoteConnectionEndpoint.InetSocketAddressCoupling<>(remoteConnectionEndpoint, inetAddress), exception);
|
||||
}
|
||||
|
||||
public RemoteConnectionException(RemoteConnectionEndpoint.InetSocketAddressCoupling<RCE> address, Exception exception) {
|
||||
this.address = address;
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
public RemoteConnectionEndpoint.InetSocketAddressCoupling<RCE> getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public Exception getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return "\'" + address + "' failed because: " + exception;
|
||||
}
|
||||
|
||||
private transient String toStringCache;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (toStringCache == null) {
|
||||
toStringCache = ToStringUtil.builderFor(RemoteConnectionException.class)
|
||||
.addValue("address", address)
|
||||
.addValue("exception", exception)
|
||||
.build();
|
||||
}
|
||||
return toStringCache;
|
||||
}
|
||||
|
||||
public static <SARCE extends SingleAddressRemoteConnectionEndpoint> RemoteConnectionException<SARCE> from(SARCE remoteConnectionEndpoint, Exception exception) {
|
||||
return new RemoteConnectionException<SARCE>(remoteConnectionEndpoint, remoteConnectionEndpoint.getInetAddress(), exception);
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 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.rce;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public interface SingleAddressRemoteConnectionEndpoint extends RemoteConnectionEndpoint {
|
||||
|
||||
InetAddress getInetAddress();
|
||||
|
||||
@Override
|
||||
default Collection<? extends InetAddress> getInetAddresses() {
|
||||
return Collections.singletonList(getInetAddress());
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Utility classes for Remote Connection Endpoints (RCE).
|
||||
*/
|
||||
package org.jivesoftware.smack.util.rce;
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
*
|
||||
* Copyright © 2014-2018 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;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jivesoftware.smack.SmackException.ConnectionException;
|
||||
import org.jivesoftware.smack.util.dns.HostAddress;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.minidns.dnsname.DnsName;
|
||||
|
||||
public class SmackExceptionTest {
|
||||
|
||||
@Test
|
||||
public void testConnectionException() throws UnknownHostException {
|
||||
List<HostAddress> failedAddresses = new LinkedList<HostAddress>();
|
||||
|
||||
DnsName host = DnsName.from("foo.bar.example");
|
||||
InetAddress inetAddress = InetAddress.getByAddress(host.toString(), new byte[] { 0, 0, 0, 0 });
|
||||
List<InetAddress> inetAddresses = Collections.singletonList(inetAddress);
|
||||
HostAddress hostAddress = new HostAddress(host, 1234, inetAddresses);
|
||||
hostAddress.setException(new Exception("Failed for some reason"));
|
||||
failedAddresses.add(hostAddress);
|
||||
|
||||
host = DnsName.from("barz.example");
|
||||
inetAddress = InetAddress.getByAddress(host.toString(), new byte[] { 0, 0, 0, 0 });
|
||||
inetAddresses = Collections.singletonList(inetAddress);
|
||||
hostAddress = new HostAddress(host, 5678, inetAddresses);
|
||||
hostAddress.setException(new Exception("Failed for some other reason"));
|
||||
failedAddresses.add(hostAddress);
|
||||
|
||||
ConnectionException connectionException = ConnectionException.from(failedAddresses);
|
||||
String message = connectionException.getMessage();
|
||||
assertEquals("The following addresses failed: 'foo.bar.example:1234' failed because: java.lang.Exception: Failed for some reason, 'barz.example:5678' failed because: java.lang.Exception: Failed for some other reason",
|
||||
message);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus.
|
||||
* Copyright 2018 Florian Schmaus.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,6 +18,7 @@ package org.jivesoftware.smack.util;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.jivesoftware.smack.util.DNSUtil.DomainType;
|
||||
import org.jivesoftware.smack.util.dns.SmackDaneProvider;
|
||||
import org.jivesoftware.smack.util.dns.SmackDaneVerifier;
|
||||
|
||||
|
@ -25,6 +26,15 @@ import org.junit.Test;
|
|||
|
||||
public class DnsUtilTest {
|
||||
|
||||
@Test
|
||||
public void simpleDomainTypeTest() {
|
||||
DomainType client = DomainType.client;
|
||||
assertEquals(DNSUtil.XMPP_CLIENT_DNS_SRV_PREFIX, client.srvPrefix.ace);
|
||||
|
||||
DomainType server = DomainType.server;
|
||||
assertEquals(DNSUtil.XMPP_SERVER_DNS_SRV_PREFIX, server.srvPrefix.ace);
|
||||
}
|
||||
|
||||
private static final SmackDaneProvider DNS_UTIL_TEST_DANE_PROVIDER = new SmackDaneProvider() {
|
||||
@Override
|
||||
public SmackDaneVerifier newInstance() {
|
||||
|
|
|
@ -26,6 +26,10 @@ public class StanzaIdProvider extends ExtensionElementProvider<StanzaIdElement>
|
|||
|
||||
public static final StanzaIdProvider INSTANCE = new StanzaIdProvider();
|
||||
|
||||
// TODO: Remove in Smack 4.4.
|
||||
@Deprecated
|
||||
public static final StanzaIdProvider TEST_INSTANCE = INSTANCE;
|
||||
|
||||
@Override
|
||||
public StanzaIdElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) {
|
||||
String id = parser.getAttributeValue(null, StanzaIdElement.ATTR_ID);
|
||||
|
|
|
@ -2,7 +2,24 @@
|
|||
<!-- Providers for workgroup extensions -->
|
||||
<smackProviders>
|
||||
|
||||
<!-- XEP-0280: Message Carbons -->
|
||||
<!-- XEP-0332 HTTP over XMPP transport -->
|
||||
<iqProvider>
|
||||
<elementName>req</elementName>
|
||||
<namespace>urn:xmpp:http</namespace>
|
||||
<className>org.jivesoftware.smackx.hoxt.provider.HttpOverXmppReqProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>resp</elementName>
|
||||
<namespace>urn:xmpp:http</namespace>
|
||||
<className>org.jivesoftware.smackx.hoxt.provider.HttpOverXmppRespProvider</className>
|
||||
</iqProvider>
|
||||
<extensionProvider>
|
||||
<elementName>chunk</elementName>
|
||||
<namespace>urn:xmpp:http</namespace>
|
||||
<className>org.jivesoftware.smackx.hoxt.provider.Base64BinaryChunkProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0280 Message Carbons -->
|
||||
<extensionProvider>
|
||||
<elementName>sent</elementName>
|
||||
<namespace>urn:xmpp:carbons:2</namespace>
|
||||
|
@ -14,7 +31,60 @@
|
|||
<className>org.jivesoftware.smackx.carbons.provider.CarbonManagerProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0313: Message Archive Management -->
|
||||
<!-- XEP-0352 Client State Indication -->
|
||||
<streamFeatureProvider>
|
||||
<elementName>csi</elementName>
|
||||
<namespace>urn:xmpp:csi:0</namespace>
|
||||
<className>org.jivesoftware.smackx.csi.provider.ClientStateIndicationFeatureProvider</className>
|
||||
</streamFeatureProvider>
|
||||
|
||||
<!-- XEP-0335 JSON Containers -->
|
||||
<extensionProvider>
|
||||
<elementName>json</elementName>
|
||||
<namespace>urn:xmpp:json:0</namespace>
|
||||
<className>org.jivesoftware.smackx.json.provider.JsonExtensionProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- GCM JSON payload -->
|
||||
<extensionProvider>
|
||||
<elementName>gcm</elementName>
|
||||
<namespace>google:mobile:data</namespace>
|
||||
<className>org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-xxxx: Multi-User Chat Light -->
|
||||
<iqProvider>
|
||||
<elementName>query</elementName>
|
||||
<namespace>urn:xmpp:muclight:0#info</namespace>
|
||||
<className>org.jivesoftware.smackx.muclight.provider.MUCLightInfoIQProvider</className>
|
||||
</iqProvider>
|
||||
<extensionProvider>
|
||||
<elementName>x</elementName>
|
||||
<namespace>urn:xmpp:muclight:0#affiliations</namespace>
|
||||
<className>org.jivesoftware.smackx.muclight.provider.MUCLightAffiliationsChangeProvider</className>
|
||||
</extensionProvider>
|
||||
<extensionProvider>
|
||||
<elementName>x</elementName>
|
||||
<namespace>urn:xmpp:muclight:0#configuration</namespace>
|
||||
<className>org.jivesoftware.smackx.muclight.provider.MUCLightConfigurationsChangeProvider</className>
|
||||
</extensionProvider>
|
||||
<iqProvider>
|
||||
<elementName>query</elementName>
|
||||
<namespace>urn:xmpp:muclight:0#configuration</namespace>
|
||||
<className>org.jivesoftware.smackx.muclight.provider.MUCLightConfigurationIQProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>query</elementName>
|
||||
<namespace>urn:xmpp:muclight:0#affiliations</namespace>
|
||||
<className>org.jivesoftware.smackx.muclight.provider.MUCLightAffiliationsIQProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>query</elementName>
|
||||
<namespace>urn:xmpp:muclight:0#blocking</namespace>
|
||||
<className>org.jivesoftware.smackx.muclight.provider.MUCLightBlockingIQProvider</className>
|
||||
</iqProvider>
|
||||
|
||||
<!-- XEP-0313 Message Archive Management -->
|
||||
<iqProvider>
|
||||
<elementName>prefs</elementName>
|
||||
<namespace>urn:xmpp:mam:1</namespace>
|
||||
|
@ -36,22 +106,42 @@
|
|||
<className>org.jivesoftware.smackx.mam.provider.MamResultProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0323: Internet of Things - Data -->
|
||||
<!-- XEP-0347: Internet of Things - Discovery -->
|
||||
<iqProvider>
|
||||
<elementName>req</elementName>
|
||||
<namespace>urn:xmpp:iot:sensordata</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.data.provider.IoTDataRequestProvider</className>
|
||||
<elementName>register</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTRegisterProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>accepted</elementName>
|
||||
<namespace>urn:xmpp:iot:sensordata</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.data.provider.IoTDataReadOutAcceptedProvider</className>
|
||||
<elementName>claimed</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTClaimedProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>disown</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTDisownProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>disowned</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTDisownedProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>remove</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTRemoveProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>disown</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTRemovedProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>unregister</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTUnregisterProvider</className>
|
||||
</iqProvider>
|
||||
<extensionProvider>
|
||||
<elementName>fields</elementName>
|
||||
<namespace>urn:xmpp:iot:sensordata</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.data.provider.IoTFieldsExtensionProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0324: Internet of Things - Provisioning -->
|
||||
<iqProvider>
|
||||
|
@ -85,6 +175,23 @@
|
|||
<className>org.jivesoftware.smackx.iot.provisioning.provider.UnfriendProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0323: Internet of Things - Data -->
|
||||
<iqProvider>
|
||||
<elementName>req</elementName>
|
||||
<namespace>urn:xmpp:iot:sensordata</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.data.provider.IoTDataRequestProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>accepted</elementName>
|
||||
<namespace>urn:xmpp:iot:sensordata</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.data.provider.IoTDataReadOutAcceptedProvider</className>
|
||||
</iqProvider>
|
||||
<extensionProvider>
|
||||
<elementName>fields</elementName>
|
||||
<namespace>urn:xmpp:iot:sensordata</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.data.provider.IoTFieldsExtensionProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0325: Internet of Things - Control -->
|
||||
<iqProvider>
|
||||
<elementName>set</elementName>
|
||||
|
@ -97,28 +204,23 @@
|
|||
<className>org.jivesoftware.smackx.iot.control.provider.IoTSetResponseProvider</className>
|
||||
</iqProvider>
|
||||
|
||||
<!-- XEP-0328: JID Preparation and Validation Service (JID Prep) -->
|
||||
<iqProvider>
|
||||
<elementName>jid</elementName>
|
||||
<namespace>urn:xmpp:jidprep:0</namespace>
|
||||
<className>org.jivesoftware.smackx.jid_prep.provider.JidPrepIqProvider</className>
|
||||
</iqProvider>
|
||||
|
||||
<!-- XEP-0332: HTTP over XMPP transport -->
|
||||
<iqProvider>
|
||||
<elementName>req</elementName>
|
||||
<namespace>urn:xmpp:http</namespace>
|
||||
<className>org.jivesoftware.smackx.hoxt.provider.HttpOverXmppReqProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>resp</elementName>
|
||||
<namespace>urn:xmpp:http</namespace>
|
||||
<className>org.jivesoftware.smackx.hoxt.provider.HttpOverXmppRespProvider</className>
|
||||
</iqProvider>
|
||||
<!-- XEP-0357 Push Notifications -->
|
||||
<extensionProvider>
|
||||
<elementName>chunk</elementName>
|
||||
<namespace>urn:xmpp:http</namespace>
|
||||
<className>org.jivesoftware.smackx.hoxt.provider.Base64BinaryChunkProvider</className>
|
||||
<elementName>pubsub</elementName>
|
||||
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
||||
<className>org.jivesoftware.smackx.push_notifications.provider.RemoteDisablingProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0359: Stable and Unique Stanza IDs -->
|
||||
<extensionProvider>
|
||||
<elementName>stanza-id</elementName>
|
||||
<namespace>urn:xmpp:sid:0</namespace>
|
||||
<className>org.jivesoftware.smackx.sid.provider.StanzaIdProvider</className>
|
||||
</extensionProvider>
|
||||
<extensionProvider>
|
||||
<elementName>origin-id</elementName>
|
||||
<namespace>urn:xmpp:sid:0</namespace>
|
||||
<className>org.jivesoftware.smackx.sid.provider.OriginIdProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0333: Chat Markers -->
|
||||
|
@ -165,76 +267,6 @@
|
|||
<className>org.jivesoftware.smackx.hints.provider.StoreHintProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0335: JSON Containers -->
|
||||
<extensionProvider>
|
||||
<elementName>json</elementName>
|
||||
<namespace>urn:xmpp:json:0</namespace>
|
||||
<className>org.jivesoftware.smackx.json.provider.JsonExtensionProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0347: Internet of Things - Discovery -->
|
||||
<iqProvider>
|
||||
<elementName>register</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTRegisterProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>claimed</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTClaimedProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>disown</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTDisownProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>disowned</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTDisownedProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>remove</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTRemoveProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>disown</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTRemovedProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>unregister</elementName>
|
||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTUnregisterProvider</className>
|
||||
</iqProvider>
|
||||
|
||||
<!-- XEP-0352: Client State Indication -->
|
||||
<streamFeatureProvider>
|
||||
<elementName>csi</elementName>
|
||||
<namespace>urn:xmpp:csi:0</namespace>
|
||||
<className>org.jivesoftware.smackx.csi.provider.ClientStateIndicationFeatureProvider</className>
|
||||
</streamFeatureProvider>
|
||||
|
||||
<!-- XEP-0357: Push Notifications -->
|
||||
<extensionProvider>
|
||||
<elementName>pubsub</elementName>
|
||||
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
||||
<className>org.jivesoftware.smackx.push_notifications.provider.RemoteDisablingProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0359: Stable and Unique Stanza IDs -->
|
||||
<extensionProvider>
|
||||
<elementName>stanza-id</elementName>
|
||||
<namespace>urn:xmpp:sid:0</namespace>
|
||||
<className>org.jivesoftware.smackx.sid.provider.StanzaIdProvider</className>
|
||||
</extensionProvider>
|
||||
<extensionProvider>
|
||||
<elementName>origin-id</elementName>
|
||||
<namespace>urn:xmpp:sid:0</namespace>
|
||||
<className>org.jivesoftware.smackx.sid.provider.OriginIdProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
<!-- XEP-0363: HTTP File Upload -->
|
||||
<iqProvider>
|
||||
<elementName>slot</elementName>
|
||||
|
@ -292,46 +324,11 @@
|
|||
<className>org.jivesoftware.smackx.dox.provider.DnsIqProvider</className>
|
||||
</iqProvider>
|
||||
|
||||
|
||||
<!-- XEP-xxxx: Multi-User Chat Light -->
|
||||
<!-- XEP-0328: JID Prep -->
|
||||
<iqProvider>
|
||||
<elementName>query</elementName>
|
||||
<namespace>urn:xmpp:muclight:0#info</namespace>
|
||||
<className>org.jivesoftware.smackx.muclight.provider.MUCLightInfoIQProvider</className>
|
||||
<elementName>jid</elementName>
|
||||
<namespace>urn:xmpp:jidprep:0</namespace>
|
||||
<className>org.jivesoftware.smackx.jid_prep.provider.JidPrepIqProvider</className>
|
||||
</iqProvider>
|
||||
<extensionProvider>
|
||||
<elementName>x</elementName>
|
||||
<namespace>urn:xmpp:muclight:0#affiliations</namespace>
|
||||
<className>org.jivesoftware.smackx.muclight.provider.MUCLightAffiliationsChangeProvider</className>
|
||||
</extensionProvider>
|
||||
<extensionProvider>
|
||||
<elementName>x</elementName>
|
||||
<namespace>urn:xmpp:muclight:0#configuration</namespace>
|
||||
<className>org.jivesoftware.smackx.muclight.provider.MUCLightConfigurationsChangeProvider</className>
|
||||
</extensionProvider>
|
||||
<iqProvider>
|
||||
<elementName>query</elementName>
|
||||
<namespace>urn:xmpp:muclight:0#configuration</namespace>
|
||||
<className>org.jivesoftware.smackx.muclight.provider.MUCLightConfigurationIQProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>query</elementName>
|
||||
<namespace>urn:xmpp:muclight:0#affiliations</namespace>
|
||||
<className>org.jivesoftware.smackx.muclight.provider.MUCLightAffiliationsIQProvider</className>
|
||||
</iqProvider>
|
||||
<iqProvider>
|
||||
<elementName>query</elementName>
|
||||
<namespace>urn:xmpp:muclight:0#blocking</namespace>
|
||||
<className>org.jivesoftware.smackx.muclight.provider.MUCLightBlockingIQProvider</className>
|
||||
</iqProvider>
|
||||
|
||||
|
||||
<!-- GCM JSON payload -->
|
||||
<extensionProvider>
|
||||
<elementName>gcm</elementName>
|
||||
<namespace>google:mobile:data</namespace>
|
||||
<className>org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider</className>
|
||||
</extensionProvider>
|
||||
|
||||
|
||||
</smackProviders>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,19 +1,18 @@
|
|||
<?xml version="1.0"?>
|
||||
<smackProviders>
|
||||
|
||||
<!-- RFC-6121: Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence -->
|
||||
<iqProvider>
|
||||
<elementName>query</elementName>
|
||||
<namespace>jabber:iq:roster</namespace>
|
||||
<className>org.jivesoftware.smack.roster.provider.RosterPacketProvider</className>
|
||||
</iqProvider>
|
||||
|
||||
<streamFeatureProvider>
|
||||
<elementName>sub</elementName>
|
||||
<namespace>urn:xmpp:features:pre-approval</namespace>
|
||||
<className>org.jivesoftware.smack.roster.provider.SubscriptionPreApprovalStreamFeatureProvider</className>
|
||||
</streamFeatureProvider>
|
||||
|
||||
<!-- XEP-0237: Roster Versioning -->
|
||||
<streamFeatureProvider>
|
||||
<elementName>ver</elementName>
|
||||
<namespace>urn:xmpp:features:rosterver</namespace>
|
||||
|
|
|
@ -7,7 +7,13 @@ mainClassName = 'org.igniterealtime.smack.inttest.SmackIntegrationTestFramework'
|
|||
applicationDefaultJvmArgs = ["-enableassertions"]
|
||||
|
||||
dependencies {
|
||||
api project(':smack-java8-full')
|
||||
compile project(':smack-java7')
|
||||
compile project(':smack-tcp')
|
||||
compile project(':smack-extensions')
|
||||
compile project(':smack-experimental')
|
||||
compile project(':smack-omemo')
|
||||
compile project(':smack-openpgp')
|
||||
compile project(':smack-debug')
|
||||
compile 'org.reflections:reflections:0.9.11'
|
||||
compile 'eu.geekplace.javapinning:java-pinning-java7:1.1.0-alpha1'
|
||||
compile group: 'commons-io', name: 'commons-io', version: "$commonsIoVersion"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-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.
|
||||
|
@ -45,7 +45,7 @@ public abstract class AbstractSmackIntTest {
|
|||
|
||||
protected final Configuration sinttestConfiguration;
|
||||
|
||||
protected AbstractSmackIntTest(SmackIntegrationTestEnvironment environment) {
|
||||
protected AbstractSmackIntTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
this.testRunId = environment.testRunId;
|
||||
this.sinttestConfiguration = environment.configuration;
|
||||
this.timeout = environment.configuration.replyTimeout;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -46,7 +46,7 @@ public abstract class AbstractSmackIntegrationTest extends AbstractSmackIntTest
|
|||
|
||||
protected final List<XMPPConnection> connections;
|
||||
|
||||
public AbstractSmackIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
public AbstractSmackIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
this.connection = this.conOne = environment.conOne;
|
||||
this.conTwo = environment.conTwo;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-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.
|
||||
|
@ -31,7 +31,7 @@ import org.jxmpp.jid.DomainBareJid;
|
|||
|
||||
public abstract class AbstractSmackLowLevelIntegrationTest extends AbstractSmackIntTest {
|
||||
|
||||
private final SmackIntegrationTestEnvironment environment;
|
||||
private final SmackIntegrationTestEnvironment<?> environment;
|
||||
|
||||
/**
|
||||
* The configuration
|
||||
|
@ -40,7 +40,7 @@ public abstract class AbstractSmackLowLevelIntegrationTest extends AbstractSmack
|
|||
|
||||
protected final DomainBareJid service;
|
||||
|
||||
protected AbstractSmackLowLevelIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
protected AbstractSmackLowLevelIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
this.environment = environment;
|
||||
this.configuration = environment.configuration;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018-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.
|
||||
|
@ -28,22 +28,19 @@ import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
|||
public abstract class AbstractSmackSpecificLowLevelIntegrationTest<C extends AbstractXMPPConnection>
|
||||
extends AbstractSmackLowLevelIntegrationTest {
|
||||
|
||||
private final SmackIntegrationTestEnvironment environment;
|
||||
private final SmackIntegrationTestEnvironment<?> environment;
|
||||
|
||||
protected final Class<C> connectionClass;
|
||||
|
||||
private final XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor;
|
||||
|
||||
public AbstractSmackSpecificLowLevelIntegrationTest(SmackIntegrationTestEnvironment environment,
|
||||
public AbstractSmackSpecificLowLevelIntegrationTest(SmackIntegrationTestEnvironment<?> environment,
|
||||
Class<C> connectionClass) {
|
||||
super(environment);
|
||||
this.environment = environment;
|
||||
this.connectionClass = connectionClass;
|
||||
|
||||
connectionDescriptor = environment.connectionManager.getConnectionDescriptorFor(connectionClass);
|
||||
if (connectionDescriptor == null) {
|
||||
throw new IllegalStateException("No connection descriptor for " + connectionClass + " known");
|
||||
}
|
||||
}
|
||||
|
||||
public Class<C> getConnectionClass() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -33,9 +33,7 @@ import javax.net.ssl.SSLContext;
|
|||
|
||||
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
|
||||
import org.jivesoftware.smack.debugger.ConsoleDebugger;
|
||||
import org.jivesoftware.smack.util.Function;
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
import org.jivesoftware.smack.util.ParserUtils;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
|
||||
import org.jivesoftware.smackx.debugger.EnhancedDebugger;
|
||||
|
@ -96,90 +94,80 @@ public final class Configuration {
|
|||
|
||||
public final Set<String> disabledTests;
|
||||
|
||||
public final String defaultConnectionNickname;
|
||||
|
||||
public final Set<String> enabledConnections;
|
||||
|
||||
public final Set<String> disabledConnections;
|
||||
|
||||
public final Set<String> testPackages;
|
||||
|
||||
public final ConnectionConfigurationBuilderApplier configurationApplier;
|
||||
|
||||
public final boolean verbose;
|
||||
|
||||
private Configuration(Configuration.Builder builder) throws KeyManagementException, NoSuchAlgorithmException {
|
||||
service = Objects.requireNonNull(builder.service,
|
||||
private Configuration(DomainBareJid service, String serviceTlsPin, SecurityMode securityMode, int replyTimeout,
|
||||
Debugger debugger, String accountOneUsername, String accountOnePassword, String accountTwoUsername,
|
||||
String accountTwoPassword, String accountThreeUsername, String accountThreePassword, Set<String> enabledTests, Set<String> disabledTests,
|
||||
Set<String> testPackages, String adminAccountUsername, String adminAccountPassword)
|
||||
throws KeyManagementException, NoSuchAlgorithmException {
|
||||
this.service = Objects.requireNonNull(service,
|
||||
"'service' must be set. Either via 'properties' files or via system property 'sinttest.service'.");
|
||||
serviceTlsPin = builder.serviceTlsPin;
|
||||
this.serviceTlsPin = serviceTlsPin;
|
||||
if (serviceTlsPin != null) {
|
||||
tlsContext = Java7Pinning.forPin(serviceTlsPin);
|
||||
} else {
|
||||
tlsContext = null;
|
||||
}
|
||||
securityMode = builder.securityMode;
|
||||
if (builder.replyTimeout > 0) {
|
||||
replyTimeout = builder.replyTimeout;
|
||||
this.securityMode = securityMode;
|
||||
if (replyTimeout > 0) {
|
||||
this.replyTimeout = replyTimeout;
|
||||
} else {
|
||||
replyTimeout = 60000;
|
||||
this.replyTimeout = 60000;
|
||||
}
|
||||
debugger = builder.debugger;
|
||||
if (StringUtils.isNotEmpty(builder.adminAccountUsername, builder.adminAccountPassword)) {
|
||||
this.debugger = debugger;
|
||||
if (StringUtils.isNotEmpty(adminAccountUsername, adminAccountPassword)) {
|
||||
accountRegistration = AccountRegistration.serviceAdministration;
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(builder.accountOneUsername, builder.accountOnePassword,
|
||||
builder.accountTwoUsername, builder.accountTwoPassword, builder.accountThreeUsername,
|
||||
builder.accountThreePassword)) {
|
||||
else if (StringUtils.isNotEmpty(accountOneUsername, accountOnePassword, accountTwoUsername, accountTwoPassword,
|
||||
accountThreeUsername, accountThreePassword)) {
|
||||
accountRegistration = AccountRegistration.disabled;
|
||||
}
|
||||
else {
|
||||
accountRegistration = AccountRegistration.inBandRegistration;
|
||||
}
|
||||
|
||||
this.adminAccountUsername = builder.adminAccountUsername;
|
||||
this.adminAccountPassword = builder.adminAccountPassword;
|
||||
this.adminAccountUsername = adminAccountUsername;
|
||||
this.adminAccountPassword = adminAccountPassword;
|
||||
|
||||
boolean accountOnePasswordSet = StringUtils.isNotEmpty(builder.accountOnePassword);
|
||||
if (accountOnePasswordSet != StringUtils.isNotEmpty(builder.accountTwoPassword) ||
|
||||
accountOnePasswordSet != StringUtils.isNotEmpty(builder.accountThreePassword)) {
|
||||
boolean accountOnePasswordSet = StringUtils.isNotEmpty(accountOnePassword);
|
||||
if (accountOnePasswordSet != StringUtils.isNotEmpty(accountTwoPassword) ||
|
||||
accountOnePasswordSet != StringUtils.isNotEmpty(accountThreePassword)) {
|
||||
// Ensure the invariant that either all main accounts have a password set, or none.
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
this.accountOneUsername = builder.accountOneUsername;
|
||||
this.accountOnePassword = builder.accountOnePassword;
|
||||
this.accountTwoUsername = builder.accountTwoUsername;
|
||||
this.accountTwoPassword = builder.accountTwoPassword;
|
||||
this.accountThreeUsername = builder.accountThreeUsername;
|
||||
this.accountThreePassword = builder.accountThreePassword;
|
||||
this.enabledTests = builder.enabledTests;
|
||||
this.disabledTests = builder.disabledTests;
|
||||
this.defaultConnectionNickname = builder.defaultConnectionNickname;
|
||||
this.enabledConnections = builder.enabledConnections;
|
||||
this.disabledConnections = builder.disabledConnections;
|
||||
this.testPackages = builder.testPackages;
|
||||
this.accountOneUsername = accountOneUsername;
|
||||
this.accountOnePassword = accountOnePassword;
|
||||
this.accountTwoUsername = accountTwoUsername;
|
||||
this.accountTwoPassword = accountTwoPassword;
|
||||
this.accountThreeUsername = accountThreeUsername;
|
||||
this.accountThreePassword = accountThreePassword;
|
||||
this.enabledTests = enabledTests;
|
||||
this.disabledTests = disabledTests;
|
||||
this.testPackages = testPackages;
|
||||
|
||||
this.configurationApplier = b -> {
|
||||
this.configurationApplier = builder -> {
|
||||
if (tlsContext != null) {
|
||||
b.setCustomSSLContext(tlsContext);
|
||||
builder.setCustomSSLContext(tlsContext);
|
||||
}
|
||||
b.setSecurityMode(securityMode);
|
||||
b.setXmppDomain(service);
|
||||
builder.setSecurityMode(securityMode);
|
||||
builder.setXmppDomain(service);
|
||||
|
||||
switch (debugger) {
|
||||
case enhanced:
|
||||
b.setDebuggerFactory(EnhancedDebugger.Factory.INSTANCE);
|
||||
builder.setDebuggerFactory(EnhancedDebugger.Factory.INSTANCE);
|
||||
break;
|
||||
case console:
|
||||
b.setDebuggerFactory(ConsoleDebugger.Factory.INSTANCE);
|
||||
builder.setDebuggerFactory(ConsoleDebugger.Factory.INSTANCE);
|
||||
break;
|
||||
case none:
|
||||
// Nothing to do :).
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
this.verbose = builder.verbose;
|
||||
}
|
||||
|
||||
public boolean isAccountRegistrationPossible() {
|
||||
|
@ -222,16 +210,8 @@ public final class Configuration {
|
|||
|
||||
private Set<String> disabledTests;
|
||||
|
||||
private String defaultConnectionNickname;
|
||||
|
||||
private Set<String> enabledConnections;
|
||||
|
||||
private Set<String> disabledConnections;
|
||||
|
||||
private Set<String> testPackages;
|
||||
|
||||
private boolean verbose;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
|
@ -344,21 +324,6 @@ public final class Configuration {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder setDefaultConnection(String defaultConnectionNickname) {
|
||||
this.defaultConnectionNickname = defaultConnectionNickname;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEnabledConnections(String enabledConnectionsString) {
|
||||
enabledConnections = split(enabledConnectionsString);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDisabledConnections(String disabledConnectionsString) {
|
||||
disabledConnections = split(disabledConnectionsString);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addTestPackages(String testPackagesString) {
|
||||
if (testPackagesString != null) {
|
||||
String[] testPackagesArray = testPackagesString.split(",");
|
||||
|
@ -385,22 +350,10 @@ public final class Configuration {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder setVerbose(boolean verbose) {
|
||||
this.verbose = verbose;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setVerbose(String verboseBooleanString) {
|
||||
if (verboseBooleanString == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean verbose = ParserUtils.parseXmlBoolean(verboseBooleanString);
|
||||
return setVerbose(verbose);
|
||||
}
|
||||
|
||||
public Configuration build() throws KeyManagementException, NoSuchAlgorithmException {
|
||||
return new Configuration(this);
|
||||
return new Configuration(service, serviceTlsPin, securityMode, replyTimeout, debugger, accountOneUsername,
|
||||
accountOnePassword, accountTwoUsername, accountTwoPassword, accountThreeUsername, accountThreePassword, enabledTests, disabledTests,
|
||||
testPackages, adminAccountUsername, adminAccountPassword);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -461,15 +414,10 @@ public final class Configuration {
|
|||
builder.setDebugger(properties.getProperty("debugger"));
|
||||
builder.setEnabledTests(properties.getProperty("enabledTests"));
|
||||
builder.setDisabledTests(properties.getProperty("disabledTests"));
|
||||
builder.setDefaultConnection(properties.getProperty("defaultConnection"));
|
||||
builder.setEnabledConnections(properties.getProperty("enabledConnections"));
|
||||
builder.setDisabledConnections(properties.getProperty("disabledConnections"));
|
||||
|
||||
builder.addTestPackages(properties.getProperty("testPackages"));
|
||||
builder.addTestPackages(testPackages);
|
||||
|
||||
builder.setVerbose(properties.getProperty("verbose"));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
@ -489,36 +437,23 @@ public final class Configuration {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static Set<String> split(String input) {
|
||||
return split(input, Function.identity());
|
||||
}
|
||||
|
||||
private static Set<String> split(String input, Function<String, String> transformer) {
|
||||
if (input == null) {
|
||||
private static Set<String> getTestSetFrom(String string) {
|
||||
if (string == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] inputArray = input.split(",");
|
||||
Set<String> res = new HashSet<>(inputArray.length);
|
||||
for (String s : inputArray) {
|
||||
s = transformer.apply(s);
|
||||
boolean newElement = res.add(s);
|
||||
if (!newElement) {
|
||||
throw new IllegalArgumentException("The argument '" + s + "' was already provided.");
|
||||
}
|
||||
String[] stringArray = string.split(",");
|
||||
Set<String> res = new HashSet<>(stringArray.length);
|
||||
for (String s : stringArray) {
|
||||
res.add(getFullTestStringFrom(s));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private static Set<String> getTestSetFrom(String input) {
|
||||
return split(input, s -> {
|
||||
s = s.trim();
|
||||
if (s.startsWith("smackx.") || s.startsWith("smack.")) {
|
||||
s = "org.jivesoftware." + s;
|
||||
}
|
||||
return s;
|
||||
});
|
||||
private static String getFullTestStringFrom(String string) {
|
||||
string = string.trim();
|
||||
if (string.startsWith("smackx.") || string.startsWith("smack.")) {
|
||||
string = "org.jivesoftware." + string;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-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.
|
||||
|
@ -18,18 +18,18 @@ package org.igniterealtime.smack.inttest;
|
|||
|
||||
import org.jivesoftware.smack.AbstractXMPPConnection;
|
||||
|
||||
public class SmackIntegrationTestEnvironment {
|
||||
public class SmackIntegrationTestEnvironment<C extends AbstractXMPPConnection> {
|
||||
|
||||
public final AbstractXMPPConnection conOne, conTwo, conThree;
|
||||
public final C conOne, conTwo, conThree;
|
||||
|
||||
public final String testRunId;
|
||||
|
||||
public final Configuration configuration;
|
||||
|
||||
public final XmppConnectionManager connectionManager;
|
||||
public final XmppConnectionManager<C> connectionManager;
|
||||
|
||||
SmackIntegrationTestEnvironment(AbstractXMPPConnection conOne, AbstractXMPPConnection conTwo, AbstractXMPPConnection conThree, String testRunId,
|
||||
Configuration configuration, XmppConnectionManager connectionManager) {
|
||||
SmackIntegrationTestEnvironment(C conOne, C conTwo, C conThree, String testRunId,
|
||||
Configuration configuration, XmppConnectionManager<C> connectionManager) {
|
||||
this.conOne = conOne;
|
||||
this.conTwo = conTwo;
|
||||
this.conThree = conThree;
|
||||
|
|
|
@ -23,7 +23,6 @@ import static org.reflections.ReflectionUtils.withParametersCount;
|
|||
import static org.reflections.ReflectionUtils.withReturnType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -33,7 +32,6 @@ import java.lang.reflect.Type;
|
|||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -45,6 +43,7 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -54,6 +53,7 @@ import org.jivesoftware.smack.SmackConfiguration;
|
|||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smack.util.TLSUtils;
|
||||
|
@ -70,7 +70,7 @@ import org.reflections.scanners.MethodParameterScanner;
|
|||
import org.reflections.scanners.SubTypesScanner;
|
||||
import org.reflections.scanners.TypeAnnotationsScanner;
|
||||
|
||||
public class SmackIntegrationTestFramework {
|
||||
public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||
|
||||
static {
|
||||
TLSUtils.setDefaultTrustStoreTypeToJksIfRequired();
|
||||
|
@ -80,12 +80,14 @@ public class SmackIntegrationTestFramework {
|
|||
|
||||
public static boolean SINTTEST_UNIT_TEST = false;
|
||||
|
||||
private final Class<DC> defaultConnectionClass;
|
||||
|
||||
protected final Configuration config;
|
||||
|
||||
protected TestRunResult testRunResult;
|
||||
|
||||
private SmackIntegrationTestEnvironment environment;
|
||||
protected XmppConnectionManager connectionManager;
|
||||
private SmackIntegrationTestEnvironment<DC> environment;
|
||||
protected XmppConnectionManager<DC> connectionManager;
|
||||
|
||||
public enum TestType {
|
||||
Normal,
|
||||
|
@ -98,7 +100,7 @@ public class SmackIntegrationTestFramework {
|
|||
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||
Configuration config = Configuration.newConfiguration(args);
|
||||
|
||||
SmackIntegrationTestFramework sinttest = new SmackIntegrationTestFramework(config);
|
||||
SmackIntegrationTestFramework<XMPPTCPConnection> sinttest = new SmackIntegrationTestFramework<>(config, XMPPTCPConnection.class);
|
||||
TestRunResult testRunResult = sinttest.run();
|
||||
|
||||
for (Entry<Class<? extends AbstractSmackIntTest>, Throwable> entry : testRunResult.impossibleTestClasses.entrySet()) {
|
||||
|
@ -114,9 +116,11 @@ public class SmackIntegrationTestFramework {
|
|||
}
|
||||
final int successfulTests = testRunResult.successfulIntegrationTests.size();
|
||||
final int failedTests = testRunResult.failedIntegrationTests.size();
|
||||
final int totalIntegrationTests = successfulTests + failedTests;
|
||||
final int availableTests = testRunResult.getNumberOfAvailableTests();
|
||||
LOGGER.info("SmackIntegrationTestFramework[" + testRunResult.testRunId + ']' + " finished: "
|
||||
+ successfulTests + '/' + availableTests + " [" + failedTests + " failed]");
|
||||
final int possibleTests = testRunResult.getNumberOfPossibleTests();
|
||||
LOGGER.info("SmackIntegrationTestFramework[" + testRunResult.testRunId + ']' + ": Finished ["
|
||||
+ successfulTests + '/' + totalIntegrationTests + "] (" + possibleTests + " test methods of " + availableTests + " where possible)");
|
||||
|
||||
final int exitStatus;
|
||||
if (failedTests > 0) {
|
||||
|
@ -142,8 +146,12 @@ public class SmackIntegrationTestFramework {
|
|||
System.exit(exitStatus);
|
||||
}
|
||||
|
||||
public SmackIntegrationTestFramework(Configuration configuration) {
|
||||
public SmackIntegrationTestFramework(Configuration configuration, Class<DC> defaultConnectionClass)
|
||||
throws KeyManagementException, InstantiationException, IllegalAccessException, IllegalArgumentException,
|
||||
InvocationTargetException, NoSuchAlgorithmException, SmackException, IOException, XMPPException,
|
||||
InterruptedException {
|
||||
this.config = configuration;
|
||||
this.defaultConnectionClass = defaultConnectionClass;
|
||||
}
|
||||
|
||||
public synchronized TestRunResult run()
|
||||
|
@ -152,7 +160,7 @@ public class SmackIntegrationTestFramework {
|
|||
testRunResult = new TestRunResult();
|
||||
|
||||
// Create a connection manager *after* we created the testRunId (in testRunResult).
|
||||
this.connectionManager = new XmppConnectionManager(this);
|
||||
this.connectionManager = new XmppConnectionManager<>(this, defaultConnectionClass);
|
||||
|
||||
LOGGER.info("SmackIntegrationTestFramework [" + testRunResult.testRunId + ']' + ": Starting");
|
||||
if (config.debugger != Configuration.Debugger.none) {
|
||||
|
@ -218,13 +226,10 @@ public class SmackIntegrationTestFramework {
|
|||
return testRunResult;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"Finally"})
|
||||
@SuppressWarnings({"unchecked", "Finally"})
|
||||
private void runTests(Set<Class<? extends AbstractSmackIntTest>> classes)
|
||||
throws InterruptedException, InstantiationException, IllegalAccessException,
|
||||
IllegalArgumentException, SmackException, IOException, XMPPException {
|
||||
List<PreparedTest> tests = new ArrayList<>(classes.size());
|
||||
int numberOfAvailableTests = 0;
|
||||
|
||||
for (Class<? extends AbstractSmackIntTest> testClass : classes) {
|
||||
final String testClassName = testClass.getName();
|
||||
|
||||
|
@ -255,19 +260,17 @@ public class SmackIntegrationTestFramework {
|
|||
// - https://discuss.gradle.org/t/main-vs-test-compile-vs-runtime-classpaths-in-eclipse-once-and-for-all-how/17403
|
||||
// - https://bugs.eclipse.org/bugs/show_bug.cgi?id=376616 (Scope of dependencies has no effect on Eclipse compilation)
|
||||
if (!SINTTEST_UNIT_TEST && testClassName.startsWith("org.igniterealtime.smack.inttest.unittest")) {
|
||||
LOGGER.warning("Skipping integration test '" + testClassName + "' from src/test classpath (should not be in classpath)");
|
||||
LOGGER.finer("Skipping integration test '" + testClassName + "' from src/test classpath");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (config.enabledTests != null && !isInSet(testClass, config.enabledTests)) {
|
||||
DisabledTestClass disabledTestClass = new DisabledTestClass(testClass, "Skipping test class " + testClassName + " because it is not enabled");
|
||||
testRunResult.disabledTestClasses.add(disabledTestClass);
|
||||
LOGGER.info("Skipping test class " + testClassName + " because it is not enabled");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isInSet(testClass, config.disabledTests)) {
|
||||
DisabledTestClass disabledTestClass = new DisabledTestClass(testClass, "Skipping test class " + testClassName + " because it is disalbed");
|
||||
testRunResult.disabledTestClasses.add(disabledTestClass);
|
||||
LOGGER.info("Skipping test class " + testClassName + " because it is disalbed");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -298,6 +301,8 @@ public class SmackIntegrationTestFramework {
|
|||
continue;
|
||||
}
|
||||
|
||||
testRunResult.numberOfAvailableTestMethods.addAndGet(smackIntegrationTestMethods.size());
|
||||
|
||||
final AbstractSmackIntTest test;
|
||||
try {
|
||||
test = cons.newInstance(environment);
|
||||
|
@ -355,14 +360,12 @@ public class SmackIntegrationTestFramework {
|
|||
final String methodName = method.getName();
|
||||
if (config.enabledTests != null && !(config.enabledTests.contains(methodName)
|
||||
|| isInSet(testClass, config.enabledTests))) {
|
||||
DisabledTest disabledTest = new DisabledTest(method, "Skipping test method " + methodName + " because it is not enabled");
|
||||
testRunResult.disabledTests.add(disabledTest);
|
||||
LOGGER.fine("Skipping test method " + methodName + " because it is not enabled");
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
if (config.disabledTests != null && config.disabledTests.contains(methodName)) {
|
||||
DisabledTest disabledTest = new DisabledTest(method, "Skipping test method " + methodName + " because it is disabled");
|
||||
testRunResult.disabledTests.add(disabledTest);
|
||||
LOGGER.info("Skipping test method " + methodName + " because it is disabled");
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
|
@ -373,77 +376,106 @@ public class SmackIntegrationTestFramework {
|
|||
continue;
|
||||
}
|
||||
|
||||
List<ConcreteTest> concreteTests = new ArrayList<>(smackIntegrationTestMethods.size());
|
||||
final int detectedTestMethodsCount = smackIntegrationTestMethods.size();
|
||||
testRunResult.numberOfPossibleTestMethods.addAndGet(detectedTestMethodsCount);
|
||||
|
||||
for (Method testMethod : smackIntegrationTestMethods) {
|
||||
switch (testType) {
|
||||
case Normal: {
|
||||
ConcreteTest.Executor concreteTestExecutor = () -> testMethod.invoke(test);
|
||||
ConcreteTest concreteTest = new ConcreteTest(testType, testMethod, concreteTestExecutor);
|
||||
concreteTests.add(concreteTest);
|
||||
try {
|
||||
// Run the @BeforeClass methods (if any)
|
||||
Set<Method> beforeClassMethods = getAllMethods(testClass,
|
||||
withAnnotation(BeforeClass.class), withReturnType(Void.TYPE),
|
||||
withParametersCount(0), withModifier(Modifier.PUBLIC
|
||||
));
|
||||
|
||||
// See if there are any methods that have the @BeforeClassAnnotation but a wrong signature
|
||||
Set<Method> allBeforeClassMethods = getAllMethods(testClass, withAnnotation(BeforeClass.class));
|
||||
allBeforeClassMethods.removeAll(beforeClassMethods);
|
||||
if (!allBeforeClassMethods.isEmpty()) {
|
||||
throw new IllegalArgumentException("@BeforeClass methods with wrong signature found");
|
||||
}
|
||||
break;
|
||||
case LowLevel:
|
||||
case SpecificLowLevel:
|
||||
LowLevelTestMethod lowLevelTestMethod = new LowLevelTestMethod(testMethod);
|
||||
|
||||
if (beforeClassMethods.size() == 1) {
|
||||
Method beforeClassMethod = beforeClassMethods.iterator().next();
|
||||
LOGGER.info("Executing @BeforeClass method of " + testClass);
|
||||
try {
|
||||
beforeClassMethod.invoke(test);
|
||||
}
|
||||
catch (InvocationTargetException | IllegalAccessException e) {
|
||||
LOGGER.log(Level.SEVERE, "Exception executing @BeforeClass method", e);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
else if (beforeClassMethods.size() > 1) {
|
||||
throw new IllegalArgumentException("Only one @BeforeClass method allowed");
|
||||
}
|
||||
|
||||
for (Method testMethod : smackIntegrationTestMethods) {
|
||||
List<ConcreteTest> concreteTests = null;
|
||||
switch (testType) {
|
||||
case LowLevel:
|
||||
List<ConcreteTest> concreteLowLevelTests = invokeLowLevel(lowLevelTestMethod, (AbstractSmackLowLevelIntegrationTest) test);
|
||||
concreteTests.addAll(concreteLowLevelTests);
|
||||
break;
|
||||
case SpecificLowLevel: {
|
||||
ConcreteTest.Executor concreteTestExecutor = () -> invokeSpecificLowLevel(
|
||||
lowLevelTestMethod, (AbstractSmackSpecificLowLevelIntegrationTest<?>) test);
|
||||
case Normal: {
|
||||
ConcreteTest.Executor concreteTestExecutor = () -> testMethod.invoke(test);
|
||||
ConcreteTest concreteTest = new ConcreteTest(testType, testMethod, concreteTestExecutor);
|
||||
concreteTests.add(concreteTest);
|
||||
concreteTests = Collections.singletonList(concreteTest);
|
||||
}
|
||||
break;
|
||||
case LowLevel:
|
||||
case SpecificLowLevel:
|
||||
LowLevelTestMethod lowLevelTestMethod = new LowLevelTestMethod(testMethod);
|
||||
switch (testType) {
|
||||
case LowLevel:
|
||||
concreteTests = invokeLowLevel(lowLevelTestMethod, (AbstractSmackLowLevelIntegrationTest) test);
|
||||
break;
|
||||
case SpecificLowLevel: {
|
||||
ConcreteTest.Executor concreteTestExecutor = () -> invokeSpecificLowLevel(
|
||||
lowLevelTestMethod, (AbstractSmackSpecificLowLevelIntegrationTest<?>) test);
|
||||
ConcreteTest concreteTest = new ConcreteTest(testType, testMethod, concreteTestExecutor);
|
||||
concreteTests = Collections.singletonList(concreteTest);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new AssertionError();
|
||||
|
||||
for (ConcreteTest concreteTest : concreteTests) {
|
||||
runConcreteTest(concreteTest);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// Run the @AfterClass method (if any)
|
||||
Set<Method> afterClassMethods = getAllMethods(testClass,
|
||||
withAnnotation(AfterClass.class), withReturnType(Void.TYPE),
|
||||
withParametersCount(0), withModifier(Modifier.PUBLIC
|
||||
));
|
||||
|
||||
// Instantiate the prepared test early as this will check the before and after class annotations.
|
||||
PreparedTest preparedTest = new PreparedTest(test, concreteTests);
|
||||
tests.add(preparedTest);
|
||||
// See if there are any methods that have the @AfterClassAnnotation but a wrong signature
|
||||
Set<Method> allAfterClassMethods = getAllMethods(testClass, withAnnotation(AfterClass.class));
|
||||
allAfterClassMethods.removeAll(afterClassMethods);
|
||||
if (!allAfterClassMethods.isEmpty()) {
|
||||
throw new IllegalArgumentException("@AfterClass methods with wrong signature found");
|
||||
}
|
||||
|
||||
numberOfAvailableTests += concreteTests.size();
|
||||
}
|
||||
|
||||
// Print status information.
|
||||
StringBuilder sb = new StringBuilder(1024);
|
||||
sb.append("Smack Integration Test Framework\n");
|
||||
sb.append("################################\n");
|
||||
if (config.verbose) {
|
||||
sb.append('\n');
|
||||
if (!testRunResult.disabledTestClasses.isEmpty()) {
|
||||
sb.append("The following test classes are disabled:\n");
|
||||
for (DisabledTestClass disabledTestClass : testRunResult.disabledTestClasses) {
|
||||
disabledTestClass.appendTo(sb).append('\n');
|
||||
if (afterClassMethods.size() == 1) {
|
||||
Method afterClassMethod = afterClassMethods.iterator().next();
|
||||
LOGGER.info("Executing @AfterClass method of " + testClass);
|
||||
try {
|
||||
afterClassMethod.invoke(test);
|
||||
}
|
||||
catch (InvocationTargetException | IllegalAccessException e) {
|
||||
LOGGER.log(Level.SEVERE, "Exception executing @AfterClass method", e);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
else if (afterClassMethods.size() > 1) {
|
||||
throw new IllegalArgumentException("Only one @AfterClass method allowed");
|
||||
}
|
||||
}
|
||||
if (!testRunResult.disabledTests.isEmpty()) {
|
||||
sb.append("The following tests are disabled:\n");
|
||||
for (DisabledTest disabledTest : testRunResult.disabledTests) {
|
||||
disabledTest.appendTo(sb).append('\n');
|
||||
}
|
||||
}
|
||||
sb.append('\n');
|
||||
}
|
||||
sb.append("Available tests: ").append(numberOfAvailableTests)
|
||||
.append("(#-classes: ").append(testRunResult.disabledTestClasses.size())
|
||||
.append(", #-tests: ").append(testRunResult.disabledTests.size())
|
||||
.append(")\n");
|
||||
LOGGER.info(sb.toString());
|
||||
|
||||
for (PreparedTest test : tests) {
|
||||
test.run();
|
||||
}
|
||||
|
||||
// Assert that all tests in the 'tests' list produced a result.
|
||||
assert numberOfAvailableTests == testRunResult.getNumberOfAvailableTests();
|
||||
}
|
||||
|
||||
private void runConcreteTest(ConcreteTest concreteTest)
|
||||
|
@ -492,35 +524,17 @@ public class SmackIntegrationTestFramework {
|
|||
}
|
||||
|
||||
private List<ConcreteTest> invokeLowLevel(LowLevelTestMethod lowLevelTestMethod, AbstractSmackLowLevelIntegrationTest test) {
|
||||
Collection<? extends XmppConnectionDescriptor<?, ?, ?>> connectionDescriptors;
|
||||
Set<Class<? extends AbstractXMPPConnection>> connectionClasses;
|
||||
if (lowLevelTestMethod.smackIntegrationTestAnnotation.onlyDefaultConnectionType()) {
|
||||
XmppConnectionDescriptor<?, ?, ?> defaultConnectionDescriptor = connectionManager.getDefaultConnectionDescriptor();
|
||||
connectionDescriptors = Collections.singleton(defaultConnectionDescriptor);
|
||||
Class<? extends AbstractXMPPConnection> defaultConnectionClass = connectionManager.getDefaultConnectionClass();
|
||||
connectionClasses = Collections.singleton(defaultConnectionClass);
|
||||
} else {
|
||||
connectionDescriptors = connectionManager.getConnectionDescriptors();
|
||||
connectionClasses = connectionManager.getConnectionClasses();
|
||||
}
|
||||
|
||||
List<ConcreteTest> resultingConcreteTests = new ArrayList<>(connectionDescriptors.size());
|
||||
|
||||
for (XmppConnectionDescriptor<?, ?, ?> connectionDescriptor : connectionDescriptors) {
|
||||
String connectionNick = connectionDescriptor.getNickname();
|
||||
|
||||
if (config.enabledConnections != null && !config.enabledConnections.contains(connectionNick)) {
|
||||
DisabledTest disabledTest = new DisabledTest(lowLevelTestMethod.testMethod, "Not creating test for " + lowLevelTestMethod + " with connection '" + connectionNick
|
||||
+ "', as this connection type is not enabled");
|
||||
testRunResult.disabledTests.add(disabledTest);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (config.disabledConnections != null && config.disabledConnections.contains(connectionNick)) {
|
||||
DisabledTest disabledTest = new DisabledTest(lowLevelTestMethod.testMethod, "Not creating test for " + lowLevelTestMethod + " with connection '" + connectionNick
|
||||
+ ", as this connection type is disabled");
|
||||
testRunResult.disabledTests.add(disabledTest);
|
||||
continue;
|
||||
}
|
||||
|
||||
Class<? extends AbstractXMPPConnection> connectionClass = connectionDescriptor.getConnectionClass();
|
||||
List<ConcreteTest> resultingConcreteTests = new ArrayList<>(connectionClasses.size());
|
||||
|
||||
for (Class<? extends AbstractXMPPConnection> connectionClass : connectionClasses) {
|
||||
ConcreteTest.Executor executor = () -> lowLevelTestMethod.invoke(test, connectionClass);
|
||||
ConcreteTest concreteTest = new ConcreteTest(TestType.LowLevel, lowLevelTestMethod.testMethod, executor, connectionClass.getSimpleName());
|
||||
resultingConcreteTests.add(concreteTest);
|
||||
|
@ -529,7 +543,7 @@ public class SmackIntegrationTestFramework {
|
|||
return resultingConcreteTests;
|
||||
}
|
||||
|
||||
private static <C extends AbstractXMPPConnection> void invokeSpecificLowLevel(LowLevelTestMethod testMethod,
|
||||
private <C extends AbstractXMPPConnection> void invokeSpecificLowLevel(LowLevelTestMethod testMethod,
|
||||
AbstractSmackSpecificLowLevelIntegrationTest<C> test)
|
||||
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InterruptedException,
|
||||
SmackException, IOException, XMPPException {
|
||||
|
@ -540,7 +554,7 @@ public class SmackIntegrationTestFramework {
|
|||
testMethod.invoke(test, connectionClass);
|
||||
}
|
||||
|
||||
protected SmackIntegrationTestEnvironment prepareEnvironment() throws SmackException,
|
||||
protected SmackIntegrationTestEnvironment<DC> prepareEnvironment() throws SmackException,
|
||||
IOException, XMPPException, InterruptedException, KeyManagementException,
|
||||
NoSuchAlgorithmException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||
return connectionManager.prepareEnvironment();
|
||||
|
@ -562,6 +576,9 @@ public class SmackIntegrationTestFramework {
|
|||
|
||||
private static Exception throwFatalException(Throwable e) throws Error, NoResponseException,
|
||||
InterruptedException {
|
||||
if (e instanceof NoResponseException) {
|
||||
throw (NoResponseException) e;
|
||||
}
|
||||
if (e instanceof InterruptedException) {
|
||||
throw (InterruptedException) e;
|
||||
}
|
||||
|
@ -595,13 +612,9 @@ public class SmackIntegrationTestFramework {
|
|||
private final List<SuccessfulTest> successfulIntegrationTests = Collections.synchronizedList(new LinkedList<SuccessfulTest>());
|
||||
private final List<FailedTest> failedIntegrationTests = Collections.synchronizedList(new LinkedList<FailedTest>());
|
||||
private final List<TestNotPossible> impossibleIntegrationTests = Collections.synchronizedList(new LinkedList<TestNotPossible>());
|
||||
|
||||
// TODO: Ideally three would only be a list of disabledTests, but since we do not process a disabled test class
|
||||
// any further, we can not determine the concrete disabled tests.
|
||||
private final List<DisabledTestClass> disabledTestClasses = Collections.synchronizedList(new ArrayList<>());
|
||||
private final List<DisabledTest> disabledTests = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
private final Map<Class<? extends AbstractSmackIntTest>, Throwable> impossibleTestClasses = new HashMap<>();
|
||||
private final AtomicInteger numberOfAvailableTestMethods = new AtomicInteger();
|
||||
private final AtomicInteger numberOfPossibleTestMethods = new AtomicInteger();
|
||||
|
||||
TestRunResult() {
|
||||
}
|
||||
|
@ -611,7 +624,11 @@ public class SmackIntegrationTestFramework {
|
|||
}
|
||||
|
||||
public int getNumberOfAvailableTests() {
|
||||
return successfulIntegrationTests.size() + failedIntegrationTests.size() + impossibleIntegrationTests.size();
|
||||
return numberOfAvailableTestMethods.get();
|
||||
}
|
||||
|
||||
public int getNumberOfPossibleTests() {
|
||||
return numberOfPossibleTestMethods.get();
|
||||
}
|
||||
|
||||
public List<SuccessfulTest> getSuccessfulTests() {
|
||||
|
@ -631,77 +648,6 @@ public class SmackIntegrationTestFramework {
|
|||
}
|
||||
}
|
||||
|
||||
final class PreparedTest {
|
||||
private final AbstractSmackIntTest test;
|
||||
private final List<ConcreteTest> concreteTests;
|
||||
|
||||
private final Method beforeClassMethod;
|
||||
private final Method afterClassMethod;
|
||||
|
||||
private PreparedTest(AbstractSmackIntTest test, List<ConcreteTest> concreteTests) {
|
||||
this.test = test;
|
||||
this.concreteTests = concreteTests;
|
||||
Class<? extends AbstractSmackIntTest> testClass = test.getClass();
|
||||
|
||||
beforeClassMethod = getSinttestSpecialMethod(testClass, BeforeClass.class);
|
||||
afterClassMethod = getSinttestSpecialMethod(testClass, AfterClass.class);
|
||||
}
|
||||
|
||||
public void run() throws InterruptedException, XMPPException, IOException, SmackException {
|
||||
try {
|
||||
// Run the @BeforeClass methods (if any)
|
||||
executeSinttestSpecialMethod(beforeClassMethod);
|
||||
|
||||
for (ConcreteTest concreteTest : concreteTests) {
|
||||
runConcreteTest(concreteTest);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
executeSinttestSpecialMethod(afterClassMethod);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeSinttestSpecialMethod(Method method) {
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
method.invoke(test);
|
||||
}
|
||||
catch (InvocationTargetException | IllegalAccessException e) {
|
||||
LOGGER.log(Level.SEVERE, "Exception executing " + method, e);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Method getSinttestSpecialMethod(Class<? extends AbstractSmackIntTest> testClass, Class<? extends Annotation> annotation) {
|
||||
Set<Method> specialClassMethods = getAllMethods(testClass,
|
||||
withAnnotation(annotation), withReturnType(Void.TYPE),
|
||||
withParametersCount(0), withModifier(Modifier.PUBLIC
|
||||
));
|
||||
|
||||
// See if there are any methods that have a special but a wrong signature
|
||||
Set<Method> allSpecialClassMethods = getAllMethods(testClass, withAnnotation(annotation));
|
||||
allSpecialClassMethods.removeAll(specialClassMethods);
|
||||
if (!allSpecialClassMethods.isEmpty()) {
|
||||
throw new IllegalArgumentException(annotation + " methods with wrong signature found");
|
||||
}
|
||||
|
||||
if (specialClassMethods.size() == 1) {
|
||||
return specialClassMethods.iterator().next();
|
||||
}
|
||||
else if (specialClassMethods.size() > 1) {
|
||||
throw new IllegalArgumentException("Only one @BeforeClass method allowed");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static final class ConcreteTest {
|
||||
private final TestType testType;
|
||||
private final Method method;
|
||||
|
@ -729,8 +675,13 @@ public class SmackIntegrationTestFramework {
|
|||
.append(method.getName())
|
||||
.append(" (")
|
||||
.append(testType.name());
|
||||
sb.append(", ");
|
||||
StringUtils.appendTo(Arrays.asList(subdescriptons), sb);
|
||||
final String SUBDESCRIPTION_DELIMITER = ", ";
|
||||
sb.append(SUBDESCRIPTION_DELIMITER);
|
||||
|
||||
for (String subdescripton : subdescriptons) {
|
||||
sb.append(subdescripton).append(SUBDESCRIPTION_DELIMITER);
|
||||
}
|
||||
sb.setLength(sb.length() - SUBDESCRIPTION_DELIMITER.length());
|
||||
sb.append(')');
|
||||
|
||||
stringCache = sb.toString();
|
||||
|
@ -754,50 +705,6 @@ public class SmackIntegrationTestFramework {
|
|||
}
|
||||
}
|
||||
|
||||
public static final class DisabledTestClass {
|
||||
private final Class<? extends AbstractSmackIntTest> testClass;
|
||||
private final String reason;
|
||||
|
||||
private DisabledTestClass(Class<? extends AbstractSmackIntTest> testClass, String reason) {
|
||||
this.testClass = testClass;
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
public Class<? extends AbstractSmackIntTest> getTestClass() {
|
||||
return testClass;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public StringBuilder appendTo(StringBuilder sb) {
|
||||
return sb.append("Disabled ").append(testClass).append(" because ").append(reason);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class DisabledTest {
|
||||
private final Method method;
|
||||
private final String reason;
|
||||
|
||||
private DisabledTest(Method method, String reason) {
|
||||
this.method = method;
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public StringBuilder appendTo(StringBuilder sb) {
|
||||
return sb.append("Disabled ").append(method).append(" because ").append(reason);
|
||||
}
|
||||
}
|
||||
|
||||
private final class LowLevelTestMethod {
|
||||
private final Method testMethod;
|
||||
private final SmackIntegrationTest smackIntegrationTestAnnotation;
|
||||
|
@ -811,7 +718,6 @@ public class SmackIntegrationTestFramework {
|
|||
parameterListOfConnections = testMethodParametersIsListOfConnections(testMethod);
|
||||
}
|
||||
|
||||
// TODO: The second parameter should probably be a connection descriptor?
|
||||
private void invoke(AbstractSmackLowLevelIntegrationTest test,
|
||||
Class<? extends AbstractXMPPConnection> connectionClass)
|
||||
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException,
|
||||
|
@ -840,11 +746,6 @@ public class SmackIntegrationTestFramework {
|
|||
testMethod.invoke(test, connectionsArray);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return testMethod.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean testMethodParametersIsListOfConnections(Method testMethod) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018-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.
|
||||
|
@ -29,13 +29,8 @@ import java.util.List;
|
|||
import org.jivesoftware.smack.AbstractXMPPConnection;
|
||||
import org.jivesoftware.smack.ConnectionConfiguration;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.util.Consumer;
|
||||
|
||||
public final class XmppConnectionDescriptor<
|
||||
C extends AbstractXMPPConnection,
|
||||
CC extends ConnectionConfiguration,
|
||||
CCB extends ConnectionConfiguration.Builder<?, CC>
|
||||
> {
|
||||
public class XmppConnectionDescriptor<C extends AbstractXMPPConnection, CC extends ConnectionConfiguration, CCB extends ConnectionConfiguration.Builder<?, CC>> {
|
||||
|
||||
private final Class<C> connectionClass;
|
||||
private final Class<CC> connectionConfigurationClass;
|
||||
|
@ -43,18 +38,13 @@ public final class XmppConnectionDescriptor<
|
|||
private final Constructor<C> connectionConstructor;
|
||||
private final Method builderMethod;
|
||||
|
||||
private final Consumer<CCB> extraBuilder;
|
||||
public XmppConnectionDescriptor(Class<C> connectionClass, Class<CC> connectionConfigurationClass)
|
||||
throws ClassNotFoundException, NoSuchMethodException, SecurityException {
|
||||
this.connectionClass = connectionClass;
|
||||
this.connectionConfigurationClass = connectionConfigurationClass;
|
||||
|
||||
private final String nickname;
|
||||
|
||||
private XmppConnectionDescriptor(Builder<C, CC, CCB> builder) throws NoSuchMethodException, SecurityException {
|
||||
connectionClass = builder.connectionClass;
|
||||
connectionConfigurationClass = builder.connectionConfigurationClass;
|
||||
extraBuilder = builder.extraBuilder;
|
||||
nickname = builder.nickname;
|
||||
|
||||
connectionConstructor = getConstructor(connectionClass, connectionConfigurationClass);
|
||||
builderMethod = getBuilderMethod(connectionConfigurationClass);
|
||||
this.connectionConstructor = getConstructor(connectionClass, connectionConfigurationClass);
|
||||
this.builderMethod = getBuilderMethod(connectionConfigurationClass);
|
||||
}
|
||||
|
||||
public C construct(Configuration sinttestConfiguration)
|
||||
|
@ -75,9 +65,6 @@ public final class XmppConnectionDescriptor<
|
|||
Collection<ConnectionConfigurationBuilderApplier> customConnectionConfigurationAppliers)
|
||||
throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||
CCB connectionConfigurationBuilder = getNewBuilder();
|
||||
if (extraBuilder != null) {
|
||||
extraBuilder.accept(connectionConfigurationBuilder);
|
||||
}
|
||||
for (ConnectionConfigurationBuilderApplier customConnectionConfigurationApplier : customConnectionConfigurationAppliers) {
|
||||
customConnectionConfigurationApplier.applyConfigurationTo(connectionConfigurationBuilder);
|
||||
}
|
||||
|
@ -101,10 +88,6 @@ public final class XmppConnectionDescriptor<
|
|||
return connectionClass;
|
||||
}
|
||||
|
||||
public String getNickname() {
|
||||
return nickname;
|
||||
}
|
||||
|
||||
private static <C extends XMPPConnection> Constructor<C> getConstructor(Class<C> connectionClass,
|
||||
Class<? extends ConnectionConfiguration> connectionConfigurationClass)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
|
@ -123,47 +106,4 @@ public final class XmppConnectionDescriptor<
|
|||
}
|
||||
return builderMethod;
|
||||
}
|
||||
|
||||
public static <C extends AbstractXMPPConnection, CC extends ConnectionConfiguration, CCB extends ConnectionConfiguration.Builder<?, CC>>
|
||||
Builder<C, CC, CCB> buildWith(Class<C> connectionClass, Class<CC> connectionConfigurationClass) {
|
||||
return buildWith(connectionClass, connectionConfigurationClass, null);
|
||||
}
|
||||
|
||||
public static <C extends AbstractXMPPConnection, CC extends ConnectionConfiguration, CCB extends ConnectionConfiguration.Builder<?, CC>>
|
||||
Builder<C, CC, CCB> buildWith(Class<C> connectionClass, Class<CC> connectionConfigurationClass, Class<CCB> connectionConfigurationBuilderClass) {
|
||||
return new Builder<>(connectionClass, connectionConfigurationClass, connectionConfigurationBuilderClass);
|
||||
}
|
||||
|
||||
public static final class Builder<C extends AbstractXMPPConnection, CC extends ConnectionConfiguration, CCB extends ConnectionConfiguration.Builder<?, CC>> {
|
||||
private final Class<C> connectionClass;
|
||||
private final Class<CC> connectionConfigurationClass;
|
||||
|
||||
private Consumer<CCB> extraBuilder;
|
||||
|
||||
private String nickname;
|
||||
|
||||
// The connectionConfigurationBuilderClass merely exists for type-checking purposes.
|
||||
@SuppressWarnings("UnusedVariable")
|
||||
private Builder(Class<C> connectionClass, Class<CC> connectionConfigurationClass,
|
||||
Class<CCB> connectionConfigurationBuilderClass) {
|
||||
this.connectionClass = connectionClass;
|
||||
this.connectionConfigurationClass = connectionConfigurationClass;
|
||||
|
||||
nickname = connectionClass.getSimpleName();
|
||||
}
|
||||
|
||||
public Builder<C, CC, CCB> applyExtraConfguration(Consumer<CCB> extraBuilder) {
|
||||
this.extraBuilder = extraBuilder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<C, CC, CCB> withNickname(String nickname) {
|
||||
this.nickname = nickname;
|
||||
return this;
|
||||
}
|
||||
|
||||
public XmppConnectionDescriptor<C, CC, CCB> build() throws NoSuchMethodException, SecurityException {
|
||||
return new XmppConnectionDescriptor<>(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018-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.
|
||||
|
@ -27,6 +27,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -37,11 +38,9 @@ import org.jivesoftware.smack.SmackException.NoResponseException;
|
|||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionConfiguration;
|
||||
import org.jivesoftware.smack.compression.CompressionModuleDescriptor;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
||||
import org.jivesoftware.smack.tcp.XmppNioTcpConnection;
|
||||
import org.jivesoftware.smack.util.MultiMap;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
|
||||
|
@ -55,92 +54,55 @@ import org.jxmpp.jid.impl.JidCreate;
|
|||
import org.jxmpp.jid.parts.Localpart;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
|
||||
public class XmppConnectionManager {
|
||||
public class XmppConnectionManager<DC extends AbstractXMPPConnection> {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(XmppConnectionManager.class.getName());
|
||||
|
||||
private static final XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> DEFAULT_CONNECTION_DESCRIPTOR;
|
||||
|
||||
private static final Map<String, XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>> NICKNAME_CONNECTION_DESCRIPTORS = new HashMap<>();
|
||||
|
||||
private static final MultiMap<
|
||||
Class<? extends AbstractXMPPConnection>,
|
||||
XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>
|
||||
> CONNECTION_DESCRIPTORS = new MultiMap<>();
|
||||
private static final Map<Class<? extends AbstractXMPPConnection>, XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>> CONNECTION_DESCRIPTORS = new ConcurrentHashMap<>();
|
||||
|
||||
static {
|
||||
try {
|
||||
DEFAULT_CONNECTION_DESCRIPTOR = XmppConnectionDescriptor.buildWith(XMPPTCPConnection.class, XMPPTCPConnectionConfiguration.class)
|
||||
.withNickname("tcp")
|
||||
.build();
|
||||
addConnectionDescriptor(DEFAULT_CONNECTION_DESCRIPTOR);
|
||||
|
||||
addConnectionDescriptor(
|
||||
XmppConnectionDescriptor.buildWith(ModularXmppClientToServerConnection.class, ModularXmppClientToServerConnectionConfiguration.class)
|
||||
.withNickname("modular")
|
||||
.build()
|
||||
);
|
||||
addConnectionDescriptor(
|
||||
XmppConnectionDescriptor.buildWith(ModularXmppClientToServerConnection.class, ModularXmppClientToServerConnectionConfiguration.class, ModularXmppClientToServerConnectionConfiguration.Builder.class)
|
||||
.withNickname("modular-nocompress")
|
||||
.applyExtraConfguration(cb -> cb.removeModule(CompressionModuleDescriptor.class))
|
||||
.build()
|
||||
);
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
addConnectionDescriptor(XmppNioTcpConnection.class, XMPPTCPConnectionConfiguration.class);
|
||||
addConnectionDescriptor(XMPPTCPConnection.class, XMPPTCPConnectionConfiguration.class);
|
||||
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean addConnectionDescriptor(
|
||||
public static void addConnectionDescriptor(Class<? extends AbstractXMPPConnection> connectionClass,
|
||||
Class<? extends ConnectionConfiguration> connectionConfigurationClass) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
|
||||
XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor = new XmppConnectionDescriptor<>(
|
||||
connectionClass, connectionConfigurationClass);
|
||||
addConnectionDescriptor(connectionDescriptor);
|
||||
}
|
||||
|
||||
public static void addConnectionDescriptor(
|
||||
XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor) {
|
||||
String nickname = connectionDescriptor.getNickname();
|
||||
Class<? extends AbstractXMPPConnection> connectionClass = connectionDescriptor.getConnectionClass();
|
||||
|
||||
boolean alreadyExisted;
|
||||
synchronized (CONNECTION_DESCRIPTORS) {
|
||||
alreadyExisted = removeConnectionDescriptor(nickname);
|
||||
|
||||
CONNECTION_DESCRIPTORS.put(connectionClass, connectionDescriptor);
|
||||
NICKNAME_CONNECTION_DESCRIPTORS.put(connectionDescriptor.getNickname(), connectionDescriptor);
|
||||
}
|
||||
return alreadyExisted;
|
||||
CONNECTION_DESCRIPTORS.put(connectionClass, connectionDescriptor);
|
||||
}
|
||||
|
||||
public static boolean removeConnectionDescriptor(String nickname) {
|
||||
synchronized (CONNECTION_DESCRIPTORS) {
|
||||
XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor = NICKNAME_CONNECTION_DESCRIPTORS.remove(nickname);
|
||||
if (connectionDescriptor == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean removed = CONNECTION_DESCRIPTORS.removeOne(connectionDescriptor.getConnectionClass(), connectionDescriptor);
|
||||
assert removed;
|
||||
}
|
||||
|
||||
return true;
|
||||
public static void removeConnectionDescriptor(Class<? extends AbstractXMPPConnection> connectionClass) {
|
||||
CONNECTION_DESCRIPTORS.remove(connectionClass);
|
||||
}
|
||||
|
||||
private final XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> defaultConnectionDescriptor;
|
||||
private final XmppConnectionDescriptor<DC, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> defaultConnectionDescriptor;
|
||||
|
||||
private final Map<String, XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>> nicknameConnectionDescriptors;
|
||||
private final Map<Class<? extends AbstractXMPPConnection>, XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>> connectionDescriptors = new HashMap<>(
|
||||
CONNECTION_DESCRIPTORS.size());
|
||||
|
||||
private final MultiMap<
|
||||
Class<? extends AbstractXMPPConnection>,
|
||||
XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>
|
||||
> connectionDescriptors;
|
||||
|
||||
private final SmackIntegrationTestFramework sinttestFramework;
|
||||
private final SmackIntegrationTestFramework<?> sinttestFramework;
|
||||
private final Configuration sinttestConfiguration;
|
||||
private final String testRunId;
|
||||
|
||||
private final AbstractXMPPConnection accountRegistrationConnection;
|
||||
private final DC accountRegistrationConnection;
|
||||
private final ServiceAdministrationManager adminManager;
|
||||
private final AccountManager accountManager;
|
||||
|
||||
/**
|
||||
* One of the three main connections. The type of the main connections is the default connection type.
|
||||
*/
|
||||
AbstractXMPPConnection conOne, conTwo, conThree;
|
||||
DC conOne, conTwo, conThree;
|
||||
|
||||
/**
|
||||
* A pool of authenticated and free to use connections.
|
||||
|
@ -152,25 +114,20 @@ public class XmppConnectionManager {
|
|||
*/
|
||||
private final List<AbstractXMPPConnection> connections = new ArrayList<>();
|
||||
|
||||
XmppConnectionManager(SmackIntegrationTestFramework sinttestFramework)
|
||||
@SuppressWarnings("unchecked")
|
||||
XmppConnectionManager(SmackIntegrationTestFramework<?> sinttestFramework,
|
||||
Class<? extends DC> defaultConnectionClass)
|
||||
throws SmackException, IOException, XMPPException, InterruptedException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||
synchronized (CONNECTION_DESCRIPTORS) {
|
||||
connectionDescriptors = CONNECTION_DESCRIPTORS.clone();
|
||||
nicknameConnectionDescriptors = new HashMap<>(NICKNAME_CONNECTION_DESCRIPTORS);
|
||||
}
|
||||
|
||||
this.sinttestFramework = sinttestFramework;
|
||||
this.sinttestConfiguration = sinttestFramework.config;
|
||||
this.testRunId = sinttestFramework.testRunResult.testRunId;
|
||||
|
||||
String configuredDefaultConnectionNickname = sinttestConfiguration.defaultConnectionNickname;
|
||||
if (configuredDefaultConnectionNickname != null) {
|
||||
defaultConnectionDescriptor = nicknameConnectionDescriptors.get(configuredDefaultConnectionNickname);
|
||||
if (defaultConnectionDescriptor == null) {
|
||||
throw new IllegalArgumentException("Could not find a connection descriptor for connection nickname '" + configuredDefaultConnectionNickname + "'");
|
||||
}
|
||||
} else {
|
||||
defaultConnectionDescriptor = DEFAULT_CONNECTION_DESCRIPTOR;
|
||||
connectionDescriptors.putAll(CONNECTION_DESCRIPTORS);
|
||||
|
||||
defaultConnectionDescriptor = (XmppConnectionDescriptor<DC, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>) connectionDescriptors.get(
|
||||
defaultConnectionClass);
|
||||
if (defaultConnectionDescriptor == null) {
|
||||
throw new IllegalArgumentException("Could not find a connection descriptor for " + defaultConnectionClass);
|
||||
}
|
||||
|
||||
switch (sinttestConfiguration.accountRegistration) {
|
||||
|
@ -200,11 +157,11 @@ public class XmppConnectionManager {
|
|||
}
|
||||
}
|
||||
|
||||
SmackIntegrationTestEnvironment prepareEnvironment() throws KeyManagementException, NoSuchAlgorithmException,
|
||||
SmackIntegrationTestEnvironment<DC> prepareEnvironment() throws KeyManagementException, NoSuchAlgorithmException,
|
||||
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
|
||||
SmackException, IOException, XMPPException, InterruptedException {
|
||||
prepareMainConnections();
|
||||
return new SmackIntegrationTestEnvironment(conOne, conTwo, conThree,
|
||||
return new SmackIntegrationTestEnvironment<DC>(conOne, conTwo, conThree,
|
||||
sinttestFramework.testRunResult.testRunId, sinttestConfiguration, this);
|
||||
}
|
||||
|
||||
|
@ -212,9 +169,9 @@ public class XmppConnectionManager {
|
|||
IllegalAccessException, IllegalArgumentException, InvocationTargetException, SmackException, IOException,
|
||||
XMPPException, InterruptedException {
|
||||
final int mainAccountCount = AccountNum.values().length;
|
||||
List<AbstractXMPPConnection> connections = new ArrayList<>(mainAccountCount);
|
||||
List<DC> connections = new ArrayList<>(mainAccountCount);
|
||||
for (AccountNum mainAccountNum : AccountNum.values()) {
|
||||
AbstractXMPPConnection mainConnection = getConnectedMainConnectionFor(mainAccountNum);
|
||||
DC mainConnection = getConnectedMainConnectionFor(mainAccountNum);
|
||||
connections.add(mainConnection);
|
||||
}
|
||||
conOne = connections.get(0);
|
||||
|
@ -222,18 +179,18 @@ public class XmppConnectionManager {
|
|||
conThree = connections.get(2);
|
||||
}
|
||||
|
||||
public XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> getDefaultConnectionDescriptor() {
|
||||
return defaultConnectionDescriptor;
|
||||
public Class<? extends AbstractXMPPConnection> getDefaultConnectionClass() {
|
||||
return defaultConnectionDescriptor.getConnectionClass();
|
||||
}
|
||||
|
||||
public Collection<XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>> getConnectionDescriptors() {
|
||||
return Collections.unmodifiableCollection(nicknameConnectionDescriptors.values());
|
||||
public Set<Class<? extends AbstractXMPPConnection>> getConnectionClasses() {
|
||||
return Collections.unmodifiableSet(connectionDescriptors.keySet());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends AbstractXMPPConnection> XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> getConnectionDescriptorFor(
|
||||
Class<C> connectionClass) {
|
||||
return (XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>) connectionDescriptors.getFirst(
|
||||
return (XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>) connectionDescriptors.get(
|
||||
connectionClass);
|
||||
}
|
||||
|
||||
|
@ -292,7 +249,7 @@ public class XmppConnectionManager {
|
|||
|
||||
private static final String USERNAME_PREFIX = "smack-inttest";
|
||||
|
||||
private AbstractXMPPConnection getConnectedMainConnectionFor(AccountNum accountNum) throws SmackException, IOException, XMPPException,
|
||||
private DC getConnectedMainConnectionFor(AccountNum accountNum) throws SmackException, IOException, XMPPException,
|
||||
InterruptedException, KeyManagementException, NoSuchAlgorithmException, InstantiationException,
|
||||
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||
String middlefix;
|
||||
|
@ -326,7 +283,7 @@ public class XmppConnectionManager {
|
|||
registerAccount(finalAccountUsername, finalAccountPassword);
|
||||
}
|
||||
|
||||
AbstractXMPPConnection mainConnection = defaultConnectionDescriptor.construct(sinttestConfiguration, builder -> {
|
||||
DC mainConnection = defaultConnectionDescriptor.construct(sinttestConfiguration, builder -> {
|
||||
try {
|
||||
builder.setUsernameAndPassword(finalAccountUsername, finalAccountPassword)
|
||||
.setResource(middlefix + '-' + testRunId);
|
||||
|
@ -390,7 +347,7 @@ public class XmppConnectionManager {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor = (XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>) connectionDescriptors
|
||||
.getFirst(connectionClass);
|
||||
.get(connectionClass);
|
||||
for (int i = 0; i < count; i++) {
|
||||
C connection = constructConnectedConnection(connectionDescriptor);
|
||||
connections.add(connection);
|
||||
|
@ -410,7 +367,7 @@ public class XmppConnectionManager {
|
|||
return connection;
|
||||
}
|
||||
|
||||
AbstractXMPPConnection constructConnection()
|
||||
DC constructConnection()
|
||||
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
return constructConnection(defaultConnectionDescriptor);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-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.
|
||||
|
@ -51,7 +51,7 @@ public class ChatTest extends AbstractSmackIntegrationTest {
|
|||
private boolean invoked;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public ChatTest(SmackIntegrationTestEnvironment environment) {
|
||||
public ChatTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
chatManagerOne = org.jivesoftware.smack.chat.ChatManager.getInstanceFor(conOne);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-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.
|
||||
|
@ -33,7 +33,7 @@ import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
|||
|
||||
public class LoginIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
||||
|
||||
public LoginIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
public LoginIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-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.
|
||||
|
@ -35,7 +35,7 @@ import org.igniterealtime.smack.inttest.TestNotPossibleException;
|
|||
|
||||
public class StreamManagementTest extends AbstractSmackSpecificLowLevelIntegrationTest<XMPPTCPConnection> {
|
||||
|
||||
public StreamManagementTest(SmackIntegrationTestEnvironment environment) throws Exception {
|
||||
public StreamManagementTest(SmackIntegrationTestEnvironment<?> environment) throws Exception {
|
||||
super(environment, XMPPTCPConnection.class);
|
||||
XMPPTCPConnection connection = getSpecificUnconnectedConnection();
|
||||
connection.connect().login();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-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.
|
||||
|
@ -26,7 +26,7 @@ import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
|||
|
||||
public class WaitForClosingStreamElementTest extends AbstractSmackLowLevelIntegrationTest {
|
||||
|
||||
public WaitForClosingStreamElementTest(SmackIntegrationTestEnvironment environment) {
|
||||
public WaitForClosingStreamElementTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018-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.
|
||||
|
@ -19,7 +19,7 @@ package org.jivesoftware.smack;
|
|||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection;
|
||||
import org.jivesoftware.smack.tcp.XmppNioTcpConnection;
|
||||
|
||||
import org.igniterealtime.smack.XmppConnectionStressTest;
|
||||
import org.igniterealtime.smack.XmppConnectionStressTest.StressTestFailedException.ErrorsWhileSendingOrReceivingException;
|
||||
|
@ -30,7 +30,7 @@ import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
|||
|
||||
public class XmppConnectionIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
||||
|
||||
public XmppConnectionIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
public XmppConnectionIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
|
@ -52,12 +52,12 @@ public class XmppConnectionIntegrationTest extends AbstractSmackLowLevelIntegrat
|
|||
|
||||
final Level connectionStatsLogLevel = Level.FINE;
|
||||
if (LOGGER.isLoggable(connectionStatsLogLevel)) {
|
||||
if (connections.get(0) instanceof ModularXmppClientToServerConnection) {
|
||||
if (connections.get(0) instanceof XmppNioTcpConnection) {
|
||||
for (XMPPConnection connection : connections) {
|
||||
ModularXmppClientToServerConnection xmppC2sConnection = (ModularXmppClientToServerConnection) connection;
|
||||
ModularXmppClientToServerConnection.Stats stats = xmppC2sConnection.getStats();
|
||||
XmppNioTcpConnection xmppNioTcpConnection = (XmppNioTcpConnection) connection;
|
||||
XmppNioTcpConnection.Stats stats = xmppNioTcpConnection.getStats();
|
||||
LOGGER.log(connectionStatsLogLevel,
|
||||
"Connections stats for " + xmppC2sConnection + ":\n{}",
|
||||
"Connections stats for " + xmppNioTcpConnection + ":\n{}",
|
||||
stats);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -25,7 +25,7 @@ public abstract class AbstractChatIntegrationTest extends AbstractSmackIntegrati
|
|||
protected final ChatManager chatManagerTwo;
|
||||
protected final ChatManager chatManagerThree;
|
||||
|
||||
protected AbstractChatIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
protected AbstractChatIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
chatManagerOne = ChatManager.getInstanceFor(conOne);
|
||||
chatManagerTwo = ChatManager.getInstanceFor(conTwo);
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.jxmpp.jid.EntityBareJid;
|
|||
|
||||
public class IncomingMessageListenerIntegrationTest extends AbstractChatIntegrationTest {
|
||||
|
||||
public IncomingMessageListenerIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
public IncomingMessageListenerIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.jxmpp.jid.EntityBareJid;
|
|||
|
||||
public class OutgoingMessageListenerIntegrationTest extends AbstractChatIntegrationTest {
|
||||
|
||||
public OutgoingMessageListenerIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
public OutgoingMessageListenerIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016-2020 Florian Schmaus
|
||||
* Copyright 2016-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.
|
||||
|
@ -30,7 +30,7 @@ import org.jxmpp.jid.FullJid;
|
|||
|
||||
public class LowLevelRosterIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
||||
|
||||
public LowLevelRosterIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
public LowLevelRosterIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-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.
|
||||
|
@ -38,7 +38,7 @@ public class RosterIntegrationTest extends AbstractSmackIntegrationTest {
|
|||
private final Roster rosterOne;
|
||||
private final Roster rosterTwo;
|
||||
|
||||
public RosterIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
public RosterIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
rosterOne = Roster.getInstanceFor(conOne);
|
||||
rosterTwo = Roster.getInstanceFor(conTwo);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018-2020 Florian Schmaus
|
||||
* Copyright 2018-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.
|
||||
|
@ -22,22 +22,21 @@ import java.security.NoSuchAlgorithmException;
|
|||
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection;
|
||||
|
||||
import org.igniterealtime.smack.inttest.AbstractSmackSpecificLowLevelIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||
|
||||
public class XmppNioTcpConnectionLowLevelIntegrationTest extends AbstractSmackSpecificLowLevelIntegrationTest<ModularXmppClientToServerConnection> {
|
||||
public class XmppNioTcpConnectionLowLevelIntegrationTest extends AbstractSmackSpecificLowLevelIntegrationTest<XmppNioTcpConnection> {
|
||||
|
||||
public XmppNioTcpConnectionLowLevelIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
super(environment, ModularXmppClientToServerConnection.class);
|
||||
public XmppNioTcpConnectionLowLevelIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment, XmppNioTcpConnection.class);
|
||||
}
|
||||
|
||||
@SmackIntegrationTest
|
||||
public void testDisconnectAfterConnect() throws KeyManagementException, NoSuchAlgorithmException, SmackException,
|
||||
IOException, XMPPException, InterruptedException {
|
||||
ModularXmppClientToServerConnection connection = getSpecificUnconnectedConnection();
|
||||
XmppNioTcpConnection connection = getSpecificUnconnectedConnection();
|
||||
|
||||
connection.connect();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2013-2020 Florian Schmaus
|
||||
* Copyright 2013-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.
|
||||
|
@ -57,7 +57,7 @@ public class EntityCapsTest extends AbstractSmackIntegrationTest {
|
|||
private final ServiceDiscoveryManager sdmOne;
|
||||
private final ServiceDiscoveryManager sdmTwo;
|
||||
|
||||
public EntityCapsTest(SmackIntegrationTestEnvironment environment) {
|
||||
public EntityCapsTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
ecmTwo = EntityCapsManager.getInstanceFor(environment.conTwo);
|
||||
sdmOne = ServiceDiscoveryManager.getInstanceFor(environment.conOne);
|
||||
|
|
|
@ -55,7 +55,7 @@ public class ChatStateIntegrationTest extends AbstractSmackIntegrationTest {
|
|||
};
|
||||
|
||||
|
||||
public ChatStateIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
public ChatStateIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-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.
|
||||
|
@ -39,7 +39,7 @@ public class FileTransferIntegrationTest extends AbstractSmackIntegrationTest {
|
|||
private final FileTransferManager ftManagerOne;
|
||||
private final FileTransferManager ftManagerTwo;
|
||||
|
||||
public FileTransferIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
public FileTransferIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
ftManagerOne = FileTransferManager.getInstanceFor(conOne);
|
||||
ftManagerTwo = FileTransferManager.getInstanceFor(conTwo);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017-2020 Florian Schmaus
|
||||
* Copyright 2017-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.
|
||||
|
@ -43,7 +43,7 @@ public class HttpFileUploadIntegrationTest extends AbstractSmackIntegrationTest
|
|||
|
||||
private final HttpFileUploadManager hfumOne;
|
||||
|
||||
public HttpFileUploadIntegrationTest(SmackIntegrationTestEnvironment environment) throws XMPPErrorException,
|
||||
public HttpFileUploadIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws XMPPErrorException,
|
||||
NotConnectedException, NoResponseException, InterruptedException, TestNotPossibleException {
|
||||
super(environment);
|
||||
hfumOne = HttpFileUploadManager.getInstanceFor(conOne);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016-2020 Florian Schmaus
|
||||
* Copyright 2016-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.
|
||||
|
@ -43,7 +43,7 @@ public class IoTControlIntegrationTest extends AbstractSmackIntegrationTest {
|
|||
|
||||
private final IoTControlManager IoTControlManagerTwo;
|
||||
|
||||
public IoTControlIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
public IoTControlIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
IoTControlManagerOne = IoTControlManager.getInstanceFor(conOne);
|
||||
IoTControlManagerTwo = IoTControlManager.getInstanceFor(conTwo);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016-2020 Florian Schmaus
|
||||
* Copyright 2016-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.
|
||||
|
@ -45,7 +45,7 @@ public class IoTDataIntegrationTest extends AbstractSmackIntegrationTest {
|
|||
|
||||
private final IoTDataManager iotDataManagerTwo;
|
||||
|
||||
public IoTDataIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
public IoTDataIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
iotDataManagerOne = IoTDataManager.getInstanceFor(conOne);
|
||||
iotDataManagerTwo = IoTDataManager.getInstanceFor(conTwo);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016-2020 Florian Schmaus
|
||||
* Copyright 2016-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.
|
||||
|
@ -41,7 +41,7 @@ public class IoTDiscoveryIntegrationTest extends AbstractSmackIntegrationTest {
|
|||
private final IoTDiscoveryManager discoveryManagerOne;
|
||||
private final IoTDiscoveryManager discoveryManagerTwo;
|
||||
|
||||
public IoTDiscoveryIntegrationTest(SmackIntegrationTestEnvironment environment) throws NoResponseException,
|
||||
public IoTDiscoveryIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws NoResponseException,
|
||||
XMPPErrorException, NotConnectedException, InterruptedException, TestNotPossibleException {
|
||||
super(environment);
|
||||
discoveryManagerOne = IoTDiscoveryManager.getInstanceFor(conOne);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-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.
|
||||
|
@ -31,7 +31,7 @@ import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
|||
|
||||
public class VersionIntegrationTest extends AbstractSmackIntegrationTest {
|
||||
|
||||
public VersionIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
public VersionIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016 Fernando Ramirez, 2018-2020 Florian Schmaus
|
||||
* Copyright 2016 Fernando Ramirez, 2018-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.
|
||||
|
@ -48,7 +48,7 @@ public class MamIntegrationTest extends AbstractSmackIntegrationTest {
|
|||
|
||||
private final MamManager mamManagerConTwo;
|
||||
|
||||
public MamIntegrationTest(SmackIntegrationTestEnvironment environment) throws NoResponseException,
|
||||
public MamIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws NoResponseException,
|
||||
XMPPErrorException, NotConnectedException, InterruptedException, TestNotPossibleException, NotLoggedInException {
|
||||
super(environment);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub, 2019-2020 Florian Schmaus.
|
||||
* Copyright 2018 Paul Schaub, 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.
|
||||
|
@ -31,7 +31,7 @@ public class MoodIntegrationTest extends AbstractSmackIntegrationTest {
|
|||
private final MoodManager mm1;
|
||||
private final MoodManager mm2;
|
||||
|
||||
public MoodIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||
public MoodIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
||||
super(environment);
|
||||
mm1 = MoodManager.getInstanceFor(conOne);
|
||||
mm2 = MoodManager.getInstanceFor(conTwo);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-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.
|
||||
|
@ -54,7 +54,7 @@ public class MultiUserChatIntegrationTest extends AbstractSmackIntegrationTest {
|
|||
private final MultiUserChatManager mucManagerTwo;
|
||||
private final DomainBareJid mucService;
|
||||
|
||||
public MultiUserChatIntegrationTest(SmackIntegrationTestEnvironment environment)
|
||||
public MultiUserChatIntegrationTest(SmackIntegrationTestEnvironment<?> environment)
|
||||
throws NoResponseException, XMPPErrorException, NotConnectedException,
|
||||
InterruptedException, TestNotPossibleException {
|
||||
super(environment);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
* Copyright 2015-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.
|
||||
|
@ -40,7 +40,7 @@ import org.jxmpp.jid.parts.Resourcepart;
|
|||
|
||||
public class MultiUserChatLowLevelIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
||||
|
||||
public MultiUserChatLowLevelIntegrationTest(SmackIntegrationTestEnvironment environment) throws Exception {
|
||||
public MultiUserChatLowLevelIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws Exception {
|
||||
super(environment);
|
||||
AbstractXMPPConnection connection = getConnectedConnection();
|
||||
try {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue