mirror of
https://github.com/vanitasvitae/Smack.git
synced 2025-09-11 10:09:38 +02:00
Compare commits
7 commits
4dd3800d82
...
12e20c2d6c
Author | SHA1 | Date | |
---|---|---|---|
|
12e20c2d6c | ||
|
0cbbac90bc | ||
|
6029ba875b | ||
e35bdb1da2 | |||
3fb4438566 | |||
|
cc636fff21 | ||
|
cec312fe64 |
153 changed files with 7397 additions and 4703 deletions
|
@ -18,7 +18,7 @@ Getting started
|
||||||
|
|
||||||
Start with having a look at the **[Documentation]** and the **[Javadoc]**.
|
Start with having a look at the **[Documentation]** and the **[Javadoc]**.
|
||||||
|
|
||||||
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).
|
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).
|
||||||
|
|
||||||
Professional Services
|
Professional Services
|
||||||
---------------------
|
---------------------
|
||||||
|
|
60
build.gradle
60
build.gradle
|
@ -14,6 +14,8 @@ buildscript {
|
||||||
plugins {
|
plugins {
|
||||||
id 'ru.vyarus.animalsniffer' version '1.5.0'
|
id 'ru.vyarus.animalsniffer' version '1.5.0'
|
||||||
id 'net.ltgt.errorprone' version '1.1.1'
|
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'
|
apply plugin: 'org.kordamp.gradle.markdown'
|
||||||
|
@ -288,14 +290,7 @@ configure (junit4Projects) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task copyAllJavadocDocFiles(type: Copy) {
|
task javadocAll(type: Javadoc) {
|
||||||
from javadocAllProjects.collect { project ->
|
|
||||||
"${project.projectDir}/src/javadoc" }
|
|
||||||
into javadocAllDir
|
|
||||||
include '**/doc-files/*.*'
|
|
||||||
}
|
|
||||||
|
|
||||||
task javadocAll(type: Javadoc, dependsOn: copyAllJavadocDocFiles) {
|
|
||||||
source javadocAllProjects.collect {project ->
|
source javadocAllProjects.collect {project ->
|
||||||
project.sourceSets.main.allJava.findAll {
|
project.sourceSets.main.allJava.findAll {
|
||||||
// Filter out symbolic links to avoid
|
// Filter out symbolic links to avoid
|
||||||
|
@ -325,6 +320,25 @@ task javadocAll(type: Javadoc, dependsOn: copyAllJavadocDocFiles) {
|
||||||
] as String[]
|
] as String[]
|
||||||
overview = "$projectDir/resources/javadoc-overview.html"
|
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
|
import org.apache.tools.ant.filters.ReplaceTokens
|
||||||
|
@ -494,31 +508,25 @@ subprojects {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Work around https://github.com/gradle/gradle/issues/4046
|
// Work around https://github.com/gradle/gradle/issues/4046
|
||||||
javadoc.dependsOn('copyJavadocDocFiles')
|
|
||||||
task copyJavadocDocFiles(type: Copy) {
|
task copyJavadocDocFiles(type: Copy) {
|
||||||
from('src/javadoc')
|
from('src/javadoc')
|
||||||
into 'build/docs/javadoc'
|
into 'build/docs/javadoc'
|
||||||
include '**/doc-files/*.*'
|
include '**/doc-files/*.*'
|
||||||
}
|
}
|
||||||
|
javadoc.dependsOn copyJavadocDocFiles
|
||||||
|
|
||||||
// If this subproject has a Makefile then make copyJavadocDocFiles
|
// Make sure root projects 'javadocAll' depends on the
|
||||||
// and the root project's javadocAll task dependend on
|
// subproject's javadoc, to ensure that all all doc-files/ are
|
||||||
// generateFiles.
|
// generated and up-to-date. Obviously this means that the
|
||||||
if (file("$projectDir/Makefile").exists()) {
|
// javadocAll task will also create the individual javadoc's of the
|
||||||
copyJavadocDocFiles.dependsOn('generateFiles')
|
// subprojects.
|
||||||
rootProject.copyAllJavadocDocFiles.dependsOn("${project.name}:generateFiles")
|
javadocAll.dependsOn javadoc
|
||||||
task generateFiles(type: Exec) {
|
}
|
||||||
workingDir projectDir
|
|
||||||
commandLine 'make'
|
|
||||||
}
|
|
||||||
|
|
||||||
clean.dependsOn('cleanGeneratedFiles')
|
// The smack-java8-full project generates the dot and png files of the
|
||||||
rootProject.clean.dependsOn("${project.name}:cleanGeneratedFiles")
|
// current state graph. Ensure they are generated before copied.
|
||||||
task cleanGeneratedFiles(type: Exec) {
|
configure (project(':smack-java8-full')) {
|
||||||
workingDir projectDir
|
copyJavadocDocFiles.dependsOn convertModularXmppClientToServerConnectionStateGraphDotToPng
|
||||||
commandLine 'make', 'clean'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configure (androidProjects + androidBootClasspathProjects) {
|
configure (androidProjects + androidBootClasspathProjects) {
|
||||||
|
|
35
documentation/connection-modules.md
Normal file
35
documentation/connection-modules.md
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
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,24 +58,28 @@ debugger=console
|
||||||
|
|
||||||
### Framework properties
|
### Framework properties
|
||||||
|
|
||||||
| Name | |
|
| Name | Description |
|
||||||
|----------------------|-------------------------------------------|
|
|----------------------|-----------------------------------------------------------------------------|
|
||||||
| service | XMPP service to run the tests on |
|
| service | XMPP service to run the tests on |
|
||||||
| serviceTlsPin | TLS Pin (used by [java-pinning](https://github.com/Flowdalic/java-pinning)) |
|
| serviceTlsPin | TLS Pin (used by [java-pinning](https://github.com/Flowdalic/java-pinning)) |
|
||||||
| securityMode | Either 'required' or 'disabled' |
|
| securityMode | Either 'required' or 'disabled' |
|
||||||
| replyTimeout | In milliseconds |
|
| replyTimeout | In milliseconds |
|
||||||
| adminAccountUsername | Username of the XEP-0133 Admin account |
|
| adminAccountUsername | Username of the XEP-0133 Admin account |
|
||||||
| adminAccountPassword | Password of the XEP-0133 Admin account |
|
| adminAccountPassword | Password of the XEP-0133 Admin account |
|
||||||
| accountOneUsername | Username of the first XMPP account |
|
| accountOneUsername | Username of the first XMPP account |
|
||||||
| accountOnePassword | Password of the first XMPP account |
|
| accountOnePassword | Password of the first XMPP account |
|
||||||
| accountTwoUsername | Username of the second XMPP account |
|
| accountTwoUsername | Username of the second XMPP account |
|
||||||
| accountTwoPassword | Password of the second XMPP account |
|
| accountTwoPassword | Password of the second XMPP account |
|
||||||
| accountThreeUsername | Username of the third XMPP account |
|
| accountThreeUsername | Username of the third XMPP account |
|
||||||
| accountThreePassword | Password of the third XMPP account |
|
| accountThreePassword | Password of the third XMPP account |
|
||||||
| debugger | 'console' for console debugger, 'enhanced' for the enhanced debugger |
|
| debugger | 'console' for console debugger, 'enhanced' for the enhanced debugger |
|
||||||
| enabledTests | List of enabled tests |
|
| enabledTests | List of enabled tests |
|
||||||
| disabledTests | List of disabled tests |
|
| disabledTests | List of disabled tests |
|
||||||
| testPackages | List of packages with 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 |
|
||||||
|
|
||||||
### Where to place the properties file
|
### Where to place the properties file
|
||||||
|
|
||||||
|
@ -99,6 +103,10 @@ 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.
|
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`
|
### `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.
|
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,6 +23,13 @@ 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). |
|
| [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
|
Smack Extensions and currently supported XEPs of smack-extensions
|
||||||
-----------------------------------------------------------------
|
-----------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -52,17 +59,19 @@ 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. |
|
| 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. |
|
| [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. |
|
| Software Version | [XEP-0092](https://xmpp.org/extensions/xep-0092.html) | n/a | Retrieve and announce the software application of an XMPP entity. |
|
||||||
| Stream Initation | [XEP-0095](https://xmpp.org/extensions/xep-0095.html) | n/a | Initiating a data stream between any two XMPP entities. |
|
| Stream Initiation | [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. |
|
| [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. |
|
| 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. |
|
| [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. |
|
| 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 . |
|
| 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. |
|
| 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.
|
| 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. |
|
| 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. |
|
| 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. |
|
| [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. |
|
| 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). |
|
| [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.
|
| XMPP Ping | [XEP-0199](https://xmpp.org/extensions/xep-0199.html) | n/a | Sending application-level pings over XML streams.
|
||||||
|
@ -73,6 +82,7 @@ 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. |
|
| 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. |
|
| 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. |
|
| 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 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. |
|
| 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. |
|
| 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. |
|
||||||
|
@ -102,6 +112,7 @@ 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. |
|
| 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. |
|
| 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. |
|
| 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](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. |
|
| [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. |
|
| [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,3 +13,4 @@
|
||||||
* [Debugging with Smack](debugging.md)
|
* [Debugging with Smack](debugging.md)
|
||||||
|
|
||||||
* [Smack Extensions Manual](extensions/index.md)
|
* [Smack Extensions Manual](extensions/index.md)
|
||||||
|
* [Smack's Modular Connection Architecture](connection-modules.md)
|
||||||
|
|
|
@ -67,6 +67,7 @@ SMACK_EXCEPTIONS[CorruptedOmemoKeyException]="if the OMEMO key is corrupted."
|
||||||
SMACK_EXCEPTIONS[CryptoFailedException]="if the OMEMO cryptography failed."
|
SMACK_EXCEPTIONS[CryptoFailedException]="if the OMEMO cryptography failed."
|
||||||
SMACK_EXCEPTIONS[CannotEstablishOmemoSessionException]="if no OMEMO session could be established."
|
SMACK_EXCEPTIONS[CannotEstablishOmemoSessionException]="if no OMEMO session could be established."
|
||||||
SMACK_EXCEPTIONS[UntrustedOmemoIdentityException]="if the OMEMO identity is not trusted."
|
SMACK_EXCEPTIONS[UntrustedOmemoIdentityException]="if the OMEMO identity is not trusted."
|
||||||
|
SMACK_EXCEPTIONS[FailedNonzaException]="if an XMPP protocol failure was received."
|
||||||
|
|
||||||
MODE=""
|
MODE=""
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ include 'smack-core',
|
||||||
'smack-android',
|
'smack-android',
|
||||||
'smack-android-extensions',
|
'smack-android-extensions',
|
||||||
'smack-java7',
|
'smack-java7',
|
||||||
|
'smack-java8-full',
|
||||||
'smack-integration-test',
|
'smack-integration-test',
|
||||||
'smack-omemo',
|
'smack-omemo',
|
||||||
'smack-omemo-signal',
|
'smack-omemo-signal',
|
||||||
|
|
|
@ -27,7 +27,7 @@ import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.jivesoftware.smack.AbstractXMPPConnection;
|
import org.jivesoftware.smack.AbstractXMPPConnection;
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
import org.jivesoftware.smack.SmackException.ConnectionException;
|
import org.jivesoftware.smack.SmackException.GenericConnectionException;
|
||||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||||
import org.jivesoftware.smack.SmackException.SmackWrappedException;
|
import org.jivesoftware.smack.SmackException.SmackWrappedException;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
@ -136,6 +136,7 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
protected void connectInternal() throws SmackException, InterruptedException {
|
protected void connectInternal() throws SmackException, InterruptedException {
|
||||||
done = false;
|
done = false;
|
||||||
|
@ -177,7 +178,7 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
|
||||||
.setAttribute(BodyQName.createWithPrefix(XMPP_BOSH_NS, "version", "xmpp"), "1.0")
|
.setAttribute(BodyQName.createWithPrefix(XMPP_BOSH_NS, "version", "xmpp"), "1.0")
|
||||||
.build());
|
.build());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ConnectionException(e);
|
throw new GenericConnectionException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the response from the server
|
// Wait for the response from the server
|
||||||
|
|
|
@ -25,6 +25,8 @@ dependencies {
|
||||||
testCompile "org.xmlunit:xmlunit-assertj:$xmlUnitVersion"
|
testCompile "org.xmlunit:xmlunit-assertj:$xmlUnitVersion"
|
||||||
testCompile 'com.jamesmurty.utils:java-xmlbuilder:1.2'
|
testCompile 'com.jamesmurty.utils:java-xmlbuilder:1.2'
|
||||||
testCompile 'org.bouncycastle:bcprov-jdk15on:1.64'
|
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 {
|
class CreateFileTask extends DefaultTask {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2009 Jive Software, 2018-2019 Florian Schmaus.
|
* Copyright 2009 Jive Software, 2018-2020 Florian Schmaus.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -34,7 +34,6 @@ import java.security.SecureRandom;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.UnrecoverableKeyException;
|
import java.security.UnrecoverableKeyException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -87,6 +86,7 @@ import org.jivesoftware.smack.XMPPException.StreamErrorException;
|
||||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
import org.jivesoftware.smack.compress.packet.Compress;
|
import org.jivesoftware.smack.compress.packet.Compress;
|
||||||
import org.jivesoftware.smack.compression.XMPPInputOutputStream;
|
import org.jivesoftware.smack.compression.XMPPInputOutputStream;
|
||||||
|
import org.jivesoftware.smack.datatypes.UInt16;
|
||||||
import org.jivesoftware.smack.debugger.SmackDebugger;
|
import org.jivesoftware.smack.debugger.SmackDebugger;
|
||||||
import org.jivesoftware.smack.debugger.SmackDebuggerFactory;
|
import org.jivesoftware.smack.debugger.SmackDebuggerFactory;
|
||||||
import org.jivesoftware.smack.filter.IQReplyFilter;
|
import org.jivesoftware.smack.filter.IQReplyFilter;
|
||||||
|
@ -136,7 +136,6 @@ import org.jivesoftware.smack.util.ParserUtils;
|
||||||
import org.jivesoftware.smack.util.Predicate;
|
import org.jivesoftware.smack.util.Predicate;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
import org.jivesoftware.smack.util.TLSUtils;
|
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.SmackDaneProvider;
|
||||||
import org.jivesoftware.smack.util.dns.SmackDaneVerifier;
|
import org.jivesoftware.smack.util.dns.SmackDaneVerifier;
|
||||||
import org.jivesoftware.smack.xml.XmlPullParser;
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||||
|
@ -150,8 +149,6 @@ import org.jxmpp.jid.impl.JidCreate;
|
||||||
import org.jxmpp.jid.parts.Resourcepart;
|
import org.jxmpp.jid.parts.Resourcepart;
|
||||||
import org.jxmpp.stringprep.XmppStringprepException;
|
import org.jxmpp.stringprep.XmppStringprepException;
|
||||||
import org.jxmpp.util.XmppStringUtils;
|
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
|
* This abstract class is commonly used as super class for XMPP connection mechanisms like TCP and BOSH. Hence it
|
||||||
|
@ -394,7 +391,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
/**
|
/**
|
||||||
* The used port to establish the connection to
|
* The used port to establish the connection to
|
||||||
*/
|
*/
|
||||||
protected int port;
|
protected UInt16 port;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag that indicates if the user is currently authenticated with the server.
|
* Flag that indicates if the user is currently authenticated with the server.
|
||||||
|
@ -484,7 +481,12 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getPort() {
|
public int getPort() {
|
||||||
return port;
|
final UInt16 port = this.port;
|
||||||
|
if (port == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return port.intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -525,6 +527,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
saslFeatureReceived.init();
|
saslFeatureReceived.init();
|
||||||
lastFeaturesReceived.init();
|
lastFeaturesReceived.init();
|
||||||
tlsHandled.init();
|
tlsHandled.init();
|
||||||
|
closingStreamReceived.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -778,38 +781,6 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
|
|
||||||
private DomainBareJid xmppServiceDomain;
|
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() {
|
protected Lock getConnectionLock() {
|
||||||
return connectionLock;
|
return connectionLock;
|
||||||
}
|
}
|
||||||
|
@ -980,6 +951,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
tlsHandled.reportGenericFailure(smackWrappedException);
|
tlsHandled.reportGenericFailure(smackWrappedException);
|
||||||
saslFeatureReceived.reportGenericFailure(smackWrappedException);
|
saslFeatureReceived.reportGenericFailure(smackWrappedException);
|
||||||
lastFeaturesReceived.reportGenericFailure(smackWrappedException);
|
lastFeaturesReceived.reportGenericFailure(smackWrappedException);
|
||||||
|
closingStreamReceived.reportFailure(smackWrappedException);
|
||||||
// TODO From XMPPTCPConnection. Was called in Smack 4.3 where notifyConnectionError() was part of
|
// TODO From XMPPTCPConnection. Was called in Smack 4.3 where notifyConnectionError() was part of
|
||||||
// XMPPTCPConnection. Create delegation method?
|
// XMPPTCPConnection. Create delegation method?
|
||||||
// maybeCompressFeaturesReceived.reportGenericFailure(smackWrappedException);
|
// maybeCompressFeaturesReceived.reportGenericFailure(smackWrappedException);
|
||||||
|
@ -2182,6 +2154,10 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
CACHED_EXECUTOR_SERVICE.execute(runnable);
|
CACHED_EXECUTOR_SERVICE.execute(runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected final SmackReactor getReactor() {
|
||||||
|
return SMACK_REACTOR;
|
||||||
|
}
|
||||||
|
|
||||||
protected static ScheduledAction schedule(Runnable runnable, long delay, TimeUnit unit) {
|
protected static ScheduledAction schedule(Runnable runnable, long delay, TimeUnit unit) {
|
||||||
return SMACK_REACTOR.schedule(runnable, delay, unit);
|
return SMACK_REACTOR.schedule(runnable, delay, unit);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* 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-2019 Florian Schmaus.
|
* Copyright 2003-2007 Jive Software, 2017-2020 Florian Schmaus.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -229,14 +229,18 @@ public abstract class ConnectionConfiguration {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DnsName getHost() {
|
public DnsName getHost() {
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
InetAddress getHostAddress() {
|
public InetAddress getHostAddress() {
|
||||||
return hostAddress;
|
return hostAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the server name of the target server.
|
* Returns the server name of the target server.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
* Copyright 2003-2007 Jive Software, 2018-2020 Florian Schmaus.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -28,6 +28,8 @@ import java.util.Set;
|
||||||
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
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.compression.XMPPInputOutputStream;
|
||||||
import org.jivesoftware.smack.debugger.ReflectionDebuggerFactory;
|
import org.jivesoftware.smack.debugger.ReflectionDebuggerFactory;
|
||||||
import org.jivesoftware.smack.debugger.SmackDebuggerFactory;
|
import org.jivesoftware.smack.debugger.SmackDebuggerFactory;
|
||||||
|
@ -238,18 +240,6 @@ public final class SmackConfiguration {
|
||||||
compressionHandlers.add(xmppInputOutputStream);
|
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.
|
* Get compression handlers.
|
||||||
*
|
*
|
||||||
|
@ -379,4 +369,19 @@ public final class SmackConfiguration {
|
||||||
return defaultConcurrencyLevelLimit;
|
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-2019 Florian Schmaus
|
* Copyright 2014-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,11 +16,15 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smack;
|
package org.jivesoftware.smack;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.c2s.XmppClientToServerTransport.LookupConnectionEndpointsFailed;
|
||||||
import org.jivesoftware.smack.filter.StanzaFilter;
|
import org.jivesoftware.smack.filter.StanzaFilter;
|
||||||
import org.jivesoftware.smack.util.dns.HostAddress;
|
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.jxmpp.jid.Jid;
|
import org.jxmpp.jid.Jid;
|
||||||
|
|
||||||
|
@ -90,16 +94,10 @@ public abstract class SmackException extends Exception {
|
||||||
public static NoResponseException newWith(XMPPConnection connection, String waitingFor) {
|
public static NoResponseException newWith(XMPPConnection connection, String waitingFor) {
|
||||||
final StringBuilder sb = getWaitingFor(connection);
|
final StringBuilder sb = getWaitingFor(connection);
|
||||||
sb.append(" While waiting for ").append(waitingFor);
|
sb.append(" While waiting for ").append(waitingFor);
|
||||||
|
sb.append(" [").append(connection).append(']');
|
||||||
return new NoResponseException(sb.toString());
|
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,
|
public static NoResponseException newWith(long timeout,
|
||||||
StanzaCollector collector, boolean stanzaCollectorCancelled) {
|
StanzaCollector collector, boolean stanzaCollectorCancelled) {
|
||||||
return newWith(timeout, collector.getStanzaFilter(), stanzaCollectorCancelled);
|
return newWith(timeout, collector.getStanzaFilter(), stanzaCollectorCancelled);
|
||||||
|
@ -264,45 +262,112 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ConnectionException is thrown if Smack is unable to connect to all hosts of a given XMPP
|
* This exception is thrown if Smack is unable to connect to all hosts of a given XMPP
|
||||||
* service. The failed hosts can be retrieved with
|
* service. The connection exceptions can be retrieved with
|
||||||
* {@link ConnectionException#getFailedAddresses()}, which will have the exception causing the
|
* {@link EndpointConnectionException#getConnectionExceptions()}, which will have the exception causing the
|
||||||
* connection failure set and retrievable with {@link HostAddress#getExceptions()}.
|
* connection failure set and retrievable with {@link RemoteConnectionException#getException()}.
|
||||||
*/
|
*/
|
||||||
public static class ConnectionException extends SmackException {
|
public static final class EndpointConnectionException extends ConnectionException {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 1686944201672697996L;
|
private static final long serialVersionUID = 1;
|
||||||
|
|
||||||
private final List<HostAddress> failedAddresses;
|
private final List<RemoteConnectionEndpointLookupFailure> lookupFailures;
|
||||||
|
private final List<? extends RemoteConnectionException<?>> connectionExceptions;
|
||||||
|
|
||||||
public ConnectionException(Throwable wrappedThrowable) {
|
private EndpointConnectionException(String message, List<RemoteConnectionEndpointLookupFailure> lookupFailures,
|
||||||
super(wrappedThrowable);
|
List<? extends RemoteConnectionException<?>> connectionExceptions) {
|
||||||
failedAddresses = new ArrayList<>(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ConnectionException(String message, List<HostAddress> failedAddresses) {
|
|
||||||
super(message);
|
super(message);
|
||||||
this.failedAddresses = failedAddresses;
|
// At least one list must contain an entry.
|
||||||
|
assert !lookupFailures.isEmpty() || !connectionExceptions.isEmpty();
|
||||||
|
this.lookupFailures = lookupFailures;
|
||||||
|
this.connectionExceptions = connectionExceptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ConnectionException from(List<HostAddress> failedAddresses) {
|
public static EndpointConnectionException from(List<RemoteConnectionEndpointLookupFailure> lookupFailures,
|
||||||
final String DELIMITER = ", ";
|
List<? extends RemoteConnectionException<?>> connectionExceptions) {
|
||||||
StringBuilder sb = new StringBuilder("The following addresses failed: ");
|
StringBuilder sb = new StringBuilder(256);
|
||||||
for (HostAddress hostAddress : failedAddresses) {
|
|
||||||
sb.append(hostAddress.getErrorMessage());
|
if (!lookupFailures.isEmpty()) {
|
||||||
sb.append(DELIMITER);
|
sb.append("Could not lookup the following endpoints: ");
|
||||||
|
StringUtils.appendTo(lookupFailures, sb);
|
||||||
}
|
}
|
||||||
// Remove the last delimiter
|
|
||||||
sb.setLength(sb.length() - DELIMITER.length());
|
if (!connectionExceptions.isEmpty()) {
|
||||||
return new ConnectionException(sb.toString(), failedAddresses);
|
sb.append("The following addresses failed: ");
|
||||||
|
StringUtils.appendTo(connectionExceptions, sb, rce -> sb.append(rce.getErrorMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new EndpointConnectionException(sb.toString(), lookupFailures, connectionExceptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<HostAddress> getFailedAddresses() {
|
public List<RemoteConnectionEndpointLookupFailure> getLookupFailures() {
|
||||||
return failedAddresses;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2017-2018 Florian Schmaus
|
* Copyright 2017-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -19,7 +19,9 @@ package org.jivesoftware.smack;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -31,6 +33,7 @@ import javax.net.SocketFactory;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.Stanza;
|
import org.jivesoftware.smack.packet.Stanza;
|
||||||
import org.jivesoftware.smack.util.CallbackRecipient;
|
import org.jivesoftware.smack.util.CallbackRecipient;
|
||||||
|
import org.jivesoftware.smack.util.Consumer;
|
||||||
import org.jivesoftware.smack.util.ExceptionCallback;
|
import org.jivesoftware.smack.util.ExceptionCallback;
|
||||||
import org.jivesoftware.smack.util.SuccessCallback;
|
import org.jivesoftware.smack.util.SuccessCallback;
|
||||||
|
|
||||||
|
@ -48,6 +51,8 @@ public abstract class SmackFuture<V, E extends Exception> implements Future<V>,
|
||||||
|
|
||||||
private ExceptionCallback<E> exceptionCallback;
|
private ExceptionCallback<E> exceptionCallback;
|
||||||
|
|
||||||
|
private Consumer<SmackFuture<V, E>> completionCallback;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final synchronized boolean cancel(boolean mayInterruptIfRunning) {
|
public final synchronized boolean cancel(boolean mayInterruptIfRunning) {
|
||||||
if (isDone()) {
|
if (isDone()) {
|
||||||
|
@ -87,6 +92,11 @@ public abstract class SmackFuture<V, E extends Exception> implements Future<V>,
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onCompletion(Consumer<SmackFuture<V, E>> completionCallback) {
|
||||||
|
this.completionCallback = completionCallback;
|
||||||
|
maybeInvokeCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
private V getOrThrowExecutionException() throws ExecutionException {
|
private V getOrThrowExecutionException() throws ExecutionException {
|
||||||
assert result != null || exception != null || cancelled;
|
assert result != null || exception != null || cancelled;
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
|
@ -148,11 +158,19 @@ public abstract class SmackFuture<V, E extends Exception> implements Future<V>,
|
||||||
return getOrThrowExecutionException();
|
return getOrThrowExecutionException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public V getIfAvailable() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
protected final synchronized void maybeInvokeCallbacks() {
|
protected final synchronized void maybeInvokeCallbacks() {
|
||||||
if (cancelled) {
|
if (cancelled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((result != null || exception != null) && completionCallback != null) {
|
||||||
|
completionCallback.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
if (result != null && successCallback != null) {
|
if (result != null && successCallback != null) {
|
||||||
AbstractXMPPConnection.asyncGo(new Runnable() {
|
AbstractXMPPConnection.asyncGo(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -308,4 +326,12 @@ public abstract class SmackFuture<V, E extends Exception> implements Future<V>,
|
||||||
return future;
|
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,12 +26,15 @@ import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.bind2.Bind2ModuleDescriptor;
|
||||||
import org.jivesoftware.smack.compress.provider.CompressedProvider;
|
import org.jivesoftware.smack.compress.provider.CompressedProvider;
|
||||||
import org.jivesoftware.smack.compress.provider.FailureProvider;
|
import org.jivesoftware.smack.compress.provider.FailureProvider;
|
||||||
|
import org.jivesoftware.smack.compression.CompressionModuleDescriptor;
|
||||||
import org.jivesoftware.smack.compression.Java7ZlibInputOutputStream;
|
import org.jivesoftware.smack.compression.Java7ZlibInputOutputStream;
|
||||||
import org.jivesoftware.smack.compression.XmppCompressionManager;
|
import org.jivesoftware.smack.compression.XmppCompressionManager;
|
||||||
import org.jivesoftware.smack.compression.zlib.ZlibXmppCompressionFactory;
|
import org.jivesoftware.smack.compression.zlib.ZlibXmppCompressionFactory;
|
||||||
import org.jivesoftware.smack.initializer.SmackInitializer;
|
import org.jivesoftware.smack.initializer.SmackInitializer;
|
||||||
|
import org.jivesoftware.smack.isr.InstantStreamResumptionModuleDescriptor;
|
||||||
import org.jivesoftware.smack.packet.Bind;
|
import org.jivesoftware.smack.packet.Bind;
|
||||||
import org.jivesoftware.smack.packet.Message.Body;
|
import org.jivesoftware.smack.packet.Message.Body;
|
||||||
import org.jivesoftware.smack.provider.BindIQProvider;
|
import org.jivesoftware.smack.provider.BindIQProvider;
|
||||||
|
@ -136,6 +139,10 @@ public final class SmackInitialization {
|
||||||
ProviderManager.addNonzaProvider(CompressedProvider.INSTANCE);
|
ProviderManager.addNonzaProvider(CompressedProvider.INSTANCE);
|
||||||
ProviderManager.addNonzaProvider(FailureProvider.INSTANCE);
|
ProviderManager.addNonzaProvider(FailureProvider.INSTANCE);
|
||||||
|
|
||||||
|
SmackConfiguration.addModule(Bind2ModuleDescriptor.class);
|
||||||
|
SmackConfiguration.addModule(CompressionModuleDescriptor.class);
|
||||||
|
SmackConfiguration.addModule(InstantStreamResumptionModuleDescriptor.class);
|
||||||
|
|
||||||
SmackConfiguration.smackInitialized = true;
|
SmackConfiguration.smackInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2018-2019 Florian Schmaus
|
* Copyright 2018-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -116,7 +116,7 @@ public class SmackReactor {
|
||||||
setReactorThreadCount(DEFAULT_REACTOR_THREAD_COUNT);
|
setReactorThreadCount(DEFAULT_REACTOR_THREAD_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectionKey registerWithSelector(SelectableChannel channel, int ops, ChannelSelectedCallback callback)
|
public SelectionKey registerWithSelector(SelectableChannel channel, int ops, ChannelSelectedCallback callback)
|
||||||
throws ClosedChannelException {
|
throws ClosedChannelException {
|
||||||
SelectionKeyAttachment selectionKeyAttachment = new SelectionKeyAttachment(callback);
|
SelectionKeyAttachment selectionKeyAttachment = new SelectionKeyAttachment(callback);
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ public class SmackReactor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setInterestOps(SelectionKey selectionKey, int interestOps) {
|
public void setInterestOps(SelectionKey selectionKey, int interestOps) {
|
||||||
SetInterestOps setInterestOps = new SetInterestOps(selectionKey, interestOps);
|
SetInterestOps setInterestOps = new SetInterestOps(selectionKey, interestOps);
|
||||||
pendingSetInterestOps.add(setInterestOps);
|
pendingSetInterestOps.add(setInterestOps);
|
||||||
selector.wakeup();
|
selector.wakeup();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2018 Florian Schmaus
|
* Copyright 2018-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -70,7 +70,7 @@ public interface XmppInputOutputFilter {
|
||||||
default void waitUntilInputOutputClosed() throws IOException, NoResponseException, CertificateException, InterruptedException, SmackException {
|
default void waitUntilInputOutputClosed() throws IOException, NoResponseException, CertificateException, InterruptedException, SmackException {
|
||||||
}
|
}
|
||||||
|
|
||||||
default Object getStats() {
|
Object getStats();
|
||||||
return null;
|
|
||||||
}
|
String getFilterName();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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
|
@ -0,0 +1,167 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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()?
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
}
|
|
@ -0,0 +1,179 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
|
@ -0,0 +1,132 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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,6 +230,11 @@ public final class ZlibXmppCompressionFactory extends XmppCompressionFactory {
|
||||||
public Stats getStats() {
|
public Stats getStats() {
|
||||||
return new Stats(this);
|
return new Stats(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFilterName() {
|
||||||
|
return "Compression (zlib)";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class Stats {
|
public static final class Stats {
|
||||||
|
|
|
@ -1,806 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* 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 Florian Schmaus
|
* Copyright 2018-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,29 +16,37 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smack.fsm;
|
package org.jivesoftware.smack.fsm;
|
||||||
|
|
||||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.State;
|
import org.jivesoftware.smack.fsm.StateDescriptorGraph.GraphVertex;
|
||||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.TransitionFailureResult;
|
|
||||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.TransitionImpossibleReason;
|
|
||||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.TransitionSuccessResult;
|
|
||||||
|
|
||||||
public class ConnectionStateEvent {
|
public class ConnectionStateEvent {
|
||||||
|
|
||||||
private final StateDescriptor stateDescriptor;
|
private final StateDescriptor currentStateDescriptor;
|
||||||
|
private final StateDescriptor successorStateDescriptor;
|
||||||
|
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
|
|
||||||
protected ConnectionStateEvent(StateDescriptor stateDescriptor) {
|
public ConnectionStateEvent(StateDescriptor currentStateDescriptor) {
|
||||||
this.stateDescriptor = stateDescriptor;
|
this(currentStateDescriptor, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConnectionStateEvent(StateDescriptor currentStateDescriptor, StateDescriptor successorStateDescriptor) {
|
||||||
|
this.currentStateDescriptor = currentStateDescriptor;
|
||||||
|
this.successorStateDescriptor = successorStateDescriptor;
|
||||||
this.timestamp = System.currentTimeMillis();
|
this.timestamp = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
public StateDescriptor getStateDescriptor() {
|
public StateDescriptor getStateDescriptor() {
|
||||||
return stateDescriptor;
|
return currentStateDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return stateDescriptor.getStateName() + ' ' + getClass().getSimpleName();
|
if (successorStateDescriptor == null) {
|
||||||
|
return getClass().getSimpleName() + ": " + currentStateDescriptor.getStateName();
|
||||||
|
} else {
|
||||||
|
return currentStateDescriptor.getStateName() + ' ' + getClass().getSimpleName() + ' '
|
||||||
|
+ successorStateDescriptor.getStateName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getTimestamp() {
|
public long getTimestamp() {
|
||||||
|
@ -46,22 +54,22 @@ public class ConnectionStateEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class StateRevertBackwardsWalk extends ConnectionStateEvent {
|
public static class StateRevertBackwardsWalk extends ConnectionStateEvent {
|
||||||
StateRevertBackwardsWalk(State state) {
|
public StateRevertBackwardsWalk(State state) {
|
||||||
super(state.getStateDescriptor());
|
super(state.getStateDescriptor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class FinalStateReached extends ConnectionStateEvent {
|
public static class FinalStateReached extends ConnectionStateEvent {
|
||||||
FinalStateReached(State state) {
|
public FinalStateReached(State state) {
|
||||||
super(state.getStateDescriptor());
|
super(state.getStateDescriptor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransitionNotPossible extends ConnectionStateEvent {
|
public static class TransitionNotPossible extends ConnectionStateEvent {
|
||||||
private final TransitionImpossibleReason transitionImpossibleReason;
|
private final StateTransitionResult.TransitionImpossible transitionImpossibleReason;
|
||||||
|
|
||||||
TransitionNotPossible(State state, TransitionImpossibleReason reason) {
|
public TransitionNotPossible(State currentState, State successorState, StateTransitionResult.TransitionImpossible reason) {
|
||||||
super(state.getStateDescriptor());
|
super(currentState.getStateDescriptor(), successorState.getStateDescriptor());
|
||||||
this.transitionImpossibleReason = reason;
|
this.transitionImpossibleReason = reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,16 +80,16 @@ public class ConnectionStateEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class AboutToTransitionInto extends ConnectionStateEvent {
|
public static class AboutToTransitionInto extends ConnectionStateEvent {
|
||||||
AboutToTransitionInto(State state) {
|
public AboutToTransitionInto(State currentState, State successorState) {
|
||||||
super(state.getStateDescriptor());
|
super(currentState.getStateDescriptor(), successorState.getStateDescriptor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransitionFailed extends ConnectionStateEvent {
|
public static class TransitionFailed extends ConnectionStateEvent {
|
||||||
private final TransitionFailureResult transitionFailedReason;
|
private final StateTransitionResult.Failure transitionFailedReason;
|
||||||
|
|
||||||
TransitionFailed(State state, TransitionFailureResult transitionFailedReason) {
|
public TransitionFailed(State currentState, State failedSuccessorState, StateTransitionResult.Failure transitionFailedReason) {
|
||||||
super(state.getStateDescriptor());
|
super(currentState.getStateDescriptor(), failedSuccessorState.getStateDescriptor());
|
||||||
this.transitionFailedReason = transitionFailedReason;
|
this.transitionFailedReason = transitionFailedReason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,10 +99,16 @@ public class ConnectionStateEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SuccessfullyTransitionedInto extends ConnectionStateEvent {
|
public static class TransitionIgnoredDueCycle extends ConnectionStateEvent {
|
||||||
private final TransitionSuccessResult transitionSuccessResult;
|
public TransitionIgnoredDueCycle(GraphVertex<State> currentStateVertex, GraphVertex<State> successorStateVertexCausingCycle) {
|
||||||
|
super(currentStateVertex.getElement().getStateDescriptor(), successorStateVertexCausingCycle.getElement().getStateDescriptor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SuccessfullyTransitionedInto(State state, TransitionSuccessResult transitionSuccessResult) {
|
public static class SuccessfullyTransitionedInto extends ConnectionStateEvent {
|
||||||
|
private final StateTransitionResult.Success transitionSuccessResult;
|
||||||
|
|
||||||
|
public SuccessfullyTransitionedInto(State state, StateTransitionResult.Success transitionSuccessResult) {
|
||||||
super(state.getStateDescriptor());
|
super(state.getStateDescriptor());
|
||||||
this.transitionSuccessResult = transitionSuccessResult;
|
this.transitionSuccessResult = transitionSuccessResult;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,11 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smack.fsm;
|
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.
|
// TODO: Mark as java.lang.FunctionalInterface once Smack's minimum Android API level is 24 or higher.
|
||||||
public interface ConnectionStateMachineListener {
|
public interface ConnectionStateMachineListener {
|
||||||
|
|
||||||
void onConnectionStateEvent(ConnectionStateEvent connectionStateEvent, AbstractXmppStateMachineConnection connection);
|
void onConnectionStateEvent(ConnectionStateEvent connectionStateEvent, ModularXmppClientToServerConnection connection);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2018 Florian Schmaus
|
* Copyright 2018-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -20,11 +20,11 @@ import org.jxmpp.jid.parts.Resourcepart;
|
||||||
|
|
||||||
// TODO: At one point SASL authzid should be part of this.
|
// TODO: At one point SASL authzid should be part of this.
|
||||||
public class LoginContext {
|
public class LoginContext {
|
||||||
final String username;
|
public final String username;
|
||||||
final String password;
|
public final String password;
|
||||||
final Resourcepart resource;
|
public final Resourcepart resource;
|
||||||
|
|
||||||
LoginContext(String username, String password, Resourcepart resource) {
|
public LoginContext(String username, String password, Resourcepart resource) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.resource = resource;
|
this.resource = resource;
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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 Florian Schmaus
|
* Copyright 2018-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -22,9 +22,9 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.State;
|
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection;
|
||||||
|
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||||
|
|
||||||
public abstract class StateDescriptor {
|
public abstract class StateDescriptor {
|
||||||
|
|
||||||
|
@ -34,15 +34,13 @@ public abstract class StateDescriptor {
|
||||||
notImplemented,
|
notImplemented,
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(StateDescriptor.class.getName());
|
|
||||||
|
|
||||||
private final String stateName;
|
private final String stateName;
|
||||||
private final int xepNum;
|
private final int xepNum;
|
||||||
private final String rfcSection;
|
private final String rfcSection;
|
||||||
private final Set<Property> properties;
|
private final Set<Property> properties;
|
||||||
|
|
||||||
private final Class<? extends AbstractXmppStateMachineConnection.State> stateClass;
|
private final Class<? extends State> stateClass;
|
||||||
private final Constructor<? extends AbstractXmppStateMachineConnection.State> stateClassConstructor;
|
private final Constructor<? extends State> stateClassConstructor;
|
||||||
|
|
||||||
private final Set<Class<? extends StateDescriptor>> successors = new HashSet<>();
|
private final Set<Class<? extends StateDescriptor>> successors = new HashSet<>();
|
||||||
|
|
||||||
|
@ -53,36 +51,36 @@ public abstract class StateDescriptor {
|
||||||
private final Set<Class<? extends StateDescriptor>> inferiorTo = new HashSet<>();
|
private final Set<Class<? extends StateDescriptor>> inferiorTo = new HashSet<>();
|
||||||
|
|
||||||
protected StateDescriptor() {
|
protected StateDescriptor() {
|
||||||
this(AbstractXmppStateMachineConnection.NoOpState.class, (Property) null);
|
this(NoOpState.class, (Property) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected StateDescriptor(Property... properties) {
|
protected StateDescriptor(Property... properties) {
|
||||||
this(AbstractXmppStateMachineConnection.NoOpState.class, properties);
|
this(NoOpState.class, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected StateDescriptor(Class<? extends AbstractXmppStateMachineConnection.State> stateClass) {
|
protected StateDescriptor(Class<? extends State> stateClass) {
|
||||||
this(stateClass, -1, null, Collections.emptySet());
|
this(stateClass, -1, null, Collections.emptySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected StateDescriptor(Class<? extends AbstractXmppStateMachineConnection.State> stateClass, Property... properties) {
|
protected StateDescriptor(Class<? extends State> stateClass, Property... properties) {
|
||||||
this(stateClass, -1, null, new HashSet<>(Arrays.asList(properties)));
|
this(stateClass, -1, null, new HashSet<>(Arrays.asList(properties)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected StateDescriptor(Class<? extends AbstractXmppStateMachineConnection.State> stateClass, int xepNum) {
|
protected StateDescriptor(Class<? extends State> stateClass, int xepNum) {
|
||||||
this(stateClass, xepNum, null, Collections.emptySet());
|
this(stateClass, xepNum, null, Collections.emptySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected StateDescriptor(Class<? extends AbstractXmppStateMachineConnection.State> stateClass, int xepNum,
|
protected StateDescriptor(Class<? extends State> stateClass, int xepNum,
|
||||||
Property... properties) {
|
Property... properties) {
|
||||||
this(stateClass, xepNum, null, new HashSet<>(Arrays.asList(properties)));
|
this(stateClass, xepNum, null, new HashSet<>(Arrays.asList(properties)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected StateDescriptor(Class<? extends AbstractXmppStateMachineConnection.State> stateClass, String rfcSection) {
|
protected StateDescriptor(Class<? extends State> stateClass, String rfcSection) {
|
||||||
this(stateClass, -1, rfcSection, Collections.emptySet());
|
this(stateClass, -1, rfcSection, Collections.emptySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private StateDescriptor(Class<? extends AbstractXmppStateMachineConnection.State> stateClass, int xepNum,
|
private StateDescriptor(Class<? extends State> stateClass, int xepNum,
|
||||||
String rfcSection, Set<Property> properties) {
|
String rfcSection, Set<Property> properties) {
|
||||||
this.stateClass = stateClass;
|
this.stateClass = stateClass;
|
||||||
if (rfcSection != null && xepNum > 0) {
|
if (rfcSection != null && xepNum > 0) {
|
||||||
|
@ -92,26 +90,32 @@ public abstract class StateDescriptor {
|
||||||
this.rfcSection = rfcSection;
|
this.rfcSection = rfcSection;
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
|
|
||||||
Constructor<? extends AbstractXmppStateMachineConnection.State> selectedConstructor = null;
|
Constructor<? extends State> selectedConstructor = null;
|
||||||
Constructor<?>[] constructors = stateClass.getDeclaredConstructors();
|
Constructor<?>[] constructors = stateClass.getDeclaredConstructors();
|
||||||
for (Constructor<?> constructor : constructors) {
|
for (Constructor<?> constructor : constructors) {
|
||||||
Class<?>[] parameterTypes = constructor.getParameterTypes();
|
Class<?>[] parameterTypes = constructor.getParameterTypes();
|
||||||
if (parameterTypes.length != 2) {
|
if (parameterTypes.length != 3) {
|
||||||
LOGGER.warning("Invalid State class constructor: " + constructor);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!AbstractXmppStateMachineConnection.class.isAssignableFrom(parameterTypes[0])) {
|
if (!ModularXmppClientToServerConnection.class.isAssignableFrom(parameterTypes[0])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!StateDescriptor.class.isAssignableFrom(parameterTypes[1])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!ModularXmppClientToServerConnectionInternal.class.isAssignableFrom(parameterTypes[2])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
selectedConstructor = (Constructor<? extends State>) constructor;
|
selectedConstructor = (Constructor<? extends State>) constructor;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedConstructor == null) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
stateClassConstructor = selectedConstructor;
|
stateClassConstructor = selectedConstructor;
|
||||||
stateClassConstructor.setAccessible(true);
|
if (stateClassConstructor != null) {
|
||||||
|
stateClassConstructor.setAccessible(true);
|
||||||
|
} else {
|
||||||
|
// TODO: Add validation check that if stateClassConstructor is 'null' the cosntructState() method is overriden.
|
||||||
|
}
|
||||||
|
|
||||||
String className = getClass().getSimpleName();
|
String className = getClass().getSimpleName();
|
||||||
stateName = className.replaceFirst("StateDescriptor", "");
|
stateName = className.replaceFirst("StateDescriptor", "");
|
||||||
|
@ -121,7 +125,7 @@ public abstract class StateDescriptor {
|
||||||
addAndCheckNonExistent(successors, successor);
|
addAndCheckNonExistent(successors, successor);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addPredeccessor(Class<? extends StateDescriptor> predeccessor) {
|
public void addPredeccessor(Class<? extends StateDescriptor> predeccessor) {
|
||||||
addAndCheckNonExistent(predecessors, predeccessor);
|
addAndCheckNonExistent(predecessors, predeccessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +193,7 @@ public abstract class StateDescriptor {
|
||||||
return referenceCache;
|
return referenceCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<? extends AbstractXmppStateMachineConnection.State> getStateClass() {
|
public Class<? extends State> getStateClass() {
|
||||||
return stateClass;
|
return stateClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,9 +209,12 @@ public abstract class StateDescriptor {
|
||||||
return properties.contains(Property.finalState);
|
return properties.contains(Property.finalState);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final AbstractXmppStateMachineConnection.State constructState(AbstractXmppStateMachineConnection connection) {
|
protected State constructState(ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||||
|
ModularXmppClientToServerConnection connection = connectionInternal.connection;
|
||||||
try {
|
try {
|
||||||
return stateClassConstructor.newInstance(connection, this);
|
// If stateClassConstructor is null here, then you probably forgot to override the the
|
||||||
|
// StateDescriptor.constructState() method?
|
||||||
|
return stateClassConstructor.newInstance(connection, this, connectionInternal);
|
||||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
||||||
| InvocationTargetException e) {
|
| InvocationTargetException e) {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
|
|
|
@ -30,7 +30,8 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.DisconnectedStateDescriptor;
|
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.DisconnectedStateDescriptor;
|
||||||
|
import org.jivesoftware.smack.c2s.internal.ModularXmppClientToServerConnectionInternal;
|
||||||
import org.jivesoftware.smack.util.Consumer;
|
import org.jivesoftware.smack.util.Consumer;
|
||||||
import org.jivesoftware.smack.util.MultiMap;
|
import org.jivesoftware.smack.util.MultiMap;
|
||||||
|
|
||||||
|
@ -134,7 +135,7 @@ public class StateDescriptorGraph {
|
||||||
|
|
||||||
// The preference graph is the graph where the precedence information of all successors is stored, which we will
|
// 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
|
// 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 representent as map. There is no special marker for the initial node
|
// this step for every node. The graph is represented as map. There is no special marker for the initial node
|
||||||
// as it is not required for the topological sort performed later.
|
// as it is not required for the topological sort performed later.
|
||||||
Map<Class<? extends StateDescriptor>, GraphVertex<Class<? extends StateDescriptor>>> preferenceGraph = new HashMap<>(numSuccessors);
|
Map<Class<? extends StateDescriptor>, GraphVertex<Class<? extends StateDescriptor>>> preferenceGraph = new HashMap<>(numSuccessors);
|
||||||
|
|
||||||
|
@ -171,7 +172,8 @@ public class StateDescriptorGraph {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform a topological sort which returns the state descriptor classes in their priority.
|
// Perform a topological sort which returns the state descriptor classes sorted by their priority. Highest
|
||||||
|
// priority state descriptors first.
|
||||||
List<GraphVertex<Class<? extends StateDescriptor>>> sortedSuccessors = topologicalSort(preferenceGraph.values());
|
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
|
// Handle the successor nodes which have not preference information available. Simply append them to the end of
|
||||||
|
@ -222,19 +224,19 @@ public class StateDescriptorGraph {
|
||||||
return initialNode;
|
return initialNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GraphVertex<AbstractXmppStateMachineConnection.State> convertToStateGraph(GraphVertex<StateDescriptor> stateDescriptorVertex,
|
private static GraphVertex<State> convertToStateGraph(GraphVertex<StateDescriptor> stateDescriptorVertex,
|
||||||
AbstractXmppStateMachineConnection connection, Map<StateDescriptor, GraphVertex<AbstractXmppStateMachineConnection.State>> handledStateDescriptors) {
|
ModularXmppClientToServerConnectionInternal connectionInternal, Map<StateDescriptor, GraphVertex<State>> handledStateDescriptors) {
|
||||||
StateDescriptor stateDescriptor = stateDescriptorVertex.getElement();
|
StateDescriptor stateDescriptor = stateDescriptorVertex.getElement();
|
||||||
GraphVertex<AbstractXmppStateMachineConnection.State> stateVertex = handledStateDescriptors.get(stateDescriptor);
|
GraphVertex<State> stateVertex = handledStateDescriptors.get(stateDescriptor);
|
||||||
if (stateVertex != null) {
|
if (stateVertex != null) {
|
||||||
return stateVertex;
|
return stateVertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractXmppStateMachineConnection.State state = stateDescriptor.constructState(connection);
|
State state = stateDescriptor.constructState(connectionInternal);
|
||||||
stateVertex = new GraphVertex<>(state);
|
stateVertex = new GraphVertex<>(state);
|
||||||
handledStateDescriptors.put(stateDescriptor, stateVertex);
|
handledStateDescriptors.put(stateDescriptor, stateVertex);
|
||||||
for (GraphVertex<StateDescriptor> successorStateDescriptorVertex : stateDescriptorVertex.getOutgoingEdges()) {
|
for (GraphVertex<StateDescriptor> successorStateDescriptorVertex : stateDescriptorVertex.getOutgoingEdges()) {
|
||||||
GraphVertex<AbstractXmppStateMachineConnection.State> successorStateVertex = convertToStateGraph(successorStateDescriptorVertex, connection, handledStateDescriptors);
|
GraphVertex<State> successorStateVertex = convertToStateGraph(successorStateDescriptorVertex, connectionInternal, handledStateDescriptors);
|
||||||
// It is important that we keep the order of the edges. This should do it.
|
// It is important that we keep the order of the edges. This should do it.
|
||||||
stateVertex.addOutgoingEdge(successorStateVertex);
|
stateVertex.addOutgoingEdge(successorStateVertex);
|
||||||
}
|
}
|
||||||
|
@ -242,10 +244,10 @@ public class StateDescriptorGraph {
|
||||||
return stateVertex;
|
return stateVertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GraphVertex<AbstractXmppStateMachineConnection.State> convertToStateGraph(GraphVertex<StateDescriptor> initialStateDescriptor,
|
public static GraphVertex<State> convertToStateGraph(GraphVertex<StateDescriptor> initialStateDescriptor,
|
||||||
AbstractXmppStateMachineConnection connection) {
|
ModularXmppClientToServerConnectionInternal connectionInternal) {
|
||||||
Map<StateDescriptor, GraphVertex<AbstractXmppStateMachineConnection.State>> handledStateDescriptors = new HashMap<>();
|
Map<StateDescriptor, GraphVertex<State>> handledStateDescriptors = new HashMap<>();
|
||||||
GraphVertex<AbstractXmppStateMachineConnection.State> initialState = convertToStateGraph(initialStateDescriptor, connection,
|
GraphVertex<State> initialState = convertToStateGraph(initialStateDescriptor, connectionInternal,
|
||||||
handledStateDescriptors);
|
handledStateDescriptors);
|
||||||
return initialState;
|
return initialState;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2018-2019 Florian Schmaus
|
* Copyright 2018-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -21,18 +21,26 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.State;
|
import org.jivesoftware.smack.c2s.internal.WalkStateGraphContext;
|
||||||
import org.jivesoftware.smack.fsm.AbstractXmppStateMachineConnection.TransitionReason;
|
import org.jivesoftware.smack.fsm.StateDescriptorGraph.GraphVertex;
|
||||||
|
|
||||||
public abstract class StateMachineException extends SmackException {
|
public abstract class StateMachineException extends SmackException {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
protected StateMachineException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected StateMachineException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
public static class SmackMandatoryStateFailedException extends StateMachineException {
|
public static class SmackMandatoryStateFailedException extends StateMachineException {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
SmackMandatoryStateFailedException(State state, TransitionReason failureReason) {
|
public SmackMandatoryStateFailedException(State state, StateTransitionResult failureReason) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,21 +48,36 @@ public abstract class StateMachineException extends SmackException {
|
||||||
|
|
||||||
private final List<State> walkedStateGraphPath;
|
private final List<State> walkedStateGraphPath;
|
||||||
|
|
||||||
private final Map<State, TransitionReason> failedStates;
|
private final Map<State, StateTransitionResult> failedStates;
|
||||||
|
|
||||||
|
private final StateDescriptor deadEndState;
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
SmackStateGraphDeadEndException(List<State> walkedStateGraphPath, Map<State, TransitionReason> failedStates) {
|
private SmackStateGraphDeadEndException(String message, WalkStateGraphContext walkStateGraphContext, GraphVertex<State> stateVertex) {
|
||||||
this.walkedStateGraphPath = Collections.unmodifiableList(walkedStateGraphPath);
|
super(message);
|
||||||
this.failedStates = Collections.unmodifiableMap(failedStates);
|
this.walkedStateGraphPath = Collections.unmodifiableList(walkStateGraphContext.getWalk());
|
||||||
|
this.failedStates = Collections.unmodifiableMap(walkStateGraphContext.getFailedStates());
|
||||||
|
|
||||||
|
deadEndState = stateVertex.getElement().getStateDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<State> getWalkedStateGraph() {
|
public List<State> getWalkedStateGraph() {
|
||||||
return walkedStateGraphPath;
|
return walkedStateGraphPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<State, TransitionReason> getFailedStates() {
|
public Map<State, StateTransitionResult> getFailedStates() {
|
||||||
return failedStates;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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,15 +163,20 @@ public class ArrayBlockingQueueWithShutdown<E> extends AbstractQueue<E> implemen
|
||||||
/**
|
/**
|
||||||
* Start the queue. Newly created instances will be started automatically, thus this only needs
|
* Start the queue. Newly created instances will be started automatically, thus this only needs
|
||||||
* to be called after {@link #shutdown()}.
|
* to be called after {@link #shutdown()}.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the queues was shutdown before, <code>false</code> if not.
|
||||||
*/
|
*/
|
||||||
public void start() {
|
public boolean start() {
|
||||||
|
boolean previousIsShutdown;
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
|
previousIsShutdown = isShutdown;
|
||||||
isShutdown = false;
|
isShutdown = false;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
return previousIsShutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2019 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -18,8 +18,10 @@ package org.jivesoftware.smack.util;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class CollectionUtil {
|
public class CollectionUtil {
|
||||||
|
|
||||||
|
@ -56,4 +58,11 @@ public class CollectionUtil {
|
||||||
}
|
}
|
||||||
return new ArrayList<>(collection);
|
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-2018 Florian Schmaus.
|
* Copyright 2003-2005 Jive Software, 2016-2020 Florian Schmaus.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,23 +16,9 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smack.util;
|
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.DNSResolver;
|
||||||
import org.jivesoftware.smack.util.dns.HostAddress;
|
|
||||||
import org.jivesoftware.smack.util.dns.SRVRecord;
|
|
||||||
import org.jivesoftware.smack.util.dns.SmackDaneProvider;
|
import org.jivesoftware.smack.util.dns.SmackDaneProvider;
|
||||||
|
|
||||||
import org.minidns.dnsname.DnsName;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class to perform DNS lookups for XMPP services.
|
* Utility class to perform DNS lookups for XMPP services.
|
||||||
*
|
*
|
||||||
|
@ -41,10 +27,6 @@ import org.minidns.dnsname.DnsName;
|
||||||
*/
|
*/
|
||||||
public class DNSUtil {
|
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 DNSResolver dnsResolver = null;
|
||||||
private static SmackDaneProvider daneProvider;
|
private static SmackDaneProvider daneProvider;
|
||||||
|
|
||||||
|
@ -84,188 +66,4 @@ public class DNSUtil {
|
||||||
return daneProvider;
|
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 Florian Schmaus
|
* Copyright 2019-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -20,4 +20,7 @@ public interface Function<R, T> {
|
||||||
|
|
||||||
R apply(T t);
|
R apply(T t);
|
||||||
|
|
||||||
|
static <T> Function<T, T> identity() {
|
||||||
|
return t -> t;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,17 +123,26 @@ public class MultiMap<K, V> implements TypedCloneable<MultiMap<K, V>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean put(K key, V value) {
|
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;
|
boolean keyExisted;
|
||||||
List<V> list = map.get(key);
|
List<V> list = map.get(key);
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
list = new ArrayList<>(ENTRY_LIST_SIZE);
|
list = new ArrayList<>(ENTRY_LIST_SIZE);
|
||||||
list.add(value);
|
|
||||||
map.put(key, list);
|
map.put(key, list);
|
||||||
keyExisted = false;
|
keyExisted = false;
|
||||||
} else {
|
} else {
|
||||||
list.add(value);
|
|
||||||
keyExisted = true;
|
keyExisted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
valueListConsumer.accept(list);
|
||||||
|
|
||||||
return keyExisted;
|
return keyExisted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software, 2016-2019 Florian Schmaus.
|
* Copyright 2003-2007 Jive Software, 2016-2020 Florian Schmaus.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -467,10 +467,24 @@ public class StringUtils {
|
||||||
return sb;
|
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) {
|
public static void appendTo(Collection<? extends Object> collection, String delimiter, StringBuilder sb) {
|
||||||
for (Iterator<? extends Object> it = collection.iterator(); it.hasNext();) {
|
appendTo(collection, delimiter, sb, o -> sb.append(o));
|
||||||
Object cs = it.next();
|
}
|
||||||
sb.append(cs);
|
|
||||||
|
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);
|
||||||
if (it.hasNext()) {
|
if (it.hasNext()) {
|
||||||
sb.append(delimiter);
|
sb.append(delimiter);
|
||||||
}
|
}
|
||||||
|
@ -565,4 +579,16 @@ public class StringUtils {
|
||||||
public static String deleteXmlWhitespace(String string) {
|
public static String deleteXmlWhitespace(String string) {
|
||||||
return XML_WHITESPACE.matcher(string).replaceAll("");
|
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-2018 Florian Schmaus
|
* Copyright 2013-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -19,13 +19,16 @@ package org.jivesoftware.smack.util.dns;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.jivesoftware.smack.ConnectionConfiguration.DnssecMode;
|
import org.jivesoftware.smack.ConnectionConfiguration.DnssecMode;
|
||||||
|
import org.jivesoftware.smack.util.rce.RemoteConnectionEndpointLookupFailure;
|
||||||
|
|
||||||
import org.minidns.dnsname.DnsName;
|
import org.minidns.dnsname.DnsName;
|
||||||
|
import org.minidns.record.SRV;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementations of this interface define a class that is capable of resolving DNS addresses.
|
* Implementations of this interface define a class that is capable of resolving DNS addresses.
|
||||||
|
@ -43,25 +46,25 @@ public abstract class DNSResolver {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a list of service records for the specified service.
|
* Gets a list of service records for the specified service.
|
||||||
|
*
|
||||||
* @param name The symbolic name of the service.
|
* @param name The symbolic name of the service.
|
||||||
* @param failedAddresses list of failed addresses.
|
* @param lookupFailures list of exceptions that occurred during lookup.
|
||||||
* @param dnssecMode security mode.
|
* @param dnssecMode security mode.
|
||||||
* @return The list of SRV records mapped to the service name.
|
* @return The list of SRV records mapped to the service name.
|
||||||
*/
|
*/
|
||||||
public final List<SRVRecord> lookupSRVRecords(DnsName name, List<HostAddress> failedAddresses, DnssecMode dnssecMode) {
|
public final Collection<SRV> lookupSrvRecords(DnsName name,
|
||||||
|
List<RemoteConnectionEndpointLookupFailure> lookupFailures, DnssecMode dnssecMode) {
|
||||||
checkIfDnssecRequestedAndSupported(dnssecMode);
|
checkIfDnssecRequestedAndSupported(dnssecMode);
|
||||||
return lookupSRVRecords0(name, failedAddresses, dnssecMode);
|
return lookupSrvRecords0(name, lookupFailures, dnssecMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract List<SRVRecord> lookupSRVRecords0(DnsName name, List<HostAddress> failedAddresses, DnssecMode dnssecMode);
|
protected abstract Collection<SRV> lookupSrvRecords0(DnsName name,
|
||||||
|
List<RemoteConnectionEndpointLookupFailure> lookupFailures, DnssecMode dnssecMode);
|
||||||
|
|
||||||
public final HostAddress lookupHostAddress(DnsName name, int port, List<HostAddress> failedAddresses, DnssecMode dnssecMode) {
|
public final List<InetAddress> lookupHostAddress(DnsName name,
|
||||||
|
List<RemoteConnectionEndpointLookupFailure> lookupFailures, DnssecMode dnssecMode) {
|
||||||
checkIfDnssecRequestedAndSupported(dnssecMode);
|
checkIfDnssecRequestedAndSupported(dnssecMode);
|
||||||
List<InetAddress> inetAddresses = lookupHostAddress0(name, failedAddresses, dnssecMode);
|
return lookupHostAddress0(name, lookupFailures, dnssecMode);
|
||||||
if (inetAddresses == null || inetAddresses.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new HostAddress(name, port, inetAddresses);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,11 +77,11 @@ public abstract class DNSResolver {
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param name the DNS name to lookup
|
* @param name the DNS name to lookup
|
||||||
* @param failedAddresses a list with the failed addresses
|
* @param lookupFailures list of exceptions that occurred during lookup.
|
||||||
* @param dnssecMode the selected DNSSEC mode
|
* @param dnssecMode the selected DNSSEC mode
|
||||||
* @return A list, either empty or non-empty, or <code>null</code>
|
* @return A list, either empty or non-empty, or <code>null</code>
|
||||||
*/
|
*/
|
||||||
protected List<InetAddress> lookupHostAddress0(DnsName name, List<HostAddress> failedAddresses, DnssecMode dnssecMode) {
|
protected List<InetAddress> lookupHostAddress0(DnsName name, List<RemoteConnectionEndpointLookupFailure> lookupFailures, DnssecMode dnssecMode) {
|
||||||
// Default implementation of a DNS name lookup for A/AAAA records. It is assumed that this method does never
|
// 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.
|
// support DNSSEC. Subclasses are free to override this method.
|
||||||
if (dnssecMode != DnssecMode.disabled) {
|
if (dnssecMode != DnssecMode.disabled) {
|
||||||
|
@ -89,14 +92,14 @@ public abstract class DNSResolver {
|
||||||
try {
|
try {
|
||||||
inetAddressArray = InetAddress.getAllByName(name.toString());
|
inetAddressArray = InetAddress.getAllByName(name.toString());
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
failedAddresses.add(new HostAddress(name, e));
|
lookupFailures.add(new RemoteConnectionEndpointLookupFailure.DnsLookupFailure(name, e));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Arrays.asList(inetAddressArray);
|
return Arrays.asList(inetAddressArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final boolean shouldContinue(CharSequence name, CharSequence hostname, List<InetAddress> hostAddresses) {
|
protected static boolean shouldContinue(CharSequence name, CharSequence hostname, List<InetAddress> hostAddresses) {
|
||||||
if (hostAddresses == null) {
|
if (hostAddresses == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,182 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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 + ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
|
@ -1,59 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* 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 Florian Schmaus.
|
* Copyright 2018-2020 Florian Schmaus.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -18,7 +18,6 @@ package org.jivesoftware.smack.util;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
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.SmackDaneProvider;
|
||||||
import org.jivesoftware.smack.util.dns.SmackDaneVerifier;
|
import org.jivesoftware.smack.util.dns.SmackDaneVerifier;
|
||||||
|
|
||||||
|
@ -26,15 +25,6 @@ import org.junit.Test;
|
||||||
|
|
||||||
public class DnsUtilTest {
|
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() {
|
private static final SmackDaneProvider DNS_UTIL_TEST_DANE_PROVIDER = new SmackDaneProvider() {
|
||||||
@Override
|
@Override
|
||||||
public SmackDaneVerifier newInstance() {
|
public SmackDaneVerifier newInstance() {
|
||||||
|
|
|
@ -26,10 +26,6 @@ public class StanzaIdProvider extends ExtensionElementProvider<StanzaIdElement>
|
||||||
|
|
||||||
public static final StanzaIdProvider INSTANCE = new StanzaIdProvider();
|
public static final StanzaIdProvider INSTANCE = new StanzaIdProvider();
|
||||||
|
|
||||||
// TODO: Remove in Smack 4.4.
|
|
||||||
@Deprecated
|
|
||||||
public static final StanzaIdProvider TEST_INSTANCE = INSTANCE;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StanzaIdElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) {
|
public StanzaIdElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) {
|
||||||
String id = parser.getAttributeValue(null, StanzaIdElement.ATTR_ID);
|
String id = parser.getAttributeValue(null, StanzaIdElement.ATTR_ID);
|
||||||
|
|
|
@ -2,24 +2,7 @@
|
||||||
<!-- Providers for workgroup extensions -->
|
<!-- Providers for workgroup extensions -->
|
||||||
<smackProviders>
|
<smackProviders>
|
||||||
|
|
||||||
<!-- XEP-0332 HTTP over XMPP transport -->
|
<!-- XEP-0280: Message Carbons -->
|
||||||
<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>
|
<extensionProvider>
|
||||||
<elementName>sent</elementName>
|
<elementName>sent</elementName>
|
||||||
<namespace>urn:xmpp:carbons:2</namespace>
|
<namespace>urn:xmpp:carbons:2</namespace>
|
||||||
|
@ -31,60 +14,7 @@
|
||||||
<className>org.jivesoftware.smackx.carbons.provider.CarbonManagerProvider</className>
|
<className>org.jivesoftware.smackx.carbons.provider.CarbonManagerProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- XEP-0352 Client State Indication -->
|
<!-- XEP-0313: Message Archive Management -->
|
||||||
<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>
|
<iqProvider>
|
||||||
<elementName>prefs</elementName>
|
<elementName>prefs</elementName>
|
||||||
<namespace>urn:xmpp:mam:1</namespace>
|
<namespace>urn:xmpp:mam:1</namespace>
|
||||||
|
@ -106,42 +36,22 @@
|
||||||
<className>org.jivesoftware.smackx.mam.provider.MamResultProvider</className>
|
<className>org.jivesoftware.smackx.mam.provider.MamResultProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- XEP-0347: Internet of Things - Discovery -->
|
<!-- XEP-0323: Internet of Things - Data -->
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>register</elementName>
|
<elementName>req</elementName>
|
||||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
<namespace>urn:xmpp:iot:sensordata</namespace>
|
||||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTRegisterProvider</className>
|
<className>org.jivesoftware.smackx.iot.data.provider.IoTDataRequestProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>claimed</elementName>
|
<elementName>accepted</elementName>
|
||||||
<namespace>urn:xmpp:iot:discovery</namespace>
|
<namespace>urn:xmpp:iot:sensordata</namespace>
|
||||||
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTClaimedProvider</className>
|
<className>org.jivesoftware.smackx.iot.data.provider.IoTDataReadOutAcceptedProvider</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>
|
</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 -->
|
<!-- XEP-0324: Internet of Things - Provisioning -->
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
|
@ -175,23 +85,6 @@
|
||||||
<className>org.jivesoftware.smackx.iot.provisioning.provider.UnfriendProvider</className>
|
<className>org.jivesoftware.smackx.iot.provisioning.provider.UnfriendProvider</className>
|
||||||
</extensionProvider>
|
</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 -->
|
<!-- XEP-0325: Internet of Things - Control -->
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>set</elementName>
|
<elementName>set</elementName>
|
||||||
|
@ -204,23 +97,28 @@
|
||||||
<className>org.jivesoftware.smackx.iot.control.provider.IoTSetResponseProvider</className>
|
<className>org.jivesoftware.smackx.iot.control.provider.IoTSetResponseProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<!-- XEP-0357 Push Notifications -->
|
<!-- XEP-0328: JID Preparation and Validation Service (JID Prep) -->
|
||||||
<extensionProvider>
|
<iqProvider>
|
||||||
<elementName>pubsub</elementName>
|
<elementName>jid</elementName>
|
||||||
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
<namespace>urn:xmpp:jidprep:0</namespace>
|
||||||
<className>org.jivesoftware.smackx.push_notifications.provider.RemoteDisablingProvider</className>
|
<className>org.jivesoftware.smackx.jid_prep.provider.JidPrepIqProvider</className>
|
||||||
</extensionProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<!-- XEP-0359: Stable and Unique Stanza IDs -->
|
<!-- 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>
|
<extensionProvider>
|
||||||
<elementName>stanza-id</elementName>
|
<elementName>chunk</elementName>
|
||||||
<namespace>urn:xmpp:sid:0</namespace>
|
<namespace>urn:xmpp:http</namespace>
|
||||||
<className>org.jivesoftware.smackx.sid.provider.StanzaIdProvider</className>
|
<className>org.jivesoftware.smackx.hoxt.provider.Base64BinaryChunkProvider</className>
|
||||||
</extensionProvider>
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>origin-id</elementName>
|
|
||||||
<namespace>urn:xmpp:sid:0</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.sid.provider.OriginIdProvider</className>
|
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- XEP-0333: Chat Markers -->
|
<!-- XEP-0333: Chat Markers -->
|
||||||
|
@ -267,6 +165,76 @@
|
||||||
<className>org.jivesoftware.smackx.hints.provider.StoreHintProvider</className>
|
<className>org.jivesoftware.smackx.hints.provider.StoreHintProvider</className>
|
||||||
</extensionProvider>
|
</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 -->
|
<!-- XEP-0363: HTTP File Upload -->
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>slot</elementName>
|
<elementName>slot</elementName>
|
||||||
|
@ -324,11 +292,46 @@
|
||||||
<className>org.jivesoftware.smackx.dox.provider.DnsIqProvider</className>
|
<className>org.jivesoftware.smackx.dox.provider.DnsIqProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<!-- XEP-0328: JID Prep -->
|
|
||||||
|
<!-- XEP-xxxx: Multi-User Chat Light -->
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>jid</elementName>
|
<elementName>query</elementName>
|
||||||
<namespace>urn:xmpp:jidprep:0</namespace>
|
<namespace>urn:xmpp:muclight:0#info</namespace>
|
||||||
<className>org.jivesoftware.smackx.jid_prep.provider.JidPrepIqProvider</className>
|
<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>
|
</iqProvider>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- GCM JSON payload -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>gcm</elementName>
|
||||||
|
<namespace>google:mobile:data</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
|
||||||
</smackProviders>
|
</smackProviders>
|
||||||
|
|
|
@ -2,426 +2,442 @@
|
||||||
<!-- Providers file for default Smack extensions -->
|
<!-- Providers file for default Smack extensions -->
|
||||||
<smackProviders>
|
<smackProviders>
|
||||||
|
|
||||||
<!-- Private Data Storage -->
|
<!-- XEP-0004: Data Forms-->
|
||||||
<iqProvider>
|
|
||||||
<elementName>query</elementName>
|
|
||||||
<namespace>jabber:iq:private</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.iqprivate.PrivateDataManager$PrivateDataIQProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<!-- Time -->
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>time</elementName>
|
|
||||||
<namespace>urn:xmpp:time</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.time.provider.TimeProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0085: Chat State -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>active</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/chatstates</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.chatstates.provider.ChatStateExtensionProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>composing</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/chatstates</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.chatstates.provider.ChatStateExtensionProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>paused</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/chatstates</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.chatstates.provider.ChatStateExtensionProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>inactive</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/chatstates</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.chatstates.provider.ChatStateExtensionProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>gone</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/chatstates</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.chatstates.provider.ChatStateExtensionProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- XHTML -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>html</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/xhtml-im</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.xhtmlim.provider.XHTMLExtensionProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- Group Chat Invitations -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>x</elementName>
|
|
||||||
<namespace>jabber:x:conference</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.muc.packet.GroupChatInvitation$Provider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- Service Discovery # Items -->
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>query</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/disco#items</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.disco.provider.DiscoverItemsProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<!-- Service Discovery # Info -->
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>query</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/disco#info</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.disco.provider.DiscoverInfoProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<!-- Data Forms-->
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>x</elementName>
|
<elementName>x</elementName>
|
||||||
<namespace>jabber:x:data</namespace>
|
<namespace>jabber:x:data</namespace>
|
||||||
<className>org.jivesoftware.smackx.xdata.provider.DataFormProvider</className>
|
<className>org.jivesoftware.smackx.xdata.provider.DataFormProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- MUC User -->
|
<!-- XEP-0012: Last Activity -->
|
||||||
<extensionProvider>
|
|
||||||
<elementName>x</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/muc#user</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.muc.provider.MUCUserProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- MUC Admin -->
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>query</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/muc#admin</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.muc.provider.MUCAdminProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<!-- MUC Owner -->
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>query</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/muc#owner</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.muc.provider.MUCOwnerProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<!-- Delayed Delivery -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>x</elementName>
|
|
||||||
<namespace>jabber:x:delay</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.delay.provider.LegacyDelayInformationProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>delay</elementName>
|
|
||||||
<namespace>urn:xmpp:delay</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.delay.provider.DelayInformationProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- Version -->
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>query</elementName>
|
|
||||||
<namespace>jabber:iq:version</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.iqversion.provider.VersionProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<!-- VCard -->
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>vCard</elementName>
|
|
||||||
<namespace>vcard-temp</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.vcardtemp.provider.VCardProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<!-- Offline Message Requests -->
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>offline</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/offline</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.offline.packet.OfflineMessageRequest$Provider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<!-- Offline Message Indicator -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>offline</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/offline</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.offline.packet.OfflineMessageInfo$Provider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- Last Activity -->
|
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>query</elementName>
|
<elementName>query</elementName>
|
||||||
<namespace>jabber:iq:last</namespace>
|
<namespace>jabber:iq:last</namespace>
|
||||||
<className>org.jivesoftware.smackx.iqlast.packet.LastActivity$Provider</className>
|
<className>org.jivesoftware.smackx.iqlast.packet.LastActivity$Provider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<!-- User Search -->
|
<!-- XEP-0013: Flexible Offline Message Retrieval -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>offline</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/offline</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.offline.packet.OfflineMessageRequest$Provider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>offline</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/offline</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.offline.packet.OfflineMessageInfo$Provider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0016: Privacy Lists -->
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>query</elementName>
|
<elementName>query</elementName>
|
||||||
<namespace>jabber:iq:search</namespace>
|
<namespace>jabber:iq:privacy</namespace>
|
||||||
<className>org.jivesoftware.smackx.search.UserSearch$Provider</className>
|
<className>org.jivesoftware.smackx.privacy.provider.PrivacyProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<!-- SharedGroupsInfo -->
|
<!-- XEP-0030: Service Discovery -->
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>sharedgroup</elementName>
|
<elementName>query</elementName>
|
||||||
<namespace>http://www.jivesoftware.org/protocol/sharedgroup</namespace>
|
<namespace>http://jabber.org/protocol/disco#items</namespace>
|
||||||
<className>org.jivesoftware.smackx.sharedgroups.packet.SharedGroupsInfo$Provider</className>
|
<className>org.jivesoftware.smackx.disco.provider.DiscoverItemsProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>query</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/disco#info</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.disco.provider.DiscoverInfoProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<!-- XEP-33: Extended Stanza Addressing -->
|
<!-- XEP-0033: Extended Stanza Addressing -->
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>addresses</elementName>
|
<elementName>addresses</elementName>
|
||||||
<namespace>http://jabber.org/protocol/address</namespace>
|
<namespace>http://jabber.org/protocol/address</namespace>
|
||||||
<className>org.jivesoftware.smackx.address.provider.MultipleAddressesProvider</className>
|
<className>org.jivesoftware.smackx.address.provider.MultipleAddressesProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- FileTransfer -->
|
<!-- XEP-0045: Multi-User Chat -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>x</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/muc#user</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.muc.provider.MUCUserProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>si</elementName>
|
<elementName>query</elementName>
|
||||||
<namespace>http://jabber.org/protocol/si</namespace>
|
<namespace>http://jabber.org/protocol/muc#admin</namespace>
|
||||||
<className>org.jivesoftware.smackx.si.provider.StreamInitiationProvider</className>
|
<className>org.jivesoftware.smackx.muc.provider.MUCAdminProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>query</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/muc#owner</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.muc.provider.MUCOwnerProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0047: In-Band Bytestreams -->
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>query</elementName>
|
<elementName>open</elementName>
|
||||||
<namespace>http://jabber.org/protocol/bytestreams</namespace>
|
<namespace>http://jabber.org/protocol/ibb</namespace>
|
||||||
<className>org.jivesoftware.smackx.bytestreams.socks5.provider.BytestreamsProvider</className>
|
<className>org.jivesoftware.smackx.bytestreams.ibb.provider.OpenIQProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>open</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/ibb</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.bytestreams.ibb.provider.OpenIQProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>data</elementName>
|
<elementName>data</elementName>
|
||||||
<namespace>http://jabber.org/protocol/ibb</namespace>
|
<namespace>http://jabber.org/protocol/ibb</namespace>
|
||||||
<className>org.jivesoftware.smackx.bytestreams.ibb.provider.DataPacketProvider$IQProvider</className>
|
<className>org.jivesoftware.smackx.bytestreams.ibb.provider.DataPacketProvider$IQProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>close</elementName>
|
<elementName>close</elementName>
|
||||||
<namespace>http://jabber.org/protocol/ibb</namespace>
|
<namespace>http://jabber.org/protocol/ibb</namespace>
|
||||||
<className>org.jivesoftware.smackx.bytestreams.ibb.provider.CloseIQProvider</className>
|
<className>org.jivesoftware.smackx.bytestreams.ibb.provider.CloseIQProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>data</elementName>
|
<elementName>data</elementName>
|
||||||
<namespace>http://jabber.org/protocol/ibb</namespace>
|
<namespace>http://jabber.org/protocol/ibb</namespace>
|
||||||
<className>org.jivesoftware.smackx.bytestreams.ibb.provider.DataPacketProvider$PacketExtensionProvider</className>
|
<className>org.jivesoftware.smackx.bytestreams.ibb.provider.DataPacketProvider$PacketExtensionProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- Ad-Hoc Command -->
|
<!-- XEP-0049: Private Data Storage -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>query</elementName>
|
||||||
|
<namespace>jabber:iq:private</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iqprivate.PrivateDataManager$PrivateDataIQProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0050: Ad-Hoc Commands -->
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>command</elementName>
|
<elementName>command</elementName>
|
||||||
<namespace>http://jabber.org/protocol/commands</namespace>
|
<namespace>http://jabber.org/protocol/commands</namespace>
|
||||||
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider</className>
|
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>bad-action</elementName>
|
<elementName>bad-action</elementName>
|
||||||
<namespace>http://jabber.org/protocol/commands</namespace>
|
<namespace>http://jabber.org/protocol/commands</namespace>
|
||||||
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider$BadActionError</className>
|
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider$BadActionError</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>malformed-actionn</elementName>
|
<elementName>malformed-actionn</elementName>
|
||||||
<namespace>http://jabber.org/protocol/commands</namespace>
|
<namespace>http://jabber.org/protocol/commands</namespace>
|
||||||
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider$MalformedActionError</className>
|
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider$MalformedActionError</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>bad-locale</elementName>
|
<elementName>bad-locale</elementName>
|
||||||
<namespace>http://jabber.org/protocol/commands</namespace>
|
<namespace>http://jabber.org/protocol/commands</namespace>
|
||||||
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider$BadLocaleError</className>
|
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider$BadLocaleError</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>bad-payload</elementName>
|
<elementName>bad-payload</elementName>
|
||||||
<namespace>http://jabber.org/protocol/commands</namespace>
|
<namespace>http://jabber.org/protocol/commands</namespace>
|
||||||
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider$BadPayloadError</className>
|
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider$BadPayloadError</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>bad-sessionid</elementName>
|
<elementName>bad-sessionid</elementName>
|
||||||
<namespace>http://jabber.org/protocol/commands</namespace>
|
<namespace>http://jabber.org/protocol/commands</namespace>
|
||||||
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider$BadSessionIDError</className>
|
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider$BadSessionIDError</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>session-expired</elementName>
|
<elementName>session-expired</elementName>
|
||||||
<namespace>http://jabber.org/protocol/commands</namespace>
|
<namespace>http://jabber.org/protocol/commands</namespace>
|
||||||
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider$SessionExpiredError</className>
|
<className>org.jivesoftware.smackx.commands.provider.AdHocCommandDataProvider$SessionExpiredError</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- SHIM -->
|
<!-- XEP-0054: VCard-Temp -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>vCard</elementName>
|
||||||
|
<namespace>vcard-temp</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.vcardtemp.provider.VCardProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0055: Jabber Search -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>query</elementName>
|
||||||
|
<namespace>jabber:iq:search</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.search.UserSearch$Provider</className>
|
||||||
|
</iqProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0059: Result Set Management (RSM) -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>set</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/rsm</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.rsm.provider.RSMSetProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0060: Publish-Subscribe -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>pubsub</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.PubSubProvider</className>
|
||||||
|
</iqProvider>
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>headers</elementName>
|
<elementName>create</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.SimpleNodeProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>items</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.ItemsProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>item</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.ItemProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>subscriptions</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.SubscriptionsProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>subscription</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>affiliations</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.AffiliationsProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>affiliation</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.AffiliationProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>options</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.FormNodeProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<!-- XEP-0060: pubsub#owner -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>affiliation</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#owner</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.AffiliationProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>pubsub</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#owner</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.PubSubProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>configure</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#owner</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.FormNodeProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>default</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#owner</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.FormNodeProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>subscriptions</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#owner</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.SubscriptionsProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>subscription</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#owner</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<!-- XEP-0060: pubsub#event -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>event</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.EventProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>configuration</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.ConfigEventProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>delete</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.SimpleNodeProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>options</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.FormNodeProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>items</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.ItemsProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>item</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.ItemProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>retract</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.RetractEventProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>purge</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.pubsub.provider.SimpleNodeProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0065: SOCKS5 Bytestreams -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>query</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/bytestreams</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.bytestreams.socks5.provider.BytestreamsProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0071: XHTML-IM -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>html</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/xhtml-im</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.xhtmlim.provider.XHTMLExtensionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0077: In-Band Registration -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>query</elementName>
|
||||||
|
<namespace>jabber:iq:register</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iqregister.provider.RegistrationProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<streamFeatureProvider>
|
||||||
|
<elementName>register</elementName>
|
||||||
|
<namespace>http://jabber.org/features/iq-register</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iqregister.provider.RegistrationStreamFeatureProvider</className>
|
||||||
|
</streamFeatureProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0079: Advanced Message Processing -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>amp</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/amp</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.amp.provider.AMPExtensionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0080: User Location -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>geoloc</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/geoloc</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.geoloc.provider.GeoLocationProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0085: Chat State Notifications -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>active</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/chatstates</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.chatstates.provider.ChatStateExtensionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>composing</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/chatstates</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.chatstates.provider.ChatStateExtensionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>paused</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/chatstates</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.chatstates.provider.ChatStateExtensionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>inactive</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/chatstates</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.chatstates.provider.ChatStateExtensionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>gone</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/chatstates</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.chatstates.provider.ChatStateExtensionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0091: Legacy Delayed Delivery -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>x</elementName>
|
||||||
|
<namespace>jabber:x:delay</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.delay.provider.LegacyDelayInformationProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0092: Software Version -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>query</elementName>
|
||||||
|
<namespace>jabber:iq:version</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iqversion.provider.VersionProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0096: SI File Transfer -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>si</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/si</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.si.provider.StreamInitiationProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0107: User Mood -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>mood</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/mood</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.mood.provider.MoodProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0115: Entity Capabilities -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>c</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/caps</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.caps.provider.CapsExtensionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
<streamFeatureProvider>
|
||||||
|
<elementName>c</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/caps</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.caps.provider.CapsExtensionProvider</className>
|
||||||
|
</streamFeatureProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0118: User Tune -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>tune</elementName>
|
||||||
|
<namespace>http://jabber.org/protocol/tune</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.usertune.provider.UserTuneProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0131: Stanza Headers and Internet Metadata (SHIM) -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>headers</elementName>
|
||||||
<namespace>http://jabber.org/protocol/shim</namespace>
|
<namespace>http://jabber.org/protocol/shim</namespace>
|
||||||
<className>org.jivesoftware.smackx.shim.provider.HeadersProvider</className>
|
<className>org.jivesoftware.smackx.shim.provider.HeadersProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>header</elementName>
|
<elementName>header</elementName>
|
||||||
<namespace>http://jabber.org/protocol/shim</namespace>
|
<namespace>http://jabber.org/protocol/shim</namespace>
|
||||||
<className>org.jivesoftware.smackx.shim.provider.HeaderProvider</className>
|
<className>org.jivesoftware.smackx.shim.provider.HeaderProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- XEP-0060 pubsub -->
|
<!-- XEP-0166: Jingle -->
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>pubsub</elementName>
|
<elementName>jingle</elementName>
|
||||||
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
<namespace>urn:xmpp:jingle:1</namespace>
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.PubSubProvider</className>
|
<className>org.jivesoftware.smackx.jingle.provider.JingleProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>create</elementName>
|
<elementName>out-of-order</elementName>
|
||||||
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
<namespace>urn:xmpp:jingle:errors:1</namespace>
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.SimpleNodeProvider</className>
|
<className>org.jivesoftware.smackx.jingle.provider.JingleErrorProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>items</elementName>
|
<elementName>unknown-session</elementName>
|
||||||
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
<namespace>urn:xmpp:jingle:errors:1</namespace>
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.ItemsProvider</className>
|
<className>org.jivesoftware.smackx.jingle.provider.JingleErrorProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>item</elementName>
|
<elementName>unsupported-content</elementName>
|
||||||
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
<namespace>urn:xmpp:jingle:errors:1</namespace>
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.ItemProvider</className>
|
<className>org.jivesoftware.smackx.jingle.provider.JingleErrorProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>subscriptions</elementName>
|
<elementName>unsupported-transports</elementName>
|
||||||
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
<namespace>urn:xmpp:jingle:errors:1</namespace>
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.SubscriptionsProvider</className>
|
<className>org.jivesoftware.smackx.jingle.provider.JingleErrorProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<!-- XEP-0172: User Nickname -->
|
||||||
<elementName>subscription</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>affiliations</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.AffiliationsProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>affiliation</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.AffiliationProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>options</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.FormNodeProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0060 pubsub#owner -->
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>affiliation</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#owner</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.AffiliationProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>pubsub</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#owner</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.PubSubProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>configure</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#owner</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.FormNodeProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>default</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#owner</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.FormNodeProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>subscriptions</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#owner</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.SubscriptionsProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>subscription</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#owner</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0060 pubsub#event -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>event</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.EventProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>configuration</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.ConfigEventProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>delete</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.SimpleNodeProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>options</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.FormNodeProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>items</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.ItemsProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>item</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.ItemProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>retract</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.RetractEventProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>purge</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/pubsub#event</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.pubsub.provider.SimpleNodeProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- Nick Exchange -->
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>nick</elementName>
|
<elementName>nick</elementName>
|
||||||
<namespace>http://jabber.org/protocol/nick</namespace>
|
<namespace>http://jabber.org/protocol/nick</namespace>
|
||||||
<className>org.jivesoftware.smackx.nick.provider.NickProvider</className>
|
<className>org.jivesoftware.smackx.nick.provider.NickProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- Attention -->
|
<!-- XEP-0184: Message Delivery Receipts -->
|
||||||
<extensionProvider>
|
|
||||||
<elementName>attention</elementName>
|
|
||||||
<namespace>urn:xmpp:attention:0</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.attention.packet.AttentionExtension$Provider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0184 Message Delivery Receipts -->
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>received</elementName>
|
<elementName>received</elementName>
|
||||||
<namespace>urn:xmpp:receipts</namespace>
|
<namespace>urn:xmpp:receipts</namespace>
|
||||||
|
@ -433,96 +449,7 @@
|
||||||
<className>org.jivesoftware.smackx.receipts.DeliveryReceiptRequest$Provider</className>
|
<className>org.jivesoftware.smackx.receipts.DeliveryReceiptRequest$Provider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- XEP-0115 Entity Capabilities -->
|
<!-- XEP-0191: Blocking Command -->
|
||||||
<extensionProvider>
|
|
||||||
<elementName>c</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/caps</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.caps.provider.CapsExtensionProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<streamFeatureProvider>
|
|
||||||
<elementName>c</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/caps</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.caps.provider.CapsExtensionProvider</className>
|
|
||||||
</streamFeatureProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0297 Stanza Forwarding -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>forwarded</elementName>
|
|
||||||
<namespace>urn:xmpp:forward:0</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.forward.provider.ForwardedProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- Ping (XEP-199) Manager -->
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>ping</elementName>
|
|
||||||
<namespace>urn:xmpp:ping</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.ping.provider.PingProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<!-- Privacy -->
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>query</elementName>
|
|
||||||
<namespace>jabber:iq:privacy</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.privacy.provider.PrivacyProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0079 Advanced Message Processing -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>amp</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/amp</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.amp.provider.AMPExtensionProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- JiveProperties -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>properties</elementName>
|
|
||||||
<namespace>http://www.jivesoftware.com/xmlns/xmpp/properties</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.jiveproperties.provider.JivePropertiesExtensionProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0077: In-Band Registration -->
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>query</elementName>
|
|
||||||
<namespace>jabber:iq:register</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.iqregister.provider.RegistrationProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<streamFeatureProvider>
|
|
||||||
<elementName>register</elementName>
|
|
||||||
<namespace>http://jabber.org/features/iq-register</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.iqregister.provider.RegistrationStreamFeatureProvider</className>
|
|
||||||
</streamFeatureProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0059: Result Set Management -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>set</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/rsm</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.rsm.provider.RSMSetProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0080: User Location -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>geoloc</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/geoloc</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.geoloc.provider.GeoLocationProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0308: Last Message Correction -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>replace</elementName>
|
|
||||||
<namespace>urn:xmpp:message-correct:0</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.message_correct.provider.MessageCorrectProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0319: Last User Interaction in Presence -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>idle</elementName>
|
|
||||||
<namespace>urn:xmpp:idle:1</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.last_interaction.provider.IdleProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0191 Blocking Command -->
|
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>blocklist</elementName>
|
<elementName>blocklist</elementName>
|
||||||
<namespace>urn:xmpp:blocking</namespace>
|
<namespace>urn:xmpp:blocking</namespace>
|
||||||
|
@ -544,6 +471,34 @@
|
||||||
<className>org.jivesoftware.smackx.blocking.provider.BlockedErrorExtensionProvider</className>
|
<className>org.jivesoftware.smackx.blocking.provider.BlockedErrorExtensionProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0199: XMPP Ping -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>ping</elementName>
|
||||||
|
<namespace>urn:xmpp:ping</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.ping.provider.PingProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0202: Entity Time -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>time</elementName>
|
||||||
|
<namespace>urn:xmpp:time</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.time.provider.TimeProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0203: Delayed Delivery -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>delay</elementName>
|
||||||
|
<namespace>urn:xmpp:delay</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.delay.provider.DelayInformationProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0224: Attention -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>attention</elementName>
|
||||||
|
<namespace>urn:xmpp:attention:0</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.attention.packet.AttentionExtension$Provider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- XEP-0231: Bits of Binary -->
|
<!-- XEP-0231: Bits of Binary -->
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>data</elementName>
|
<elementName>data</elementName>
|
||||||
|
@ -551,49 +506,46 @@
|
||||||
<className>org.jivesoftware.smackx.bob.provider.BoBIQProvider</className>
|
<className>org.jivesoftware.smackx.bob.provider.BoBIQProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<!-- XEP-0166: Jingle -->
|
<!-- XEP-0249: Group Chat Invitations -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>x</elementName>
|
||||||
|
<namespace>jabber:x:conference</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.muc.packet.GroupChatInvitation$Provider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0297: Stanza Forwarding -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>forwarded</elementName>
|
||||||
|
<namespace>urn:xmpp:forward:0</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.forward.provider.ForwardedProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0308: Last Message Correction -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>replace</elementName>
|
||||||
|
<namespace>urn:xmpp:message-correct:0</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.message_correct.provider.MessageCorrectProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0319: Last User Interaction in Presence -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>idle</elementName>
|
||||||
|
<namespace>urn:xmpp:idle:1</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.last_interaction.provider.IdleProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- JiveProperties -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>properties</elementName>
|
||||||
|
<namespace>http://www.jivesoftware.com/xmlns/xmpp/properties</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.jiveproperties.provider.JivePropertiesExtensionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- SharedGroupsInfo -->
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>jingle</elementName>
|
<elementName>sharedgroup</elementName>
|
||||||
<namespace>urn:xmpp:jingle:1</namespace>
|
<namespace>http://www.jivesoftware.org/protocol/sharedgroup</namespace>
|
||||||
<className>org.jivesoftware.smackx.jingle.provider.JingleProvider</className>
|
<className>org.jivesoftware.smackx.sharedgroups.packet.SharedGroupsInfo$Provider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>out-of-order</elementName>
|
|
||||||
<namespace>urn:xmpp:jingle:errors:1</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.jingle.provider.JingleErrorProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>unknown-session</elementName>
|
|
||||||
<namespace>urn:xmpp:jingle:errors:1</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.jingle.provider.JingleErrorProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>unsupported-content</elementName>
|
|
||||||
<namespace>urn:xmpp:jingle:errors:1</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.jingle.provider.JingleErrorProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>unsupported-transports</elementName>
|
|
||||||
<namespace>urn:xmpp:jingle:errors:1</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.jingle.provider.JingleErrorProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0107: User Mood -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>mood</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/mood</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.mood.provider.MoodProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0118: User Tune -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>tune</elementName>
|
|
||||||
<namespace>http://jabber.org/protocol/tune</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.usertune.provider.UserTuneProvider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
</smackProviders>
|
</smackProviders>
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<smackProviders>
|
<smackProviders>
|
||||||
|
|
||||||
|
<!-- RFC-6121: Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence -->
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>query</elementName>
|
<elementName>query</elementName>
|
||||||
<namespace>jabber:iq:roster</namespace>
|
<namespace>jabber:iq:roster</namespace>
|
||||||
<className>org.jivesoftware.smack.roster.provider.RosterPacketProvider</className>
|
<className>org.jivesoftware.smack.roster.provider.RosterPacketProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<streamFeatureProvider>
|
<streamFeatureProvider>
|
||||||
<elementName>sub</elementName>
|
<elementName>sub</elementName>
|
||||||
<namespace>urn:xmpp:features:pre-approval</namespace>
|
<namespace>urn:xmpp:features:pre-approval</namespace>
|
||||||
<className>org.jivesoftware.smack.roster.provider.SubscriptionPreApprovalStreamFeatureProvider</className>
|
<className>org.jivesoftware.smack.roster.provider.SubscriptionPreApprovalStreamFeatureProvider</className>
|
||||||
</streamFeatureProvider>
|
</streamFeatureProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0237: Roster Versioning -->
|
||||||
<streamFeatureProvider>
|
<streamFeatureProvider>
|
||||||
<elementName>ver</elementName>
|
<elementName>ver</elementName>
|
||||||
<namespace>urn:xmpp:features:rosterver</namespace>
|
<namespace>urn:xmpp:features:rosterver</namespace>
|
||||||
|
|
|
@ -7,13 +7,7 @@ mainClassName = 'org.igniterealtime.smack.inttest.SmackIntegrationTestFramework'
|
||||||
applicationDefaultJvmArgs = ["-enableassertions"]
|
applicationDefaultJvmArgs = ["-enableassertions"]
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':smack-java7')
|
api project(':smack-java8-full')
|
||||||
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 'org.reflections:reflections:0.9.11'
|
||||||
compile 'eu.geekplace.javapinning:java-pinning-java7:1.1.0-alpha1'
|
compile 'eu.geekplace.javapinning:java-pinning-java7:1.1.0-alpha1'
|
||||||
compile group: 'commons-io', name: 'commons-io', version: "$commonsIoVersion"
|
compile group: 'commons-io', name: 'commons-io', version: "$commonsIoVersion"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2019 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -45,7 +45,7 @@ public abstract class AbstractSmackIntTest {
|
||||||
|
|
||||||
protected final Configuration sinttestConfiguration;
|
protected final Configuration sinttestConfiguration;
|
||||||
|
|
||||||
protected AbstractSmackIntTest(SmackIntegrationTestEnvironment<?> environment) {
|
protected AbstractSmackIntTest(SmackIntegrationTestEnvironment environment) {
|
||||||
this.testRunId = environment.testRunId;
|
this.testRunId = environment.testRunId;
|
||||||
this.sinttestConfiguration = environment.configuration;
|
this.sinttestConfiguration = environment.configuration;
|
||||||
this.timeout = environment.configuration.replyTimeout;
|
this.timeout = environment.configuration.replyTimeout;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2018 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -46,7 +46,7 @@ public abstract class AbstractSmackIntegrationTest extends AbstractSmackIntTest
|
||||||
|
|
||||||
protected final List<XMPPConnection> connections;
|
protected final List<XMPPConnection> connections;
|
||||||
|
|
||||||
public AbstractSmackIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public AbstractSmackIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
this.connection = this.conOne = environment.conOne;
|
this.connection = this.conOne = environment.conOne;
|
||||||
this.conTwo = environment.conTwo;
|
this.conTwo = environment.conTwo;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2019 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -31,7 +31,7 @@ import org.jxmpp.jid.DomainBareJid;
|
||||||
|
|
||||||
public abstract class AbstractSmackLowLevelIntegrationTest extends AbstractSmackIntTest {
|
public abstract class AbstractSmackLowLevelIntegrationTest extends AbstractSmackIntTest {
|
||||||
|
|
||||||
private final SmackIntegrationTestEnvironment<?> environment;
|
private final SmackIntegrationTestEnvironment environment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The configuration
|
* The configuration
|
||||||
|
@ -40,7 +40,7 @@ public abstract class AbstractSmackLowLevelIntegrationTest extends AbstractSmack
|
||||||
|
|
||||||
protected final DomainBareJid service;
|
protected final DomainBareJid service;
|
||||||
|
|
||||||
protected AbstractSmackLowLevelIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
protected AbstractSmackLowLevelIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
this.configuration = environment.configuration;
|
this.configuration = environment.configuration;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2018-2019 Florian Schmaus
|
* Copyright 2018-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -28,19 +28,22 @@ import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
public abstract class AbstractSmackSpecificLowLevelIntegrationTest<C extends AbstractXMPPConnection>
|
public abstract class AbstractSmackSpecificLowLevelIntegrationTest<C extends AbstractXMPPConnection>
|
||||||
extends AbstractSmackLowLevelIntegrationTest {
|
extends AbstractSmackLowLevelIntegrationTest {
|
||||||
|
|
||||||
private final SmackIntegrationTestEnvironment<?> environment;
|
private final SmackIntegrationTestEnvironment environment;
|
||||||
|
|
||||||
protected final Class<C> connectionClass;
|
protected final Class<C> connectionClass;
|
||||||
|
|
||||||
private final XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor;
|
private final XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor;
|
||||||
|
|
||||||
public AbstractSmackSpecificLowLevelIntegrationTest(SmackIntegrationTestEnvironment<?> environment,
|
public AbstractSmackSpecificLowLevelIntegrationTest(SmackIntegrationTestEnvironment environment,
|
||||||
Class<C> connectionClass) {
|
Class<C> connectionClass) {
|
||||||
super(environment);
|
super(environment);
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
this.connectionClass = connectionClass;
|
this.connectionClass = connectionClass;
|
||||||
|
|
||||||
connectionDescriptor = environment.connectionManager.getConnectionDescriptorFor(connectionClass);
|
connectionDescriptor = environment.connectionManager.getConnectionDescriptorFor(connectionClass);
|
||||||
|
if (connectionDescriptor == null) {
|
||||||
|
throw new IllegalStateException("No connection descriptor for " + connectionClass + " known");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<C> getConnectionClass() {
|
public Class<C> getConnectionClass() {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2018 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -33,7 +33,9 @@ import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
|
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
|
||||||
import org.jivesoftware.smack.debugger.ConsoleDebugger;
|
import org.jivesoftware.smack.debugger.ConsoleDebugger;
|
||||||
|
import org.jivesoftware.smack.util.Function;
|
||||||
import org.jivesoftware.smack.util.Objects;
|
import org.jivesoftware.smack.util.Objects;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.debugger.EnhancedDebugger;
|
import org.jivesoftware.smackx.debugger.EnhancedDebugger;
|
||||||
|
@ -94,80 +96,90 @@ public final class Configuration {
|
||||||
|
|
||||||
public final Set<String> disabledTests;
|
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 Set<String> testPackages;
|
||||||
|
|
||||||
public final ConnectionConfigurationBuilderApplier configurationApplier;
|
public final ConnectionConfigurationBuilderApplier configurationApplier;
|
||||||
|
|
||||||
private Configuration(DomainBareJid service, String serviceTlsPin, SecurityMode securityMode, int replyTimeout,
|
public final boolean verbose;
|
||||||
Debugger debugger, String accountOneUsername, String accountOnePassword, String accountTwoUsername,
|
|
||||||
String accountTwoPassword, String accountThreeUsername, String accountThreePassword, Set<String> enabledTests, Set<String> disabledTests,
|
private Configuration(Configuration.Builder builder) throws KeyManagementException, NoSuchAlgorithmException {
|
||||||
Set<String> testPackages, String adminAccountUsername, String adminAccountPassword)
|
service = Objects.requireNonNull(builder.service,
|
||||||
throws KeyManagementException, NoSuchAlgorithmException {
|
|
||||||
this.service = Objects.requireNonNull(service,
|
|
||||||
"'service' must be set. Either via 'properties' files or via system property 'sinttest.service'.");
|
"'service' must be set. Either via 'properties' files or via system property 'sinttest.service'.");
|
||||||
this.serviceTlsPin = serviceTlsPin;
|
serviceTlsPin = builder.serviceTlsPin;
|
||||||
if (serviceTlsPin != null) {
|
if (serviceTlsPin != null) {
|
||||||
tlsContext = Java7Pinning.forPin(serviceTlsPin);
|
tlsContext = Java7Pinning.forPin(serviceTlsPin);
|
||||||
} else {
|
} else {
|
||||||
tlsContext = null;
|
tlsContext = null;
|
||||||
}
|
}
|
||||||
this.securityMode = securityMode;
|
securityMode = builder.securityMode;
|
||||||
if (replyTimeout > 0) {
|
if (builder.replyTimeout > 0) {
|
||||||
this.replyTimeout = replyTimeout;
|
replyTimeout = builder.replyTimeout;
|
||||||
} else {
|
} else {
|
||||||
this.replyTimeout = 60000;
|
replyTimeout = 60000;
|
||||||
}
|
}
|
||||||
this.debugger = debugger;
|
debugger = builder.debugger;
|
||||||
if (StringUtils.isNotEmpty(adminAccountUsername, adminAccountPassword)) {
|
if (StringUtils.isNotEmpty(builder.adminAccountUsername, builder.adminAccountPassword)) {
|
||||||
accountRegistration = AccountRegistration.serviceAdministration;
|
accountRegistration = AccountRegistration.serviceAdministration;
|
||||||
}
|
}
|
||||||
else if (StringUtils.isNotEmpty(accountOneUsername, accountOnePassword, accountTwoUsername, accountTwoPassword,
|
else if (StringUtils.isNotEmpty(builder.accountOneUsername, builder.accountOnePassword,
|
||||||
accountThreeUsername, accountThreePassword)) {
|
builder.accountTwoUsername, builder.accountTwoPassword, builder.accountThreeUsername,
|
||||||
|
builder.accountThreePassword)) {
|
||||||
accountRegistration = AccountRegistration.disabled;
|
accountRegistration = AccountRegistration.disabled;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
accountRegistration = AccountRegistration.inBandRegistration;
|
accountRegistration = AccountRegistration.inBandRegistration;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.adminAccountUsername = adminAccountUsername;
|
this.adminAccountUsername = builder.adminAccountUsername;
|
||||||
this.adminAccountPassword = adminAccountPassword;
|
this.adminAccountPassword = builder.adminAccountPassword;
|
||||||
|
|
||||||
boolean accountOnePasswordSet = StringUtils.isNotEmpty(accountOnePassword);
|
boolean accountOnePasswordSet = StringUtils.isNotEmpty(builder.accountOnePassword);
|
||||||
if (accountOnePasswordSet != StringUtils.isNotEmpty(accountTwoPassword) ||
|
if (accountOnePasswordSet != StringUtils.isNotEmpty(builder.accountTwoPassword) ||
|
||||||
accountOnePasswordSet != StringUtils.isNotEmpty(accountThreePassword)) {
|
accountOnePasswordSet != StringUtils.isNotEmpty(builder.accountThreePassword)) {
|
||||||
// Ensure the invariant that either all main accounts have a password set, or none.
|
// Ensure the invariant that either all main accounts have a password set, or none.
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.accountOneUsername = accountOneUsername;
|
this.accountOneUsername = builder.accountOneUsername;
|
||||||
this.accountOnePassword = accountOnePassword;
|
this.accountOnePassword = builder.accountOnePassword;
|
||||||
this.accountTwoUsername = accountTwoUsername;
|
this.accountTwoUsername = builder.accountTwoUsername;
|
||||||
this.accountTwoPassword = accountTwoPassword;
|
this.accountTwoPassword = builder.accountTwoPassword;
|
||||||
this.accountThreeUsername = accountThreeUsername;
|
this.accountThreeUsername = builder.accountThreeUsername;
|
||||||
this.accountThreePassword = accountThreePassword;
|
this.accountThreePassword = builder.accountThreePassword;
|
||||||
this.enabledTests = enabledTests;
|
this.enabledTests = builder.enabledTests;
|
||||||
this.disabledTests = disabledTests;
|
this.disabledTests = builder.disabledTests;
|
||||||
this.testPackages = testPackages;
|
this.defaultConnectionNickname = builder.defaultConnectionNickname;
|
||||||
|
this.enabledConnections = builder.enabledConnections;
|
||||||
|
this.disabledConnections = builder.disabledConnections;
|
||||||
|
this.testPackages = builder.testPackages;
|
||||||
|
|
||||||
this.configurationApplier = builder -> {
|
this.configurationApplier = b -> {
|
||||||
if (tlsContext != null) {
|
if (tlsContext != null) {
|
||||||
builder.setCustomSSLContext(tlsContext);
|
b.setCustomSSLContext(tlsContext);
|
||||||
}
|
}
|
||||||
builder.setSecurityMode(securityMode);
|
b.setSecurityMode(securityMode);
|
||||||
builder.setXmppDomain(service);
|
b.setXmppDomain(service);
|
||||||
|
|
||||||
switch (debugger) {
|
switch (debugger) {
|
||||||
case enhanced:
|
case enhanced:
|
||||||
builder.setDebuggerFactory(EnhancedDebugger.Factory.INSTANCE);
|
b.setDebuggerFactory(EnhancedDebugger.Factory.INSTANCE);
|
||||||
break;
|
break;
|
||||||
case console:
|
case console:
|
||||||
builder.setDebuggerFactory(ConsoleDebugger.Factory.INSTANCE);
|
b.setDebuggerFactory(ConsoleDebugger.Factory.INSTANCE);
|
||||||
break;
|
break;
|
||||||
case none:
|
case none:
|
||||||
// Nothing to do :).
|
// Nothing to do :).
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.verbose = builder.verbose;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAccountRegistrationPossible() {
|
public boolean isAccountRegistrationPossible() {
|
||||||
|
@ -210,8 +222,16 @@ public final class Configuration {
|
||||||
|
|
||||||
private Set<String> disabledTests;
|
private Set<String> disabledTests;
|
||||||
|
|
||||||
|
private String defaultConnectionNickname;
|
||||||
|
|
||||||
|
private Set<String> enabledConnections;
|
||||||
|
|
||||||
|
private Set<String> disabledConnections;
|
||||||
|
|
||||||
private Set<String> testPackages;
|
private Set<String> testPackages;
|
||||||
|
|
||||||
|
private boolean verbose;
|
||||||
|
|
||||||
private Builder() {
|
private Builder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,6 +344,21 @@ public final class Configuration {
|
||||||
return this;
|
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) {
|
public Builder addTestPackages(String testPackagesString) {
|
||||||
if (testPackagesString != null) {
|
if (testPackagesString != null) {
|
||||||
String[] testPackagesArray = testPackagesString.split(",");
|
String[] testPackagesArray = testPackagesString.split(",");
|
||||||
|
@ -350,10 +385,22 @@ public final class Configuration {
|
||||||
return this;
|
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 {
|
public Configuration build() throws KeyManagementException, NoSuchAlgorithmException {
|
||||||
return new Configuration(service, serviceTlsPin, securityMode, replyTimeout, debugger, accountOneUsername,
|
return new Configuration(this);
|
||||||
accountOnePassword, accountTwoUsername, accountTwoPassword, accountThreeUsername, accountThreePassword, enabledTests, disabledTests,
|
|
||||||
testPackages, adminAccountUsername, adminAccountPassword);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,10 +461,15 @@ public final class Configuration {
|
||||||
builder.setDebugger(properties.getProperty("debugger"));
|
builder.setDebugger(properties.getProperty("debugger"));
|
||||||
builder.setEnabledTests(properties.getProperty("enabledTests"));
|
builder.setEnabledTests(properties.getProperty("enabledTests"));
|
||||||
builder.setDisabledTests(properties.getProperty("disabledTests"));
|
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(properties.getProperty("testPackages"));
|
||||||
builder.addTestPackages(testPackages);
|
builder.addTestPackages(testPackages);
|
||||||
|
|
||||||
|
builder.setVerbose(properties.getProperty("verbose"));
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,23 +489,36 @@ public final class Configuration {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> getTestSetFrom(String string) {
|
private static Set<String> split(String input) {
|
||||||
if (string == null) {
|
return split(input, Function.identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<String> split(String input, Function<String, String> transformer) {
|
||||||
|
if (input == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String[] stringArray = string.split(",");
|
|
||||||
Set<String> res = new HashSet<>(stringArray.length);
|
String[] inputArray = input.split(",");
|
||||||
for (String s : stringArray) {
|
Set<String> res = new HashSet<>(inputArray.length);
|
||||||
res.add(getFullTestStringFrom(s));
|
for (String s : inputArray) {
|
||||||
|
s = transformer.apply(s);
|
||||||
|
boolean newElement = res.add(s);
|
||||||
|
if (!newElement) {
|
||||||
|
throw new IllegalArgumentException("The argument '" + s + "' was already provided.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getFullTestStringFrom(String string) {
|
private static Set<String> getTestSetFrom(String input) {
|
||||||
string = string.trim();
|
return split(input, s -> {
|
||||||
if (string.startsWith("smackx.") || string.startsWith("smack.")) {
|
s = s.trim();
|
||||||
string = "org.jivesoftware." + string;
|
if (s.startsWith("smackx.") || s.startsWith("smack.")) {
|
||||||
}
|
s = "org.jivesoftware." + s;
|
||||||
return string;
|
}
|
||||||
|
return s;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2019 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -18,18 +18,18 @@ package org.igniterealtime.smack.inttest;
|
||||||
|
|
||||||
import org.jivesoftware.smack.AbstractXMPPConnection;
|
import org.jivesoftware.smack.AbstractXMPPConnection;
|
||||||
|
|
||||||
public class SmackIntegrationTestEnvironment<C extends AbstractXMPPConnection> {
|
public class SmackIntegrationTestEnvironment {
|
||||||
|
|
||||||
public final C conOne, conTwo, conThree;
|
public final AbstractXMPPConnection conOne, conTwo, conThree;
|
||||||
|
|
||||||
public final String testRunId;
|
public final String testRunId;
|
||||||
|
|
||||||
public final Configuration configuration;
|
public final Configuration configuration;
|
||||||
|
|
||||||
public final XmppConnectionManager<C> connectionManager;
|
public final XmppConnectionManager connectionManager;
|
||||||
|
|
||||||
SmackIntegrationTestEnvironment(C conOne, C conTwo, C conThree, String testRunId,
|
SmackIntegrationTestEnvironment(AbstractXMPPConnection conOne, AbstractXMPPConnection conTwo, AbstractXMPPConnection conThree, String testRunId,
|
||||||
Configuration configuration, XmppConnectionManager<C> connectionManager) {
|
Configuration configuration, XmppConnectionManager connectionManager) {
|
||||||
this.conOne = conOne;
|
this.conOne = conOne;
|
||||||
this.conTwo = conTwo;
|
this.conTwo = conTwo;
|
||||||
this.conThree = conThree;
|
this.conThree = conThree;
|
||||||
|
|
|
@ -23,6 +23,7 @@ import static org.reflections.ReflectionUtils.withParametersCount;
|
||||||
import static org.reflections.ReflectionUtils.withReturnType;
|
import static org.reflections.ReflectionUtils.withReturnType;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
@ -32,6 +33,7 @@ import java.lang.reflect.Type;
|
||||||
import java.security.KeyManagementException;
|
import java.security.KeyManagementException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -43,7 +45,6 @@ import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
@ -53,7 +54,6 @@ import org.jivesoftware.smack.SmackConfiguration;
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
import org.jivesoftware.smack.XMPPException;
|
||||||
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
|
||||||
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
import org.jivesoftware.smack.util.TLSUtils;
|
import org.jivesoftware.smack.util.TLSUtils;
|
||||||
|
@ -70,7 +70,7 @@ import org.reflections.scanners.MethodParameterScanner;
|
||||||
import org.reflections.scanners.SubTypesScanner;
|
import org.reflections.scanners.SubTypesScanner;
|
||||||
import org.reflections.scanners.TypeAnnotationsScanner;
|
import org.reflections.scanners.TypeAnnotationsScanner;
|
||||||
|
|
||||||
public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
public class SmackIntegrationTestFramework {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
TLSUtils.setDefaultTrustStoreTypeToJksIfRequired();
|
TLSUtils.setDefaultTrustStoreTypeToJksIfRequired();
|
||||||
|
@ -80,14 +80,12 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
|
|
||||||
public static boolean SINTTEST_UNIT_TEST = false;
|
public static boolean SINTTEST_UNIT_TEST = false;
|
||||||
|
|
||||||
private final Class<DC> defaultConnectionClass;
|
|
||||||
|
|
||||||
protected final Configuration config;
|
protected final Configuration config;
|
||||||
|
|
||||||
protected TestRunResult testRunResult;
|
protected TestRunResult testRunResult;
|
||||||
|
|
||||||
private SmackIntegrationTestEnvironment<DC> environment;
|
private SmackIntegrationTestEnvironment environment;
|
||||||
protected XmppConnectionManager<DC> connectionManager;
|
protected XmppConnectionManager connectionManager;
|
||||||
|
|
||||||
public enum TestType {
|
public enum TestType {
|
||||||
Normal,
|
Normal,
|
||||||
|
@ -100,7 +98,7 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||||
Configuration config = Configuration.newConfiguration(args);
|
Configuration config = Configuration.newConfiguration(args);
|
||||||
|
|
||||||
SmackIntegrationTestFramework<XMPPTCPConnection> sinttest = new SmackIntegrationTestFramework<>(config, XMPPTCPConnection.class);
|
SmackIntegrationTestFramework sinttest = new SmackIntegrationTestFramework(config);
|
||||||
TestRunResult testRunResult = sinttest.run();
|
TestRunResult testRunResult = sinttest.run();
|
||||||
|
|
||||||
for (Entry<Class<? extends AbstractSmackIntTest>, Throwable> entry : testRunResult.impossibleTestClasses.entrySet()) {
|
for (Entry<Class<? extends AbstractSmackIntTest>, Throwable> entry : testRunResult.impossibleTestClasses.entrySet()) {
|
||||||
|
@ -116,11 +114,9 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
}
|
}
|
||||||
final int successfulTests = testRunResult.successfulIntegrationTests.size();
|
final int successfulTests = testRunResult.successfulIntegrationTests.size();
|
||||||
final int failedTests = testRunResult.failedIntegrationTests.size();
|
final int failedTests = testRunResult.failedIntegrationTests.size();
|
||||||
final int totalIntegrationTests = successfulTests + failedTests;
|
|
||||||
final int availableTests = testRunResult.getNumberOfAvailableTests();
|
final int availableTests = testRunResult.getNumberOfAvailableTests();
|
||||||
final int possibleTests = testRunResult.getNumberOfPossibleTests();
|
LOGGER.info("SmackIntegrationTestFramework[" + testRunResult.testRunId + ']' + " finished: "
|
||||||
LOGGER.info("SmackIntegrationTestFramework[" + testRunResult.testRunId + ']' + ": Finished ["
|
+ successfulTests + '/' + availableTests + " [" + failedTests + " failed]");
|
||||||
+ successfulTests + '/' + totalIntegrationTests + "] (" + possibleTests + " test methods of " + availableTests + " where possible)");
|
|
||||||
|
|
||||||
final int exitStatus;
|
final int exitStatus;
|
||||||
if (failedTests > 0) {
|
if (failedTests > 0) {
|
||||||
|
@ -146,12 +142,8 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
System.exit(exitStatus);
|
System.exit(exitStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SmackIntegrationTestFramework(Configuration configuration, Class<DC> defaultConnectionClass)
|
public SmackIntegrationTestFramework(Configuration configuration) {
|
||||||
throws KeyManagementException, InstantiationException, IllegalAccessException, IllegalArgumentException,
|
|
||||||
InvocationTargetException, NoSuchAlgorithmException, SmackException, IOException, XMPPException,
|
|
||||||
InterruptedException {
|
|
||||||
this.config = configuration;
|
this.config = configuration;
|
||||||
this.defaultConnectionClass = defaultConnectionClass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized TestRunResult run()
|
public synchronized TestRunResult run()
|
||||||
|
@ -160,7 +152,7 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
testRunResult = new TestRunResult();
|
testRunResult = new TestRunResult();
|
||||||
|
|
||||||
// Create a connection manager *after* we created the testRunId (in testRunResult).
|
// Create a connection manager *after* we created the testRunId (in testRunResult).
|
||||||
this.connectionManager = new XmppConnectionManager<>(this, defaultConnectionClass);
|
this.connectionManager = new XmppConnectionManager(this);
|
||||||
|
|
||||||
LOGGER.info("SmackIntegrationTestFramework [" + testRunResult.testRunId + ']' + ": Starting");
|
LOGGER.info("SmackIntegrationTestFramework [" + testRunResult.testRunId + ']' + ": Starting");
|
||||||
if (config.debugger != Configuration.Debugger.none) {
|
if (config.debugger != Configuration.Debugger.none) {
|
||||||
|
@ -226,10 +218,13 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
return testRunResult;
|
return testRunResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "Finally"})
|
@SuppressWarnings({"Finally"})
|
||||||
private void runTests(Set<Class<? extends AbstractSmackIntTest>> classes)
|
private void runTests(Set<Class<? extends AbstractSmackIntTest>> classes)
|
||||||
throws InterruptedException, InstantiationException, IllegalAccessException,
|
throws InterruptedException, InstantiationException, IllegalAccessException,
|
||||||
IllegalArgumentException, SmackException, IOException, XMPPException {
|
IllegalArgumentException, SmackException, IOException, XMPPException {
|
||||||
|
List<PreparedTest> tests = new ArrayList<>(classes.size());
|
||||||
|
int numberOfAvailableTests = 0;
|
||||||
|
|
||||||
for (Class<? extends AbstractSmackIntTest> testClass : classes) {
|
for (Class<? extends AbstractSmackIntTest> testClass : classes) {
|
||||||
final String testClassName = testClass.getName();
|
final String testClassName = testClass.getName();
|
||||||
|
|
||||||
|
@ -260,17 +255,19 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
// - https://discuss.gradle.org/t/main-vs-test-compile-vs-runtime-classpaths-in-eclipse-once-and-for-all-how/17403
|
// - 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)
|
// - 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")) {
|
if (!SINTTEST_UNIT_TEST && testClassName.startsWith("org.igniterealtime.smack.inttest.unittest")) {
|
||||||
LOGGER.finer("Skipping integration test '" + testClassName + "' from src/test classpath");
|
LOGGER.warning("Skipping integration test '" + testClassName + "' from src/test classpath (should not be in classpath)");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.enabledTests != null && !isInSet(testClass, config.enabledTests)) {
|
if (config.enabledTests != null && !isInSet(testClass, config.enabledTests)) {
|
||||||
LOGGER.info("Skipping test class " + testClassName + " because it is not enabled");
|
DisabledTestClass disabledTestClass = new DisabledTestClass(testClass, "Skipping test class " + testClassName + " because it is not enabled");
|
||||||
|
testRunResult.disabledTestClasses.add(disabledTestClass);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInSet(testClass, config.disabledTests)) {
|
if (isInSet(testClass, config.disabledTests)) {
|
||||||
LOGGER.info("Skipping test class " + testClassName + " because it is disalbed");
|
DisabledTestClass disabledTestClass = new DisabledTestClass(testClass, "Skipping test class " + testClassName + " because it is disalbed");
|
||||||
|
testRunResult.disabledTestClasses.add(disabledTestClass);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,8 +298,6 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
testRunResult.numberOfAvailableTestMethods.addAndGet(smackIntegrationTestMethods.size());
|
|
||||||
|
|
||||||
final AbstractSmackIntTest test;
|
final AbstractSmackIntTest test;
|
||||||
try {
|
try {
|
||||||
test = cons.newInstance(environment);
|
test = cons.newInstance(environment);
|
||||||
|
@ -360,12 +355,14 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
final String methodName = method.getName();
|
final String methodName = method.getName();
|
||||||
if (config.enabledTests != null && !(config.enabledTests.contains(methodName)
|
if (config.enabledTests != null && !(config.enabledTests.contains(methodName)
|
||||||
|| isInSet(testClass, config.enabledTests))) {
|
|| isInSet(testClass, config.enabledTests))) {
|
||||||
LOGGER.fine("Skipping test method " + methodName + " because it is not enabled");
|
DisabledTest disabledTest = new DisabledTest(method, "Skipping test method " + methodName + " because it is not enabled");
|
||||||
|
testRunResult.disabledTests.add(disabledTest);
|
||||||
it.remove();
|
it.remove();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (config.disabledTests != null && config.disabledTests.contains(methodName)) {
|
if (config.disabledTests != null && config.disabledTests.contains(methodName)) {
|
||||||
LOGGER.info("Skipping test method " + methodName + " because it is disabled");
|
DisabledTest disabledTest = new DisabledTest(method, "Skipping test method " + methodName + " because it is disabled");
|
||||||
|
testRunResult.disabledTests.add(disabledTest);
|
||||||
it.remove();
|
it.remove();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -376,106 +373,77 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int detectedTestMethodsCount = smackIntegrationTestMethods.size();
|
List<ConcreteTest> concreteTests = new ArrayList<>(smackIntegrationTestMethods.size());
|
||||||
testRunResult.numberOfPossibleTestMethods.addAndGet(detectedTestMethodsCount);
|
|
||||||
|
|
||||||
try {
|
for (Method testMethod : smackIntegrationTestMethods) {
|
||||||
// Run the @BeforeClass methods (if any)
|
switch (testType) {
|
||||||
Set<Method> beforeClassMethods = getAllMethods(testClass,
|
case Normal: {
|
||||||
withAnnotation(BeforeClass.class), withReturnType(Void.TYPE),
|
ConcreteTest.Executor concreteTestExecutor = () -> testMethod.invoke(test);
|
||||||
withParametersCount(0), withModifier(Modifier.PUBLIC
|
ConcreteTest concreteTest = new ConcreteTest(testType, testMethod, concreteTestExecutor);
|
||||||
));
|
concreteTests.add(concreteTest);
|
||||||
|
|
||||||
// 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;
|
||||||
if (beforeClassMethods.size() == 1) {
|
case LowLevel:
|
||||||
Method beforeClassMethod = beforeClassMethods.iterator().next();
|
case SpecificLowLevel:
|
||||||
LOGGER.info("Executing @BeforeClass method of " + testClass);
|
LowLevelTestMethod lowLevelTestMethod = new LowLevelTestMethod(testMethod);
|
||||||
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) {
|
switch (testType) {
|
||||||
case Normal: {
|
|
||||||
ConcreteTest.Executor concreteTestExecutor = () -> testMethod.invoke(test);
|
|
||||||
ConcreteTest concreteTest = new ConcreteTest(testType, testMethod, concreteTestExecutor);
|
|
||||||
concreteTests = Collections.singletonList(concreteTest);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LowLevel:
|
case LowLevel:
|
||||||
case SpecificLowLevel:
|
List<ConcreteTest> concreteLowLevelTests = invokeLowLevel(lowLevelTestMethod, (AbstractSmackLowLevelIntegrationTest) test);
|
||||||
LowLevelTestMethod lowLevelTestMethod = new LowLevelTestMethod(testMethod);
|
concreteTests.addAll(concreteLowLevelTests);
|
||||||
switch (testType) {
|
break;
|
||||||
case LowLevel:
|
case SpecificLowLevel: {
|
||||||
concreteTests = invokeLowLevel(lowLevelTestMethod, (AbstractSmackLowLevelIntegrationTest) test);
|
ConcreteTest.Executor concreteTestExecutor = () -> invokeSpecificLowLevel(
|
||||||
break;
|
lowLevelTestMethod, (AbstractSmackSpecificLowLevelIntegrationTest<?>) test);
|
||||||
case SpecificLowLevel: {
|
ConcreteTest concreteTest = new ConcreteTest(testType, testMethod, concreteTestExecutor);
|
||||||
ConcreteTest.Executor concreteTestExecutor = () -> invokeSpecificLowLevel(
|
concreteTests.add(concreteTest);
|
||||||
lowLevelTestMethod, (AbstractSmackSpecificLowLevelIntegrationTest<?>) test);
|
|
||||||
ConcreteTest concreteTest = new ConcreteTest(testType, testMethod, concreteTestExecutor);
|
|
||||||
concreteTests = Collections.singletonList(concreteTest);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new AssertionError();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
for (ConcreteTest concreteTest : concreteTests) {
|
throw new AssertionError();
|
||||||
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
|
|
||||||
));
|
|
||||||
|
|
||||||
// See if there are any methods that have the @AfterClassAnnotation but a wrong signature
|
// Instantiate the prepared test early as this will check the before and after class annotations.
|
||||||
Set<Method> allAfterClassMethods = getAllMethods(testClass, withAnnotation(AfterClass.class));
|
PreparedTest preparedTest = new PreparedTest(test, concreteTests);
|
||||||
allAfterClassMethods.removeAll(afterClassMethods);
|
tests.add(preparedTest);
|
||||||
if (!allAfterClassMethods.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("@AfterClass methods with wrong signature found");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (afterClassMethods.size() == 1) {
|
numberOfAvailableTests += concreteTests.size();
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 (!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)
|
private void runConcreteTest(ConcreteTest concreteTest)
|
||||||
|
@ -524,17 +492,35 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ConcreteTest> invokeLowLevel(LowLevelTestMethod lowLevelTestMethod, AbstractSmackLowLevelIntegrationTest test) {
|
private List<ConcreteTest> invokeLowLevel(LowLevelTestMethod lowLevelTestMethod, AbstractSmackLowLevelIntegrationTest test) {
|
||||||
Set<Class<? extends AbstractXMPPConnection>> connectionClasses;
|
Collection<? extends XmppConnectionDescriptor<?, ?, ?>> connectionDescriptors;
|
||||||
if (lowLevelTestMethod.smackIntegrationTestAnnotation.onlyDefaultConnectionType()) {
|
if (lowLevelTestMethod.smackIntegrationTestAnnotation.onlyDefaultConnectionType()) {
|
||||||
Class<? extends AbstractXMPPConnection> defaultConnectionClass = connectionManager.getDefaultConnectionClass();
|
XmppConnectionDescriptor<?, ?, ?> defaultConnectionDescriptor = connectionManager.getDefaultConnectionDescriptor();
|
||||||
connectionClasses = Collections.singleton(defaultConnectionClass);
|
connectionDescriptors = Collections.singleton(defaultConnectionDescriptor);
|
||||||
} else {
|
} else {
|
||||||
connectionClasses = connectionManager.getConnectionClasses();
|
connectionDescriptors = connectionManager.getConnectionDescriptors();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ConcreteTest> resultingConcreteTests = new ArrayList<>(connectionClasses.size());
|
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();
|
||||||
|
|
||||||
for (Class<? extends AbstractXMPPConnection> connectionClass : connectionClasses) {
|
|
||||||
ConcreteTest.Executor executor = () -> lowLevelTestMethod.invoke(test, connectionClass);
|
ConcreteTest.Executor executor = () -> lowLevelTestMethod.invoke(test, connectionClass);
|
||||||
ConcreteTest concreteTest = new ConcreteTest(TestType.LowLevel, lowLevelTestMethod.testMethod, executor, connectionClass.getSimpleName());
|
ConcreteTest concreteTest = new ConcreteTest(TestType.LowLevel, lowLevelTestMethod.testMethod, executor, connectionClass.getSimpleName());
|
||||||
resultingConcreteTests.add(concreteTest);
|
resultingConcreteTests.add(concreteTest);
|
||||||
|
@ -543,7 +529,7 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
return resultingConcreteTests;
|
return resultingConcreteTests;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <C extends AbstractXMPPConnection> void invokeSpecificLowLevel(LowLevelTestMethod testMethod,
|
private static <C extends AbstractXMPPConnection> void invokeSpecificLowLevel(LowLevelTestMethod testMethod,
|
||||||
AbstractSmackSpecificLowLevelIntegrationTest<C> test)
|
AbstractSmackSpecificLowLevelIntegrationTest<C> test)
|
||||||
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InterruptedException,
|
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InterruptedException,
|
||||||
SmackException, IOException, XMPPException {
|
SmackException, IOException, XMPPException {
|
||||||
|
@ -554,7 +540,7 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
testMethod.invoke(test, connectionClass);
|
testMethod.invoke(test, connectionClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SmackIntegrationTestEnvironment<DC> prepareEnvironment() throws SmackException,
|
protected SmackIntegrationTestEnvironment prepareEnvironment() throws SmackException,
|
||||||
IOException, XMPPException, InterruptedException, KeyManagementException,
|
IOException, XMPPException, InterruptedException, KeyManagementException,
|
||||||
NoSuchAlgorithmException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
NoSuchAlgorithmException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||||
return connectionManager.prepareEnvironment();
|
return connectionManager.prepareEnvironment();
|
||||||
|
@ -576,9 +562,6 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
|
|
||||||
private static Exception throwFatalException(Throwable e) throws Error, NoResponseException,
|
private static Exception throwFatalException(Throwable e) throws Error, NoResponseException,
|
||||||
InterruptedException {
|
InterruptedException {
|
||||||
if (e instanceof NoResponseException) {
|
|
||||||
throw (NoResponseException) e;
|
|
||||||
}
|
|
||||||
if (e instanceof InterruptedException) {
|
if (e instanceof InterruptedException) {
|
||||||
throw (InterruptedException) e;
|
throw (InterruptedException) e;
|
||||||
}
|
}
|
||||||
|
@ -612,9 +595,13 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
private final List<SuccessfulTest> successfulIntegrationTests = Collections.synchronizedList(new LinkedList<SuccessfulTest>());
|
private final List<SuccessfulTest> successfulIntegrationTests = Collections.synchronizedList(new LinkedList<SuccessfulTest>());
|
||||||
private final List<FailedTest> failedIntegrationTests = Collections.synchronizedList(new LinkedList<FailedTest>());
|
private final List<FailedTest> failedIntegrationTests = Collections.synchronizedList(new LinkedList<FailedTest>());
|
||||||
private final List<TestNotPossible> impossibleIntegrationTests = Collections.synchronizedList(new LinkedList<TestNotPossible>());
|
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 Map<Class<? extends AbstractSmackIntTest>, Throwable> impossibleTestClasses = new HashMap<>();
|
||||||
private final AtomicInteger numberOfAvailableTestMethods = new AtomicInteger();
|
|
||||||
private final AtomicInteger numberOfPossibleTestMethods = new AtomicInteger();
|
|
||||||
|
|
||||||
TestRunResult() {
|
TestRunResult() {
|
||||||
}
|
}
|
||||||
|
@ -624,11 +611,7 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumberOfAvailableTests() {
|
public int getNumberOfAvailableTests() {
|
||||||
return numberOfAvailableTestMethods.get();
|
return successfulIntegrationTests.size() + failedIntegrationTests.size() + impossibleIntegrationTests.size();
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumberOfPossibleTests() {
|
|
||||||
return numberOfPossibleTestMethods.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SuccessfulTest> getSuccessfulTests() {
|
public List<SuccessfulTest> getSuccessfulTests() {
|
||||||
|
@ -648,6 +631,77 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
static final class ConcreteTest {
|
||||||
private final TestType testType;
|
private final TestType testType;
|
||||||
private final Method method;
|
private final Method method;
|
||||||
|
@ -675,13 +729,8 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
.append(method.getName())
|
.append(method.getName())
|
||||||
.append(" (")
|
.append(" (")
|
||||||
.append(testType.name());
|
.append(testType.name());
|
||||||
final String SUBDESCRIPTION_DELIMITER = ", ";
|
sb.append(", ");
|
||||||
sb.append(SUBDESCRIPTION_DELIMITER);
|
StringUtils.appendTo(Arrays.asList(subdescriptons), sb);
|
||||||
|
|
||||||
for (String subdescripton : subdescriptons) {
|
|
||||||
sb.append(subdescripton).append(SUBDESCRIPTION_DELIMITER);
|
|
||||||
}
|
|
||||||
sb.setLength(sb.length() - SUBDESCRIPTION_DELIMITER.length());
|
|
||||||
sb.append(')');
|
sb.append(')');
|
||||||
|
|
||||||
stringCache = sb.toString();
|
stringCache = sb.toString();
|
||||||
|
@ -705,6 +754,50 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 class LowLevelTestMethod {
|
||||||
private final Method testMethod;
|
private final Method testMethod;
|
||||||
private final SmackIntegrationTest smackIntegrationTestAnnotation;
|
private final SmackIntegrationTest smackIntegrationTestAnnotation;
|
||||||
|
@ -718,6 +811,7 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
parameterListOfConnections = testMethodParametersIsListOfConnections(testMethod);
|
parameterListOfConnections = testMethodParametersIsListOfConnections(testMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: The second parameter should probably be a connection descriptor?
|
||||||
private void invoke(AbstractSmackLowLevelIntegrationTest test,
|
private void invoke(AbstractSmackLowLevelIntegrationTest test,
|
||||||
Class<? extends AbstractXMPPConnection> connectionClass)
|
Class<? extends AbstractXMPPConnection> connectionClass)
|
||||||
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException,
|
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException,
|
||||||
|
@ -746,6 +840,11 @@ public class SmackIntegrationTestFramework<DC extends AbstractXMPPConnection> {
|
||||||
testMethod.invoke(test, connectionsArray);
|
testMethod.invoke(test, connectionsArray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return testMethod.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean testMethodParametersIsListOfConnections(Method testMethod) {
|
private static boolean testMethodParametersIsListOfConnections(Method testMethod) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2018-2019 Florian Schmaus
|
* Copyright 2018-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -29,8 +29,13 @@ import java.util.List;
|
||||||
import org.jivesoftware.smack.AbstractXMPPConnection;
|
import org.jivesoftware.smack.AbstractXMPPConnection;
|
||||||
import org.jivesoftware.smack.ConnectionConfiguration;
|
import org.jivesoftware.smack.ConnectionConfiguration;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
import org.jivesoftware.smack.util.Consumer;
|
||||||
|
|
||||||
public class XmppConnectionDescriptor<C extends AbstractXMPPConnection, CC extends ConnectionConfiguration, CCB extends ConnectionConfiguration.Builder<?, CC>> {
|
public final class XmppConnectionDescriptor<
|
||||||
|
C extends AbstractXMPPConnection,
|
||||||
|
CC extends ConnectionConfiguration,
|
||||||
|
CCB extends ConnectionConfiguration.Builder<?, CC>
|
||||||
|
> {
|
||||||
|
|
||||||
private final Class<C> connectionClass;
|
private final Class<C> connectionClass;
|
||||||
private final Class<CC> connectionConfigurationClass;
|
private final Class<CC> connectionConfigurationClass;
|
||||||
|
@ -38,13 +43,18 @@ public class XmppConnectionDescriptor<C extends AbstractXMPPConnection, CC exten
|
||||||
private final Constructor<C> connectionConstructor;
|
private final Constructor<C> connectionConstructor;
|
||||||
private final Method builderMethod;
|
private final Method builderMethod;
|
||||||
|
|
||||||
public XmppConnectionDescriptor(Class<C> connectionClass, Class<CC> connectionConfigurationClass)
|
private final Consumer<CCB> extraBuilder;
|
||||||
throws ClassNotFoundException, NoSuchMethodException, SecurityException {
|
|
||||||
this.connectionClass = connectionClass;
|
|
||||||
this.connectionConfigurationClass = connectionConfigurationClass;
|
|
||||||
|
|
||||||
this.connectionConstructor = getConstructor(connectionClass, connectionConfigurationClass);
|
private final String nickname;
|
||||||
this.builderMethod = getBuilderMethod(connectionConfigurationClass);
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
public C construct(Configuration sinttestConfiguration)
|
public C construct(Configuration sinttestConfiguration)
|
||||||
|
@ -65,6 +75,9 @@ public class XmppConnectionDescriptor<C extends AbstractXMPPConnection, CC exten
|
||||||
Collection<ConnectionConfigurationBuilderApplier> customConnectionConfigurationAppliers)
|
Collection<ConnectionConfigurationBuilderApplier> customConnectionConfigurationAppliers)
|
||||||
throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||||
CCB connectionConfigurationBuilder = getNewBuilder();
|
CCB connectionConfigurationBuilder = getNewBuilder();
|
||||||
|
if (extraBuilder != null) {
|
||||||
|
extraBuilder.accept(connectionConfigurationBuilder);
|
||||||
|
}
|
||||||
for (ConnectionConfigurationBuilderApplier customConnectionConfigurationApplier : customConnectionConfigurationAppliers) {
|
for (ConnectionConfigurationBuilderApplier customConnectionConfigurationApplier : customConnectionConfigurationAppliers) {
|
||||||
customConnectionConfigurationApplier.applyConfigurationTo(connectionConfigurationBuilder);
|
customConnectionConfigurationApplier.applyConfigurationTo(connectionConfigurationBuilder);
|
||||||
}
|
}
|
||||||
|
@ -88,6 +101,10 @@ public class XmppConnectionDescriptor<C extends AbstractXMPPConnection, CC exten
|
||||||
return connectionClass;
|
return connectionClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getNickname() {
|
||||||
|
return nickname;
|
||||||
|
}
|
||||||
|
|
||||||
private static <C extends XMPPConnection> Constructor<C> getConstructor(Class<C> connectionClass,
|
private static <C extends XMPPConnection> Constructor<C> getConstructor(Class<C> connectionClass,
|
||||||
Class<? extends ConnectionConfiguration> connectionConfigurationClass)
|
Class<? extends ConnectionConfiguration> connectionConfigurationClass)
|
||||||
throws NoSuchMethodException, SecurityException {
|
throws NoSuchMethodException, SecurityException {
|
||||||
|
@ -106,4 +123,47 @@ public class XmppConnectionDescriptor<C extends AbstractXMPPConnection, CC exten
|
||||||
}
|
}
|
||||||
return builderMethod;
|
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-2019 Florian Schmaus
|
* Copyright 2018-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -27,7 +27,6 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
@ -38,9 +37,11 @@ import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
import org.jivesoftware.smack.XMPPException;
|
||||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
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.XMPPTCPConnection;
|
||||||
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
||||||
import org.jivesoftware.smack.tcp.XmppNioTcpConnection;
|
|
||||||
import org.jivesoftware.smack.util.MultiMap;
|
import org.jivesoftware.smack.util.MultiMap;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
|
||||||
|
@ -54,55 +55,92 @@ import org.jxmpp.jid.impl.JidCreate;
|
||||||
import org.jxmpp.jid.parts.Localpart;
|
import org.jxmpp.jid.parts.Localpart;
|
||||||
import org.jxmpp.stringprep.XmppStringprepException;
|
import org.jxmpp.stringprep.XmppStringprepException;
|
||||||
|
|
||||||
public class XmppConnectionManager<DC extends AbstractXMPPConnection> {
|
public class XmppConnectionManager {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(XmppConnectionManager.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(XmppConnectionManager.class.getName());
|
||||||
|
|
||||||
private static final Map<Class<? extends AbstractXMPPConnection>, XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>> CONNECTION_DESCRIPTORS = new ConcurrentHashMap<>();
|
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<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
addConnectionDescriptor(XmppNioTcpConnection.class, XMPPTCPConnectionConfiguration.class);
|
DEFAULT_CONNECTION_DESCRIPTOR = XmppConnectionDescriptor.buildWith(XMPPTCPConnection.class, XMPPTCPConnectionConfiguration.class)
|
||||||
addConnectionDescriptor(XMPPTCPConnection.class, XMPPTCPConnectionConfiguration.class);
|
.withNickname("tcp")
|
||||||
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
|
.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) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addConnectionDescriptor(Class<? extends AbstractXMPPConnection> connectionClass,
|
public static boolean addConnectionDescriptor(
|
||||||
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) {
|
XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor) {
|
||||||
|
String nickname = connectionDescriptor.getNickname();
|
||||||
Class<? extends AbstractXMPPConnection> connectionClass = connectionDescriptor.getConnectionClass();
|
Class<? extends AbstractXMPPConnection> connectionClass = connectionDescriptor.getConnectionClass();
|
||||||
CONNECTION_DESCRIPTORS.put(connectionClass, connectionDescriptor);
|
|
||||||
|
boolean alreadyExisted;
|
||||||
|
synchronized (CONNECTION_DESCRIPTORS) {
|
||||||
|
alreadyExisted = removeConnectionDescriptor(nickname);
|
||||||
|
|
||||||
|
CONNECTION_DESCRIPTORS.put(connectionClass, connectionDescriptor);
|
||||||
|
NICKNAME_CONNECTION_DESCRIPTORS.put(connectionDescriptor.getNickname(), connectionDescriptor);
|
||||||
|
}
|
||||||
|
return alreadyExisted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void removeConnectionDescriptor(Class<? extends AbstractXMPPConnection> connectionClass) {
|
public static boolean removeConnectionDescriptor(String nickname) {
|
||||||
CONNECTION_DESCRIPTORS.remove(connectionClass);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final XmppConnectionDescriptor<DC, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> defaultConnectionDescriptor;
|
private final XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> defaultConnectionDescriptor;
|
||||||
|
|
||||||
private final Map<Class<? extends AbstractXMPPConnection>, XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>> connectionDescriptors = new HashMap<>(
|
private final Map<String, XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>> nicknameConnectionDescriptors;
|
||||||
CONNECTION_DESCRIPTORS.size());
|
|
||||||
|
|
||||||
private final SmackIntegrationTestFramework<?> sinttestFramework;
|
private final MultiMap<
|
||||||
|
Class<? extends AbstractXMPPConnection>,
|
||||||
|
XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>
|
||||||
|
> connectionDescriptors;
|
||||||
|
|
||||||
|
private final SmackIntegrationTestFramework sinttestFramework;
|
||||||
private final Configuration sinttestConfiguration;
|
private final Configuration sinttestConfiguration;
|
||||||
private final String testRunId;
|
private final String testRunId;
|
||||||
|
|
||||||
private final DC accountRegistrationConnection;
|
private final AbstractXMPPConnection accountRegistrationConnection;
|
||||||
private final ServiceAdministrationManager adminManager;
|
private final ServiceAdministrationManager adminManager;
|
||||||
private final AccountManager accountManager;
|
private final AccountManager accountManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One of the three main connections. The type of the main connections is the default connection type.
|
* One of the three main connections. The type of the main connections is the default connection type.
|
||||||
*/
|
*/
|
||||||
DC conOne, conTwo, conThree;
|
AbstractXMPPConnection conOne, conTwo, conThree;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pool of authenticated and free to use connections.
|
* A pool of authenticated and free to use connections.
|
||||||
|
@ -114,20 +152,25 @@ public class XmppConnectionManager<DC extends AbstractXMPPConnection> {
|
||||||
*/
|
*/
|
||||||
private final List<AbstractXMPPConnection> connections = new ArrayList<>();
|
private final List<AbstractXMPPConnection> connections = new ArrayList<>();
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
XmppConnectionManager(SmackIntegrationTestFramework sinttestFramework)
|
||||||
XmppConnectionManager(SmackIntegrationTestFramework<?> sinttestFramework,
|
|
||||||
Class<? extends DC> defaultConnectionClass)
|
|
||||||
throws SmackException, IOException, XMPPException, InterruptedException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
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.sinttestFramework = sinttestFramework;
|
||||||
this.sinttestConfiguration = sinttestFramework.config;
|
this.sinttestConfiguration = sinttestFramework.config;
|
||||||
this.testRunId = sinttestFramework.testRunResult.testRunId;
|
this.testRunId = sinttestFramework.testRunResult.testRunId;
|
||||||
|
|
||||||
connectionDescriptors.putAll(CONNECTION_DESCRIPTORS);
|
String configuredDefaultConnectionNickname = sinttestConfiguration.defaultConnectionNickname;
|
||||||
|
if (configuredDefaultConnectionNickname != null) {
|
||||||
defaultConnectionDescriptor = (XmppConnectionDescriptor<DC, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>) connectionDescriptors.get(
|
defaultConnectionDescriptor = nicknameConnectionDescriptors.get(configuredDefaultConnectionNickname);
|
||||||
defaultConnectionClass);
|
if (defaultConnectionDescriptor == null) {
|
||||||
if (defaultConnectionDescriptor == null) {
|
throw new IllegalArgumentException("Could not find a connection descriptor for connection nickname '" + configuredDefaultConnectionNickname + "'");
|
||||||
throw new IllegalArgumentException("Could not find a connection descriptor for " + defaultConnectionClass);
|
}
|
||||||
|
} else {
|
||||||
|
defaultConnectionDescriptor = DEFAULT_CONNECTION_DESCRIPTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (sinttestConfiguration.accountRegistration) {
|
switch (sinttestConfiguration.accountRegistration) {
|
||||||
|
@ -157,11 +200,11 @@ public class XmppConnectionManager<DC extends AbstractXMPPConnection> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SmackIntegrationTestEnvironment<DC> prepareEnvironment() throws KeyManagementException, NoSuchAlgorithmException,
|
SmackIntegrationTestEnvironment prepareEnvironment() throws KeyManagementException, NoSuchAlgorithmException,
|
||||||
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
|
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
|
||||||
SmackException, IOException, XMPPException, InterruptedException {
|
SmackException, IOException, XMPPException, InterruptedException {
|
||||||
prepareMainConnections();
|
prepareMainConnections();
|
||||||
return new SmackIntegrationTestEnvironment<DC>(conOne, conTwo, conThree,
|
return new SmackIntegrationTestEnvironment(conOne, conTwo, conThree,
|
||||||
sinttestFramework.testRunResult.testRunId, sinttestConfiguration, this);
|
sinttestFramework.testRunResult.testRunId, sinttestConfiguration, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,9 +212,9 @@ public class XmppConnectionManager<DC extends AbstractXMPPConnection> {
|
||||||
IllegalAccessException, IllegalArgumentException, InvocationTargetException, SmackException, IOException,
|
IllegalAccessException, IllegalArgumentException, InvocationTargetException, SmackException, IOException,
|
||||||
XMPPException, InterruptedException {
|
XMPPException, InterruptedException {
|
||||||
final int mainAccountCount = AccountNum.values().length;
|
final int mainAccountCount = AccountNum.values().length;
|
||||||
List<DC> connections = new ArrayList<>(mainAccountCount);
|
List<AbstractXMPPConnection> connections = new ArrayList<>(mainAccountCount);
|
||||||
for (AccountNum mainAccountNum : AccountNum.values()) {
|
for (AccountNum mainAccountNum : AccountNum.values()) {
|
||||||
DC mainConnection = getConnectedMainConnectionFor(mainAccountNum);
|
AbstractXMPPConnection mainConnection = getConnectedMainConnectionFor(mainAccountNum);
|
||||||
connections.add(mainConnection);
|
connections.add(mainConnection);
|
||||||
}
|
}
|
||||||
conOne = connections.get(0);
|
conOne = connections.get(0);
|
||||||
|
@ -179,18 +222,18 @@ public class XmppConnectionManager<DC extends AbstractXMPPConnection> {
|
||||||
conThree = connections.get(2);
|
conThree = connections.get(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<? extends AbstractXMPPConnection> getDefaultConnectionClass() {
|
public XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> getDefaultConnectionDescriptor() {
|
||||||
return defaultConnectionDescriptor.getConnectionClass();
|
return defaultConnectionDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Class<? extends AbstractXMPPConnection>> getConnectionClasses() {
|
public Collection<XmppConnectionDescriptor<? extends AbstractXMPPConnection, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>> getConnectionDescriptors() {
|
||||||
return Collections.unmodifiableSet(connectionDescriptors.keySet());
|
return Collections.unmodifiableCollection(nicknameConnectionDescriptors.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <C extends AbstractXMPPConnection> XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> getConnectionDescriptorFor(
|
public <C extends AbstractXMPPConnection> XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> getConnectionDescriptorFor(
|
||||||
Class<C> connectionClass) {
|
Class<C> connectionClass) {
|
||||||
return (XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>) connectionDescriptors.get(
|
return (XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>) connectionDescriptors.getFirst(
|
||||||
connectionClass);
|
connectionClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +292,7 @@ public class XmppConnectionManager<DC extends AbstractXMPPConnection> {
|
||||||
|
|
||||||
private static final String USERNAME_PREFIX = "smack-inttest";
|
private static final String USERNAME_PREFIX = "smack-inttest";
|
||||||
|
|
||||||
private DC getConnectedMainConnectionFor(AccountNum accountNum) throws SmackException, IOException, XMPPException,
|
private AbstractXMPPConnection getConnectedMainConnectionFor(AccountNum accountNum) throws SmackException, IOException, XMPPException,
|
||||||
InterruptedException, KeyManagementException, NoSuchAlgorithmException, InstantiationException,
|
InterruptedException, KeyManagementException, NoSuchAlgorithmException, InstantiationException,
|
||||||
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||||
String middlefix;
|
String middlefix;
|
||||||
|
@ -283,7 +326,7 @@ public class XmppConnectionManager<DC extends AbstractXMPPConnection> {
|
||||||
registerAccount(finalAccountUsername, finalAccountPassword);
|
registerAccount(finalAccountUsername, finalAccountPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
DC mainConnection = defaultConnectionDescriptor.construct(sinttestConfiguration, builder -> {
|
AbstractXMPPConnection mainConnection = defaultConnectionDescriptor.construct(sinttestConfiguration, builder -> {
|
||||||
try {
|
try {
|
||||||
builder.setUsernameAndPassword(finalAccountUsername, finalAccountPassword)
|
builder.setUsernameAndPassword(finalAccountUsername, finalAccountPassword)
|
||||||
.setResource(middlefix + '-' + testRunId);
|
.setResource(middlefix + '-' + testRunId);
|
||||||
|
@ -347,7 +390,7 @@ public class XmppConnectionManager<DC extends AbstractXMPPConnection> {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor = (XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>) connectionDescriptors
|
XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>> connectionDescriptor = (XmppConnectionDescriptor<C, ? extends ConnectionConfiguration, ? extends ConnectionConfiguration.Builder<?, ?>>) connectionDescriptors
|
||||||
.get(connectionClass);
|
.getFirst(connectionClass);
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
C connection = constructConnectedConnection(connectionDescriptor);
|
C connection = constructConnectedConnection(connectionDescriptor);
|
||||||
connections.add(connection);
|
connections.add(connection);
|
||||||
|
@ -367,7 +410,7 @@ public class XmppConnectionManager<DC extends AbstractXMPPConnection> {
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
DC constructConnection()
|
AbstractXMPPConnection constructConnection()
|
||||||
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
return constructConnection(defaultConnectionDescriptor);
|
return constructConnection(defaultConnectionDescriptor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2019 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -51,7 +51,7 @@ public class ChatTest extends AbstractSmackIntegrationTest {
|
||||||
private boolean invoked;
|
private boolean invoked;
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public ChatTest(SmackIntegrationTestEnvironment<?> environment) {
|
public ChatTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
chatManagerOne = org.jivesoftware.smack.chat.ChatManager.getInstanceFor(conOne);
|
chatManagerOne = org.jivesoftware.smack.chat.ChatManager.getInstanceFor(conOne);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2019 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -33,7 +33,7 @@ import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||||
|
|
||||||
public class LoginIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
public class LoginIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
||||||
|
|
||||||
public LoginIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public LoginIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2019 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -35,7 +35,7 @@ import org.igniterealtime.smack.inttest.TestNotPossibleException;
|
||||||
|
|
||||||
public class StreamManagementTest extends AbstractSmackSpecificLowLevelIntegrationTest<XMPPTCPConnection> {
|
public class StreamManagementTest extends AbstractSmackSpecificLowLevelIntegrationTest<XMPPTCPConnection> {
|
||||||
|
|
||||||
public StreamManagementTest(SmackIntegrationTestEnvironment<?> environment) throws Exception {
|
public StreamManagementTest(SmackIntegrationTestEnvironment environment) throws Exception {
|
||||||
super(environment, XMPPTCPConnection.class);
|
super(environment, XMPPTCPConnection.class);
|
||||||
XMPPTCPConnection connection = getSpecificUnconnectedConnection();
|
XMPPTCPConnection connection = getSpecificUnconnectedConnection();
|
||||||
connection.connect().login();
|
connection.connect().login();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2019 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -26,7 +26,7 @@ import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||||
|
|
||||||
public class WaitForClosingStreamElementTest extends AbstractSmackLowLevelIntegrationTest {
|
public class WaitForClosingStreamElementTest extends AbstractSmackLowLevelIntegrationTest {
|
||||||
|
|
||||||
public WaitForClosingStreamElementTest(SmackIntegrationTestEnvironment<?> environment) {
|
public WaitForClosingStreamElementTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2018-2019 Florian Schmaus
|
* Copyright 2018-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -19,7 +19,7 @@ package org.jivesoftware.smack;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.jivesoftware.smack.tcp.XmppNioTcpConnection;
|
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection;
|
||||||
|
|
||||||
import org.igniterealtime.smack.XmppConnectionStressTest;
|
import org.igniterealtime.smack.XmppConnectionStressTest;
|
||||||
import org.igniterealtime.smack.XmppConnectionStressTest.StressTestFailedException.ErrorsWhileSendingOrReceivingException;
|
import org.igniterealtime.smack.XmppConnectionStressTest.StressTestFailedException.ErrorsWhileSendingOrReceivingException;
|
||||||
|
@ -30,7 +30,7 @@ import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||||
|
|
||||||
public class XmppConnectionIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
public class XmppConnectionIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
||||||
|
|
||||||
public XmppConnectionIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public XmppConnectionIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,12 +52,12 @@ public class XmppConnectionIntegrationTest extends AbstractSmackLowLevelIntegrat
|
||||||
|
|
||||||
final Level connectionStatsLogLevel = Level.FINE;
|
final Level connectionStatsLogLevel = Level.FINE;
|
||||||
if (LOGGER.isLoggable(connectionStatsLogLevel)) {
|
if (LOGGER.isLoggable(connectionStatsLogLevel)) {
|
||||||
if (connections.get(0) instanceof XmppNioTcpConnection) {
|
if (connections.get(0) instanceof ModularXmppClientToServerConnection) {
|
||||||
for (XMPPConnection connection : connections) {
|
for (XMPPConnection connection : connections) {
|
||||||
XmppNioTcpConnection xmppNioTcpConnection = (XmppNioTcpConnection) connection;
|
ModularXmppClientToServerConnection xmppC2sConnection = (ModularXmppClientToServerConnection) connection;
|
||||||
XmppNioTcpConnection.Stats stats = xmppNioTcpConnection.getStats();
|
ModularXmppClientToServerConnection.Stats stats = xmppC2sConnection.getStats();
|
||||||
LOGGER.log(connectionStatsLogLevel,
|
LOGGER.log(connectionStatsLogLevel,
|
||||||
"Connections stats for " + xmppNioTcpConnection + ":\n{}",
|
"Connections stats for " + xmppC2sConnection + ":\n{}",
|
||||||
stats);
|
stats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2018 Florian Schmaus
|
* Copyright 2018-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -25,7 +25,7 @@ public abstract class AbstractChatIntegrationTest extends AbstractSmackIntegrati
|
||||||
protected final ChatManager chatManagerTwo;
|
protected final ChatManager chatManagerTwo;
|
||||||
protected final ChatManager chatManagerThree;
|
protected final ChatManager chatManagerThree;
|
||||||
|
|
||||||
protected AbstractChatIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
protected AbstractChatIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
chatManagerOne = ChatManager.getInstanceFor(conOne);
|
chatManagerOne = ChatManager.getInstanceFor(conOne);
|
||||||
chatManagerTwo = ChatManager.getInstanceFor(conTwo);
|
chatManagerTwo = ChatManager.getInstanceFor(conTwo);
|
||||||
|
|
|
@ -26,7 +26,7 @@ import org.jxmpp.jid.EntityBareJid;
|
||||||
|
|
||||||
public class IncomingMessageListenerIntegrationTest extends AbstractChatIntegrationTest {
|
public class IncomingMessageListenerIntegrationTest extends AbstractChatIntegrationTest {
|
||||||
|
|
||||||
public IncomingMessageListenerIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public IncomingMessageListenerIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ import org.jxmpp.jid.EntityBareJid;
|
||||||
|
|
||||||
public class OutgoingMessageListenerIntegrationTest extends AbstractChatIntegrationTest {
|
public class OutgoingMessageListenerIntegrationTest extends AbstractChatIntegrationTest {
|
||||||
|
|
||||||
public OutgoingMessageListenerIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public OutgoingMessageListenerIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2016-2019 Florian Schmaus
|
* Copyright 2016-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -30,7 +30,7 @@ import org.jxmpp.jid.FullJid;
|
||||||
|
|
||||||
public class LowLevelRosterIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
public class LowLevelRosterIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
||||||
|
|
||||||
public LowLevelRosterIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public LowLevelRosterIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2019 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -38,7 +38,7 @@ public class RosterIntegrationTest extends AbstractSmackIntegrationTest {
|
||||||
private final Roster rosterOne;
|
private final Roster rosterOne;
|
||||||
private final Roster rosterTwo;
|
private final Roster rosterTwo;
|
||||||
|
|
||||||
public RosterIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public RosterIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
rosterOne = Roster.getInstanceFor(conOne);
|
rosterOne = Roster.getInstanceFor(conOne);
|
||||||
rosterTwo = Roster.getInstanceFor(conTwo);
|
rosterTwo = Roster.getInstanceFor(conTwo);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2018-2019 Florian Schmaus
|
* Copyright 2018-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -22,21 +22,22 @@ import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection;
|
||||||
|
|
||||||
import org.igniterealtime.smack.inttest.AbstractSmackSpecificLowLevelIntegrationTest;
|
import org.igniterealtime.smack.inttest.AbstractSmackSpecificLowLevelIntegrationTest;
|
||||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||||
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||||
|
|
||||||
public class XmppNioTcpConnectionLowLevelIntegrationTest extends AbstractSmackSpecificLowLevelIntegrationTest<XmppNioTcpConnection> {
|
public class XmppNioTcpConnectionLowLevelIntegrationTest extends AbstractSmackSpecificLowLevelIntegrationTest<ModularXmppClientToServerConnection> {
|
||||||
|
|
||||||
public XmppNioTcpConnectionLowLevelIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public XmppNioTcpConnectionLowLevelIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment, XmppNioTcpConnection.class);
|
super(environment, ModularXmppClientToServerConnection.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SmackIntegrationTest
|
@SmackIntegrationTest
|
||||||
public void testDisconnectAfterConnect() throws KeyManagementException, NoSuchAlgorithmException, SmackException,
|
public void testDisconnectAfterConnect() throws KeyManagementException, NoSuchAlgorithmException, SmackException,
|
||||||
IOException, XMPPException, InterruptedException {
|
IOException, XMPPException, InterruptedException {
|
||||||
XmppNioTcpConnection connection = getSpecificUnconnectedConnection();
|
ModularXmppClientToServerConnection connection = getSpecificUnconnectedConnection();
|
||||||
|
|
||||||
connection.connect();
|
connection.connect();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2013-2019 Florian Schmaus
|
* Copyright 2013-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -57,7 +57,7 @@ public class EntityCapsTest extends AbstractSmackIntegrationTest {
|
||||||
private final ServiceDiscoveryManager sdmOne;
|
private final ServiceDiscoveryManager sdmOne;
|
||||||
private final ServiceDiscoveryManager sdmTwo;
|
private final ServiceDiscoveryManager sdmTwo;
|
||||||
|
|
||||||
public EntityCapsTest(SmackIntegrationTestEnvironment<?> environment) {
|
public EntityCapsTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
ecmTwo = EntityCapsManager.getInstanceFor(environment.conTwo);
|
ecmTwo = EntityCapsManager.getInstanceFor(environment.conTwo);
|
||||||
sdmOne = ServiceDiscoveryManager.getInstanceFor(environment.conOne);
|
sdmOne = ServiceDiscoveryManager.getInstanceFor(environment.conOne);
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class ChatStateIntegrationTest extends AbstractSmackIntegrationTest {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
public ChatStateIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public ChatStateIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2019 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -39,7 +39,7 @@ public class FileTransferIntegrationTest extends AbstractSmackIntegrationTest {
|
||||||
private final FileTransferManager ftManagerOne;
|
private final FileTransferManager ftManagerOne;
|
||||||
private final FileTransferManager ftManagerTwo;
|
private final FileTransferManager ftManagerTwo;
|
||||||
|
|
||||||
public FileTransferIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public FileTransferIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
ftManagerOne = FileTransferManager.getInstanceFor(conOne);
|
ftManagerOne = FileTransferManager.getInstanceFor(conOne);
|
||||||
ftManagerTwo = FileTransferManager.getInstanceFor(conTwo);
|
ftManagerTwo = FileTransferManager.getInstanceFor(conTwo);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2017-2019 Florian Schmaus
|
* Copyright 2017-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -43,7 +43,7 @@ public class HttpFileUploadIntegrationTest extends AbstractSmackIntegrationTest
|
||||||
|
|
||||||
private final HttpFileUploadManager hfumOne;
|
private final HttpFileUploadManager hfumOne;
|
||||||
|
|
||||||
public HttpFileUploadIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws XMPPErrorException,
|
public HttpFileUploadIntegrationTest(SmackIntegrationTestEnvironment environment) throws XMPPErrorException,
|
||||||
NotConnectedException, NoResponseException, InterruptedException, TestNotPossibleException {
|
NotConnectedException, NoResponseException, InterruptedException, TestNotPossibleException {
|
||||||
super(environment);
|
super(environment);
|
||||||
hfumOne = HttpFileUploadManager.getInstanceFor(conOne);
|
hfumOne = HttpFileUploadManager.getInstanceFor(conOne);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2016-2019 Florian Schmaus
|
* Copyright 2016-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -43,7 +43,7 @@ public class IoTControlIntegrationTest extends AbstractSmackIntegrationTest {
|
||||||
|
|
||||||
private final IoTControlManager IoTControlManagerTwo;
|
private final IoTControlManager IoTControlManagerTwo;
|
||||||
|
|
||||||
public IoTControlIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public IoTControlIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
IoTControlManagerOne = IoTControlManager.getInstanceFor(conOne);
|
IoTControlManagerOne = IoTControlManager.getInstanceFor(conOne);
|
||||||
IoTControlManagerTwo = IoTControlManager.getInstanceFor(conTwo);
|
IoTControlManagerTwo = IoTControlManager.getInstanceFor(conTwo);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2016-2019 Florian Schmaus
|
* Copyright 2016-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -45,7 +45,7 @@ public class IoTDataIntegrationTest extends AbstractSmackIntegrationTest {
|
||||||
|
|
||||||
private final IoTDataManager iotDataManagerTwo;
|
private final IoTDataManager iotDataManagerTwo;
|
||||||
|
|
||||||
public IoTDataIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public IoTDataIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
iotDataManagerOne = IoTDataManager.getInstanceFor(conOne);
|
iotDataManagerOne = IoTDataManager.getInstanceFor(conOne);
|
||||||
iotDataManagerTwo = IoTDataManager.getInstanceFor(conTwo);
|
iotDataManagerTwo = IoTDataManager.getInstanceFor(conTwo);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2016-2019 Florian Schmaus
|
* Copyright 2016-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -41,7 +41,7 @@ public class IoTDiscoveryIntegrationTest extends AbstractSmackIntegrationTest {
|
||||||
private final IoTDiscoveryManager discoveryManagerOne;
|
private final IoTDiscoveryManager discoveryManagerOne;
|
||||||
private final IoTDiscoveryManager discoveryManagerTwo;
|
private final IoTDiscoveryManager discoveryManagerTwo;
|
||||||
|
|
||||||
public IoTDiscoveryIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws NoResponseException,
|
public IoTDiscoveryIntegrationTest(SmackIntegrationTestEnvironment environment) throws NoResponseException,
|
||||||
XMPPErrorException, NotConnectedException, InterruptedException, TestNotPossibleException {
|
XMPPErrorException, NotConnectedException, InterruptedException, TestNotPossibleException {
|
||||||
super(environment);
|
super(environment);
|
||||||
discoveryManagerOne = IoTDiscoveryManager.getInstanceFor(conOne);
|
discoveryManagerOne = IoTDiscoveryManager.getInstanceFor(conOne);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2019 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -31,7 +31,7 @@ import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||||
|
|
||||||
public class VersionIntegrationTest extends AbstractSmackIntegrationTest {
|
public class VersionIntegrationTest extends AbstractSmackIntegrationTest {
|
||||||
|
|
||||||
public VersionIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public VersionIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2016 Fernando Ramirez, 2018-2019 Florian Schmaus
|
* Copyright 2016 Fernando Ramirez, 2018-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -48,7 +48,7 @@ public class MamIntegrationTest extends AbstractSmackIntegrationTest {
|
||||||
|
|
||||||
private final MamManager mamManagerConTwo;
|
private final MamManager mamManagerConTwo;
|
||||||
|
|
||||||
public MamIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws NoResponseException,
|
public MamIntegrationTest(SmackIntegrationTestEnvironment environment) throws NoResponseException,
|
||||||
XMPPErrorException, NotConnectedException, InterruptedException, TestNotPossibleException, NotLoggedInException {
|
XMPPErrorException, NotConnectedException, InterruptedException, TestNotPossibleException, NotLoggedInException {
|
||||||
super(environment);
|
super(environment);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2018 Paul Schaub, 2019 Florian Schmaus.
|
* Copyright 2018 Paul Schaub, 2019-2020 Florian Schmaus.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -31,7 +31,7 @@ public class MoodIntegrationTest extends AbstractSmackIntegrationTest {
|
||||||
private final MoodManager mm1;
|
private final MoodManager mm1;
|
||||||
private final MoodManager mm2;
|
private final MoodManager mm2;
|
||||||
|
|
||||||
public MoodIntegrationTest(SmackIntegrationTestEnvironment<?> environment) {
|
public MoodIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
super(environment);
|
super(environment);
|
||||||
mm1 = MoodManager.getInstanceFor(conOne);
|
mm1 = MoodManager.getInstanceFor(conOne);
|
||||||
mm2 = MoodManager.getInstanceFor(conTwo);
|
mm2 = MoodManager.getInstanceFor(conTwo);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2019 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -54,7 +54,7 @@ public class MultiUserChatIntegrationTest extends AbstractSmackIntegrationTest {
|
||||||
private final MultiUserChatManager mucManagerTwo;
|
private final MultiUserChatManager mucManagerTwo;
|
||||||
private final DomainBareJid mucService;
|
private final DomainBareJid mucService;
|
||||||
|
|
||||||
public MultiUserChatIntegrationTest(SmackIntegrationTestEnvironment<?> environment)
|
public MultiUserChatIntegrationTest(SmackIntegrationTestEnvironment environment)
|
||||||
throws NoResponseException, XMPPErrorException, NotConnectedException,
|
throws NoResponseException, XMPPErrorException, NotConnectedException,
|
||||||
InterruptedException, TestNotPossibleException {
|
InterruptedException, TestNotPossibleException {
|
||||||
super(environment);
|
super(environment);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2015-2019 Florian Schmaus
|
* Copyright 2015-2020 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -40,7 +40,7 @@ import org.jxmpp.jid.parts.Resourcepart;
|
||||||
|
|
||||||
public class MultiUserChatLowLevelIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
public class MultiUserChatLowLevelIntegrationTest extends AbstractSmackLowLevelIntegrationTest {
|
||||||
|
|
||||||
public MultiUserChatLowLevelIntegrationTest(SmackIntegrationTestEnvironment<?> environment) throws Exception {
|
public MultiUserChatLowLevelIntegrationTest(SmackIntegrationTestEnvironment environment) throws Exception {
|
||||||
super(environment);
|
super(environment);
|
||||||
AbstractXMPPConnection connection = getConnectedConnection();
|
AbstractXMPPConnection connection = getConnectedConnection();
|
||||||
try {
|
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