1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-11-22 12:02:05 +01:00

Compare commits

...

78 commits

Author SHA1 Message Date
Florian Schmaus
c6c904cc3e Add support for XEP-0350: Data Forms Geolocation Element
Fixes SMACK-871.
2019-06-12 17:13:05 +02:00
Florian Schmaus
fa0c16d75c Introduce EqualsUtil and HashCode.(Builder|Cache) 2019-06-12 14:51:17 +02:00
Florian Schmaus
92b02afbff Improve exceptions of Socks5Proxy 2019-06-11 12:47:40 +02:00
Florian Schmaus
818ee8a727 Make Objects.requireNonNull() throw IllegalArgumentException
and not NullPointerException. Altough this differs from
java.util.Objects behavior, throwing an IllegalArgumentException
appears more sensible and makes it easier to catch it in Smack's
parsing function.
2019-06-11 12:47:40 +02:00
Florian Schmaus
9bb36fc63c Make Socks5TestProxy a subclass of Socks5Proxy
to reduce the duplicated code. This also means we are now testing the
real implementation.
2019-06-11 12:47:39 +02:00
Florian Schmaus
6e1193edaf Use QName instead of XmppStringUtils.generateKey() 2019-06-11 12:47:39 +02:00
Florian Schmaus
7d59df9eed Change type of presence priority to 'Byte' 2019-06-11 12:47:39 +02:00
Florian Schmaus
e911874e72 Make MultiMap use generics where sensible
I wonder why I orginally did not do it that way…
2019-06-11 12:47:39 +02:00
Florian Schmaus
ce70308099 Introduce UInt(16|32) datatypes 2019-06-11 12:47:39 +02:00
Florian Schmaus
c0183775fe Add support for XEP-0221: Data Forms Media Element
Fixes SMACK-824.
2019-06-11 12:47:39 +02:00
Florian Schmaus
832b20a897 Add XmlPullParser.getAttributeValue(String) 2019-06-11 12:47:39 +02:00
Florian Schmaus
b834df65e9 Add NumberUtil.requireUShort16(int) 2019-06-11 12:47:39 +02:00
Florian Schmaus
b3b242f397 Add TODO comment to XmlStringBuilder 2019-06-11 12:47:39 +02:00
Florian Schmaus
1f8b7273a8 Improve junit test in Socks5ByteStreamManager
It could be that the test is flapping. This helps to see the origin of
the unexpected exception.
2019-06-11 12:47:39 +02:00
Florian Schmaus
4d36e3b521 Introduce FormFieldChildElement and make FormField immutable 2019-06-11 12:47:39 +02:00
Florian Schmaus
1a99801501 Fix typo in FormField's javadoc: s/fold/field/ 2019-06-05 10:54:17 +02:00
Florian Schmaus
3c306eaff9 Improve comment in SmackReactor 2019-06-05 10:54:07 +02:00
Florian Schmaus
9a2cca2bd3 Merge branch 'master' of github.com:Flowdalic/Smack 2019-06-03 17:41:49 +02:00
Florian Schmaus
b288768f77 Introduce util.InternetAddress
and use it where sensible. Also fixes a few unit tests along the way.
2019-06-03 17:41:10 +02:00
Florian Schmaus
4334ca33ff Add missing selector.wakeup() in SmackRactor.schedule()
Without this, newly scheduled runnables would potentially not be
scheduled in case the reactor thread was blocking in select(0)
indefinetly.

Thanks to Eng ChongMeng for reporting this.
2019-06-03 09:28:52 +02:00
Florian Schmaus
027cae3bd0 Remove unnecessary synchronization in SmackReater.schedule()
The DelayQueue 'scheduledActions' is already thread-safe.
2019-06-03 09:27:28 +02:00
Florian Schmaus
619b8e6f4a Add secure(OnlineAttackSafe|Unique|OfflineAttackSafe)RandomString()
and replace usages of java.util.UUID in Smack with
secureUniqueRandomString() because it uses a thread-local secure random
number generator.
2019-06-02 20:08:03 +02:00
Florian Schmaus
58fc39714f Use assertThrows() in Socks5ByteStreamManagerTest 2019-06-02 11:00:37 +02:00
Florian Schmaus
839e347676 Rename NumberUtil.checkIfInUInt32Range() to requireUInt32 2019-06-02 10:46:53 +02:00
Florian Schmaus
726a2de273 Deprecate ParserUtils.getQName() 2019-06-02 10:44:50 +02:00
Florian Schmaus
af6ee76f4c Remove empty lines in Socks5BytestreamManager 2019-06-02 10:41:39 +02:00
Florian Schmaus
49aa7ce21b Do not swallow exception in Socks5BytestreamManager 2019-06-02 10:41:27 +02:00
Florian Schmaus
6619372bb8 Enable parallel unit test execution 2019-06-02 10:40:44 +02:00
Florian Schmaus
9352225f44 Rework SOCKS5 unit tests so that they can be run in parallel
As result it is now also possible to start multiple local SOCKS5
proxies with different port, which is usually not necessary in real
life but useful for unit tests.
2019-06-02 10:38:19 +02:00
Florian Schmaus
d337474a86 Add DiscoverItems.Item.toString() 2019-05-23 23:06:39 +02:00
Florian Schmaus
02f7cfcf27 Improve session sweeping logic in AdHocCommandManager
Fixes SMACK-624.
2019-05-20 10:41:01 +02:00
Florian Schmaus
e8d9aed4be
Merge pull request #303 from adiaholic/SMACK-839
Generic Exception replaced with Type Specific Exceptions.
2019-05-20 09:44:04 +02:00
adiaholic
f91044657f Generic Exception replaced with Type Specific Exceptions.
'parseAndProcessStanza()' throws generic Exceptions.
Since there are plenty of exceptions that should not be
catched by smack, it's better to throw Type Specific Exceptions.
This Commit is was in response to SMACK-839.
2019-05-19 17:09:01 +05:30
Florian Schmaus
04238bd36a Add CloseableUtil.maybeClose(Closeable) 2019-05-18 13:25:31 +02:00
Florian Schmaus
02e2eba556 Socks5Proxy: Remove empty line 2019-05-18 13:24:48 +02:00
Florian Schmaus
48010f3b82 Socks5Proxy: Log if server thread termination was interrupted 2019-05-18 13:24:30 +02:00
Florian Schmaus
11ae6d6960 Socks5Proxy: Use CloseableUtil to close server socket 2019-05-18 13:24:05 +02:00
Florian Schmaus
ab99f629a3 Socks5Proxy: Include server socket in thread name 2019-05-18 13:23:24 +02:00
Florian Schmaus
f7762c5db7 Add "whitespace after comma" checkstyle rule 2019-05-17 21:56:46 +02:00
Florian Schmaus
db5f6f648c Bump AnimalSniffer to 1.5.0 2019-05-17 18:04:27 +02:00
Florian Schmaus
7e25c3ada5 Merge branch '4.3' 2019-05-16 20:52:27 +02:00
Florian Schmaus
2ceadc0de1 Introduce verificationSuccessful boolean 2019-05-16 16:51:31 +02:00
Florian Schmaus
f60e4055ec Use ACE representation of XMPP domain on certificate verification
This is based on the patch provided by Georg Lukas, modified to take
XMPP domain names that can not be represented as DNS names into
account. See c42d2eea24 (r269250137)

Fixes SMACK-870.
2019-05-16 14:14:10 +02:00
Florian Schmaus
381190a45c Add ConnectionConfiguration.getXmppServiceDomainAsDnsNameIfPossible()
in preperation of SMACK-870, so that the DNS name can be used for the
certificate verification.
2019-05-16 14:02:28 +02:00
Florian Schmaus
04f1d79d72 Try GC in MemoryLeakTestUtil.assertReferencesQueueSize()
It appears that we observe a partion GC run on some systems,
especially ones with few resources. Hopefully this increases the
chances to observe the expected GC affects so that the unit test
passes also on those systems.
2019-05-09 12:33:43 +02:00
Florian Schmaus
2dedd75cd7 Add comment about Thread.yield() in MemoryLeakTestUtil 2019-05-09 12:06:01 +02:00
Florian Schmaus
edcde28ecd Set UncaughtExceptionHandler for CACHED_EXECUTOR_SERVICE
In order to avoid uncaught exceptions from terminating the
program (SMACK-896).
2019-05-09 11:04:26 +02:00
Florian Schmaus
49f4de0cdb Replace 'key' with QName 2019-05-08 21:10:39 +02:00
Florian Schmaus
7c6d1f4340 Remove no-op configure block in build.gradle
Become a no-op configure block with
4108b9a83e.
2019-05-08 20:43:45 +02:00
Florian Schmaus
f6be434f66 Remove deprecated methods in StanzaCollector 2019-05-08 20:42:08 +02:00
Florian Schmaus
68b7eb26f3 Fix PacketWriterTest: Expect also InterruptedException
which is thrown in case the queue was shut down.
2019-05-08 15:19:48 +02:00
Florian Schmaus
32429bcb9c Add message to InterruptedException if blocking queue was shut down 2019-05-08 15:19:10 +02:00
Greg Thomas
07c069e1a1 Use the default integration test packages if the supplied list is empty 2019-05-08 15:10:03 +02:00
Florian Schmaus
5e1c3c7aa5 Use FileTagCharacter checkstyle module to check for tabs in source code
instead of RegexpSingleline.
2019-05-08 15:10:03 +02:00
Florian Schmaus
60db42e2f4
Merge pull request #299 from magnetsystems/autojoin-callback-on-reconnect
Autojoin callback on reconnect
2019-05-08 13:43:46 +02:00
Florian Schmaus
d20a2675a8 Make StanzaCollector final 2019-05-08 12:44:48 +02:00
Florian Schmaus
f4ee7dd541 Update PowerMock to 2.0.2
and set Mockito 2's mock-maker-inline as MockMaker to allow mocking of
final classes.
2019-05-08 12:44:48 +02:00
Florian Schmaus
f8de22478b Double the timeout to 120s in MemoryLeakTestUtil
Because an failing test on Travis was observered using a timeout of
60s:

org.jivesoftware.smackx.muc.MucMemoryLeakTest > mucMemoryLeakTest FAILED
    java.lang.AssertionError: No reference found after 60000ms
        at org.junit.Assert.fail(Assert.java:88)
        at org.junit.Assert.assertTrue(Assert.java:41)
        at org.junit.Assert.assertNotNull(Assert.java:712)
        at org.jivesoftware.smack.util.MemoryLeakTestUtil.assertReferencesQueueSize(MemoryLeakTestUtil.java:110)
        at org.jivesoftware.smack.util.MemoryLeakTestUtil.noResourceLeakTest(MemoryLeakTestUtil.java:103)
        at org.jivesoftware.smackx.muc.MucMemoryLeakTest.mucMemoryLeakTest(MucMemoryLeakTest.java:29)
2019-05-08 12:44:48 +02:00
Florian Schmaus
d2f5efcb20 Use StandardCharsets.(UTF_8|US_ASCII)
This also gets rid of a ton of UnsupportedEncodingException s.
2019-05-08 12:44:48 +02:00
Florian Schmaus
2a4d110b22 Add Socks5Exception and improve SOCKS5 bytestream exception messages
The exception message now also contains the stream hosts and their
exception.
2019-05-08 11:07:18 +02:00
Florian Schmaus
fd89a5e5a5 Add StreamHost.toString() 2019-05-08 09:24:23 +02:00
Florian Schmaus
7f0dc72dab Update errorprone(-plugin) and make Unused(Variable|Method) an error 2019-05-07 23:09:00 +02:00
Florian Schmaus
68d7d738b6 Remove all tabs and add checkstyle rule that enforces no-tabs
Fixes SMACK-866.
2019-05-07 21:24:00 +02:00
Florian Schmaus
575364cc1f Print exception's stacktrace in PacketWriterTest 2019-05-07 21:02:07 +02:00
Florian Schmaus
e1ed035beb Remove xmlunit-lagacy and add xmlunit-assertj 2019-05-07 19:06:16 +02:00
Florian Schmaus
95dbf5bb36 Change JUnit API from 4 to 5 in smack-experimental 2019-05-07 18:51:22 +02:00
Florian Schmaus
505493d889 Add XmlStringBuilder.optAttribute(String, Number) 2019-05-07 10:18:55 +02:00
Florian Schmaus
0e52560358 Add test fo smack-xmlparser
mostly to make jacoco happy, but it can not hurt anyway :).
2019-05-07 10:12:43 +02:00
Florian Schmaus
4a3dda93af
Merge pull request #315 from adiaholic/doc-fix-in-index
Minor changes in documentation.
2019-05-06 22:57:59 +02:00
Florian Schmaus
7980e2cedb
Merge pull request #318 from vanitasvitae/xhtml_fix
SMACK-868: Fix XHTMLText producing invalid XML
2019-05-06 22:56:01 +02:00
Florian Schmaus
4133eb175c Replace XPP3 by XmlPullParser interface wrapping StAX and XPP3
Introducing Smack's own XmlPullParser interface which tries to stay as
compatible as possible to XPP3. The interface is used to either wrap
StAX's XMLStreamReader if Smack is used on Java SE, and XPP3's
XmlPullParser if Smack is used on on Android.

Fixes SMACK-591.

Also introduce JUnit 5 and non-strict javadoc projects.
2019-05-06 22:10:50 +02:00
Eng ChongMeng
dd903bec95
SMACK-868: Fix XHTMLText producing invalid XML 2019-05-06 00:39:41 +02:00
adiaholic
1554a33518 Changed XEP-031 to XEP-0131 2019-05-04 14:18:46 +05:30
Florian Schmaus
b3646abecd XMPPTCPConnection: Move openStream() call from writer into reader thread
and also call notifyConnectionError() on exception thrown by
openStream().

In hindsight I wonder why openStream() was ever called in the writer
thread, as it only caused unnecessary synchronization overhead, as can
be seen by the initialOpenStreamSend synchronization point.
2019-04-30 13:55:55 +02:00
Florian Schmaus
ae2c57f56b Fix XML in MamResultProviderTest
Add missing whitespace between XML attributes.
2019-04-29 13:56:16 +02:00
adiaholic
3b657d36c4 Changed XEP-0116 to XEP-0166
Rearranged as per the expected XEP sequence
2019-04-29 13:32:26 +05:30
Florian Schmaus
4e7cd83220 Fix (Privacy|Time)ProviderTest
XML attributes must be separated by a whitespace.
2019-04-29 08:52:36 +02:00
V Lau
f1fb03d08c Add a success callback for auto-join on reconnect.
When auto-join on reconnection is success, invoke a callback.

Conform to the proper copyright format.
2019-04-09 14:21:11 -07:00
588 changed files with 8799 additions and 5100 deletions

View file

@ -1,7 +1,7 @@
language: android
android:
components:
- android-16
- android-19
jdk:
- oraclejdk8
- openjdk8
@ -11,7 +11,7 @@ cache:
- $HOME/.m2
before_install:
- export GRADLE_VERSION=5.1.1
- export GRADLE_VERSION=5.2.1
- wget https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-all.zip
- unzip -q gradle-${GRADLE_VERSION}-all.zip
- export PATH="$(pwd)/gradle-${GRADLE_VERSION}/bin:$PATH"

View file

@ -14,8 +14,8 @@ buildscript {
}
plugins {
id 'ru.vyarus.animalsniffer' version '1.4.6'
id 'net.ltgt.errorprone' version '0.6'
id 'ru.vyarus.animalsniffer' version '1.5.0'
id 'net.ltgt.errorprone' version '0.8'
}
apply plugin: 'org.kordamp.gradle.markdown'
@ -24,6 +24,7 @@ apply from: 'version.gradle'
allprojects {
apply plugin: 'java'
apply plugin: 'java-library'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'jacoco'
@ -80,6 +81,8 @@ allprojects {
':smack-omemo',
':smack-omemo-signal',
':smack-openpgp',
':smack-xmlparser',
':smack-xmlparser-xpp3',
].collect{ project(it) }
androidBootClasspathProjects = [
':smack-android',
@ -97,13 +100,37 @@ allprojects {
':smack-omemo-signal',
':smack-omemo-signal-integration-test',
].collect{ project(it) }
// When this list is empty, then move the according javadoc
// tool Werror option into the global configure section.
nonStrictJavadocProjects = [
':smack-bosh',
':smack-core',
':smack-experimental',
':smack-extensions',
':smack-im',
':smack-integration-test',
':smack-jingle-old',
':smack-legacy',
':smack-omemo',
':smack-tcp',
].collect{ project(it) }
// Lazily evaluate the Android bootClasspath and offline
// Javadoc using a closure, so that targets which do not
// require it are still able to succeed without an Android
// SDK.
androidBootClasspath = { getAndroidRuntimeJar() }
androidJavadocOffline = { getAndroidJavadocOffline() }
junitVersion = '5.2.0'
junit4Projects = [
':smack-core',
':smack-extensions',
':smack-im',
':smack-integration-test',
':smack-omemo',
':smack-omemo-signal',
':smack-openpgp',
].collect { project(it) }
junitVersion = '5.4.2'
powerMockVersion = '2.0.2'
}
group = 'org.igniterealtime.smack'
sourceCompatibility = JavaVersion.VERSION_1_8
@ -114,6 +141,10 @@ allprojects {
}
test {
useJUnitPlatform()
maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
// Enable full stacktraces of failed tests. Especially handy
// for environments like Travis.
testLogging {
@ -170,21 +201,25 @@ allprojects {
'-Xlint:-options',
'-Werror',
]
options.errorprone.errorproneArgs = [
// Disable errorprone checks
'-Xep:TypeParameterUnusedInFormals:OFF',
// Disable errorpone StringSplitter check, as it
// recommends using Splitter from Guava, which we don't
// have (nor want to use in Smack).
'-Xep:StringSplitter:OFF',
'-Xep:JdkObsolete:OFF',
// Disabled because sinttest re-uses BeforeClass from junit.
// TODO: change sinttest so that it has it's own
// BeforeClass and re-enable this check.
'-Xep:JUnit4ClassAnnotationNonStatic:OFF',
// Disabled but should be re-enabled at some point
//'-Xep:InconsistentCapitalization:OFF',
]
options.errorprone {
error("UnusedVariable", "UnusedMethod")
errorproneArgs = [
// Disable errorprone checks
'-Xep:TypeParameterUnusedInFormals:OFF',
// Disable errorpone StringSplitter check, as it
// recommends using Splitter from Guava, which we don't
// have (nor want to use in Smack).
'-Xep:StringSplitter:OFF',
'-Xep:JdkObsolete:OFF',
// Disabled because sinttest re-uses BeforeClass from junit.
// TODO: change sinttest so that it has it's own
// BeforeClass and re-enable this check.
'-Xep:JUnit4ClassAnnotationNonStatic:OFF',
// Disabled but should be re-enabled at some point
//'-Xep:InconsistentCapitalization:OFF',
'-Xep:MixedMutabilityReturnType:OFF',
]
}
}
tasks.withType(ScalaCompile) {
@ -232,7 +267,11 @@ allprojects {
}
dependencies {
errorprone 'com.google.errorprone:error_prone_core:2.3.2'
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
errorprone 'com.google.errorprone:error_prone_core:2.3.3'
errorproneJavac('com.google.errorprone:javac:9+181-r4173-1')
}
@ -241,6 +280,15 @@ allprojects {
test { dependsOn javadoc }
}
configure (junit4Projects) {
dependencies {
testImplementation "org.junit.vintage:junit-vintage-engine:$junitVersion"
testImplementation "org.powermock:powermock-module-junit4:$powerMockVersion"
testImplementation "org.powermock:powermock-module-junit4-rule:$powerMockVersion"
testImplementation "org.powermock:powermock-api-mockito2:$powerMockVersion"
}
}
gradle.taskGraph.whenReady { taskGraph ->
if (signingRequired
&& taskGraph.allTasks.any { it instanceof Sign }) {
@ -519,19 +567,21 @@ configure(integrationTestProjects + project(':smack-repl')) {
project(':smack-omemo').clirr.enabled = false
project(':smack-omemo-signal').clirr.enabled = false
configure(
[ ':smack-omemo',
':smack-omemo-signal',
':smack-omemo-signal-integration-test',
].collect{ project(it) }) {
}
subprojects*.jar {
manifest {
from sharedManifest
}
}
configure(subprojects - nonStrictJavadocProjects) {
tasks.withType(Javadoc) {
// Abort on javadoc warnings.
// See JDK-8200363 (https://bugs.openjdk.java.net/browse/JDK-8200363)
// for information about the -Xwerror option.
options.addStringOption('Xwerror', '-quiet')
}
}
configure(subprojects - gplLicensedProjects) {
checkstyle {
configProperties.checkstyleLicenseHeader = "header"
@ -646,15 +696,7 @@ def getGitCommit() {
}
def getAndroidRuntimeJar() {
// We set a different Android API level compared to
// smackMinAndroidSdk here. The runtime jar retrieved via this
// method is, compared to earlier Smack versions, not used to
// check for Android API compatibility. Instead it is used to for
// the eclipse classpath, for javadoc and when compiling the pure
// Android subprojects of Smack. Currently we require level 16
// here, because of the @TargetApi annotation found in
// AndroidUsingLinkProperties of minidns-android21.
def androidApiLevel = 16
def androidApiLevel = ext.smackMinAndroidSdk
def androidHome = getAndroidHome()
def androidJar = new File("$androidHome/platforms/android-${androidApiLevel}/android.jar")
if (androidJar.isFile()) {

View file

@ -39,12 +39,7 @@
<property name="format" value="^\s+$"/>
<property name="message" value="Line containing only whitespace character(s)"/>
</module>
<module name="RegexpSingleline">
<!-- We use {2,} instead of + here to address the typical case where a file was written
with tabs but javadoc is causing '\t *' -->
<property name="format" value="^\t+ {2,}"/>
<property name="message" value="Line containing space(s) after tab(s)"/>
</module>
<module name="FileTabCharacter"/>
<module name="RegexpSingleline">
<!--
Explaining the following Regex
@ -147,6 +142,7 @@
, LITERAL_DO
, LITERAL_FOR
, DO_WHILE
, COMMA
"/>
</module>
<module name="WhitespaceAround">

View file

@ -27,11 +27,11 @@ public MyExtension parse(XmlPullParser parser, int initialDepth) {
outerloop: while(true) {
// Make sure to have already parse all attributes of the outermost element,
// i.e. 'attrFoo' of 'myExtension' in this example. Then advance the parser
int event = parser.next();
XmlPullParser.Event event = parser.next();
// Use switch/case of int instead of a if/else-if cascade
switch (event) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
// Determine the name of the element which start tag we are seeing
String name = parser.getName();
// We can use switch/case of Strings since Java7, make use of its advantages
@ -52,12 +52,15 @@ public MyExtension parse(XmlPullParser parser, int initialDepth) {
break;
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
// The abort condition with the break labeled loop statement
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}

View file

@ -56,23 +56,25 @@ Smack Extensions and currently supported XEPs of smack-extensions
| [SI File Transfer](filetransfer.md) | [XEP-0096](https://xmpp.org/extensions/xep-0096.html) | n/a | Transfer files between two users over XMPP. |
| User Mood | [XEP-0107](https://xmpp.org/extensions/xep-0107.html) | 1.2.1 | Communicate the users current mood. |
| [Entity Capabilities](caps.md) | [XEP-0115](https://xmpp.org/extensions/xep-0115.html) | n/a | Broadcasting and dynamic discovery of entity capabilities. |
| [Jingle](jingle.html) | [XEP-0116](https://xmpp.org/extensions/xep-0166.html) | n/a | Initiate and manage sessions between two XMPP entities. |
| Data Forms Validation | [XEP-0122](https://xmpp.org/extensions/xep-0122.html) | n/a | Enables an application to specify additional validation guidelines . |
| Service Administration | [XEP-0133](https://xmpp.org/extensions/xep-0133.html) | n/a | Recommended best practices for service-level administration of servers and components using Ad-Hoc Commands. |
| Stream Compression | [XEP-0138](https://xmpp.org/extensions/xep-0138.html) | n/a | Support for optional compression of the XMPP stream.
| Data Forms Layout | [XEP-0141](https://xmpp.org/extensions/xep-0141.html) | n/a | Enables an application to specify form layouts. |
| Personal Eventing Protocol | [XEP-0163](https://xmpp.org/extensions/xep-0163.html) | n/a | Using the XMPP publish-subscribe protocol to broadcast state change events associated with an XMPP account. |
| [Jingle](jingle.html) | [XEP-0166](https://xmpp.org/extensions/xep-0166.html) | n/a | Initiate and manage sessions between two XMPP entities. |
| Message Delivery Receipts | [XEP-0184](https://xmpp.org/extensions/xep-0184.html) | n/a | Extension for message delivery receipts. The sender can request notification that the message has been delivered. |
| [Blocking Command](blockingcommand.md) | [XEP-0191](https://xmpp.org/extensions/xep-0191.html) | n/a | Communications blocking that is intended to be simpler than privacy lists (XEP-0016). |
| XMPP Ping | [XEP-0199](https://xmpp.org/extensions/xep-0199.html) | n/a | Sending application-level pings over XML streams.
| Entity Time | [XEP-0202](https://xmpp.org/extensions/xep-0202.html) | n/a | Allows entities to communicate their local time |
| Delayed Delivery | [XEP-0203](https://xmpp.org/extensions/xep-0203.html) | n/a | Extension for communicating the fact that an XML stanza has been delivered with a delay. |
| XMPP Over BOSH | [XEP-0206](https://xmpp.org/extensions/xep-0206.html) | n/a | Use Bidirectional-streams Over Synchronous HTTP (BOSH) to transport XMPP stanzas. |
| Data Forms Media Element | [XEP-0221](https://xmpp.org/extensions/xep-0221.html) | n/a | Allows to include media data in XEP-0004 data forms. |
| Attention | [XEP-0224](https://xmpp.org/extensions/xep-0224.html) | n/a | Getting attention of another user. |
| Bits of Binary | [XEP-0231](https://xmpp.org/extensions/xep-0231.html) | n/a | Including or referring to small bits of binary data in an XML stanza. |
| Best Practices for Resource Locking | [XEP-0296](https://xmpp.org/extensions/xep-0296.html) | n/a | Specifies best practices to be followed by Jabber/XMPP clients about when to lock into, and unlock away from, resources. |
| Last Message Correction | [XEP-0308](https://xmpp.org/extensions/xep-0308.html) | n/a | Provides a method for indicating that a message is a correction of the last sent message. |
| Last User Interaction in Presence | [XEP-0319](https://xmpp.org/extensions/xep-0319.html) | n/a | Communicate time of last user interaction via XMPP presence notifications. |
| Data Forms Geolocation Element | [XEP-0350](https://xmpp.org/extensions/xep-0350.html) | n/a | Allows to include XEP-0080 gelocation data in XEP-0004 data forms. |
| [Group Chat Invitations](invitation.md) | n/a | n/a | Send invitations to other users to join a group chat room. |
| [Jive Properties](properties.md) | n/a | n/a | TODO |

View file

@ -23,7 +23,7 @@ Whenever a packet extension is found in a packet, parsing will be
passed to the correct provider. Each provider must extend the
ExtensionElementProvider abstract class. Each extension provider is
responsible for parsing the raw XML stream, via the
[XML Pull Parser](http://www.xmlpull.org/), to contruct an object.
Smack's `XmlPullParser` interface, to construct an object.
You can also create an introspection provider
(`provider.IntrospectionProvider.PacketExtensionIntrospectionProvider`). Here,
@ -161,9 +161,9 @@ public class MyIQProvider extends IQProvider<MyIQ> {
// Start parsing loop
outerloop: while(true) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
switch(eventType) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
String elementName = parser.getName();
switch (elementName) {
case "user":
@ -175,12 +175,15 @@ public class MyIQProvider extends IQProvider<MyIQ> {
break;
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
// Abort condition: if the are on a end tag (closing element) of the same depth
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}
@ -225,9 +228,9 @@ _Disco Items IQProvider_
String node = "";
discoverItems.setNode(parser.getAttributeValue("", "node"));
outerloop: while (true) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
switch (eventType) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
String elementName = parser.getName();
switch (elementName) {
case "item":
@ -239,7 +242,7 @@ _Disco Items IQProvider_
break;
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
String elementName = parser.getName();
switch (elementName) {
case "item":
@ -295,17 +298,17 @@ _Subscription PacketExtensionProvider Implementation_
String state = parser.getAttributeValue(null, "subscription");
boolean isRequired = false;
int tag = parser.next();
XmlPullParser.Event tag = parser.next();
if ((tag == XmlPullParser.START_TAG) && parser.getName().equals("subscribe-options")) {
if ((tag == XmlPullParser.START_ELEMENT) && parser.getName().equals("subscribe-options")) {
tag = parser.next();
if ((tag == XmlPullParser.START_TAG) && parser.getName().equals("required"))
if ((tag == XmlPullParser.START_ELEMENT) && parser.getName().equals("required"))
isRequired = true;
while (parser.next() != XmlPullParser.END_TAG && parser.getName() != "subscribe-options");
while (parser.next() != XmlPullParser.END_ELEMENT && parser.getName() != "subscribe-options");
}
while (parser.getEventType() != XmlPullParser.END_TAG) parser.next();
while (parser.getEventType() != XmlPullParser.END_ELEMENT) parser.next();
return new Subscription(jid, nodeId, subId, state == null ? null : Subscription.State.valueOf(state), isRequired);
}
}

View file

@ -169,14 +169,10 @@ recommended when using Smack.
</p>
<p>
If you dont' use a
dependency resolution system, like gradle or maven, then you will need
to download at least
the <a href="http://www.extreme.indiana.edu/xgws/xsoap/xpp/mxp1/">Xml
Pull Parser 3rd Edition (XPP3) library</a> or any other library that
implements the XmlPullParser interface
(like <a href="http://kxml.org/">kXML</a>) and the set of
<a href="http://jxmpp.org">jXMPP libraries</a>.
Smack tries to depend on as few as possible libraries. The only
requirement is <a href="http://jxmpp.org">jXMPP</a>. For DNS
resolution we recommend to
use <a href="http://minidns.org">MiniDNS</a>.
</p>
<p>

View file

@ -28,4 +28,7 @@ include 'smack-core',
'smack-omemo-signal',
'smack-omemo-signal-integration-test',
'smack-repl',
'smack-openpgp'
'smack-openpgp',
'smack-xmlparser',
'smack-xmlparser-stax',
'smack-xmlparser-xpp3'

View file

@ -7,6 +7,7 @@ smack-extensions and smack-experimental."""
// Note that the test dependencies (junit, ) are inferred from the
// sourceSet.test of the core subproject
dependencies {
api project(':smack-xmlparser-xpp3')
// Depend on minidns-android21 as optional dependency, even if may
// not need it. Can't hurt to have it in the programm path with
// the correct MiniDNS version as it won't hurt even if the

View file

@ -1,6 +1,6 @@
/**
*
* Copyright © 2014-2018 Florian Schmaus
* Copyright © 2014-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,9 +16,8 @@
*/
package org.jivesoftware.smack.util.stringencoder.android;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.stringencoder.StringEncoder;
import android.util.Base64;
@ -39,21 +38,13 @@ public final class AndroidBase64UrlSafeEncoder implements StringEncoder<String>
@Override
public String encode(String string) {
try {
return Base64.encodeToString(string.getBytes(StringUtils.UTF8), BASE64_ENCODER_FLAGS);
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 not supported", e);
}
return Base64.encodeToString(string.getBytes(StandardCharsets.UTF_8), BASE64_ENCODER_FLAGS);
}
@Override
public String decode(String string) {
byte[] bytes = Base64.decode(string, BASE64_ENCODER_FLAGS);
try {
return new String(bytes, StringUtils.UTF8);
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 not supported", e);
}
return new String(bytes, StandardCharsets.UTF_8);
}
}

View file

@ -20,7 +20,6 @@ package org.jivesoftware.smack.bosh;
import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.StringReader;
import java.io.Writer;
import java.util.Map;
import java.util.logging.Level;
@ -44,6 +43,7 @@ import org.jivesoftware.smack.sasl.packet.SaslStreamElements.SASLFailure;
import org.jivesoftware.smack.sasl.packet.SaslStreamElements.Success;
import org.jivesoftware.smack.util.CloseableUtil;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.igniterealtime.jbosh.AbstractBody;
import org.igniterealtime.jbosh.BOSHClient;
@ -56,11 +56,8 @@ import org.igniterealtime.jbosh.BOSHException;
import org.igniterealtime.jbosh.BOSHMessageEvent;
import org.igniterealtime.jbosh.BodyQName;
import org.igniterealtime.jbosh.ComposableBody;
import org.jxmpp.jid.DomainBareJid;
import org.jxmpp.jid.parts.Resourcepart;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
/**
* Creates a connection to an XMPP server via HTTP binding.
@ -479,14 +476,13 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
if (streamId == null) {
streamId = body.getAttribute(BodyQName.create(XMPPBOSHConnection.BOSH_URI, "authid"));
}
final XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(new StringReader(body.toXML()));
int eventType = parser.getEventType();
final XmlPullParser parser = PacketParserUtils.getParserFor(body.toXML());
XmlPullParser.Event eventType = parser.getEventType();
do {
eventType = parser.next();
switch (eventType) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
String name = parser.getName();
switch (name) {
case Message.ELEMENT:
@ -528,9 +524,12 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
}
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}
while (eventType != XmlPullParser.END_DOCUMENT);
while (eventType != XmlPullParser.Event.END_DOCUMENT);
}
catch (Exception e) {
if (isConnected()) {

View file

@ -2,23 +2,27 @@ description = """\
Smack core components."""
ext {
xmlUnitVersion = "2.6.0"
powerMockVersion = "1.7.3"
xmlUnitVersion = '2.6.2'
}
dependencies {
compile 'xpp3:xpp3:1.1.4c'
compile project(':smack-xmlparser')
compile "org.jxmpp:jxmpp-core:$jxmppVersion"
compile "org.jxmpp:jxmpp-jid:$jxmppVersion"
compile "org.minidns:minidns-core:$miniDnsVersion"
testCompile project(':smack-xmlparser-stax')
testCompile project(':smack-xmlparser-xpp3')
testCompile "org.jxmpp:jxmpp-jid:$jxmppVersion:tests"
testCompile "org.junit.jupiter:junit-jupiter-api:$junitVersion"
testCompile "org.junit.vintage:junit-vintage-engine:$junitVersion"
testCompile "org.xmlunit:xmlunit-core:$xmlUnitVersion"
testCompile "org.xmlunit:xmlunit-legacy:$xmlUnitVersion"
testCompile "org.powermock:powermock-module-junit4:$powerMockVersion"
testCompile "org.powermock:powermock-module-junit4-rule:$powerMockVersion"
testCompile "org.powermock:powermock-api-mockito2:$powerMockVersion"
// Explictily add assertj-core which is a dependency of
// xmlunit-assertj, but gradle fails to resolves it with:
// Execution failed for task ':smack-core:compileTestJava'.
// > Could not resolve all files for configuration ':smack-core:testCompileClasspath'.
// > Could not find org.assertj:assertj-core:.
// Required by:
// project :smack-core > org.xmlunit:xmlunit-assertj:2.6.2
testCompile "org.assertj:assertj-core:3.11.1"
testCompile "org.xmlunit:xmlunit-assertj:$xmlUnitVersion"
testCompile 'com.jamesmurty.utils:java-xmlbuilder:1.2'
}

View file

@ -16,9 +16,9 @@ package org.jivesoftware.smack.packet;
import org.jivesoftware.smack.provider.PrivacyProvider;
import org.jivesoftware.smack.test.SmackTestCase;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.jivesoftware.smack.xml.XmlPullParserFactory;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
import java.io.StringReader;

View file

@ -32,8 +32,8 @@ import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.TCPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.util.ConnectionUtils;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserFactory;
import org.jivesoftware.smack.xml.XmlPullParser;
/**
* Base class for all the test cases which provides a pre-configured execution context. This
@ -414,9 +414,9 @@ public abstract class SmackTestCase extends TestCase {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(systemStream, "UTF-8");
int eventType = parser.getEventType();
XmlPullParser.Event eventType = parser.getEventType();
do {
if (eventType == XmlPullParser.START_TAG) {
if (eventType == START_ELEMENT) {
if (parser.getName().equals("host")) {
host = parser.nextText();
}
@ -459,7 +459,7 @@ public abstract class SmackTestCase extends TestCase {
}
eventType = parser.next();
}
while (eventType != XmlPullParser.END_DOCUMENT);
while (eventType != END_DOCUMENT);
parsedOK = true;
}
catch (Exception e) {

View file

@ -20,9 +20,9 @@ import java.io.StringReader;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.test.SmackTestCase;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.jivesoftware.smack.xml.XmlPullParserFactory;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
public class XMPPErrorTest extends SmackTestCase {

View file

@ -23,6 +23,7 @@ import java.io.InputStream;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
@ -64,6 +65,7 @@ import javax.net.ssl.X509TrustManager;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.PasswordCallback;
import javax.xml.namespace.QName;
import org.jivesoftware.smack.ConnectionConfiguration.DnssecMode;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
@ -121,6 +123,8 @@ import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.dns.HostAddress;
import org.jivesoftware.smack.util.dns.SmackDaneProvider;
import org.jivesoftware.smack.util.dns.SmackDaneVerifier;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jxmpp.jid.DomainBareJid;
import org.jxmpp.jid.EntityFullJid;
@ -130,8 +134,6 @@ import org.jxmpp.jid.parts.Resourcepart;
import org.jxmpp.stringprep.XmppStringprepException;
import org.jxmpp.util.XmppStringUtils;
import org.minidns.dnsname.DnsName;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
/**
@ -233,11 +235,11 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
private XmlEnvironment incomingStreamXmlEnvironment;
final Map<String, NonzaCallback> nonzaCallbacks = new HashMap<>();
final Map<QName, NonzaCallback> nonzaCallbacks = new HashMap<>();
protected final Lock connectionLock = new ReentrantLock();
protected final Map<String, FullyQualifiedElement> streamFeatures = new HashMap<>();
protected final Map<QName, FullyQualifiedElement> streamFeatures = new HashMap<>();
/**
* The full JID of the authenticated user, as returned by the resource binding response of the server.
@ -336,6 +338,12 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
Thread thread = new Thread(runnable);
thread.setName("Smack Cached Executor");
thread.setDaemon(true);
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
LOGGER.log(Level.WARNING, t + " encountered uncaught exception", e);
}
});
return thread;
}
});
@ -381,8 +389,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
protected Exception currentConnectionException;
private final Map<String, IQRequestHandler> setIqRequestHandler = new HashMap<>();
private final Map<String, IQRequestHandler> getIqRequestHandler = new HashMap<>();
private final Map<QName, IQRequestHandler> setIqRequestHandler = new HashMap<>();
private final Map<QName, IQRequestHandler> getIqRequestHandler = new HashMap<>();
/**
* Create a new XMPPConnection to an XMPP server.
@ -1213,7 +1221,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
protected final void parseAndProcessNonza(XmlPullParser parser) throws IOException, XmlPullParserException, SmackParsingException {
final String element = parser.getName();
final String namespace = parser.getNamespace();
final String key = XmppStringUtils.generateKey(element, namespace);
final QName key = new QName(namespace, element);
NonzaProvider<? extends Nonza> nonzaProvider = ProviderManager.getNonzaProvider(key);
if (nonzaProvider == null) {
@ -1243,7 +1251,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
try {
stanza = PacketParserUtils.parseStanza(parser, incomingStreamXmlEnvironment);
}
catch (Exception e) {
catch (XmlPullParserException | SmackParsingException | IOException e) {
CharSequence content = PacketParserUtils.parseContentDepth(parser,
parserDepth);
UnparseableStanza message = new UnparseableStanza(content, e);
@ -1295,7 +1303,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
final IQ iq = (IQ) packet;
if (iq.isRequestIQ()) {
final IQ iqRequest = iq;
final String key = XmppStringUtils.generateKey(iq.getChildElementName(), iq.getChildElementNamespace());
final QName key = iqRequest.getChildElementQName();
IQRequestHandler iqRequestHandler;
final IQ.Type type = iq.getType();
switch (type) {
@ -1614,9 +1622,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
streamFeatures.clear();
final int initialDepth = parser.getDepth();
while (true) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
if (eventType == XmlPullParser.START_TAG && parser.getDepth() == initialDepth + 1) {
if (eventType == XmlPullParser.Event.START_ELEMENT && parser.getDepth() == initialDepth + 1) {
FullyQualifiedElement streamFeature = null;
String name = parser.getName();
String namespace = parser.getNamespace();
@ -1647,7 +1655,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
addStreamFeature(streamFeature);
}
}
else if (eventType == XmlPullParser.END_TAG && parser.getDepth() == initialDepth) {
else if (eventType == XmlPullParser.Event.END_ELEMENT && parser.getDepth() == initialDepth) {
break;
}
}
@ -1686,7 +1694,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
@SuppressWarnings("unchecked")
@Override
public <F extends FullyQualifiedElement> F getFeature(String element, String namespace) {
return (F) streamFeatures.get(XmppStringUtils.generateKey(element, namespace));
QName qname = new QName(namespace, element);
return (F) streamFeatures.get(qname);
}
@Override
@ -1695,7 +1704,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
}
protected void addStreamFeature(FullyQualifiedElement feature) {
String key = XmppStringUtils.generateKey(feature.getElementName(), feature.getNamespace());
QName key = feature.getQName();
streamFeatures.put(key, feature);
}
@ -1804,7 +1813,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
@Override
public IQRequestHandler registerIQRequestHandler(final IQRequestHandler iqRequestHandler) {
final String key = XmppStringUtils.generateKey(iqRequestHandler.getElement(), iqRequestHandler.getNamespace());
final QName key = iqRequestHandler.getQName();
switch (iqRequestHandler.getType()) {
case set:
synchronized (setIqRequestHandler) {
@ -1827,7 +1836,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
@Override
public IQRequestHandler unregisterIQRequestHandler(String element, String namespace, IQ.Type type) {
final String key = XmppStringUtils.generateKey(element, namespace);
final QName key = new QName(namespace, element);
switch (type) {
case set:
synchronized (setIqRequestHandler) {
@ -2044,13 +2053,13 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
try {
Constructor<?> c = Class.forName("sun.security.pkcs11.SunPKCS11").getConstructor(InputStream.class);
String pkcs11Config = "name = SmartCard\nlibrary = " + config.getPKCS11Library();
ByteArrayInputStream config = new ByteArrayInputStream(pkcs11Config.getBytes(StringUtils.UTF8));
ByteArrayInputStream config = new ByteArrayInputStream(pkcs11Config.getBytes(StandardCharsets.UTF_8));
Provider p = (Provider) c.newInstance(config);
Security.addProvider(p);
ks = KeyStore.getInstance("PKCS11",p);
pcb = new PasswordCallback("PKCS11 Password: ",false);
ks = KeyStore.getInstance("PKCS11", p);
pcb = new PasswordCallback("PKCS11 Password: ", false);
callbackHandler.handle(new Callback[] {pcb});
ks.load(null,pcb.getPassword());
ks.load(null, pcb.getPassword());
}
catch (Exception e) {
LOGGER.log(Level.WARNING, "Exception", e);
@ -2058,8 +2067,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
}
}
else if ("Apple".equals(keyStoreType)) {
ks = KeyStore.getInstance("KeychainStore","Apple");
ks.load(null,null);
ks = KeyStore.getInstance("KeychainStore", "Apple");
ks.load(null, null);
// pcb = new PasswordCallback("Apple Keychain",false);
// pcb.setPassword(null);
}

View file

@ -25,6 +25,8 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.SocketFactory;
import javax.net.ssl.HostnameVerifier;
@ -46,6 +48,7 @@ import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Resourcepart;
import org.jxmpp.stringprep.XmppStringprepException;
import org.minidns.dnsname.DnsName;
import org.minidns.dnsname.InvalidDnsNameException;
import org.minidns.util.InetAddressUtil;
/**
@ -81,6 +84,8 @@ public abstract class ConnectionConfiguration {
SmackConfiguration.getVersion();
}
private static final Logger LOGGER = Logger.getLogger(ConnectionConfiguration.class.getName());
/**
* The XMPP domain of the XMPP Service. Usually servers use the same service name as the name
* of the server. However, there are some servers like google where host would be
@ -88,6 +93,8 @@ public abstract class ConnectionConfiguration {
*/
protected final DomainBareJid xmppServiceDomain;
protected final DnsName xmppServiceDomainDnsName;
protected final InetAddress hostAddress;
protected final DnsName host;
protected final int port;
@ -149,7 +156,7 @@ public abstract class ConnectionConfiguration {
private final boolean compressionEnabled;
protected ConnectionConfiguration(Builder<?,?> builder) {
protected ConnectionConfiguration(Builder<?, ?> builder) {
authzid = builder.authzid;
username = builder.username;
password = builder.password;
@ -162,6 +169,19 @@ public abstract class ConnectionConfiguration {
if (xmppServiceDomain == null) {
throw new IllegalArgumentException("Must define the XMPP domain");
}
DnsName xmppServiceDomainDnsName;
try {
xmppServiceDomainDnsName = DnsName.from(xmppServiceDomain);
} catch (InvalidDnsNameException e) {
LOGGER.log(Level.INFO,
"Could not transform XMPP service domain '" + xmppServiceDomain
+ "' to a DNS name. TLS X.509 certificate validiation may not be possible.",
e);
xmppServiceDomainDnsName = null;
}
this.xmppServiceDomainDnsName = xmppServiceDomainDnsName;
hostAddress = builder.hostAddress;
host = builder.host;
port = builder.port;
@ -225,6 +245,17 @@ public abstract class ConnectionConfiguration {
return xmppServiceDomain;
}
/**
* Returns the XMPP service domain as DNS name if possible. Note that since not every XMPP address domainpart is a
* valid DNS name, this method may return <code>null</code>.
*
* @return the XMPP service domain as DNS name or <code>null</code>.
* @since 4.3.4
*/
public DnsName getXmppServiceDomainAsDnsNameIfPossible() {
return xmppServiceDomainDnsName;
}
/**
* Returns the TLS security mode used when making the connection. By default,
* the mode is {@link SecurityMode#ifpossible}.

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2018 Florian Schmaus
* Copyright 2018-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,18 +19,18 @@ package org.jivesoftware.smack;
import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPException.FailedNonzaException;
import org.jivesoftware.smack.packet.Nonza;
import org.jivesoftware.smack.util.XmppElementUtil;
import org.jxmpp.util.XmppStringUtils;
public class NonzaCallback {
protected final AbstractXMPPConnection connection;
protected final Map<String, GenericElementListener<? extends Nonza>> filterAndListeners;
protected final Map<QName, GenericElementListener<? extends Nonza>> filterAndListeners;
private NonzaCallback(Builder builder) {
this.connection = builder.connection;
@ -39,7 +39,7 @@ public class NonzaCallback {
}
void onNonzaReceived(Nonza nonza) {
String key = XmppStringUtils.generateKey(nonza.getElementName(), nonza.getNamespace());
QName key = nonza.getQName();
GenericElementListener<? extends Nonza> nonzaListener = filterAndListeners.get(key);
nonzaListener.processElement(nonza);
@ -47,8 +47,8 @@ public class NonzaCallback {
public void cancel() {
synchronized (connection.nonzaCallbacks) {
for (Map.Entry<String, GenericElementListener<? extends Nonza>> entry : filterAndListeners.entrySet()) {
String filterKey = entry.getKey();
for (Map.Entry<QName, GenericElementListener<? extends Nonza>> entry : filterAndListeners.entrySet()) {
QName filterKey = entry.getKey();
NonzaCallback installedCallback = connection.nonzaCallbacks.get(filterKey);
if (equals(installedCallback)) {
connection.nonzaCallbacks.remove(filterKey);
@ -63,7 +63,7 @@ public class NonzaCallback {
}
synchronized (connection.nonzaCallbacks) {
for (String key : filterAndListeners.keySet()) {
for (QName key : filterAndListeners.keySet()) {
connection.nonzaCallbacks.put(key, this);
}
}
@ -78,8 +78,8 @@ public class NonzaCallback {
Builder builder) {
super(builder);
final String successNonzaKey = XmppElementUtil.getKeyFor(successNonzaClass);
final String failedNonzaKey = XmppElementUtil.getKeyFor(failedNonzaClass);
final QName successNonzaKey = XmppElementUtil.getQNameFor(successNonzaClass);
final QName failedNonzaKey = XmppElementUtil.getQNameFor(failedNonzaClass);
final GenericElementListener<SN> successListener = new GenericElementListener<SN>(successNonzaClass) {
@Override
@ -139,14 +139,14 @@ public class NonzaCallback {
public static final class Builder {
private final AbstractXMPPConnection connection;
private Map<String, GenericElementListener<? extends Nonza>> filterAndListeners = new HashMap<>();
private Map<QName, GenericElementListener<? extends Nonza>> filterAndListeners = new HashMap<>();
Builder(AbstractXMPPConnection connection) {
this.connection = connection;
}
public <N extends Nonza> Builder listenFor(Class<? extends N> nonza, GenericElementListener<? extends N> nonzaListener) {
String key = XmppElementUtil.getKeyFor(nonza);
QName key = XmppElementUtil.getQNameFor(nonza);
filterAndListeners.put(key, nonzaListener);
return this;
}

View file

@ -29,6 +29,7 @@ import javax.net.ssl.HostnameVerifier;
import org.jivesoftware.smack.compression.XMPPInputOutputStream;
import org.jivesoftware.smack.debugger.ReflectionDebuggerFactory;
import org.jivesoftware.smack.debugger.SmackDebuggerFactory;
import org.jivesoftware.smack.parsing.ExceptionThrowingCallback;
import org.jivesoftware.smack.parsing.ExceptionThrowingCallbackWithHint;
import org.jivesoftware.smack.parsing.ParsingExceptionCallback;
import org.jivesoftware.smack.util.Objects;
@ -380,4 +381,5 @@ public final class SmackConfiguration {
public static int getDefaultConcurrencyLevelLimit() {
return defaultConcurrencyLevelLimit;
}
}

View file

@ -20,6 +20,7 @@ package org.jivesoftware.smack;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
@ -44,10 +45,9 @@ import org.jivesoftware.smack.sasl.core.SCRAMSHA1Mechanism;
import org.jivesoftware.smack.sasl.core.ScramSha1PlusMechanism;
import org.jivesoftware.smack.util.CloseableUtil;
import org.jivesoftware.smack.util.FileUtils;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import org.jivesoftware.smack.xml.XmlPullParser;
public final class SmackInitialization {
@ -69,7 +69,7 @@ public final class SmackInitialization {
String smackVersion;
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(FileUtils.getStreamForClasspathFile("org.jivesoftware.smack/version", null), StringUtils.UTF8));
reader = new BufferedReader(new InputStreamReader(FileUtils.getStreamForClasspathFile("org.jivesoftware.smack/version", null), StandardCharsets.UTF_8));
smackVersion = reader.readLine();
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Could not determine Smack version", e);
@ -141,12 +141,10 @@ public final class SmackInitialization {
public static void processConfigFile(InputStream cfgFileStream,
Collection<Exception> exceptions, ClassLoader classLoader) throws Exception {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(cfgFileStream, "UTF-8");
int eventType = parser.getEventType();
XmlPullParser parser = PacketParserUtils.getParserFor(cfgFileStream);
XmlPullParser.Event eventType = parser.getEventType();
do {
if (eventType == XmlPullParser.START_TAG) {
if (eventType == XmlPullParser.Event.START_ELEMENT) {
if (parser.getName().equals("startupClasses")) {
parseClassesToLoad(parser, false, exceptions, classLoader);
}
@ -156,7 +154,7 @@ public final class SmackInitialization {
}
eventType = parser.next();
}
while (eventType != XmlPullParser.END_DOCUMENT);
while (eventType != XmlPullParser.Event.END_DOCUMENT);
CloseableUtil.maybeClose(cfgFileStream, LOGGER);
}
@ -164,12 +162,10 @@ public final class SmackInitialization {
Collection<Exception> exceptions, ClassLoader classLoader)
throws Exception {
final String startName = parser.getName();
int eventType;
String name;
XmlPullParser.Event eventType;
outerloop: do {
eventType = parser.next();
name = parser.getName();
if (eventType == XmlPullParser.START_TAG && "className".equals(name)) {
if (eventType == XmlPullParser.Event.START_ELEMENT && "className".equals(parser.getName())) {
String classToLoad = parser.nextText();
if (SmackConfiguration.isDisabledSmackClass(classToLoad)) {
continue outerloop;
@ -188,7 +184,7 @@ public final class SmackInitialization {
}
}
}
while (!(eventType == XmlPullParser.END_TAG && startName.equals(name)));
while (!(eventType == XmlPullParser.Event.END_ELEMENT && startName.equals(parser.getName())));
}
private static void loadSmackClass(String className, boolean optional, ClassLoader classLoader) throws Exception {

View file

@ -149,9 +149,8 @@ public class SmackReactor {
long releaseTimeEpoch = System.currentTimeMillis() + unit.toMillis(delay);
Date releaseTimeDate = new Date(releaseTimeEpoch);
ScheduledAction scheduledAction = new ScheduledAction(runnable, releaseTimeDate, this);
synchronized (scheduledActions) {
scheduledActions.add(scheduledAction);
}
scheduledActions.add(scheduledAction);
selector.wakeup();
return scheduledAction;
}
@ -209,7 +208,8 @@ public class SmackReactor {
long selectWait;
if (nextScheduledAction == null) {
// There is no next scheduled action, wait indefinitely in select().
// There is no next scheduled action, wait indefinitely in select() or until another thread invokes
// selector.wakeup().
selectWait = 0;
} else {
selectWait = nextScheduledAction.getTimeToDueMillis();

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2003-2007 Jive Software, 2016-2018 Florian Schmaus.
* Copyright 2003-2007 Jive Software, 2016-2019 Florian Schmaus.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -41,7 +41,7 @@ import org.jivesoftware.smack.packet.Stanza;
* @see XMPPConnection#createStanzaCollector(StanzaFilter)
* @author Matt Tucker
*/
public class StanzaCollector implements AutoCloseable {
public final class StanzaCollector implements AutoCloseable {
private final StanzaFilter packetFilter;
@ -69,7 +69,7 @@ public class StanzaCollector implements AutoCloseable {
* @param connection the connection the collector is tied to.
* @param configuration the configuration used to construct this collector
*/
protected StanzaCollector(XMPPConnection connection, Configuration configuration) {
StanzaCollector(XMPPConnection connection, Configuration configuration) {
this.connection = connection;
this.packetFilter = configuration.packetFilter;
this.resultQueue = new ArrayDeque<>(configuration.size);
@ -98,18 +98,6 @@ public class StanzaCollector implements AutoCloseable {
}
}
/**
* Returns the stanza filter associated with this stanza collector. The packet
* filter is used to determine what packets are queued as results.
*
* @return the stanza filter.
* @deprecated use {@link #getStanzaFilter()} instead.
*/
@Deprecated
public StanzaFilter getPacketFilter() {
return getStanzaFilter();
}
/**
* Returns the stanza filter associated with this stanza collector. The stanza
* filter is used to determine what stanzas are queued as results.
@ -329,6 +317,21 @@ public class StanzaCollector implements AutoCloseable {
return resultQueue.size();
}
private String stringCache;
@Override
public String toString() {
if (stringCache == null) {
StringBuilder sb = new StringBuilder(128);
sb.append("Stanza Collector filter='").append(packetFilter).append('\'');
if (request != null) {
sb.append(" request='").append(request).append('\'');
}
stringCache = sb.toString();
}
return stringCache;
}
synchronized void notifyConnectionError(Exception exception) {
connectionException = exception;
notifyAll();
@ -380,19 +383,6 @@ public class StanzaCollector implements AutoCloseable {
private Configuration() {
}
/**
* Set the stanza filter used by this collector. If <code>null</code>, then all packets will
* get collected by this collector.
*
* @param packetFilter
* @return a reference to this configuration.
* @deprecated use {@link #setStanzaFilter(StanzaFilter)} instead.
*/
@Deprecated
public Configuration setPacketFilter(StanzaFilter packetFilter) {
return setStanzaFilter(packetFilter);
}
/**
* Set the stanza filter used by this collector. If <code>null</code>, then all stanzas will
* get collected by this collector.

View file

@ -20,7 +20,7 @@ import org.jivesoftware.smack.compress.packet.Compressed;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.provider.NonzaProvider;
import org.xmlpull.v1.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParser;
public final class CompressedProvider extends NonzaProvider<Compressed> {

View file

@ -27,8 +27,8 @@ import org.jivesoftware.smack.parsing.SmackParsingException;
import org.jivesoftware.smack.provider.NonzaProvider;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
public final class FailureProvider extends NonzaProvider<Failure> {
@ -46,9 +46,9 @@ public final class FailureProvider extends NonzaProvider<Failure> {
XmlEnvironment failureXmlEnvironment = XmlEnvironment.from(parser, xmlEnvironment);
outerloop: while (true) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
switch (eventType) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
String name = parser.getName();
String namespace = parser.getNamespace();
switch (namespace) {
@ -72,11 +72,12 @@ public final class FailureProvider extends NonzaProvider<Failure> {
break;
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
default: // fall out
}
}

View file

@ -0,0 +1,70 @@
/**
*
* Copyright 2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smack.datatypes;
public abstract class Scalar extends java.lang.Number {
/**
*
*/
private static final long serialVersionUID = 1L;
private final java.lang.Number number;
protected Scalar(java.lang.Number number) {
this.number = number;
}
public final Number number() {
return number;
}
@Override
public final int intValue() {
return number.intValue();
}
@Override
public final long longValue() {
return number.longValue();
}
@Override
public final float floatValue() {
return number.floatValue();
}
@Override
public final double doubleValue() {
return number.doubleValue();
}
@Override
public final int hashCode() {
return number.hashCode();
}
@Override
public final boolean equals(Object other) {
return number.equals(other);
}
@Override
public final String toString() {
return number.toString();
}
}

View file

@ -0,0 +1,42 @@
/**
*
* Copyright 2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smack.datatypes;
import org.jivesoftware.smack.util.NumberUtil;
/**
* A number representing an unsigned 16-bit integer. Can be used for values with the XML schema type "xs:unsingedShort".
*/
public final class UInt16 extends Scalar {
private static final long serialVersionUID = 1L;
private final int number;
private UInt16(int number) {
super(NumberUtil.requireUShort16(number));
this.number = number;
}
public int nativeRepresentation() {
return number;
}
public static UInt16 from(int number) {
return new UInt16(number);
}
}

View file

@ -0,0 +1,42 @@
/**
*
* Copyright 2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smack.datatypes;
import org.jivesoftware.smack.util.NumberUtil;
/**
* A number representing an unsigned 32-bit integer. Can be used for values with the XML schema type "xs:unsignedInt".
*/
public final class UInt32 extends Scalar {
private static final long serialVersionUID = 1L;
private final long number;
private UInt32(long number) {
super(NumberUtil.requireUInt32(number));
this.number = number;
}
public long nativeRepresentation() {
return number;
}
public static UInt32 from(long number) {
return new UInt32(number);
}
}

View file

@ -0,0 +1,21 @@
/**
*
* Copyright 2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Custom datatypes for Integers.
*/
package org.jivesoftware.smack.datatypes;

View file

@ -57,10 +57,10 @@ import org.jivesoftware.smack.sasl.packet.SaslStreamElements.Challenge;
import org.jivesoftware.smack.sasl.packet.SaslStreamElements.Success;
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;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
public abstract class AbstractXmppStateMachineConnection extends AbstractXMPPConnection {
@ -310,10 +310,10 @@ public abstract class AbstractXmppStateMachineConnection extends AbstractXMPPCon
// Skip the enclosing stream open what is guaranteed to be there.
parser.next();
int event = parser.getEventType();
XmlPullParser.Event event = parser.getEventType();
outerloop: while (true) {
switch (event) {
case XmlPullParser.START_TAG:
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) {
@ -353,8 +353,9 @@ public abstract class AbstractXmppStateMachineConnection extends AbstractXMPPCon
break;
}
break;
case XmlPullParser.END_DOCUMENT:
case END_DOCUMENT:
break outerloop;
default: // fall out
}
event = parser.next();
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,8 @@
*/
package org.jivesoftware.smack.iqrequest;
import javax.xml.namespace.QName;
import org.jivesoftware.smack.packet.IQ;
/**
@ -50,4 +52,8 @@ public interface IQRequestHandler {
String getElement();
String getNamespace();
default QName getQName() {
return new QName(getNamespace(), getElement());
}
}

View file

@ -52,7 +52,7 @@ public class DefaultExtensionElement implements ExtensionElement {
private String elementName;
private String namespace;
private Map<String,String> map;
private Map<String, String> map;
/**
* Creates a new generic stanza extension.
@ -107,7 +107,7 @@ public class DefaultExtensionElement implements ExtensionElement {
if (map == null) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(new HashMap<String,String>(map).keySet());
return Collections.unmodifiableSet(new HashMap<String, String>(map).keySet());
}
/**
@ -131,7 +131,7 @@ public class DefaultExtensionElement implements ExtensionElement {
*/
public synchronized void setValue(String name, String value) {
if (map == null) {
map = new HashMap<String,String>();
map = new HashMap<String, String>();
}
map.put(name, value);
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2018 Florian Schmaus
* Copyright 2018-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,8 @@
*/
package org.jivesoftware.smack.packet;
import javax.xml.namespace.QName;
public interface FullyQualifiedElement extends NamedElement {
/**
@ -25,4 +27,9 @@ public interface FullyQualifiedElement extends NamedElement {
*/
String getNamespace();
default QName getQName() {
String namespaceURI = getNamespace();
String localPart = getElementName();
return new QName(namespaceURI, localPart);
}
}

View file

@ -20,6 +20,8 @@ package org.jivesoftware.smack.packet;
import java.util.List;
import java.util.Locale;
import javax.xml.namespace.QName;
import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.XmlStringBuilder;
@ -46,6 +48,7 @@ public abstract class IQ extends Stanza {
public static final String IQ_ELEMENT = "iq";
public static final String QUERY_ELEMENT = "query";
private final QName childElementQName;
private final String childElementName;
private final String childElementNamespace;
@ -56,6 +59,7 @@ public abstract class IQ extends Stanza {
type = iq.getType();
this.childElementName = iq.childElementName;
this.childElementNamespace = iq.childElementNamespace;
this.childElementQName = iq.childElementQName;
}
protected IQ(String childElementName) {
@ -65,6 +69,11 @@ public abstract class IQ extends Stanza {
protected IQ(String childElementName, String childElementNamespace) {
this.childElementName = childElementName;
this.childElementNamespace = childElementNamespace;
if (childElementName == null) {
childElementQName = null;
} else {
childElementQName = new QName(childElementNamespace, childElementName);
}
}
/**
@ -115,6 +124,10 @@ public abstract class IQ extends Stanza {
return !isRequestIQ();
}
public final QName getChildElementQName() {
return childElementQName;
}
public final String getChildElementName() {
return childElementName;
}

View file

@ -24,6 +24,8 @@ import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.jivesoftware.smack.util.EqualsUtil;
import org.jivesoftware.smack.util.HashCode;
import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.TypedCloneable;
import org.jivesoftware.smack.util.XmlStringBuilder;
@ -561,32 +563,22 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
return subject;
}
private final HashCode.Cache hashCodeCache = new HashCode.Cache();
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
if (language != null) {
result = prime * result + this.language.hashCode();
}
result = prime * result + this.subject.hashCode();
return result;
return hashCodeCache.getHashCode(c ->
c.append(language)
.append(subject)
);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Subject other = (Subject) obj;
// simplified comparison because language and subject are always set
return this.language.equals(other.language) && this.subject.equals(other.subject);
return EqualsUtil.equals(this, obj, (e, o) ->
e.append(language, o.language)
.append(subject, o.subject)
);
}
@Override
@ -670,31 +662,22 @@ public final class Message extends Stanza implements TypedCloneable<Message> {
return message;
}
private final HashCode.Cache hashCodeCache = new HashCode.Cache();
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
if (language != null) {
result = prime * result + this.language.hashCode();
}
result = prime * result + this.message.hashCode();
return result;
return hashCodeCache.getHashCode(c ->
c.append(language)
.append(message)
);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Body other = (Body) obj;
// simplified comparison because language and message are always set
return Objects.equals(this.language, other.language) && this.message.equals(other.message);
return EqualsUtil.equals(this, obj, (e, o) ->
e.append(language, o.language)
.append(message, o.message)
);
}
@Override

View file

@ -150,7 +150,7 @@ public interface Packet extends TopLevelStreamElement {
/**
* Returns the first extension of this stanza that has the given namespace.
* <p>
* When possible, use {@link #getExtension(String,String)} instead.
* When possible, use {@link #getExtension(String, String)} instead.
* </p>
*
* @param namespace the namespace of the extension that is desired.

View file

@ -68,12 +68,12 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
private String status = null;
/**
* The priority of the presence. The magic value {@link Integer#MIN_VALUE} is used to indicate that the original
* The priority of the presence. It is <code>null</code> to indicate that the original
* presence stanza did not had an explicit priority set. In which case the priority defaults to 0.
*
* @see <a href="https://tools.ietf.org/html/rfc6121#section-4.7.2.3">RFC 6121 § 4.7.2.3.</a>
*/
private int priority = Integer.MIN_VALUE;
private Byte priority;
private Mode mode = null;
@ -203,13 +203,13 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
}
/**
* Returns the priority of the presence, or Integer.MIN_VALUE if no priority has been set.
* Returns the priority of the presence.
*
* @return the priority.
* @see <a href="https://tools.ietf.org/html/rfc6121#section-4.7.2.3">RFC 6121 § 4.7.2.3. Priority Element</a>
*/
public int getPriority() {
if (priority == Integer.MIN_VALUE) {
if (priority == null) {
return 0;
}
return priority;
@ -227,6 +227,10 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
throw new IllegalArgumentException("Priority value " + priority +
" is not valid. Valid range is -128 through 127.");
}
setPriority((byte) priority);
}
public void setPriority(byte priority) {
this.priority = priority;
}
@ -264,7 +268,7 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
if (!StringUtils.isNullOrEmpty(status)) {
sb.append("status=").append(status).append(',');
}
if (priority != Integer.MIN_VALUE) {
if (priority != null) {
sb.append("prio=").append(priority).append(',');
}
sb.append(']');
@ -282,9 +286,7 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
buf.rightAngleBracket();
buf.optElement("status", status);
if (priority != Integer.MIN_VALUE) {
buf.element("priority", Integer.toString(priority));
}
buf.optElement("priority", priority);
if (mode != null && mode != Mode.available) {
buf.element("show", mode);
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus.
* Copyright 2015-2019 Florian Schmaus.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,13 +21,13 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import org.jivesoftware.smack.util.MultiMap;
import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jxmpp.util.XmppStringUtils;
/**
* An {@link ExtensionElement} modeling the often required and used XML features when using XMPP. It
* is therefore suitable for most use cases. Use
@ -47,7 +47,7 @@ public final class StandardExtensionElement implements ExtensionElement {
private final String namespace;
private final Map<String, String> attributes;
private final String text;
private final MultiMap<String, StandardExtensionElement> elements;
private final MultiMap<QName, StandardExtensionElement> elements;
private XmlStringBuilder xmlCache;
@ -65,7 +65,7 @@ public final class StandardExtensionElement implements ExtensionElement {
}
private StandardExtensionElement(String name, String namespace, Map<String, String> attributes, String text,
MultiMap<String, StandardExtensionElement> elements) {
MultiMap<QName, StandardExtensionElement> elements) {
this.name = StringUtils.requireNotNullNorEmpty(name, "Name must not be null nor empty");
this.namespace = StringUtils.requireNotNullNorEmpty(namespace, "Namespace must not be null nor empty");
if (attributes == null) {
@ -100,7 +100,7 @@ public final class StandardExtensionElement implements ExtensionElement {
if (elements == null) {
return null;
}
String key = XmppStringUtils.generateKey(element, namespace);
QName key = new QName(namespace, element);
return elements.getFirst(key);
}
@ -112,7 +112,7 @@ public final class StandardExtensionElement implements ExtensionElement {
if (elements == null) {
return null;
}
String key = XmppStringUtils.generateKey(element, namespace);
QName key = new QName(namespace, element);
return elements.getAll(key);
}
@ -145,7 +145,7 @@ public final class StandardExtensionElement implements ExtensionElement {
xml.optEscape(text);
if (elements != null) {
for (Map.Entry<String, StandardExtensionElement> entry : elements.entrySet()) {
for (Map.Entry<QName, StandardExtensionElement> entry : elements.entrySet()) {
xml.append(entry.getValue().toXML(getNamespace()));
}
}
@ -165,7 +165,7 @@ public final class StandardExtensionElement implements ExtensionElement {
private Map<String, String> attributes;
private String text;
private MultiMap<String, StandardExtensionElement> elements;
private MultiMap<QName, StandardExtensionElement> elements;
private Builder(String name, String namespace) {
this.name = name;
@ -200,7 +200,8 @@ public final class StandardExtensionElement implements ExtensionElement {
if (elements == null) {
elements = new MultiMap<>();
}
String key = XmppStringUtils.generateKey(element.getElementName(), element.getNamespace());
QName key = element.getQName();
elements.put(key, element);
return this;
}

View file

@ -23,6 +23,8 @@ import java.util.Collection;
import java.util.List;
import java.util.Locale;
import javax.xml.namespace.QName;
import org.jivesoftware.smack.packet.id.StanzaIdUtil;
import org.jivesoftware.smack.util.MultiMap;
import org.jivesoftware.smack.util.PacketUtil;
@ -31,7 +33,6 @@ import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
import org.jxmpp.util.XmppStringUtils;
/**
* Base class for XMPP Stanzas, which are called Stanza in older versions of Smack (i.e. &lt; 4.1).
@ -56,7 +57,7 @@ public abstract class Stanza implements TopLevelStreamElement {
protected static final String DEFAULT_LANGUAGE =
java.util.Locale.getDefault().getLanguage().toLowerCase(Locale.US);
private final MultiMap<String, ExtensionElement> packetExtensions = new MultiMap<>();
private final MultiMap<QName, ExtensionElement> extensionElements = new MultiMap<>();
private String id = null;
private Jid to;
@ -306,9 +307,9 @@ public abstract class Stanza implements TopLevelStreamElement {
* @return a list of all extension elements of this stanza.
*/
public List<ExtensionElement> getExtensions() {
synchronized (packetExtensions) {
synchronized (extensionElements) {
// No need to create a new list, values() will already create a new one for us
return packetExtensions.values();
return extensionElements.values();
}
}
@ -326,14 +327,14 @@ public abstract class Stanza implements TopLevelStreamElement {
public List<ExtensionElement> getExtensions(String elementName, String namespace) {
requireNotNullNorEmpty(elementName, "elementName must not be null nor empty");
requireNotNullNorEmpty(namespace, "namespace must not be null nor empty");
String key = XmppStringUtils.generateKey(elementName, namespace);
return packetExtensions.getAll(key);
QName key = new QName(namespace, elementName);
return extensionElements.getAll(key);
}
/**
* Returns the first extension of this stanza that has the given namespace.
* <p>
* When possible, use {@link #getExtension(String,String)} instead.
* When possible, use {@link #getExtension(String, String)} instead.
* </p>
*
* @param namespace the namespace of the extension that is desired.
@ -359,10 +360,10 @@ public abstract class Stanza implements TopLevelStreamElement {
if (namespace == null) {
return null;
}
String key = XmppStringUtils.generateKey(elementName, namespace);
QName key = new QName(namespace, elementName);
ExtensionElement packetExtension;
synchronized (packetExtensions) {
packetExtension = packetExtensions.getFirst(key);
synchronized (extensionElements) {
packetExtension = extensionElements.getFirst(key);
}
if (packetExtension == null) {
return null;
@ -377,9 +378,9 @@ public abstract class Stanza implements TopLevelStreamElement {
*/
public void addExtension(ExtensionElement extension) {
if (extension == null) return;
String key = XmppStringUtils.generateKey(extension.getElementName(), extension.getNamespace());
synchronized (packetExtensions) {
packetExtensions.put(key, extension);
QName key = extension.getQName();
synchronized (extensionElements) {
extensionElements.put(key, extension);
}
}
@ -393,7 +394,7 @@ public abstract class Stanza implements TopLevelStreamElement {
*/
public ExtensionElement overrideExtension(ExtensionElement extension) {
if (extension == null) return null;
synchronized (packetExtensions) {
synchronized (extensionElements) {
// Note that we need to use removeExtension(String, String) here. If would use
// removeExtension(ExtensionElement) then we would remove based on the equality of ExtensionElement, which
// is not what we want in this case.
@ -429,9 +430,9 @@ public abstract class Stanza implements TopLevelStreamElement {
if (elementName == null) {
return hasExtension(namespace);
}
String key = XmppStringUtils.generateKey(elementName, namespace);
synchronized (packetExtensions) {
return packetExtensions.containsKey(key);
QName key = new QName(namespace, elementName);
synchronized (extensionElements) {
return extensionElements.containsKey(key);
}
}
@ -442,8 +443,8 @@ public abstract class Stanza implements TopLevelStreamElement {
* @return true if a stanza extension exists, false otherwise.
*/
public boolean hasExtension(String namespace) {
synchronized (packetExtensions) {
for (ExtensionElement packetExtension : packetExtensions.values()) {
synchronized (extensionElements) {
for (ExtensionElement packetExtension : extensionElements.values()) {
if (packetExtension.getNamespace().equals(namespace)) {
return true;
}
@ -460,9 +461,9 @@ public abstract class Stanza implements TopLevelStreamElement {
* @return the removed stanza extension or null.
*/
public ExtensionElement removeExtension(String elementName, String namespace) {
String key = XmppStringUtils.generateKey(elementName, namespace);
synchronized (packetExtensions) {
return packetExtensions.remove(key);
QName key = new QName(namespace, elementName);
synchronized (extensionElements) {
return extensionElements.remove(key);
}
}
@ -473,9 +474,9 @@ public abstract class Stanza implements TopLevelStreamElement {
* @return the removed stanza extension or null.
*/
public ExtensionElement removeExtension(ExtensionElement extension) {
String key = XmppStringUtils.generateKey(extension.getElementName(), extension.getNamespace());
synchronized (packetExtensions) {
List<ExtensionElement> list = packetExtensions.getAll(key);
QName key = extension.getQName();
synchronized (extensionElements) {
List<ExtensionElement> list = extensionElements.getAll(key);
boolean removed = list.remove(extension);
if (removed) {
return extension;

View file

@ -19,7 +19,7 @@ package org.jivesoftware.smack.packet;
import org.jivesoftware.smack.util.ParserUtils;
import org.jivesoftware.smack.util.StringUtils;
import org.xmlpull.v1.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParser;
public class XmlEnvironment {

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015 Florian Schmaus.
* Copyright 2015-2019 Florian Schmaus.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -26,8 +26,8 @@ import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smack.util.ParserUtils;
import org.jivesoftware.smack.util.StringUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
/**
* The parser for {@link StandardExtensionElement}s.
@ -47,7 +47,7 @@ public class StandardExtensionElementProvider extends ExtensionElementProvider<S
String name = parser.getName();
String namespace = parser.getNamespace();
StandardExtensionElement.Builder builder = StandardExtensionElement.builder(name, namespace);
final int namespaceCount = parser.getNamespaceCount(initialDepth);
final int namespaceCount = parser.getNamespaceCount();
final int attributeCount = parser.getAttributeCount();
final Map<String, String> attributes = new LinkedHashMap<>(namespaceCount + attributeCount);
for (int i = 0; i < namespaceCount; i++) {
@ -77,19 +77,22 @@ public class StandardExtensionElementProvider extends ExtensionElementProvider<S
builder.addAttributes(attributes);
outerloop: while (true) {
int event = parser.next();
XmlPullParser.Event event = parser.next();
switch (event) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
builder.addElement(parse(parser, parser.getDepth(), xmlEnvironment));
break;
case XmlPullParser.TEXT:
case TEXT_CHARACTERS:
builder.setText(parser.getText());
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
if (initialDepth == parser.getDepth()) {
break outerloop;
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}

View file

@ -20,12 +20,12 @@ import java.io.IOException;
import org.jivesoftware.smack.packet.Bind;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jxmpp.jid.EntityFullJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Resourcepart;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
public class BindIQProvider extends IQProvider<Bind> {
@ -34,9 +34,9 @@ public class BindIQProvider extends IQProvider<Bind> {
String name;
Bind bind = null;
outerloop: while (true) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
switch (eventType) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
name = parser.getName();
switch (name) {
case "resource":
@ -49,11 +49,14 @@ public class BindIQProvider extends IQProvider<Bind> {
break;
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}
return bind;

View file

@ -24,8 +24,8 @@ import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.util.ParserUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
public class BodyElementProvider extends ExtensionElementProvider<Message.Body> {

View file

@ -27,8 +27,8 @@ import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.parsing.SmackParsingException;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
/**
*
@ -97,14 +97,14 @@ public abstract class EmbeddedExtensionProvider<PE extends ExtensionElement> ext
}
List<ExtensionElement> extensions = new ArrayList<>();
int event;
XmlPullParser.Event event;
do {
event = parser.next();
if (event == XmlPullParser.START_TAG)
if (event == XmlPullParser.Event.START_ELEMENT)
PacketParserUtils.addExtensionElement(extensions, parser, xmlEnvironment);
}
while (!(event == XmlPullParser.END_TAG && parser.getDepth() == initialDepth));
while (!(event == XmlPullParser.Event.END_ELEMENT && parser.getDepth() == initialDepth));
return createReturnExtension(name, namespace, attMap, extensions);
}

View file

@ -24,8 +24,8 @@ import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.util.ParserUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
public class IntrospectionProvider{
@ -81,9 +81,9 @@ public class IntrospectionProvider{
ParserUtils.assertAtStartTag(parser);
Object object = objectClass.getConstructor().newInstance();
outerloop: while (true) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
switch (eventType) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
String name = parser.getName();
String stringValue = parser.nextText();
Class<?> propertyType = object.getClass().getMethod(
@ -97,11 +97,14 @@ public class IntrospectionProvider{
propertyType).invoke(object, value);
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}
ParserUtils.assertAtEndTag(parser);

View file

@ -26,8 +26,8 @@ import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.parsing.SmackParsingException;
import org.jivesoftware.smack.util.ParserUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
/**
* Smack provider are the parsers used to deserialize raw XMPP into the according Java {@link Element}s.

View file

@ -26,9 +26,8 @@ import java.util.logging.Logger;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.IQ;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.xml.XmlPullParser;
/**
* Loads the {@link IQProvider} and {@link ExtensionElementProvider} information from a standard provider file in preparation
@ -54,12 +53,10 @@ public class ProviderFileLoader implements ProviderLoader {
public ProviderFileLoader(InputStream providerStream, ClassLoader classLoader) {
// Load processing providers.
try (InputStream is = providerStream) {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(is, "UTF-8");
int eventType = parser.getEventType();
XmlPullParser parser = PacketParserUtils.getParserFor(is);
XmlPullParser.Event eventType = parser.getEventType();
do {
if (eventType == XmlPullParser.START_TAG) {
if (eventType == XmlPullParser.Event.START_ELEMENT) {
final String typeName = parser.getName();
try {
@ -134,7 +131,7 @@ public class ProviderFileLoader implements ProviderLoader {
}
eventType = parser.next();
}
while (eventType != XmlPullParser.END_DOCUMENT);
while (eventType != XmlPullParser.Event.END_DOCUMENT);
}
catch (Exception e) {
LOGGER.log(Level.SEVERE, "Unknown error occurred while parsing provider file", e);

View file

@ -22,6 +22,8 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.namespace.QName;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.IQ;
@ -29,8 +31,6 @@ import org.jivesoftware.smack.packet.Nonza;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.XmppElementUtil;
import org.jxmpp.util.XmppStringUtils;
/**
* Manages providers for parsing custom XML sub-documents of XMPP packets. Two types of
* providers exist:<ul>
@ -112,10 +112,10 @@ import org.jxmpp.util.XmppStringUtils;
*/
public final class ProviderManager {
private static final Map<String, ExtensionElementProvider<ExtensionElement>> extensionProviders = new ConcurrentHashMap<String, ExtensionElementProvider<ExtensionElement>>();
private static final Map<String, IQProvider<IQ>> iqProviders = new ConcurrentHashMap<String, IQProvider<IQ>>();
private static final Map<String, ExtensionElementProvider<ExtensionElement>> streamFeatureProviders = new ConcurrentHashMap<String, ExtensionElementProvider<ExtensionElement>>();
private static final Map<String, NonzaProvider<? extends Nonza>> nonzaProviders = new ConcurrentHashMap<>();
private static final Map<QName, ExtensionElementProvider<ExtensionElement>> extensionProviders = new ConcurrentHashMap<>();
private static final Map<QName, IQProvider<IQ>> iqProviders = new ConcurrentHashMap<>();
private static final Map<QName, ExtensionElementProvider<ExtensionElement>> streamFeatureProviders = new ConcurrentHashMap<>();
private static final Map<QName, NonzaProvider<? extends Nonza>> nonzaProviders = new ConcurrentHashMap<>();
static {
// Ensure that Smack is initialized by calling getVersion, so that user
@ -168,7 +168,7 @@ public final class ProviderManager {
* @return the IQ provider.
*/
public static IQProvider<IQ> getIQProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace);
QName key = getQName(elementName, namespace);
return iqProviders.get(key);
}
@ -199,7 +199,7 @@ public final class ProviderManager {
Object provider) {
validate(elementName, namespace);
// First remove existing providers
String key = removeIQProvider(elementName, namespace);
QName key = removeIQProvider(elementName, namespace);
if (provider instanceof IQProvider) {
iqProviders.put(key, (IQProvider<IQ>) provider);
} else {
@ -214,10 +214,10 @@ public final class ProviderManager {
*
* @param elementName the XML element name.
* @param namespace the XML namespace.
* @return the key of the removed IQ Provider
* @return the QName of the removed provider
*/
public static String removeIQProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace);
public static QName removeIQProvider(String elementName, String namespace) {
QName key = getQName(elementName, namespace);
iqProviders.remove(key);
return key;
}
@ -242,7 +242,7 @@ public final class ProviderManager {
* @return the extension provider.
*/
public static ExtensionElementProvider<ExtensionElement> getExtensionProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace);
QName key = getQName(elementName, namespace);
return extensionProviders.get(key);
}
@ -260,7 +260,7 @@ public final class ProviderManager {
Object provider) {
validate(elementName, namespace);
// First remove existing providers
String key = removeExtensionProvider(elementName, namespace);
QName key = removeExtensionProvider(elementName, namespace);
if (provider instanceof ExtensionElementProvider) {
extensionProviders.put(key, (ExtensionElementProvider<ExtensionElement>) provider);
} else {
@ -275,10 +275,10 @@ public final class ProviderManager {
*
* @param elementName the XML element name.
* @param namespace the XML namespace.
* @return the key of the removed stanza extension provider
* @return the QName of the removed stanza extension provider
*/
public static String removeExtensionProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace);
public static QName removeExtensionProvider(String elementName, String namespace) {
QName key = getQName(elementName, namespace);
extensionProviders.remove(key);
return key;
}
@ -297,48 +297,48 @@ public final class ProviderManager {
}
public static ExtensionElementProvider<ExtensionElement> getStreamFeatureProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace);
QName key = getQName(elementName, namespace);
return streamFeatureProviders.get(key);
}
public static void addStreamFeatureProvider(String elementName, String namespace, ExtensionElementProvider<ExtensionElement> provider) {
validate(elementName, namespace);
String key = getKey(elementName, namespace);
QName key = getQName(elementName, namespace);
streamFeatureProviders.put(key, provider);
}
public static void removeStreamFeatureProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace);
QName key = getQName(elementName, namespace);
streamFeatureProviders.remove(key);
}
public static NonzaProvider<? extends Nonza> getNonzaProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace);
QName key = getQName(elementName, namespace);
return getNonzaProvider(key);
}
public static NonzaProvider<? extends Nonza> getNonzaProvider(String key) {
public static NonzaProvider<? extends Nonza> getNonzaProvider(QName key) {
return nonzaProviders.get(key);
}
public static void addNonzaProvider(NonzaProvider<? extends Nonza> nonzaProvider) {
Class<? extends Nonza> nonzaClass = nonzaProvider.getElementClass();
String key = XmppElementUtil.getKeyFor(nonzaClass);
QName key = XmppElementUtil.getQNameFor(nonzaClass);
nonzaProviders.put(key, nonzaProvider);
}
public static void removeNonzaProvider(Class<? extends Nonza> nonzaClass) {
String key = XmppElementUtil.getKeyFor(nonzaClass);
QName key = XmppElementUtil.getQNameFor(nonzaClass);
nonzaProviders.remove(key);
}
public static void removeNonzaProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace);
QName key = getQName(elementName, namespace);
nonzaProviders.remove(key);
}
private static String getKey(String elementName, String namespace) {
return XmppStringUtils.generateKey(elementName, namespace);
private static QName getQName(String elementName, String namespace) {
return new QName(namespace, elementName);
}
private static void validate(String elementName, String namespace) {

View file

@ -19,7 +19,7 @@ package org.jivesoftware.smack.provider;
import org.jivesoftware.smack.packet.TlsProceed;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.xmlpull.v1.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParser;
public final class TlsFailureProvider extends NonzaProvider<TlsProceed> {

View file

@ -19,7 +19,7 @@ package org.jivesoftware.smack.provider;
import org.jivesoftware.smack.packet.TlsFailure;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.xmlpull.v1.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParser;
public final class TlsProceedProvider extends NonzaProvider<TlsFailure> {

View file

@ -22,8 +22,7 @@ import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import org.jivesoftware.smack.util.StringUtils;
import java.nio.charset.StandardCharsets;
/**
* Socket factory for socks4 proxy.
@ -73,7 +72,6 @@ public class Socks4ProxySocketConnection implements ProxySocketConnection {
of all zero bits.
*/
index = 0;
buf[index++] = 4;
buf[index++] = 1;
@ -87,7 +85,7 @@ public class Socks4ProxySocketConnection implements ProxySocketConnection {
}
if (user != null) {
byte[] userBytes = user.getBytes(StringUtils.UTF8);
byte[] userBytes = user.getBytes(StandardCharsets.UTF_8);
System.arraycopy(userBytes, 0, buf, index, user.length());
index += user.length();
}

View file

@ -21,10 +21,10 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.logging.Logger;
import org.jivesoftware.smack.util.CloseableUtil;
import org.jivesoftware.smack.util.StringUtils;
/**
* Socket factory for Socks5 proxy.
@ -133,11 +133,11 @@ public class Socks5ProxySocketConnection implements ProxySocketConnection {
index = 0;
buf[index++] = 1;
buf[index++] = (byte) user.length();
byte[] userBytes = user.getBytes(StringUtils.UTF8);
byte[] userBytes = user.getBytes(StandardCharsets.UTF_8);
System.arraycopy(userBytes, 0, buf, index,
user.length());
index += user.length();
byte[] passwordBytes = passwd.getBytes(StringUtils.UTF8);
byte[] passwordBytes = passwd.getBytes(StandardCharsets.UTF_8);
buf[index++] = (byte) passwordBytes.length;
System.arraycopy(passwordBytes, 0, buf, index,
passwd.length());
@ -204,7 +204,7 @@ public class Socks5ProxySocketConnection implements ProxySocketConnection {
buf[index++] = 1; // CONNECT
buf[index++] = 0;
byte[] hostb = host.getBytes(StringUtils.UTF8);
byte[] hostb = host.getBytes(StandardCharsets.UTF_8);
int len = hostb.length;
buf[index++] = 3; // DOMAINNAME
buf[index++] = (byte) len;

View file

@ -31,13 +31,13 @@ public class SASLErrorException extends XMPPException {
private final SASLFailure saslFailure;
private final String mechanism;
private final Map<String,String> texts;
private final Map<String, String> texts;
public SASLErrorException(String mechanism, SASLFailure saslFailure) {
this(mechanism, saslFailure, new HashMap<String, String>());
}
public SASLErrorException(String mechanism, SASLFailure saslFailure, Map<String,String> texts) {
public SASLErrorException(String mechanism, SASLFailure saslFailure, Map<String, String> texts) {
super("SASLError using " + mechanism + ": " + saslFailure.getSASLErrorString());
this.mechanism = mechanism;
this.saslFailure = saslFailure;
@ -52,7 +52,7 @@ public class SASLErrorException extends XMPPException {
return mechanism;
}
public Map<String,String> getTexts() {
public Map<String, String> getTexts() {
return texts;
}
}

View file

@ -16,7 +16,7 @@
*/
package org.jivesoftware.smack.sasl.core;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.SecureRandom;
import java.util.Collections;
@ -114,14 +114,8 @@ public abstract class ScramMechanism extends SASLMechanism {
@Override
protected byte[] evaluateChallenge(byte[] challenge) throws SmackSaslException {
String challengeString;
try {
// TODO: Where is it specified that this is an UTF-8 encoded string?
challengeString = new String(challenge, StringUtils.UTF8);
}
catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}
// TODO: Where is it specified that this is an UTF-8 encoded string?
String challengeString = new String(challenge, StandardCharsets.UTF_8);
switch (state) {
case AUTH_TEXT_SENT:
@ -386,14 +380,9 @@ public abstract class ScramMechanism extends SASLMechanism {
* @throws SmackSaslException if a SASL related error occurs.
*/
private byte[] hi(String normalizedPassword, byte[] salt, int iterations) throws SmackSaslException {
byte[] key;
try {
// According to RFC 5802 § 2.2, the resulting string of the normalization is also in UTF-8.
key = normalizedPassword.getBytes(StringUtils.UTF8);
}
catch (UnsupportedEncodingException e) {
throw new AssertionError();
}
// According to RFC 5802 § 2.2, the resulting string of the normalization is also in UTF-8.
byte[] key = normalizedPassword.getBytes(StandardCharsets.UTF_8);
// U1 := HMAC(str, salt + INT(1))
byte[] u = hmac(key, ByteUtils.concat(salt, ONE));
byte[] res = u.clone();

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2014-2018 Florian Schmaus
* Copyright 2014-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -110,7 +110,7 @@ public class ArrayBlockingQueueWithShutdown<E> extends AbstractQueue<E> implemen
private void checkNotShutdown() throws InterruptedException {
if (isShutdown) {
throw new InterruptedException();
throw new InterruptedException("Queue was already shut down");
}
}

View file

@ -16,7 +16,7 @@
*/
package org.jivesoftware.smack.util;
public interface CallbackRecipient<V,E> {
public interface CallbackRecipient<V, E> {
CallbackRecipient<V, E> onSuccess(SuccessCallback<V> successCallback);

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2018 Florian Schmaus
* Copyright 2018-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,6 +23,10 @@ import java.util.logging.Logger;
public class CloseableUtil {
public static void maybeClose(Closeable closable) {
maybeClose(closable, null);
}
public static void maybeClose(Closeable closable, Logger logger) {
if (closable == null) {
return;
@ -31,7 +35,9 @@ public class CloseableUtil {
try {
closable.close();
} catch (IOException e) {
logger.log(Level.WARNING, "Could not close " + closable, e);
if (logger != null) {
logger.log(Level.WARNING, "Could not close " + closable, e);
}
}
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015-2018 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -49,4 +49,10 @@ public class CollectionUtil {
public interface Predicate<T> {
boolean test(T t);
}
public static <T> ArrayList<T> newListWith(Collection<? extends T> collection) {
ArrayList<T> arrayList = new ArrayList<>(collection.size());
arrayList.addAll(collection);
return arrayList;
}
}

View file

@ -0,0 +1,243 @@
/**
*
* Copyright 2019 Florian Schmaus.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smack.util;
public final class EqualsUtil {
private EqualsUtil() {
}
public static <T> boolean equals(T thisObject, Object other, EqualsComperator<T> equalsComperator) {
if (other == null) {
return false;
}
if (thisObject == other) {
return true;
}
@SuppressWarnings("unchecked")
Class<T> thisObjectClass = (Class<T>) thisObject.getClass();
if (thisObjectClass != other.getClass()) {
return false;
}
EqualsUtil.Builder equalsBuilder = new EqualsUtil.Builder();
equalsComperator.compare(equalsBuilder, thisObjectClass.cast(other));
return equalsBuilder.isEquals;
}
@FunctionalInterface
public interface EqualsComperator<T> {
void compare(EqualsUtil.Builder equalsBuilder, T other);
}
public static final class Builder {
private boolean isEquals = true;
private Builder() {
}
private void nullSafeCompare(Object left, Object right, Runnable runnable) {
if (!isEquals) {
return;
}
if (left == right) {
return;
}
if (left == null || right == null) {
isEquals = false;
return;
}
runnable.run();
}
public <O> Builder append(O left, O right) {
if (!isEquals) {
return this;
}
if (left == right) {
return this;
}
if (left == null || right == null) {
isEquals = false;
return this;
}
isEquals = left.equals(right);
return this;
}
public Builder append(boolean left, boolean right) {
if (!isEquals) {
return this;
}
isEquals = left == right;
return this;
}
public Builder append(boolean[] left, boolean[] right) {
nullSafeCompare(left, right, () -> {
if (left.length != right.length) {
isEquals = false;
return;
}
for (int i = 0; i < left.length && isEquals; i++) {
append(left[i], right[i]);
}
});
return this;
}
public Builder append(byte left, byte right) {
if (!isEquals) {
return this;
}
isEquals = left == right;
return this;
}
public Builder append(byte[] left, byte[] right) {
nullSafeCompare(left, right, () -> {
if (left.length != right.length) {
isEquals = false;
return;
}
for (int i = 0; i < left.length && isEquals; i++) {
append(left[i], right[i]);
}
});
return this;
}
public Builder append(char left, char right) {
if (!isEquals) {
return this;
}
isEquals = left == right;
return this;
}
public Builder append(char[] left, char[] right) {
nullSafeCompare(left, right, () -> {
if (left.length != right.length) {
isEquals = false;
return;
}
for (int i = 0; i < left.length && isEquals; i++) {
append(left[i], right[i]);
}
});
return this;
}
public Builder append(double left, double right) {
if (!isEquals) {
return this;
}
return append(Double.doubleToLongBits(left), Double.doubleToLongBits(right));
}
public Builder append(double[] left, double[] right) {
nullSafeCompare(left, right, () -> {
if (left.length != right.length) {
isEquals = false;
return;
}
for (int i = 0; i < left.length && isEquals; i++) {
append(left[i], right[i]);
}
});
return this;
}
public Builder append(float left, float right) {
if (!isEquals) {
return this;
}
return append(Float.floatToIntBits(left), Float.floatToIntBits(right));
}
public Builder append(float[] left, float[] right) {
nullSafeCompare(left, right, () -> {
if (left.length != right.length) {
isEquals = false;
return;
}
for (int i = 0; i < left.length && isEquals; i++) {
append(left[i], right[i]);
}
});
return this;
}
public Builder append(int left, int right) {
if (!isEquals) {
return this;
}
isEquals = left == right;
return this;
}
public Builder append(int[] left, int[] right) {
nullSafeCompare(left, right, () -> {
if (left.length != right.length) {
isEquals = false;
return;
}
for (int i = 0; i < left.length && isEquals; i++) {
append(left[i], right[i]);
}
});
return this;
}
public Builder append(long left, long right) {
if (!isEquals) {
return this;
}
isEquals = left == right;
return this;
}
public Builder append(long[] left, long[] right) {
nullSafeCompare(left, right, () -> {
if (left.length != right.length) {
isEquals = false;
return;
}
for (int i = 0; i < left.length && isEquals; i++) {
append(left[i], right[i]);
}
});
return this;
}
}
}

View file

@ -34,7 +34,7 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class EventManger<K, R, E extends Exception> {
private final Map<K,Reference<R>> events = new ConcurrentHashMap<>();
private final Map<K, Reference<R>> events = new ConcurrentHashMap<>();
/**
* Perform an action and wait for an event.

View file

@ -30,6 +30,7 @@ import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@ -90,7 +91,7 @@ public final class FileUtils {
public static boolean addLines(String uriString, Set<String> set) throws MalformedURLException, IOException {
URI uri = URI.create(uriString);
InputStream is = getStreamForUri(uri, null);
InputStreamReader sr = new InputStreamReader(is, StringUtils.UTF8);
InputStreamReader sr = new InputStreamReader(is, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(sr);
try {
String line;

View file

@ -0,0 +1,211 @@
/**
*
* Copyright 2019 Florian Schmaus.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smack.util;
public class HashCode {
private static final int MULTIPLIER_VALUE = 37;
public static class Cache {
private boolean calculated;
private int hashcode;
public int getHashCode(Calculator hashCodeCalculator) {
if (calculated) {
return hashcode;
}
HashCode.Builder hashCodeBuilder = new HashCode.Builder();
hashCodeCalculator.calculateHash(hashCodeBuilder);
calculated = true;
hashcode = hashCodeBuilder.hashcode;
return hashcode;
}
}
@FunctionalInterface
public interface Calculator {
void calculateHash(HashCode.Builder hashCodeBuilder);
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private int hashcode = 17;
private void applyHash() {
applyHash(0);
}
private void applyHash(int hash) {
hashcode = MULTIPLIER_VALUE * hashcode + hash;
}
public Builder append(Object object) {
if (object == null) {
applyHash();
return this;
}
if (object.getClass().isArray()) {
if (object instanceof int[]) {
append((int[]) object);
} else if (object instanceof long[]) {
append((long[]) object);
} else if (object instanceof boolean[]) {
append((boolean[]) object);
} else if (object instanceof double[]) {
append((double[]) object);
} else if (object instanceof float[]) {
append((float[]) object);
} else if (object instanceof short[]) {
append((short[]) object);
} else if (object instanceof char[]) {
append((char[]) object);
} else if (object instanceof byte[]) {
append((byte[]) object);
} else {
append((Object[]) object);
}
}
applyHash(object.hashCode());
return this;
}
public Builder append(boolean value) {
applyHash(value ? 0 : 1);
return this;
}
public Builder append(boolean[] array) {
if (array == null) {
applyHash();
return this;
}
for (boolean bool : array) {
append(bool);
}
return this;
}
public Builder append(byte value) {
applyHash(value);
return this;
}
public Builder append(byte[] array) {
if (array == null) {
applyHash();
return this;
}
for (byte b : array) {
append(b);
}
return this;
}
public Builder append(char value) {
applyHash(value);
return this;
}
public Builder append(char[] array) {
if (array == null) {
applyHash();
return this;
}
for (char c : array) {
append(c);
}
return this;
}
public Builder append(double value) {
return append(Double.doubleToLongBits(value));
}
public Builder append(double[] array) {
if (array == null) {
applyHash();
return this;
}
for (double d : array) {
append(d);
}
return this;
}
public Builder append(float value) {
return append(Float.floatToIntBits(value));
}
public Builder append(float[] array) {
if (array == null) {
applyHash();
return this;
}
for (float f : array) {
append(f);
}
return this;
}
public Builder append(long value) {
applyHash((int) (value ^ (value >>> 32)));
return this;
}
public Builder append(long[] array) {
if (array == null) {
applyHash();
return this;
}
for (long l : array) {
append(l);
}
return this;
}
public Builder append(Object[] array) {
if (array == null) {
applyHash();
return this;
}
for (Object element : array) {
append(element);
}
return this;
}
public int build() {
return hashcode;
}
}
}

View file

@ -0,0 +1,213 @@
/**
*
* Copyright 2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smack.util;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.minidns.dnslabel.DnsLabel;
import org.minidns.dnsname.DnsName;
import org.minidns.dnsname.InvalidDnsNameException;
import org.minidns.util.InetAddressUtil;
/**
* An internet address, can be given as IP or as DNS name.
* <p>
* This type is meant for strings that hold an internet address. The original string used to construct this type is
* stored and returning in the {@link #toString()} method.
* </p>
*
* @since 4.4.0
*/
public abstract class InternetAddress implements CharSequence {
protected final String originalString;
protected InternetAddress(String originalString) {
this.originalString = Objects.requireNonNull(originalString, "The 'originalString' argument must not be null");
}
public abstract InetAddress asInetAddress() throws UnknownHostException;
@Override
public String toString() {
return originalString;
}
@Override
public int length() {
return originalString.length();
}
@Override
public char charAt(int index) {
return originalString.charAt(index);
}
@Override
public CharSequence subSequence(int start, int end) {
return originalString.subSequence(start, end);
}
public static InternetAddress from(String address) {
final InternetAddress internetAddress;
if (InetAddressUtil.isIpV4Address(address)) {
internetAddress = new InternetAddress.Ipv4(address);
} else if (InetAddressUtil.isIpV6Address(address)) {
internetAddress = new InternetAddress.Ipv6(address);
} else if (address.contains(".")) {
InternetAddress domainNameInternetAddress;
try {
DnsName dnsName = DnsName.from(address);
domainNameInternetAddress = new InternetAddress.DomainName(address, dnsName);
} catch (InvalidDnsNameException e) {
domainNameInternetAddress = new InternetAddress.InvalidDomainName(address, e);
}
internetAddress = domainNameInternetAddress;
} else {
DnsLabel dnsLabel = DnsLabel.from(address);
internetAddress = new InternetAddress.DomainNameLabel(address, dnsLabel);
}
return internetAddress;
}
public static InternetAddress from(InetAddress inetAddress) {
if (inetAddress instanceof Inet4Address) {
return new InternetAddress.Ipv4(inetAddress.getHostAddress(), (Inet4Address) inetAddress);
} else if (inetAddress instanceof Inet6Address) {
return new InternetAddress.Ipv6(inetAddress.getHostAddress(), (Inet6Address) inetAddress);
} else {
throw new IllegalArgumentException("Unknown type " + inetAddress.getClass() + " of " + inetAddress);
}
}
private static class InetAddressInternetAddress extends InternetAddress {
private final InetAddress inetAddress;
protected InetAddressInternetAddress(String originalString, InetAddress inetAddress) {
super(originalString);
this.inetAddress = inetAddress;
}
@Override
public InetAddress asInetAddress() {
return inetAddress;
}
}
public static final class Ipv4 extends InetAddressInternetAddress {
private final Inet4Address inet4Address;
private Ipv4(String originalString) {
this(originalString, InetAddressUtil.ipv4From(originalString));
}
private Ipv4(String originalString, Inet4Address inet4Address) {
super(originalString, inet4Address);
this.inet4Address = inet4Address;
}
public Inet4Address getInet4Address() {
return inet4Address;
}
}
public static final class Ipv6 extends InetAddressInternetAddress {
private Inet6Address inet6Address;
private Ipv6(String originalString) {
this(originalString, InetAddressUtil.ipv6From(originalString));
}
private Ipv6(String originalString, Inet6Address inet6Address) {
super(originalString, inet6Address);
this.inet6Address = inet6Address;
}
public Inet6Address getInet6Address() {
return inet6Address;
}
}
private static class NonNumericInternetAddress extends InternetAddress {
private boolean attemptedToResolveInetAddress;
private InetAddress inetAddress;
protected NonNumericInternetAddress(String originalString) {
super(originalString);
}
@Override
public InetAddress asInetAddress() throws UnknownHostException {
if (inetAddress != null || attemptedToResolveInetAddress) {
return inetAddress;
}
attemptedToResolveInetAddress = true;
inetAddress = InetAddress.getByName(originalString);
return inetAddress;
}
}
public static final class DomainName extends NonNumericInternetAddress {
private final DnsName dnsName;
private DomainName(String originalString, DnsName dnsName) {
super(originalString);
this.dnsName = dnsName;
}
public DnsName getDnsName() {
return dnsName;
}
}
public static final class DomainNameLabel extends NonNumericInternetAddress {
private final DnsLabel dnsLabel;
private DomainNameLabel(String originalString, DnsLabel dnsLabel) {
super(originalString);
this.dnsLabel = dnsLabel;
}
public DnsLabel getDnsLabel() {
return dnsLabel;
}
}
public static final class InvalidDomainName extends NonNumericInternetAddress {
private final InvalidDnsNameException invalidDnsNameException;
private InvalidDomainName(String originalString, InvalidDnsNameException invalidDnsNameException) {
super(originalString);
this.invalidDnsNameException = invalidDnsNameException;
}
public InvalidDnsNameException getInvalidDnsNameException() {
return invalidDnsNameException;
}
}
}

View file

@ -22,6 +22,7 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
@ -33,7 +34,7 @@ import java.util.Set;
* @param <K> the type of the keys the map uses.
* @param <V> the type of the values the map uses.
*/
public class MultiMap<K,V> {
public class MultiMap<K, V> {
/**
* The constant value {@value}.
@ -57,7 +58,11 @@ public class MultiMap<K,V> {
* @param size the initial capacity.
*/
public MultiMap(int size) {
map = new LinkedHashMap<>(size);
this(new LinkedHashMap<>(size));
}
private MultiMap(Map<K, List<V>> map) {
this.map = map;
}
public int size() {
@ -72,11 +77,11 @@ public class MultiMap<K,V> {
return map.isEmpty();
}
public boolean containsKey(Object key) {
public boolean containsKey(K key) {
return map.containsKey(key);
}
public boolean containsValue(Object value) {
public boolean containsValue(V value) {
for (List<V> list : map.values()) {
if (list.contains(value)) {
return true;
@ -91,7 +96,7 @@ public class MultiMap<K,V> {
* @param key
* @return the first value or null.
*/
public V getFirst(Object key) {
public V getFirst(K key) {
List<V> res = getAll(key);
if (res.isEmpty()) {
return null;
@ -109,7 +114,7 @@ public class MultiMap<K,V> {
* @param key
* @return all values for the given key.
*/
public List<V> getAll(Object key) {
public List<V> getAll(K key) {
List<V> res = map.get(key);
if (res == null) {
res = Collections.emptyList();
@ -138,7 +143,7 @@ public class MultiMap<K,V> {
* @param key
* @return the first value of the given key or null.
*/
public V remove(Object key) {
public V remove(K key) {
List<V> res = map.remove(key);
if (res == null) {
return null;
@ -157,7 +162,7 @@ public class MultiMap<K,V> {
* @param value
* @return true if the mapping was removed, false otherwise.
*/
public boolean removeOne(Object key, V value) {
public boolean removeOne(K key, V value) {
List<V> list = map.get(key);
if (list == null) {
return false;
@ -235,6 +240,18 @@ public class MultiMap<K,V> {
return entrySet;
}
public MultiMap<K, V> asUnmodifiableMultiMap() {
LinkedHashMap<K, List<V>> mapCopy = new LinkedHashMap<>(map.size());
for (Entry<K, List<V>> entry : map.entrySet()) {
K key = entry.getKey();
List<V> values = entry.getValue();
mapCopy.put(key, Collections.unmodifiableList(values));
}
return new MultiMap<K, V>(Collections.unmodifiableMap(mapCopy));
}
private static final class SimpleMapEntry<K, V> implements Map.Entry<K, V> {
private final K key;

View file

@ -1,6 +1,6 @@
/**
*
* Copyright © 2015 Florian Schmaus
* Copyright © 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -22,13 +22,41 @@ public class NumberUtil {
* Checks if the given long is within the range of an unsigned 32-bit integer, the XML type "xs:unsignedInt".
*
* @param value
* @deprecated use {@link #requireUInt32(long)} instead.
*/
@Deprecated
// TODO: Remove in Smack 4.5.
public static void checkIfInUInt32Range(long value) {
requireUInt32(value);
}
/**
* Checks if the given long is within the range of an unsigned 32-bit integer, the XML type "xs:unsignedInt".
*
* @param value
*/
public static long requireUInt32(long value) {
if (value < 0) {
throw new IllegalArgumentException("unsigned 32-bit integers can't be negative");
}
if (value > ((1L << 32) - 1)) {
throw new IllegalArgumentException("unsigned 32-bit integers can't be greater then 2^32 - 1");
}
return value;
}
/**
* Checks if the given int is within the range of an unsigned 16-bit integer, the XML type "xs:unsignedShort".
*
* @param value
*/
public static int requireUShort16(int value) {
if (value < 0) {
throw new IllegalArgumentException("unsigned 16-bit integers can't be negative");
}
if (value > ((1 << 16) - 1)) {
throw new IllegalArgumentException("unsigned 16-bit integers can't be greater than 2^16 - 1");
}
return value;
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2015-2018 Florian Schmaus
* Copyright 2015-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,9 +20,26 @@ import java.util.Collection;
public class Objects {
public static <T> T requireNonNull(T obj, String message) {
/**
* Checks that the specified object reference is not <code>null</code> and throws a customized
* {@link IllegalArgumentException} if it is.
* <p>
* Note that unlike <code>java.util.Objects</code>, this method throws an {@link IllegalArgumentException} instead
* of an {@link NullPointerException}.
* </p>
*
* @param <T> the type of the reference.
* @param obj the object reference to check for nullity.
* @param message detail message to be used in the event that a {@link IllegalArgumentException} is thrown.
* @return <code>obj</code> if not null.
* @throws IllegalArgumentException in case <code>obj</code> is <code>null</code>.
*/
public static <T> T requireNonNull(T obj, String message) throws IllegalArgumentException {
if (obj == null) {
throw new NullPointerException(message);
if (message == null) {
message = "Can not provide null argument";
}
throw new IllegalArgumentException(message);
}
return obj;
}

View file

@ -17,18 +17,19 @@
package org.jivesoftware.smack.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.compress.packet.Compress;
import org.jivesoftware.smack.packet.EmptyResultIQ;
import org.jivesoftware.smack.packet.ErrorIQ;
@ -49,11 +50,12 @@ import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.sasl.packet.SaslStreamElements.SASLFailure;
import org.jivesoftware.smack.xml.SmackXmlParser;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jxmpp.jid.Jid;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import org.jxmpp.stringprep.XmppStringprepException;
/**
* Utility class that helps to parse packets. Any parsing packets method that must be shared
@ -64,51 +66,22 @@ import org.xmlpull.v1.XmlPullParserFactory;
public class PacketParserUtils {
private static final Logger LOGGER = Logger.getLogger(PacketParserUtils.class.getName());
public static final String FEATURE_XML_ROUNDTRIP = "http://xmlpull.org/v1/doc/features.html#xml-roundtrip";
private static final XmlPullParserFactory XML_PULL_PARSER_FACTORY;
/**
* True if the XmlPullParser supports the XML_ROUNDTRIP feature.
*/
public static final boolean XML_PULL_PARSER_SUPPORTS_ROUNDTRIP;
static {
// Ensure that Smack is initialized.
SmackConfiguration.getVersion();
XmlPullParser xmlPullParser;
boolean roundtrip = false;
try {
XML_PULL_PARSER_FACTORY = XmlPullParserFactory.newInstance();
xmlPullParser = XML_PULL_PARSER_FACTORY.newPullParser();
try {
xmlPullParser.setFeature(FEATURE_XML_ROUNDTRIP, true);
// We could successfully set the feature
roundtrip = true;
} catch (XmlPullParserException e) {
// Doesn't matter if FEATURE_XML_ROUNDTRIP isn't available
LOGGER.log(Level.FINEST, "XmlPullParser does not support XML_ROUNDTRIP", e);
}
}
catch (XmlPullParserException e) {
// Something really bad happened
throw new AssertionError(e);
}
XML_PULL_PARSER_SUPPORTS_ROUNDTRIP = roundtrip;
}
// TODO: Rename argument name from 'stanza' to 'element'.
public static XmlPullParser getParserFor(String stanza) throws XmlPullParserException, IOException {
return getParserFor(new StringReader(stanza));
}
public static XmlPullParser getParserFor(InputStream inputStream) throws XmlPullParserException {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
return SmackXmlParser.newXmlParser(inputStreamReader);
}
public static XmlPullParser getParserFor(Reader reader) throws XmlPullParserException, IOException {
XmlPullParser parser = newXmppParser(reader);
XmlPullParser parser = SmackXmlParser.newXmlParser(reader);
// Wind the parser forward to the first start tag
int event = parser.getEventType();
while (event != XmlPullParser.START_TAG) {
if (event == XmlPullParser.END_DOCUMENT) {
XmlPullParser.Event event = parser.getEventType();
while (event != XmlPullParser.Event.START_ELEMENT) {
if (event == XmlPullParser.Event.END_DOCUMENT) {
throw new IllegalArgumentException("Document contains no start tag");
}
event = parser.next();
@ -116,28 +89,8 @@ public class PacketParserUtils {
return parser;
}
public static XmlPullParser getParserFor(String stanza, String startTag)
throws XmlPullParserException, IOException {
XmlPullParser parser = getParserFor(stanza);
while (true) {
int event = parser.getEventType();
String name = parser.getName();
if (event == XmlPullParser.START_TAG && name.equals(startTag)) {
break;
}
else if (event == XmlPullParser.END_DOCUMENT) {
throw new IllegalArgumentException("Could not find start tag '" + startTag
+ "' in stanza: " + stanza);
}
parser.next();
}
return parser;
}
@SuppressWarnings("unchecked")
public static <S extends Stanza> S parseStanza(String stanza) throws Exception {
public static <S extends Stanza> S parseStanza(String stanza) throws XmlPullParserException, SmackParsingException, IOException {
return (S) parseStanza(getParserFor(stanza), null);
}
@ -149,9 +102,11 @@ public class PacketParserUtils {
* @param parser
* @param outerXmlEnvironment the outer XML environment (optional).
* @return a stanza which is either a Message, IQ or Presence.
* @throws Exception
* @throws XmlPullParserException
* @throws SmackParsingException
* @throws IOException
*/
public static Stanza parseStanza(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws Exception {
public static Stanza parseStanza(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, SmackParsingException, IOException {
ParserUtils.assertAtStartTag(parser);
final String name = parser.getName();
switch (name) {
@ -166,53 +121,6 @@ public class PacketParserUtils {
}
}
/**
* Creates a new XmlPullParser suitable for parsing XMPP. This means in particular that
* FEATURE_PROCESS_NAMESPACES is enabled.
* <p>
* Note that not all XmlPullParser implementations will return a String on
* <code>getText()</code> if the parser is on START_TAG or END_TAG. So you must not rely on this
* behavior when using the parser.
* </p>
*
* @return A suitable XmlPullParser for XMPP parsing
* @throws XmlPullParserException
*/
public static XmlPullParser newXmppParser() throws XmlPullParserException {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
if (XML_PULL_PARSER_SUPPORTS_ROUNDTRIP) {
try {
parser.setFeature(FEATURE_XML_ROUNDTRIP, true);
}
catch (XmlPullParserException e) {
LOGGER.log(Level.SEVERE,
"XmlPullParser does not support XML_ROUNDTRIP, although it was first determined to be supported",
e);
}
}
return parser;
}
/**
* Creates a new XmlPullParser suitable for parsing XMPP. This means in particular that
* FEATURE_PROCESS_NAMESPACES is enabled.
* <p>
* Note that not all XmlPullParser implementations will return a String on
* <code>getText()</code> if the parser is on START_TAG or END_TAG. So you must not rely on this
* behavior when using the parser.
* </p>
*
* @param reader
* @return A suitable XmlPullParser for XMPP parsing
* @throws XmlPullParserException
*/
public static XmlPullParser newXmppParser(Reader reader) throws XmlPullParserException {
XmlPullParser parser = newXmppParser();
parser.setInput(reader);
return parser;
}
public static Message parseMessage(XmlPullParser parser) throws XmlPullParserException, IOException, SmackParsingException {
return parseMessage(parser, null);
}
@ -249,9 +157,9 @@ public class PacketParserUtils {
// in arbitrary sub-elements.
String thread = null;
outerloop: while (true) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
switch (eventType) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
String elementName = parser.getName();
String namespace = parser.getNamespace();
switch (elementName) {
@ -276,11 +184,12 @@ public class PacketParserUtils {
break;
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
default: // fall out
}
}
@ -295,9 +204,9 @@ public class PacketParserUtils {
/**
* Returns the textual content of an element as String. After this method returns the parser
* position will be END_TAG, following the established pull parser calling convention.
* position will be END_ELEMENT, following the established pull parser calling convention.
* <p>
* The parser must be positioned on a START_TAG of an element which MUST NOT contain Mixed
* The parser must be positioned on a START_ELEMENT of an element which MUST NOT contain Mixed
* Content (as defined in XML 3.2.2), or else an XmlPullParserException will be thrown.
* </p>
* This method is used for the parts where the XMPP specification requires elements that contain
@ -309,41 +218,36 @@ public class PacketParserUtils {
* @throws IOException
*/
public static String parseElementText(XmlPullParser parser) throws XmlPullParserException, IOException {
assert (parser.getEventType() == XmlPullParser.START_TAG);
assert (parser.getEventType() == XmlPullParser.Event.START_ELEMENT);
String res;
if (parser.isEmptyElementTag()) {
res = "";
}
else {
// Advance to the text of the Element
int event = parser.next();
if (event != XmlPullParser.TEXT) {
if (event == XmlPullParser.END_TAG) {
// Assume this is the end tag of the start tag at the
// beginning of this method. Typical examples where this
// happens are body elements containing the empty string,
// ie. <body></body>, which appears to be valid XMPP, or a
// least it's not explicitly forbidden by RFC 6121 5.2.3
return "";
} else {
throw new XmlPullParserException(
"Non-empty element tag not followed by text, while Mixed Content (XML 3.2.2) is disallowed");
}
}
res = parser.getText();
event = parser.next();
if (event != XmlPullParser.END_TAG) {
// Advance to the text of the Element
XmlPullParser.Event event = parser.next();
if (event != XmlPullParser.Event.TEXT_CHARACTERS) {
if (event == XmlPullParser.Event.END_ELEMENT) {
// Assume this is the end tag of the start tag at the
// beginning of this method. Typical examples where this
// happens are body elements containing the empty string,
// ie. <body></body>, which appears to be valid XMPP, or a
// least it's not explicitly forbidden by RFC 6121 5.2.3
return "";
} else {
throw new XmlPullParserException(
"Non-empty element tag contains child-elements, while Mixed Content (XML 3.2.2) is disallowed");
"Non-empty element tag not followed by text, while Mixed Content (XML 3.2.2) is disallowed");
}
}
res = parser.getText();
event = parser.next();
if (event != XmlPullParser.Event.END_ELEMENT) {
throw new XmlPullParserException(
"Non-empty element tag contains child-elements, while Mixed Content (XML 3.2.2) is disallowed");
}
return res;
}
/**
* Returns the current element as string.
* <p>
* The parser must be positioned on START_TAG.
* The parser must be positioned on START_ELEMENT.
* </p>
* Note that only the outermost namespace attributes ("xmlns") will be returned, not nested ones.
*
@ -359,37 +263,10 @@ public class PacketParserUtils {
public static CharSequence parseElement(XmlPullParser parser,
boolean fullNamespaces) throws XmlPullParserException,
IOException {
assert (parser.getEventType() == XmlPullParser.START_TAG);
assert (parser.getEventType() == XmlPullParser.Event.START_ELEMENT);
return parseContentDepth(parser, parser.getDepth(), fullNamespaces);
}
/**
* Returns the content of a element.
* <p>
* The parser must be positioned on the START_TAG of the element which content is going to get
* returned. If the current element is the empty element, then the empty string is returned. If
* it is a element which contains just text, then just the text is returned. If it contains
* nested elements (and text), then everything from the current opening tag to the corresponding
* closing tag of the same depth is returned as String.
* </p>
* Note that only the outermost namespace attributes ("xmlns") will be returned, not nested ones.
*
* @param parser the XML pull parser
* @return the content of a tag
* @throws XmlPullParserException if parser encounters invalid XML
* @throws IOException if an IO error occurs
*/
public static CharSequence parseContent(XmlPullParser parser)
throws XmlPullParserException, IOException {
assert (parser.getEventType() == XmlPullParser.START_TAG);
if (parser.isEmptyElementTag()) {
return "";
}
// Advance the parser, since we want to parse the content of the current element
parser.next();
return parseContentDepth(parser, parser.getDepth(), false);
}
public static CharSequence parseContentDepth(XmlPullParser parser, int depth)
throws XmlPullParserException, IOException {
return parseContentDepth(parser, depth, false);
@ -402,7 +279,7 @@ public class PacketParserUtils {
* parent elements will be added to child elements that don't define a different namespace.
* <p>
* This method is able to parse the content with MX- and KXmlParser. KXmlParser does not support
* xml-roundtrip. i.e. return a String on getText() on START_TAG and END_TAG. We check for the
* xml-roundtrip. i.e. return a String on getText() on START_ELEMENT and END_ELEMENT. We check for the
* XML_ROUNDTRIP feature. If it's not found we are required to work around this limitation, which
* results in only partial support for XML namespaces ("xmlns"): Only the outermost namespace of
* elements will be included in the resulting String, if <code>fullNamespaces</code> is set to false.
@ -419,7 +296,7 @@ public class PacketParserUtils {
* @throws IOException
*/
public static CharSequence parseContentDepth(XmlPullParser parser, int depth, boolean fullNamespaces) throws XmlPullParserException, IOException {
if (parser.getFeature(FEATURE_XML_ROUNDTRIP)) {
if (parser.supportsRoundtrip()) {
return parseContentDepthWithRoundtrip(parser, depth, fullNamespaces);
} else {
return parseContentDepthWithoutRoundtrip(parser, depth, fullNamespaces);
@ -429,15 +306,21 @@ public class PacketParserUtils {
private static CharSequence parseContentDepthWithoutRoundtrip(XmlPullParser parser, int depth,
boolean fullNamespaces) throws XmlPullParserException, IOException {
XmlStringBuilder xml = new XmlStringBuilder();
int event = parser.getEventType();
boolean isEmptyElement = false;
XmlPullParser.Event event = parser.getEventType();
// XmlPullParser reports namespaces in nested elements even if *only* the outer ones defines
// it. This 'flag' ensures that when a namespace is set for an element, it won't be set again
// in a nested element. It's an ugly workaround that has the potential to break things.
String namespaceElement = null;
boolean startElementJustSeen = false;
outerloop: while (true) {
switch (event) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
if (startElementJustSeen) {
xml.rightAngleBracket();
}
else {
startElementJustSeen = true;
}
xml.halfOpenElement(parser.getName());
if (namespaceElement == null || fullNamespaces) {
String namespace = parser.getNamespace();
@ -449,18 +332,11 @@ public class PacketParserUtils {
for (int i = 0; i < parser.getAttributeCount(); i++) {
xml.attribute(parser.getAttributeName(i), parser.getAttributeValue(i));
}
if (parser.isEmptyElementTag()) {
xml.closeEmptyElement();
isEmptyElement = true;
}
else {
xml.rightAngleBracket();
}
break;
case XmlPullParser.END_TAG:
if (isEmptyElement) {
// Do nothing as the element was already closed, just reset the flag
isEmptyElement = false;
case END_ELEMENT:
if (startElementJustSeen) {
xml.closeEmptyElement();
startElementJustSeen = false;
}
else {
xml.closeElement(parser.getName());
@ -474,31 +350,58 @@ public class PacketParserUtils {
break outerloop;
}
break;
case XmlPullParser.TEXT:
case TEXT_CHARACTERS:
if (startElementJustSeen) {
startElementJustSeen = false;
xml.rightAngleBracket();
}
xml.escape(parser.getText());
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
event = parser.next();
}
return xml;
}
@SuppressWarnings("UnusedVariable")
private static CharSequence parseContentDepthWithRoundtrip(XmlPullParser parser, int depth, boolean fullNamespaces)
throws XmlPullParserException, IOException {
StringBuilder sb = new StringBuilder();
int event = parser.getEventType();
XmlStringBuilder sb = new XmlStringBuilder();
XmlPullParser.Event event = parser.getEventType();
boolean startElementJustSeen = false;
outerloop: while (true) {
// Only append the text if the parser is not on on an empty element' start tag. Empty elements are reported
// twice, so in order to prevent duplication we only add their text when we are on their end tag.
if (!(event == XmlPullParser.START_TAG && parser.isEmptyElementTag())) {
switch (event) {
case START_ELEMENT:
if (startElementJustSeen) {
sb.rightAngleBracket();
}
startElementJustSeen = true;
break;
case END_ELEMENT:
boolean isEmptyElement = false;
if (startElementJustSeen) {
isEmptyElement = true;
startElementJustSeen = false;
}
if (!isEmptyElement) {
String text = parser.getText();
sb.append(text);
}
if (parser.getDepth() <= depth) {
break outerloop;
}
break;
default:
startElementJustSeen = false;
CharSequence text = parser.getText();
if (event == XmlPullParser.TEXT) {
text = StringUtils.escapeForXmlText(text);
if (event == XmlPullParser.Event.TEXT_CHARACTERS) {
text = StringUtils.escapeForXml(text);
}
sb.append(text);
}
if (event == XmlPullParser.END_TAG && parser.getDepth() <= depth) {
break outerloop;
break;
}
event = parser.next();
}
@ -536,16 +439,14 @@ public class PacketParserUtils {
String language = ParserUtils.getXmlLang(parser);
if (language != null && !"".equals(language.trim())) {
// CHECKSTYLE:OFF
presence.setLanguage(language);
// CHECKSTYLE:ON
presence.setLanguage(language);
}
// Parse sub-elements
outerloop: while (true) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
switch (eventType) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
String elementName = parser.getName();
String namespace = parser.getNamespace();
switch (elementName) {
@ -553,7 +454,7 @@ public class PacketParserUtils {
presence.setStatus(parser.nextText());
break;
case "priority":
int priority = Integer.parseInt(parser.nextText());
Byte priority = ParserUtils.getByteAttributeFromNextText(parser);
presence.setPriority(priority);
break;
case "show":
@ -587,11 +488,14 @@ public class PacketParserUtils {
break;
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}
return presence;
@ -607,9 +511,12 @@ public class PacketParserUtils {
* @param parser the XML parser, positioned at the start of an IQ packet.
* @param outerXmlEnvironment the outer XML environment (optional).
* @return an IQ object.
* @throws Exception
* @throws XmlPullParserException
* @throws XmppStringprepException
* @throws IOException
* @throws SmackParsingException
*/
public static IQ parseIQ(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws Exception {
public static IQ parseIQ(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws XmlPullParserException, XmppStringprepException, IOException, SmackParsingException {
ParserUtils.assertAtStartTag(parser);
final int initialDepth = parser.getDepth();
XmlEnvironment iqXmlEnvironment = XmlEnvironment.from(parser, outerXmlEnvironment);
@ -622,10 +529,10 @@ public class PacketParserUtils {
final IQ.Type type = IQ.Type.fromString(parser.getAttributeValue("", "type"));
outerloop: while (true) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
switch (eventType) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
String elementName = parser.getName();
String namespace = parser.getNamespace();
switch (elementName) {
@ -640,7 +547,7 @@ public class PacketParserUtils {
iqPacket = provider.parse(parser, outerXmlEnvironment);
}
// Note that if we reach this code, it is guranteed that the result IQ contained a child element
// (RFC 6120 § 8.2.3 6) because otherwhise we would have reached the END_TAG first.
// (RFC 6120 § 8.2.3 6) because otherwhise we would have reached the END_ELEMENT first.
else {
// No Provider found for the IQ stanza, parse it to an UnparsedIQ instance
// so that the content of the IQ can be examined later on
@ -649,11 +556,14 @@ public class PacketParserUtils {
break;
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}
// Decide what to do when an IQ packet was not understood
@ -694,15 +604,15 @@ public class PacketParserUtils {
List<String> mechanisms = new ArrayList<String>();
boolean done = false;
while (!done) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
if (eventType == XmlPullParser.START_TAG) {
if (eventType == XmlPullParser.Event.START_ELEMENT) {
String elementName = parser.getName();
if (elementName.equals("mechanism")) {
mechanisms.add(parser.nextText());
}
}
else if (eventType == XmlPullParser.END_TAG) {
else if (eventType == XmlPullParser.Event.END_ELEMENT) {
if (parser.getName().equals("mechanisms")) {
done = true;
}
@ -721,14 +631,14 @@ public class PacketParserUtils {
*/
public static Compress.Feature parseCompressionFeature(XmlPullParser parser)
throws IOException, XmlPullParserException {
assert (parser.getEventType() == XmlPullParser.START_TAG);
assert (parser.getEventType() == XmlPullParser.Event.START_ELEMENT);
String name;
final int initialDepth = parser.getDepth();
List<String> methods = new LinkedList<>();
outerloop: while (true) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
switch (eventType) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
name = parser.getName();
switch (name) {
case "method":
@ -736,7 +646,7 @@ public class PacketParserUtils {
break;
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
name = parser.getName();
switch (name) {
case Compress.Feature.ELEMENT:
@ -744,9 +654,13 @@ public class PacketParserUtils {
break outerloop;
}
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}
assert (parser.getEventType() == XmlPullParser.END_TAG);
assert (parser.getEventType() == XmlPullParser.Event.END_ELEMENT);
assert (parser.getDepth() == initialDepth);
return new Compress.Feature(methods);
}
@ -782,9 +696,9 @@ public class PacketParserUtils {
String condition = null;
Map<String, String> descriptiveTexts = null;
outerloop: while (true) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
switch (eventType) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
String name = parser.getName();
if (name.equals("text")) {
descriptiveTexts = parseDescriptiveTexts(parser, descriptiveTexts);
@ -794,11 +708,14 @@ public class PacketParserUtils {
condition = parser.getName();
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}
return new SASLFailure(condition, descriptiveTexts);
@ -826,9 +743,9 @@ public class PacketParserUtils {
String conditionText = null;
XmlEnvironment streamErrorXmlEnvironment = XmlEnvironment.from(parser, outerXmlEnvironment);
outerloop: while (true) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
switch (eventType) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
String name = parser.getName();
String namespace = parser.getNamespace();
switch (namespace) {
@ -841,8 +758,9 @@ public class PacketParserUtils {
// If it's not a text element, that is qualified by the StreamError.NAMESPACE,
// then it has to be the stream error code
condition = StreamError.Condition.fromString(name);
if (!parser.isEmptyElementTag()) {
conditionText = parser.nextText();
conditionText = parser.nextText();
if (conditionText.isEmpty()) {
conditionText = null;
}
break;
}
@ -852,11 +770,14 @@ public class PacketParserUtils {
break;
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}
return new StreamError(condition, conditionText, descriptiveTexts, extensions);
@ -888,9 +809,9 @@ public class PacketParserUtils {
builder.setErrorGenerator(parser.getAttributeValue("", "by"));
outerloop: while (true) {
int eventType = parser.next();
XmlPullParser.Event eventType = parser.next();
switch (eventType) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
String name = parser.getName();
String namespace = parser.getNamespace();
switch (namespace) {
@ -901,8 +822,9 @@ public class PacketParserUtils {
break;
default:
builder.setCondition(StanzaError.Condition.fromString(name));
if (!parser.isEmptyElementTag()) {
builder.setConditionText(parser.nextText());
String conditionText = parser.nextText();
if (!conditionText.isEmpty()) {
builder.setConditionText(conditionText);
}
break;
}
@ -911,10 +833,14 @@ public class PacketParserUtils {
PacketParserUtils.addExtensionElement(extensions, parser, name, namespace, stanzaErrorXmlEnvironment);
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}
builder.setExtensions(extensions).setDescriptiveTexts(descriptiveTexts);
@ -949,14 +875,14 @@ public class PacketParserUtils {
public static StartTls parseStartTlsFeature(XmlPullParser parser)
throws XmlPullParserException, IOException {
assert (parser.getEventType() == XmlPullParser.START_TAG);
assert (parser.getEventType() == XmlPullParser.Event.START_ELEMENT);
assert (parser.getNamespace().equals(StartTls.NAMESPACE));
int initalDepth = parser.getDepth();
boolean required = false;
outerloop: while (true) {
int event = parser.next();
XmlPullParser.Event event = parser.next();
switch (event) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
String name = parser.getName();
switch (name) {
case "required":
@ -964,13 +890,17 @@ public class PacketParserUtils {
break;
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
if (parser.getDepth() == initalDepth) {
break outerloop;
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}
assert (parser.getEventType() == XmlPullParser.END_TAG);
assert (parser.getEventType() == XmlPullParser.Event.END_ELEMENT);
return new StartTls(required);
}
@ -978,14 +908,11 @@ public class PacketParserUtils {
ParserUtils.assertAtStartTag(parser);
final int initialDepth = parser.getDepth();
boolean optional = false;
if (parser.isEmptyElementTag()) {
return new Session.Feature(optional);
}
outerloop: while (true) {
int event = parser.next();
XmlPullParser.Event event = parser.next();
switch (event) {
case XmlPullParser.START_TAG:
case START_ELEMENT:
String name = parser.getName();
switch (name) {
case Session.Feature.OPTIONAL_ELEMENT:
@ -993,10 +920,14 @@ public class PacketParserUtils {
break;
}
break;
case XmlPullParser.END_TAG:
case END_ELEMENT:
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}

View file

@ -23,12 +23,15 @@ import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import org.jivesoftware.smack.datatypes.UInt16;
import org.jivesoftware.smack.datatypes.UInt32;
import org.jivesoftware.smack.parsing.SmackParsingException;
import org.jivesoftware.smack.parsing.SmackParsingException.SmackTextParseException;
import org.jivesoftware.smack.parsing.SmackParsingException.SmackUriSyntaxParsingException;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.EntityFullJid;
@ -38,8 +41,6 @@ import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Resourcepart;
import org.jxmpp.stringprep.XmppStringprepException;
import org.jxmpp.util.XmppDateTime;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
public class ParserUtils {
@ -49,7 +50,7 @@ public class ParserUtils {
public static final String JID = "jid";
public static void assertAtStartTag(XmlPullParser parser) throws XmlPullParserException {
assert (parser.getEventType() == XmlPullParser.START_TAG);
assert (parser.getEventType() == XmlPullParser.Event.START_ELEMENT);
}
public static void assertAtStartTag(XmlPullParser parser, String name) throws XmlPullParserException {
@ -58,13 +59,13 @@ public class ParserUtils {
}
public static void assertAtEndTag(XmlPullParser parser) throws XmlPullParserException {
assert (parser.getEventType() == XmlPullParser.END_TAG);
assert (parser.getEventType() == XmlPullParser.Event.END_ELEMENT);
}
public static void forwardToEndTagOfDepth(XmlPullParser parser, int depth)
throws XmlPullParserException, IOException {
int event = parser.getEventType();
while (!(event == XmlPullParser.END_TAG && parser.getDepth() == depth)) {
XmlPullParser.Event event = parser.getEventType();
while (!(event == XmlPullParser.Event.END_ELEMENT && parser.getDepth() == depth)) {
event = parser.next();
}
}
@ -178,6 +179,11 @@ public class ParserUtils {
}
}
public static Byte getByteAttributeFromNextText(XmlPullParser parser) throws IOException, XmlPullParserException {
String nextText = parser.nextText();
return Byte.valueOf(nextText);
}
public static int getIntegerAttributeOrThrow(XmlPullParser parser, String name, String throwMessage)
throws IOException {
Integer res = getIntegerAttribute(parser, name);
@ -205,6 +211,14 @@ public class ParserUtils {
}
}
public static UInt16 getUInt16Attribute(XmlPullParser parser, String name) {
Integer integer = getIntegerAttribute(parser, name);
if (integer == null) {
return null;
}
return UInt16.from(integer);
}
public static int getIntegerFromNextText(XmlPullParser parser) throws XmlPullParserException, IOException {
String intString = parser.nextText();
return Integer.valueOf(intString);
@ -227,6 +241,14 @@ public class ParserUtils {
}
}
public static UInt32 getUInt32Attribute(XmlPullParser parser, String name) {
Long l = getLongAttribute(parser, name);
if (l == null) {
return null;
}
return UInt32.from(l);
}
public static double getDoubleFromNextText(XmlPullParser parser) throws XmlPullParserException, IOException {
String doubleString = parser.nextText();
return Double.valueOf(doubleString);
@ -323,13 +345,16 @@ public class ParserUtils {
return parser.getAttributeValue("http://www.w3.org/XML/1998/namespace", "lang");
}
/**
* Get the QName of the current element.
*
* @param parser the parser.
* @return the Qname.
* @deprecated use {@link XmlPullParser#getQName()} instead.
*/
@Deprecated
// TODO: Remove in Smack 4.5
public static QName getQName(XmlPullParser parser) {
String elementName = parser.getName();
String prefix = parser.getPrefix();
if (prefix == null) {
prefix = XMLConstants.DEFAULT_NS_PREFIX;
}
String namespace = parser.getNamespace();
return new QName(namespace, elementName, prefix);
return parser.getQName();
}
}

View file

@ -17,7 +17,9 @@
package org.jivesoftware.smack.util;
import java.io.UnsupportedEncodingException;
import java.io.IOException;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Iterator;
import java.util.Random;
@ -29,7 +31,23 @@ public class StringUtils {
public static final String MD5 = "MD5";
public static final String SHA1 = "SHA-1";
/**
* Deprecated, do not use.
*
* @deprecated use StandardCharsets.UTF_8 instead.
*/
// TODO: Remove in Smack 4.5.
@Deprecated
public static final String UTF8 = "UTF-8";
/**
* Deprecated, do not use.
*
* @deprecated use StandardCharsets.US_ASCII instead.
*/
// TODO: Remove in Smack 4.5.
@Deprecated
public static final String USASCII = "US-ASCII";
public static final String QUOTE_ENCODE = "&quot;";
@ -244,22 +262,13 @@ public class StringUtils {
}
public static byte[] toUtf8Bytes(String string) {
try {
return string.getBytes(StringUtils.UTF8);
}
catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 encoding not supported by platform", e);
}
return string.getBytes(StandardCharsets.UTF_8);
}
/**
* Array of numbers and letters of mixed case. Numbers appear in the list
* twice so that there is a more equal chance that a number will be picked.
* We can use the array to get a random number or letter by picking a random
* array index.
* 24 upper case characters from the latin alphabet and numbers without '0' and 'O'.
*/
private static final char[] numbersAndLetters = ("0123456789abcdefghijklmnopqrstuvwxyz" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
private static final char[] UNAMBIGUOUS_NUMBERS_AND_LETTER = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ".toCharArray();
/**
* Returns a random String of numbers and letters (lower and upper case)
@ -278,6 +287,74 @@ public class StringUtils {
return randomString(length, RandomUtil.RANDOM.get());
}
public static String secureOnlineAttackSafeRandomString() {
// 34^10 = 2.06e15 possible combinations. Which is enough to protect against online brute force attacks.
// See also https://www.grc.com/haystack.htm
final int REQUIRED_LENGTH = 10;
return randomString(RandomUtil.SECURE_RANDOM.get(), UNAMBIGUOUS_NUMBERS_AND_LETTER, REQUIRED_LENGTH);
}
public static String secureUniqueRandomString() {
// 34^13 = 8.11e19 possible combinations, which is > 2^64.
final int REQUIRED_LENGTH = 13;
return randomString(RandomUtil.SECURE_RANDOM.get(), UNAMBIGUOUS_NUMBERS_AND_LETTER, REQUIRED_LENGTH);
}
/**
* Generate a secure random string with is human readable. The resulting string consists of 24 upper case characters
* from the Latin alphabet and numbers without '0' and 'O', grouped into 4-characters chunks, e.g.
* "TWNK-KD5Y-MT3T-E1GS-DRDB-KVTW". The characters are randomly selected by a cryptographically secure pseudorandom
* number generator (CSPRNG).
* <p>
* The string can be used a backup "code" for secrets, and is in fact the same as the one backup code specified in
* XEP-0373 and the one used by the <a href="https://github.com/open-keychain/open-keychain/wiki/Backups">Backup
* Format v2 of OpenKeychain</a>.
* </p>
*
* @see <a href="https://xmpp.org/extensions/xep-0373.html#backup-encryption"> XEP-0373 §5.4 Encrypting the Secret
* Key Backup</a>
* @return a human readable secure random string.
*/
public static String secureOfflineAttackSafeRandomString() {
// 34^24 = 2^122.10 possible combinations. Which is enough to protect against offline brute force attacks.
// See also https://www.grc.com/haystack.htm
final int REQUIRED_LENGTH = 24;
return randomString(RandomUtil.SECURE_RANDOM.get(), UNAMBIGUOUS_NUMBERS_AND_LETTER, REQUIRED_LENGTH);
}
private static final int RANDOM_STRING_CHUNK_SIZE = 4;
private static String randomString(Random random, char[] alphabet, int numRandomChars) {
// The buffer most hold the size of the requested number of random chars and the chunk separators ('-').
int bufferSize = numRandomChars + ((numRandomChars - 1) / RANDOM_STRING_CHUNK_SIZE);
CharBuffer charBuffer = CharBuffer.allocate(bufferSize);
try {
randomString(charBuffer, random, alphabet, numRandomChars);
} catch (IOException e) {
// This should never happen if we calcuate the buffer size correctly.
throw new AssertionError(e);
}
return charBuffer.flip().toString();
}
private static void randomString(Appendable appendable, Random random, char[] alphabet, int numRandomChars)
throws IOException {
for (int randomCharNum = 1; randomCharNum <= numRandomChars; randomCharNum++) {
int randomIndex = random.nextInt(alphabet.length);
char randomChar = alphabet[randomIndex];
appendable.append(randomChar);
if (randomCharNum % RANDOM_STRING_CHUNK_SIZE == 0 && randomCharNum < numRandomChars) {
appendable.append('-');
}
}
}
public static String randomString(final int length) {
return randomString(length, RandomUtil.SECURE_RANDOM.get());
}
@ -287,24 +364,14 @@ public class StringUtils {
return "";
}
byte[] randomBytes = new byte[length];
random.nextBytes(randomBytes);
char[] randomChars = new char[length];
for (int i = 0; i < length; i++) {
randomChars[i] = getPrintableChar(randomBytes[i]);
int index = random.nextInt(UNAMBIGUOUS_NUMBERS_AND_LETTER.length);
randomChars[i] = UNAMBIGUOUS_NUMBERS_AND_LETTER[index];
}
return new String(randomChars);
}
private static char getPrintableChar(byte indexByte) {
assert (numbersAndLetters.length < Byte.MAX_VALUE * 2);
// Convert indexByte as it where an unsigned byte by promoting it to int
// and masking it with 0xff. Yields results from 0 - 254.
int index = indexByte & 0xff;
return numbersAndLetters[index % numbersAndLetters.length];
}
/**
* Returns true if CharSequence is not null and is not empty, false otherwise.
* Examples:

View file

@ -64,7 +64,7 @@ public class TLSUtils {
*
* @return the given builder
*/
public static <B extends ConnectionConfiguration.Builder<B,?>> B setTLSOnly(B builder) {
public static <B extends ConnectionConfiguration.Builder<B, ?>> B setTLSOnly(B builder) {
builder.setEnabledSSLProtocols(new String[] { PROTO_TLSV1_2, PROTO_TLSV1_1, PROTO_TLSV1 });
return builder;
}
@ -84,7 +84,7 @@ public class TLSUtils {
*
* @return the given builder
*/
public static <B extends ConnectionConfiguration.Builder<B,?>> B setSSLv3AndTLSOnly(B builder) {
public static <B extends ConnectionConfiguration.Builder<B, ?>> B setSSLv3AndTLSOnly(B builder) {
builder.setEnabledSSLProtocols(new String[] { PROTO_TLSV1_2, PROTO_TLSV1_1, PROTO_TLSV1, PROTO_SSL3 });
return builder;
}
@ -103,7 +103,7 @@ public class TLSUtils {
* @throws KeyManagementException
* @return the given builder.
*/
public static <B extends ConnectionConfiguration.Builder<B,?>> B acceptAllCertificates(B builder) throws NoSuchAlgorithmException, KeyManagementException {
public static <B extends ConnectionConfiguration.Builder<B, ?>> B acceptAllCertificates(B builder) throws NoSuchAlgorithmException, KeyManagementException {
SSLContext context = SSLContext.getInstance(TLS);
context.init(null, new TrustManager[] { new AcceptAllTrustManager() }, new SecureRandom());
builder.setCustomSSLContext(context);
@ -130,7 +130,7 @@ public class TLSUtils {
* @param <B> Type of the ConnectionConfiguration builder.
* @return the given builder.
*/
public static <B extends ConnectionConfiguration.Builder<B,?>> B disableHostnameVerificationForTlsCertificates(B builder) {
public static <B extends ConnectionConfiguration.Builder<B, ?>> B disableHostnameVerificationForTlsCertificates(B builder) {
builder.setHostnameVerifier(DOES_NOT_VERIFY_VERIFIER);
return builder;
}

View file

@ -269,10 +269,20 @@ public class XmlStringBuilder implements Appendable, CharSequence, Element {
public XmlStringBuilder attribute(String name, Enum<?> value) {
assert value != null;
// TODO: Should use toString() instead of name().
attribute(name, value.name());
return this;
}
public <E extends Enum<?>> XmlStringBuilder attribute(String name, E value, E implicitDefault) {
if (value == null || value == implicitDefault) {
return this;
}
attribute(name, value.toString());
return this;
}
public XmlStringBuilder attribute(String name, int value) {
assert name != null;
return attribute(name, String.valueOf(value));
@ -327,6 +337,13 @@ public class XmlStringBuilder implements Appendable, CharSequence, Element {
return this;
}
public XmlStringBuilder optAttribute(String name, Number number) {
if (number != null) {
attribute(name, number.toString());
}
return this;
}
/**
* Add the given attribute if {@code value => 0}.
*

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2018 Florian Schmaus
* Copyright 2018-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +16,13 @@
*/
package org.jivesoftware.smack.util;
import org.jivesoftware.smack.packet.FullyQualifiedElement;
import javax.xml.namespace.QName;
import org.jxmpp.util.XmppStringUtils;
import org.jivesoftware.smack.packet.FullyQualifiedElement;
public class XmppElementUtil {
public static String getKeyFor(Class<? extends FullyQualifiedElement> fullyQualifiedElement) {
public static QName getQNameFor(Class<? extends FullyQualifiedElement> fullyQualifiedElement) {
String element, namespace;
try {
element = (String) fullyQualifiedElement.getField("ELEMENT").get(null);
@ -32,14 +32,7 @@ public class XmppElementUtil {
throw new IllegalArgumentException(e);
}
String key = XmppStringUtils.generateKey(element, namespace);
return key;
return new QName(namespace, element);
}
public static String getKeyFor(FullyQualifiedElement fullyQualifiedElement) {
String element = fullyQualifiedElement.getElementName();
String namespace = fullyQualifiedElement.getNamespace();
String key = XmppStringUtils.generateKey(element, namespace);
return key;
}
}

View file

@ -19,9 +19,7 @@ package org.jivesoftware.smack.util.stringencoder;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.jivesoftware.smack.util.StringUtils;
import java.nio.charset.StandardCharsets;
/**
* Base32 string encoding is useful for when filenames case-insensitive filesystems are encoded.
@ -55,13 +53,8 @@ public class Base32 {
public static String decode(String str) {
ByteArrayOutputStream bs = new ByteArrayOutputStream();
byte[] raw;
try {
raw = str.getBytes(StringUtils.UTF8);
}
catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}
byte[] raw = str.getBytes(StandardCharsets.UTF_8);
for (int i = 0; i < raw.length; i++) {
char c = (char) raw[i];
if (!Character.isWhitespace(c)) {
@ -114,24 +107,12 @@ public class Base32 {
}
}
String res;
try {
res = new String(bs.toByteArray(), StringUtils.UTF8);
}
catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}
String res = new String(bs.toByteArray(), StandardCharsets.UTF_8);
return res;
}
public static String encode(String str) {
byte[] b;
try {
b = str.getBytes(StringUtils.UTF8);
}
catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}
byte[] b = str.getBytes(StandardCharsets.UTF_8);
ByteArrayOutputStream os = new ByteArrayOutputStream();
for (int i = 0; i < (b.length + 4) / 5; i++) {
@ -174,13 +155,7 @@ public class Base32 {
os.write(c);
}
}
String res;
try {
res = new String(os.toByteArray(), StringUtils.UTF8);
}
catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}
String res = new String(os.toByteArray(), StandardCharsets.UTF_8);
return res;
}

View file

@ -16,10 +16,9 @@
*/
package org.jivesoftware.smack.util.stringencoder;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.StringUtils;
public class Base64 {
@ -31,11 +30,7 @@ public class Base64 {
}
public static final String encode(String string) {
try {
return encodeToString(string.getBytes(StringUtils.UTF8));
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 not supported", e);
}
return encodeToString(string.getBytes(StandardCharsets.UTF_8));
}
public static final String encodeToString(byte[] input) {
@ -56,11 +51,7 @@ public class Base64 {
public static final String decodeToString(String string) {
byte[] bytes = decode(string);
try {
return new String(bytes, StringUtils.UTF8);
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 not supported", e);
}
return new String(bytes, StandardCharsets.UTF_8);
}
// TODO: We really should not mask the IllegalArgumentException. But some unit test depend on this behavior, like
@ -74,12 +65,7 @@ public class Base64 {
}
public static final byte[] decode(byte[] input) {
String string;
try {
string = new String(input, StringUtils.USASCII);
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}
String string = new String(input, StandardCharsets.US_ASCII);
return decode(string);
}

View file

@ -30,7 +30,7 @@ public class StanzaCollectorTest {
@Test
public void verifyRollover() throws InterruptedException {
TestStanzaCollector collector = new TestStanzaCollector(null, new OKEverything(), 5);
StanzaCollector collector = createTestStanzaCollector(null, new OKEverything(), 5);
for (int i = 0; i < 6; i++) {
Stanza testPacket = new TestPacket(i);
@ -70,7 +70,7 @@ public class StanzaCollectorTest {
@Test
public void verifyThreadSafety() throws InterruptedException {
final int insertCount = 500;
final TestStanzaCollector collector = new TestStanzaCollector(null, new OKEverything(), insertCount);
final StanzaCollector collector = createTestStanzaCollector(null, new OKEverything(), insertCount);
final AtomicInteger consumer1Dequeued = new AtomicInteger();
final AtomicInteger consumer2Dequeued = new AtomicInteger();
@ -170,10 +170,8 @@ public class StanzaCollectorTest {
}
static class TestStanzaCollector extends StanzaCollector {
protected TestStanzaCollector(XMPPConnection conection, StanzaFilter packetFilter, int size) {
super(conection, StanzaCollector.newConfiguration().setStanzaFilter(packetFilter).setSize(size));
}
private static StanzaCollector createTestStanzaCollector(XMPPConnection connection, StanzaFilter packetFilter, int size) {
return new StanzaCollector(connection, StanzaCollector.newConfiguration().setStanzaFilter(packetFilter).setSize(size));
}
static class TestPacket extends Stanza {

View file

@ -16,7 +16,7 @@
*/
package org.jivesoftware.smack.compress.packet;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.jivesoftware.smack.test.util.XmlUnitUtils.assertXmlSimilar;
import java.io.IOException;
@ -35,7 +35,7 @@ public class FailureTest {
final String expectedXml = "<failure xmlns='http://jabber.org/protocol/compress'><processing-failed/></failure>";
assertXMLEqual(expectedXml, xml.toString());
assertXmlSimilar(expectedXml, xml.toString());
}
@Test
@ -53,6 +53,6 @@ public class FailureTest {
+ "</error>"
+ "</failure>";
assertXMLEqual(expectedXml, xml.toString());
assertXmlSimilar(expectedXml, xml.toString());
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2018 Florian Schmaus
* Copyright 2018-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -22,9 +22,9 @@ import org.jivesoftware.smack.compress.packet.Failure;
import org.jivesoftware.smack.packet.StanzaError;
import org.jivesoftware.smack.packet.StanzaError.Condition;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
public class FailureProviderTest {

View file

@ -16,7 +16,7 @@
*/
package org.jivesoftware.smack.packet;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.jivesoftware.smack.test.util.XmlUnitUtils.assertXmlSimilar;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@ -26,8 +26,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.jivesoftware.smack.test.util.XmlUnitUtils;
import org.junit.Test;
import org.xml.sax.SAXException;
@ -49,7 +47,7 @@ public class MessageTest {
Message messageTypeInConstructor = new Message(null, Message.Type.chat);
messageTypeInConstructor.setStanzaId(null);
assertEquals(type, messageTypeInConstructor.getType());
assertXMLEqual(control, messageTypeInConstructor.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, messageTypeInConstructor.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
controlBuilder = new StringBuilder();
controlBuilder.append("<message")
@ -62,7 +60,7 @@ public class MessageTest {
Message messageTypeSet = getNewMessage();
messageTypeSet.setType(type2);
assertEquals(type2, messageTypeSet.getType());
assertXMLEqual(control, messageTypeSet.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, messageTypeSet.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
}
@Test(expected = NullPointerException.class)
@ -87,7 +85,7 @@ public class MessageTest {
message.setSubject(messageSubject);
assertEquals(messageSubject, message.getSubject());
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
}
@Test
@ -106,7 +104,7 @@ public class MessageTest {
message.setBody(messageBody);
assertEquals(messageBody, message.getBody());
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
}
@Test
@ -139,7 +137,7 @@ public class MessageTest {
message.addBody(null, messageBody1);
message.addBody(lang2, messageBody2);
message.addBody(lang3, messageBody3);
XmlUnitUtils.assertSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE));
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE));
Collection<String> languages = message.getBodyLanguages();
List<String> controlLanguages = new ArrayList<>();
@ -183,7 +181,7 @@ public class MessageTest {
message.setThread(messageThread);
assertEquals(messageThread, message.getThread());
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
}
@Test
@ -201,7 +199,7 @@ public class MessageTest {
Message message = getNewMessage();
message.setLanguage(lang);
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
}
private static Message getNewMessage() {

View file

@ -16,14 +16,15 @@
*/
package org.jivesoftware.smack.packet;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.jivesoftware.smack.test.util.XmlUnitUtils.assertXmlSimilar;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.IOException;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.xml.sax.SAXException;
public class PresenceTest {
@ -43,7 +44,7 @@ public class PresenceTest {
Presence presenceTypeInConstructor = new Presence(type);
presenceTypeInConstructor.setStanzaId(null);
assertEquals(type, presenceTypeInConstructor.getType());
assertXMLEqual(control, presenceTypeInConstructor.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, presenceTypeInConstructor.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
controlBuilder = new StringBuilder();
controlBuilder.append("<presence")
@ -56,12 +57,14 @@ public class PresenceTest {
Presence presenceTypeSet = getNewPresence();
presenceTypeSet.setType(type2);
assertEquals(type2, presenceTypeSet.getType());
assertXMLEqual(control, presenceTypeSet.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, presenceTypeSet.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
}
@Test(expected = NullPointerException.class)
@Test
public void setNullPresenceTypeTest() {
getNewPresence().setType(null);
assertThrows(IllegalArgumentException.class, () ->
getNewPresence().setType(null)
);
}
@Test
@ -90,7 +93,7 @@ public class PresenceTest {
presence.setStatus(status);
assertEquals(status, presence.getStatus());
assertXMLEqual(control, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
}
@Test
@ -109,12 +112,14 @@ public class PresenceTest {
presence.setPriority(priority);
assertEquals(priority, presence.getPriority());
assertXMLEqual(control, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
}
@Test(expected = IllegalArgumentException.class)
@Test
public void setIllegalPriorityTest() {
getNewPresence().setPriority(Integer.MIN_VALUE);
assertThrows(IllegalArgumentException.class, () ->
getNewPresence().setPriority(Integer.MIN_VALUE)
);
}
@Test
@ -142,7 +147,7 @@ public class PresenceTest {
mode1);
presenceModeInConstructor.setStanzaId(null);
assertEquals(mode1, presenceModeInConstructor.getMode());
assertXMLEqual(control, presenceModeInConstructor.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, presenceModeInConstructor.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
controlBuilder = new StringBuilder();
controlBuilder.append("<presence>")
@ -155,7 +160,7 @@ public class PresenceTest {
Presence presenceModeSet = getNewPresence();
presenceModeSet.setMode(mode2);
assertEquals(mode2, presenceModeSet.getMode());
assertXMLEqual(control, presenceModeSet.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, presenceModeSet.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
}
@Test
@ -183,7 +188,7 @@ public class PresenceTest {
Presence presence = getNewPresence();
presence.setLanguage(lang);
assertXMLEqual(control, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
}
private static Presence getNewPresence() {

View file

@ -18,19 +18,25 @@ package org.jivesoftware.smack.packet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import java.io.IOException;
import org.jivesoftware.smack.packet.StreamError.Condition;
import org.jivesoftware.smack.parsing.SmackParsingException;
import org.jivesoftware.smack.test.util.SmackTestUtil;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
public class StreamErrorTest {
@Test
public void testParsingOfSimpleStreamError() {
StreamError error = null;
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testParsingOfSimpleStreamError(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException, SmackParsingException {
final String xml =
// Usually the stream:stream element has more attributes (to, version, ...)
// We omit those, since they are not relevant for testing
@ -39,19 +45,17 @@ public class StreamErrorTest {
"<conflict xmlns='urn:ietf:params:xml:ns:xmpp-streams' /> +" +
"</stream:error>" +
"</stream:stream>";
try {
XmlPullParser parser = PacketParserUtils.getParserFor(xml, "error");
error = PacketParserUtils.parseStreamError(parser);
} catch (Exception e) {
fail(e.getMessage());
}
XmlPullParser parser = SmackTestUtil.getParserFor(xml, "error", parserKind);
StreamError error = PacketParserUtils.parseStreamError(parser);
assertNotNull(error);
assertEquals(Condition.conflict, error.getCondition());
}
@Test
public void testParsingOfStreamErrorWithText() {
StreamError error = null;
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testParsingOfStreamErrorWithText(SmackTestUtil.XmlPullParserKind parserKind) throws XmlPullParserException, IOException, SmackParsingException {
final String xml =
// Usually the stream:stream element has more attributes (to, version, ...)
// We omit those, since they are not relevant for testing
@ -63,20 +67,19 @@ public class StreamErrorTest {
"</text>" +
"</stream:error>" +
"</stream:stream>";
try {
XmlPullParser parser = PacketParserUtils.getParserFor(xml, "error");
error = PacketParserUtils.parseStreamError(parser);
} catch (Exception e) {
fail(e.getMessage());
}
XmlPullParser parser = SmackTestUtil.getParserFor(xml, "error", parserKind);
StreamError error = PacketParserUtils.parseStreamError(parser);
assertNotNull(error);
assertEquals(Condition.conflict, error.getCondition());
assertEquals("Replaced by new connection", error.getDescriptiveText());
}
@Test
public void testParsingOfStreamErrorWithTextAndOptionalElement() {
StreamError error = null;
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testParsingOfStreamErrorWithTextAndOptionalElement(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException, SmackParsingException {
final String xml =
// Usually the stream:stream element has more attributes (to, version, ...)
// We omit those, since they are not relevant for testing
@ -91,12 +94,10 @@ public class StreamErrorTest {
"</appSpecificElement>" +
"</stream:error>" +
"</stream:stream>";
try {
XmlPullParser parser = PacketParserUtils.getParserFor(xml, "error");
error = PacketParserUtils.parseStreamError(parser);
} catch (Exception e) {
fail(e.getMessage());
}
XmlPullParser parser = SmackTestUtil.getParserFor(xml, "error", parserKind);
StreamError error = PacketParserUtils.parseStreamError(parser);
assertNotNull(error);
assertEquals(Condition.conflict, error.getCondition());
assertEquals("Replaced by new connection", error.getDescriptiveText());
@ -104,21 +105,20 @@ public class StreamErrorTest {
assertNotNull(appSpecificElement);
}
@Test
public void testStreamErrorXmlNotWellFormed() {
StreamError error = null;
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testStreamErrorXmlNotWellFormed(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException, SmackParsingException {
final String xml =
// Usually the stream:stream element has more attributes (to, version, ...)
// We omit those, since they are not relevant for testing
"<stream:stream from='im.example.com' id='++TR84Sm6A3hnt3Q065SnAbbk3Y=' xmlns:stream='http://etherx.jabber.org/streams'>" +
"<stream:error><xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/></stream:error>" +
"</stream:stream>";
try {
XmlPullParser parser = PacketParserUtils.getParserFor(xml, "error");
error = PacketParserUtils.parseStreamError(parser);
} catch (Exception e) {
fail(e.getMessage());
}
XmlPullParser parser = SmackTestUtil.getParserFor(xml, "error", parserKind);
StreamError error = PacketParserUtils.parseStreamError(parser);
assertNotNull(error);
assertEquals(Condition.not_well_formed, error.getCondition());
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright © 2014 Florian Schmaus
* Copyright © 2014-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,7 +19,7 @@ package org.jivesoftware.smack.packet;
public class TestIQ extends SimpleIQ {
public TestIQ() {
this(null, null);
this("https://igniterealtime.org/projects/smack", "test-iq");
}
public TestIQ(String element, String namespace) {

View file

@ -27,11 +27,11 @@ import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
public class ParsingExceptionTest {
@ -39,6 +39,7 @@ public class ParsingExceptionTest {
"<extension2 xmlns='namespace'>" +
"<bar node='testNode'>" +
"<i id='testid1'>" +
"text content" +
"</i>" +
"</bar>" +
"</extension2>";
@ -57,8 +58,7 @@ public class ParsingExceptionTest {
public void consumeUnparsedInput() throws Exception {
final String MESSAGE_EXCEPTION_ELEMENT =
"<" + ThrowException.ELEMENT + " xmlns='" + ThrowException.NAMESPACE + "'>" +
"<nothingInHere>" +
"</nothingInHere>" +
"<nothingInHere/>" +
"</" + ThrowException.ELEMENT + ">";
XmlPullParser parser = TestUtils.getMessageParser(
"<message from='user@server.example' to='francisco@denmark.lit' id='foo'>" +

View file

@ -22,10 +22,10 @@ import java.util.Collection;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.util.FileUtils;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.junit.Assert;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
public class ProviderConfigTest {

View file

@ -21,9 +21,9 @@ import static org.junit.Assert.assertTrue;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
public class ProviderManagerTest {

View file

@ -1,6 +1,6 @@
/**
*
* Copyright © 2014-2017 Florian Schmaus
* Copyright © 2014-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,10 +16,10 @@
*/
package org.jivesoftware.smack.sasl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
@ -39,14 +39,14 @@ public class DigestMd5SaslTest extends AbstractSaslTest {
super(saslMechanism);
}
protected void runTest(boolean useAuthzid) throws SmackException, InterruptedException, XmppStringprepException, UnsupportedEncodingException {
protected void runTest(boolean useAuthzid) throws SmackException, InterruptedException, XmppStringprepException {
EntityBareJid authzid = null;
if (useAuthzid) {
authzid = JidCreate.entityBareFrom("shazbat@xmpp.org");
}
saslMechanism.authenticate("florian", "irrelevant", JidCreate.domainBareFrom("xmpp.org"), "secret", authzid, null);
byte[] response = saslMechanism.evaluateChallenge(challengeBytes);
String responseString = new String(response, StringUtils.UTF8);
String responseString = new String(response, StandardCharsets.UTF_8);
String[] responseParts = responseString.split(",");
Map<String, String> responsePairs = new HashMap<String, String>();
for (String part : responseParts) {

View file

@ -18,6 +18,7 @@ package org.jivesoftware.smack.test.util;
import java.util.Base64;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.util.stringencoder.Base64.Encoder;
/**
@ -27,6 +28,7 @@ import org.jivesoftware.smack.util.stringencoder.Base64.Encoder;
public class SmackTestSuite {
static {
SmackConfiguration.getVersion();
org.jivesoftware.smack.util.stringencoder.Base64.setEncoder(new Encoder() {
@Override

View file

@ -0,0 +1,165 @@
/**
*
* Copyright 2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smack.test.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.util.function.Predicate;
import javax.xml.namespace.QName;
import org.jivesoftware.smack.packet.Element;
import org.jivesoftware.smack.parsing.SmackParsingException;
import org.jivesoftware.smack.provider.Provider;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jivesoftware.smack.xml.XmlPullParserFactory;
import org.jivesoftware.smack.xml.stax.StaxXmlPullParserFactory;
import org.jivesoftware.smack.xml.xpp3.Xpp3XmlPullParserFactory;
public class SmackTestUtil {
@SuppressWarnings("ImmutableEnumChecker")
public enum XmlPullParserKind {
StAX(StaxXmlPullParserFactory.class),
XPP3(Xpp3XmlPullParserFactory.class),
;
public final XmlPullParserFactory factory;
XmlPullParserKind(Class<? extends XmlPullParserFactory> factoryClass) {
try {
factory = factoryClass.getDeclaredConstructor().newInstance();
}
catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
throw new AssertionError(e);
}
}
}
public static <E extends Element, P extends Provider<E>> E parse(CharSequence xml, Class<P> providerClass, XmlPullParserKind parserKind)
throws XmlPullParserException, IOException, SmackParsingException {
P provider = providerClassToProvider(providerClass);
return parse(xml, provider, parserKind);
}
public static <E extends Element, P extends Provider<E>> E parse(InputStream inputStream, Class<P> providerClass, XmlPullParserKind parserKind)
throws XmlPullParserException, IOException, SmackParsingException {
P provider = providerClassToProvider(providerClass);
return parse(inputStream, provider, parserKind);
}
public static <E extends Element, P extends Provider<E>> E parse(Reader reader, Class<P> providerClass, XmlPullParserKind parserKind)
throws XmlPullParserException, IOException, SmackParsingException {
P provider = providerClassToProvider(providerClass);
return parse(reader, provider, parserKind);
}
public static <E extends Element> E parse(CharSequence xml, Provider<E> provider, XmlPullParserKind parserKind)
throws XmlPullParserException, IOException, SmackParsingException {
String xmlString = xml.toString();
Reader reader = new StringReader(xmlString);
return parse(reader, provider, parserKind);
}
public static <E extends Element> E parse(InputStream inputStream, Provider<E> provider, XmlPullParserKind parserKind)
throws XmlPullParserException, IOException, SmackParsingException {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
return parse(inputStreamReader, provider, parserKind);
}
public static <E extends Element> E parse(Reader reader, Provider<E> provider, XmlPullParserKind parserKind)
throws XmlPullParserException, IOException, SmackParsingException {
XmlPullParser parser = getParserFor(reader, parserKind);
E element = provider.parse(parser);
return element;
}
public static XmlPullParser getParserFor(String xml, XmlPullParserKind parserKind) throws XmlPullParserException, IOException {
Reader reader = new StringReader(xml);
return getParserFor(reader, parserKind);
}
public static XmlPullParser getParserFor(InputStream inputStream, XmlPullParserKind parserKind) throws XmlPullParserException, IOException {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
return getParserFor(inputStreamReader, parserKind);
}
public static XmlPullParser getParserFor(Reader reader, XmlPullParserKind parserKind) throws XmlPullParserException, IOException {
XmlPullParser parser = parserKind.factory.newXmlPullParser(reader);
forwardParserToStartElement(parser);
return parser;
}
public static XmlPullParser getParserFor(String xml, QName startTagQName, XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
XmlPullParser parser = getParserFor(xml, parserKind);
forwardParserToStartElement(parser, (p) -> p.getQName().equals(startTagQName));
return parser;
}
public static XmlPullParser getParserFor(String xml, String startTagLocalpart, XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
XmlPullParser parser = getParserFor(xml, parserKind);
forwardParserToStartElement(parser, (p) -> p.getName().equals(startTagLocalpart));
return parser;
}
private static <E extends Element, P extends Provider<E>> P providerClassToProvider(Class<P> providerClass) {
P provider;
// TODO: Consider adding a shortcut in case there is a static INSTANCE field holding an instance of the
// requested provider.
try {
provider = providerClass.getDeclaredConstructor().newInstance();
}
catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
throw new AssertionError(e);
}
return provider;
}
private static void forwardParserToStartElement(XmlPullParser parser) throws XmlPullParserException, IOException {
forwardParserToStartElement(parser, p -> true);
}
private static void forwardParserToStartElement(XmlPullParser parser,
Predicate<XmlPullParser> doneForwarding) throws XmlPullParserException, IOException {
outerloop: while (true) {
XmlPullParser.Event event = parser.getEventType();
switch (event) {
case START_ELEMENT:
if (doneForwarding.test(parser)) {
break outerloop;
}
break;
case END_DOCUMENT:
throw new IllegalArgumentException("Not matching START_ELEMENT found");
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
parser.next();
}
}
}

View file

@ -20,14 +20,11 @@ import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.util.ParserUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.jivesoftware.smack.xml.SmackXmlParser;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
// TODO: Remove this class and replace it with SmackTestUtil.
public final class TestUtils {
private TestUtils() {
}
@ -52,12 +49,12 @@ public final class TestUtils {
return getParser(new StringReader(string), startTag);
}
public static XmlPullParser getParser(Reader reader, String startTag) {
private static XmlPullParser getParser(Reader reader, String startTag) {
XmlPullParser parser;
try {
parser = PacketParserUtils.newXmppParser(reader);
parser = SmackXmlParser.newXmlParser(reader);
if (startTag == null) {
while (parser.getEventType() != XmlPullParser.START_TAG) {
while (parser.getEventType() != XmlPullParser.Event.START_ELEMENT) {
parser.next();
}
return parser;
@ -65,7 +62,7 @@ public final class TestUtils {
boolean found = false;
while (!found) {
if ((parser.next() == XmlPullParser.START_TAG) && parser.getName().equals(startTag))
if ((parser.next() == XmlPullParser.Event.START_ELEMENT) && parser.getName().equals(startTag))
found = true;
}
@ -79,17 +76,4 @@ public final class TestUtils {
return parser;
}
public static <EE extends ExtensionElement> EE parseExtensionElement(String elementString)
throws Exception {
return parseExtensionElement(getParser(elementString), null);
}
@SuppressWarnings("unchecked")
public static <EE extends ExtensionElement> EE parseExtensionElement(XmlPullParser parser, XmlEnvironment outerXmlEnvironment)
throws Exception {
ParserUtils.assertAtStartTag(parser);
final String elementName = parser.getName();
final String namespace = parser.getNamespace();
return (EE) PacketParserUtils.parseExtensionElement(elementName, namespace, parser, outerXmlEnvironment);
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2014-2018 Florian Schmaus
* Copyright 2014-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,24 +16,36 @@
*/
package org.jivesoftware.smack.test.util;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import java.io.StringReader;
import java.io.IOException;
import javax.xml.transform.stream.StreamSource;
import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier;
import org.xml.sax.SAXException;
import org.xmlunit.assertj.CompareAssert;
import org.xmlunit.assertj.XmlAssert;
import org.xmlunit.diff.DefaultNodeMatcher;
import org.xmlunit.diff.ElementSelectors;
import org.xmlunit.input.NormalizedSource;
// TODO: Rename this class to XmlAssertUtil
public class XmlUnitUtils {
// TOOD: Remove this method.
public static void assertSimilar(CharSequence expected, CharSequence actual) throws SAXException, IOException {
assertXmlSimilar(expected, actual);
public static void assertXmlNotSimilar(CharSequence xmlOne, CharSequence xmlTwo) {
normalizedCompare(xmlOne, xmlTwo).areNotSimilar();
}
public static void assertXmlSimilar(CharSequence expected, CharSequence actual) throws SAXException, IOException {
Diff diff = new Diff(expected.toString(), actual.toString());
diff.overrideElementQualifier(new RecursiveElementNameAndTextQualifier());
assertXMLEqual(diff, true);
public static void assertXmlSimilar(CharSequence expected, CharSequence actual) {
normalizedCompare(expected, actual).areSimilar();
}
private static CompareAssert normalizedCompare(CharSequence expectedCharSequence, CharSequence actualCharSequence) {
String expectedString = expectedCharSequence.toString();
String actualString = actualCharSequence.toString();
NormalizedSource expected = new NormalizedSource(new StreamSource(new StringReader(expectedString)));
NormalizedSource actual = new NormalizedSource(new StreamSource(new StringReader(actualString)));
return XmlAssert.assertThat(expected).and(actual)
.ignoreChildNodesOrder()
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndAllAttributes, ElementSelectors.byNameAndText))
.normalizeWhitespace();
}
}

View file

@ -16,8 +16,8 @@
*/
package org.jivesoftware.smack.util;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.jupiter.api.Assertions.fail;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
@ -51,6 +51,7 @@ public class MemoryLeakTestUtil {
private static final Logger LOGGER = Logger.getLogger(MemoryLeakTestUtil.class.getName());
@SuppressWarnings("UnusedVariable")
public static <M extends Manager> void noResourceLeakTest(Function<DummyConnection, M> managerSupplier)
throws XmppStringprepException, IllegalArgumentException, InterruptedException {
final int numConnections = 10;
@ -103,10 +104,27 @@ public class MemoryLeakTestUtil {
}
private static void assertReferencesQueueSize(ReferenceQueue<?> referenceQueue, int expectedSize) throws IllegalArgumentException, InterruptedException {
final int timeout = 60000;
final int timeout = 120000;
final int maxAttempts = 3;
for (int itemsRemoved = 0; itemsRemoved < expectedSize; ++itemsRemoved) {
Reference<?> reference = referenceQueue.remove(timeout);
assertNotNull("No reference found after " + timeout + "ms", reference);
int attempt = 0;
Reference<?> reference = null;
do {
reference = referenceQueue.remove(timeout);
if (reference != null) {
break;
}
attempt++;
String message = "No reference to a gc'ed object found after " + timeout + "ms in the " + attempt
+ ". attempt.";
if (attempt >= maxAttempts) {
fail(message);
}
LOGGER.warning(message);
triggerGarbageCollection();
} while (true);
reference.clear();
}
@ -119,6 +137,7 @@ public class MemoryLeakTestUtil {
assertNull(reference);
}
@SuppressWarnings("UnusedVariable")
private static void triggerGarbageCollection() {
Object object = new Object();
WeakReference<Object> weakReference = new WeakReference<>(object);
@ -130,6 +149,8 @@ public class MemoryLeakTestUtil {
throw new AssertionError("No observed gargabe collection after " + gcCalls + " calls of System.gc()");
}
System.gc();
// TODO: Would a Thread.yield() here improve the chances of a full GC? It appears that on some systems we
// observe a partial GC here.
gcCalls++;
} while (weakReference.get() != null);

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2016 Florian Schmaus
* Copyright 2016-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -27,7 +27,7 @@ public class NetworkUtil {
private static final Logger LOGGER = Logger.getLogger(NetworkUtil.class.getName());
public static ServerSocket getSocketOnLoopback() {
public static ServerSocket getSocketOnLoopback() throws IOException {
final InetAddress loopbackAddress = InetAddress.getLoopbackAddress();
final int portMin = 1024;
final int portMax = (1 << 16) - 1;
@ -40,13 +40,12 @@ public class NetworkUtil {
break;
} catch (BindException e) {
LOGGER.log(Level.FINEST, "Could not bind port " + port + ", trying next", e);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
if (serverSocket == null) {
throw new IllegalStateException();
throw new IOException("Could not bind any port between " + portMin + " and " + portMax
+ " on loopback address" + loopbackAddress);
}
return serverSocket;

View file

@ -16,8 +16,8 @@
*/
package org.jivesoftware.smack.util;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLNotEqual;
import static org.jivesoftware.smack.test.util.XmlUnitUtils.assertXmlNotSimilar;
import static org.jivesoftware.smack.test.util.XmlUnitUtils.assertXmlSimilar;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@ -29,6 +29,8 @@ import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
@ -42,15 +44,17 @@ import org.jivesoftware.smack.packet.StreamOpen;
import org.jivesoftware.smack.sasl.SASLError;
import org.jivesoftware.smack.sasl.packet.SaslStreamElements;
import org.jivesoftware.smack.sasl.packet.SaslStreamElements.SASLFailure;
import org.jivesoftware.smack.test.util.SmackTestUtil;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.test.util.XmlUnitUtils;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
import com.jamesmurty.utils.XMLBuilder;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
public class PacketParserUtilsTest {
@ -59,8 +63,9 @@ public class PacketParserUtilsTest {
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
}
@Test
public void singleMessageBodyTest() throws Exception {
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void singleMessageBodyTest(SmackTestUtil.XmlPullParserKind parserKind) throws Exception {
String defaultLanguage = Stanza.getDefaultLanguage();
String otherLanguage = determineNonDefaultLanguage();
@ -79,13 +84,13 @@ public class PacketParserUtilsTest {
.asString(outputProperties);
Message message = PacketParserUtils
.parseMessage(PacketParserUtils.getParserFor(control));
.parseMessage(SmackTestUtil.getParserFor(control, parserKind));
assertEquals(defaultLanguage, message.getBody());
assertTrue(message.getBodyLanguages().isEmpty());
assertEquals(defaultLanguage, message.getBody(defaultLanguage));
assertNull(message.getBody(otherLanguage));
assertXMLEqual(control, message.toXML().toString());
assertXmlSimilar(control, message.toXML().toString());
// message has non-default language, body has no language
control = XMLBuilder.create("message")
@ -99,13 +104,13 @@ public class PacketParserUtilsTest {
.t(otherLanguage)
.asString(outputProperties);
message = PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(control));
message = PacketParserUtils.parseMessage(SmackTestUtil.getParserFor(control, parserKind));
assertEquals(otherLanguage, message.getBody());
assertTrue(message.getBodyLanguages().isEmpty());
assertEquals(otherLanguage, message.getBody(otherLanguage));
assertNull(message.getBody(defaultLanguage));
assertXMLEqual(control, message.toXML().toString());
assertXmlSimilar(control, message.toXML().toString());
// message has no language, body has no language
control = XMLBuilder.create("message")
@ -118,13 +123,13 @@ public class PacketParserUtilsTest {
.t(defaultLanguage)
.asString(outputProperties);
message = PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(control));
message = PacketParserUtils.parseMessage(SmackTestUtil.getParserFor(control, parserKind));
assertEquals(defaultLanguage, message.getBody());
assertTrue(message.getBodyLanguages().isEmpty());
assertEquals(defaultLanguage, message.getBody(null));
assertNull(message.getBody(otherLanguage));
assertXMLEqual(control, message.toXML().toString());
assertXmlSimilar(control, message.toXML().toString());
// message has no language, body has default language
control = XMLBuilder.create("message")
@ -138,14 +143,14 @@ public class PacketParserUtilsTest {
.t(defaultLanguage)
.asString(outputProperties);
message = PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(control));
message = PacketParserUtils.parseMessage(SmackTestUtil.getParserFor(control, parserKind));
assertNull(message.getBody());
assertFalse(message.getBodyLanguages().isEmpty());
assertEquals(defaultLanguage, message.getBody(defaultLanguage));
assertNull(message.getBody(otherLanguage));
assertXMLEqual(control, message.toXML().toString());
assertXmlSimilar(control, message.toXML().toString());
// message has no language, body has non-default language
control = XMLBuilder.create("message")
@ -159,14 +164,14 @@ public class PacketParserUtilsTest {
.t(otherLanguage)
.asString(outputProperties);
message = PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(control));
message = PacketParserUtils.parseMessage(SmackTestUtil.getParserFor(control, parserKind));
assertNull(message.getBody());
assertFalse(message.getBodyLanguages().isEmpty());
assertTrue(message.getBodyLanguages().contains(otherLanguage));
assertEquals(otherLanguage, message.getBody(otherLanguage));
assertNull(message.getBody(defaultLanguage));
assertXMLEqual(control, message.toXML().toString());
assertXmlSimilar(control, message.toXML().toString());
// message has default language, body has non-default language
control = XMLBuilder.create("message")
@ -181,14 +186,14 @@ public class PacketParserUtilsTest {
.t(otherLanguage)
.asString(outputProperties);
message = PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(control));
message = PacketParserUtils.parseMessage(SmackTestUtil.getParserFor(control, parserKind));
assertNull(message.getBody());
assertFalse(message.getBodyLanguages().isEmpty());
assertTrue(message.getBodyLanguages().contains(otherLanguage));
assertEquals(otherLanguage, message.getBody(otherLanguage));
assertNull(message.getBody(defaultLanguage));
assertXMLEqual(control, message.toXML().toString());
assertXmlSimilar(control, message.toXML().toString());
// message has non-default language, body has default language
control = XMLBuilder.create("message")
@ -203,14 +208,14 @@ public class PacketParserUtilsTest {
.t(defaultLanguage)
.asString(outputProperties);
message = PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(control));
message = PacketParserUtils.parseMessage(SmackTestUtil.getParserFor(control, parserKind));
assertNull(message.getBody());
assertFalse(message.getBodyLanguages().isEmpty());
assertTrue(message.getBodyLanguages().contains(defaultLanguage));
assertEquals(defaultLanguage, message.getBody(defaultLanguage));
assertNull(message.getBody(otherLanguage));
assertXMLEqual(control, message.toXML().toString());
assertXmlSimilar(control, message.toXML().toString());
}
@ -239,7 +244,7 @@ public class PacketParserUtilsTest {
assertTrue(message.getSubjectLanguages().isEmpty());
assertEquals(defaultLanguage, message.getSubject(defaultLanguage));
assertNull(message.getSubject(otherLanguage));
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
// message has non-default language, subject has no language
control = XMLBuilder.create("message")
@ -258,7 +263,7 @@ public class PacketParserUtilsTest {
assertTrue(message.getSubjectLanguages().isEmpty());
assertEquals(otherLanguage, message.getSubject(otherLanguage));
assertNull(message.getSubject(defaultLanguage));
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
// message has no language, subject has no language
control = XMLBuilder.create("message")
@ -276,7 +281,7 @@ public class PacketParserUtilsTest {
assertTrue(message.getSubjectLanguages().isEmpty());
assertEquals(defaultLanguage, message.getSubject(null));
assertNull(message.getSubject(otherLanguage));
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
// message has no language, subject has default language
control = XMLBuilder.create("message")
@ -295,7 +300,7 @@ public class PacketParserUtilsTest {
assertEquals(defaultLanguage, message.getSubject(defaultLanguage));
assertNull(message.getSubject(otherLanguage));
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
// message has no language, subject has non-default language
control = XMLBuilder.create("message")
@ -315,7 +320,7 @@ public class PacketParserUtilsTest {
assertTrue(message.getSubjectLanguages().contains(otherLanguage));
assertEquals(otherLanguage, message.getSubject(otherLanguage));
assertNull(message.getSubject(defaultLanguage));
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
// message has default language, subject has non-default language
control = XMLBuilder.create("message")
@ -336,7 +341,7 @@ public class PacketParserUtilsTest {
assertTrue(message.getSubjectLanguages().contains(otherLanguage));
assertEquals(otherLanguage, message.getSubject(otherLanguage));
assertNull(message.getSubject(defaultLanguage));
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
// message has non-default language, subject has default language
control = XMLBuilder.create("message")
@ -357,7 +362,7 @@ public class PacketParserUtilsTest {
assertTrue(message.getSubjectLanguages().contains(defaultLanguage));
assertEquals(defaultLanguage, message.getSubject(defaultLanguage));
assertNull(message.getSubject(otherLanguage));
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
}
@ -393,7 +398,7 @@ public class PacketParserUtilsTest {
assertEquals(2, message.getBodies().size());
assertEquals(1, message.getBodyLanguages().size());
assertTrue(message.getBodyLanguages().contains(otherLanguage));
assertXMLEqual(control, message.toXML().toString());
assertXmlSimilar(control, message.toXML().toString());
// message has non-default language, first body no language, second body default language
control = XMLBuilder.create("message")
@ -419,7 +424,7 @@ public class PacketParserUtilsTest {
assertEquals(2, message.getBodies().size());
assertEquals(1, message.getBodyLanguages().size());
assertTrue(message.getBodyLanguages().contains(defaultLanguage));
assertXMLEqual(control, message.toXML().toString());
assertXmlSimilar(control, message.toXML().toString());
}
// TODO: Re-enable once we throw an exception on duplicate body elements.
@ -452,7 +457,7 @@ public class PacketParserUtilsTest {
assertEquals(defaultLanguage, message.getBody(defaultLanguage));
assertEquals(1, message.getBodies().size());
assertEquals(0, message.getBodyLanguages().size());
assertXMLNotEqual(control, message.toXML().toString());
assertXmlNotSimilar(control, message.toXML().toString());
}
@Ignore
@ -510,7 +515,7 @@ public class PacketParserUtilsTest {
assertEquals(otherLanguage, message.getBody(otherLanguage));
assertEquals(2, message.getBodies().size());
assertEquals(1, message.getBodyLanguages().size());
assertXMLEqual(control, message.toXML().toString());
assertXmlSimilar(control, message.toXML().toString());
}
@Test
@ -544,7 +549,7 @@ public class PacketParserUtilsTest {
assertEquals(2, message.getSubjects().size());
assertEquals(1, message.getSubjectLanguages().size());
assertTrue(message.getSubjectLanguages().contains(otherLanguage));
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
// message has default language, first subject no language, second subject default language
control = XMLBuilder.create("message")
@ -568,7 +573,7 @@ public class PacketParserUtilsTest {
assertEquals(defaultLanguage, message.getSubject(defaultLanguage));
assertEquals(1, message.getSubjects().size());
assertEquals(0, message.getSubjectLanguages().size());
assertXMLNotEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlNotSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
// message has non-default language, first subject no language, second subject default language
control = XMLBuilder.create("message")
@ -593,7 +598,7 @@ public class PacketParserUtilsTest {
assertEquals(2, message.getSubjects().size());
assertEquals(1, message.getSubjectLanguages().size());
assertTrue(message.getSubjectLanguages().contains(defaultLanguage));
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
/*
// message has no language, first subject no language, second subject default language
@ -641,7 +646,7 @@ public class PacketParserUtilsTest {
assertEquals(otherLanguage, message.getSubject(otherLanguage));
assertEquals(2, message.getSubjects().size());
assertEquals(1, message.getSubjectLanguages().size());
assertXMLEqual(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertXmlSimilar(control, message.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
// message has no language, first subject no language, second subject no language
control = XMLBuilder.create("message")
@ -708,13 +713,18 @@ public class PacketParserUtilsTest {
.t("Good Message Body")
.asString(outputProperties);
// XPP3 writes "end tag", StAX writes "end-tag".
Supplier<Stream<String>> expectedContentOfExceptionMessage = () -> Stream.of("end tag", "end-tag");
String invalidControl = validControl.replace("Good Message Body", "Bad </span> Body");
try {
PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(invalidControl));
fail("Exception should be thrown");
} catch (XmlPullParserException e) {
assertTrue(e.getMessage().contains("end tag name </span>"));
String exceptionMessage = e.getMessage();
boolean expectedContentFound = expectedContentOfExceptionMessage.get().anyMatch((expected) -> exceptionMessage.contains(expected));
assertTrue(expectedContentFound);
}
invalidControl = validControl.replace("Good Message Body", "Bad </body> Body");
@ -723,7 +733,9 @@ public class PacketParserUtilsTest {
PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(invalidControl));
fail("Exception should be thrown");
} catch (XmlPullParserException e) {
assertTrue(e.getMessage().contains("end tag name </body>"));
String exceptionMessage = e.getMessage();
boolean expectedContentFound = expectedContentOfExceptionMessage.get().anyMatch((expected) -> exceptionMessage.contains(expected));
assertTrue(expectedContentFound);
}
invalidControl = validControl.replace("Good Message Body", "Bad </message> Body");
@ -732,9 +744,10 @@ public class PacketParserUtilsTest {
PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(invalidControl));
fail("Exception should be thrown");
} catch (XmlPullParserException e) {
assertTrue(e.getMessage().contains("end tag name </message>"));
String exceptionMessage = e.getMessage();
boolean expectedContentFound = expectedContentOfExceptionMessage.get().anyMatch((expected) -> exceptionMessage.contains(expected));
assertTrue(expectedContentFound);
}
}
@Test
@ -763,58 +776,52 @@ public class PacketParserUtilsTest {
.asString(outputProperties);
Stanza message = PacketParserUtils.parseStanza(control);
XmlUnitUtils.assertSimilar(control, message.toXML());
assertXmlSimilar(control, message.toXML());
}
@Test
public void validateSimplePresence() throws Exception {
// CHECKSTYLE:OFF
String stanza = "<presence from='juliet@example.com/balcony' to='romeo@example.net'/>";
String stanza = "<presence from='juliet@example.com/balcony' to='romeo@example.net'/>";
Presence presence = PacketParserUtils.parsePresence(PacketParserUtils.getParserFor(stanza));
Presence presence = PacketParserUtils.parsePresence(PacketParserUtils.getParserFor(stanza));
assertXMLEqual(stanza, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
// CHECKSTYLE:ON
assertXmlSimilar(stanza, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
}
@Test
public void validatePresenceProbe() throws Exception {
// CHECKSTYLE:OFF
String stanza = "<presence from='mercutio@example.com' id='xv291f38' to='juliet@example.com' type='unsubscribed'/>";
String stanza = "<presence from='mercutio@example.com' id='xv291f38' to='juliet@example.com' type='unsubscribed'/>";
Presence presence = PacketParserUtils.parsePresence(PacketParserUtils.getParserFor(stanza));
Presence presence = PacketParserUtils.parsePresence(PacketParserUtils.getParserFor(stanza));
assertXMLEqual(stanza, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertEquals(Presence.Type.unsubscribed, presence.getType());
// CHECKSTYLE:ON
assertXmlSimilar(stanza, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertEquals(Presence.Type.unsubscribed, presence.getType());
}
@Test
public void validatePresenceOptionalElements() throws Exception {
// CHECKSTYLE:OFF
String stanza = "<presence xml:lang='en' type='unsubscribed'>"
+ "<show>dnd</show>"
+ "<status>Wooing Juliet</status>"
+ "<priority>1</priority>"
+ "</presence>";
String stanza = "<presence xml:lang='en' type='unsubscribed'>"
+ "<show>dnd</show>"
+ "<status>Wooing Juliet</status>"
+ "<priority>1</priority>"
+ "</presence>";
Presence presence = PacketParserUtils.parsePresence(PacketParserUtils.getParserFor(stanza));
assertXMLEqual(stanza, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertEquals(Presence.Type.unsubscribed, presence.getType());
assertEquals("dnd", presence.getMode().name());
assertEquals("en", presence.getLanguage());
assertEquals("Wooing Juliet", presence.getStatus());
assertEquals(1, presence.getPriority());
// CHECKSTYLE:ON
Presence presence = PacketParserUtils.parsePresence(PacketParserUtils.getParserFor(stanza));
assertXmlSimilar(stanza, presence.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
assertEquals(Presence.Type.unsubscribed, presence.getType());
assertEquals("dnd", presence.getMode().name());
assertEquals("en", presence.getLanguage());
assertEquals("Wooing Juliet", presence.getStatus());
assertEquals(1, presence.getPriority());
}
@Test
public void parseContentDepthTest() throws Exception {
final String stanza = "<iq type='result' to='foo@bar.com' from='baz.com' id='42'/>";
XmlPullParser parser = TestUtils.getParser(stanza, "iq");
CharSequence content = PacketParserUtils.parseContent(parser);
assertEquals("", content.toString());
}
// @Test
// public void parseContentDepthTest() throws Exception {
// final String stanza = "<iq type='result' to='foo@bar.com' from='baz.com' id='42'/>";
// XmlPullParser parser = TestUtils.getParser(stanza, "iq");
// CharSequence content = PacketParserUtils.parseContent(parser);
// assertEquals("", content.toString());
// }
@Test
public void parseElementMultipleNamespace()
@ -830,7 +837,7 @@ public class PacketParserUtilsTest {
// @formatter:on
XmlPullParser parser = TestUtils.getParser(stanza, "outer");
CharSequence result = PacketParserUtils.parseElement(parser, true);
assertXMLEqual(stanza, result.toString());
assertXmlSimilar(stanza, result.toString());
}
@Test
@ -843,7 +850,7 @@ public class PacketParserUtilsTest {
// @formatter:on
XmlPullParser parser = TestUtils.getParser(saslFailureString, SASLFailure.ELEMENT);
SASLFailure saslFailure = PacketParserUtils.parseSASLFailure(parser);
assertXMLEqual(saslFailureString, saslFailure.toString());
assertXmlSimilar(saslFailureString, saslFailure.toString());
}
@Test
@ -865,7 +872,7 @@ public class PacketParserUtilsTest {
// @formatter:on
XmlPullParser parser = TestUtils.getParser(saslFailureString, SASLFailure.ELEMENT);
SASLFailure saslFailure = PacketParserUtils.parseSASLFailure(parser);
XmlUnitUtils.assertSimilar(saslFailureString, saslFailure.toXML(StreamOpen.CLIENT_NAMESPACE));
assertXmlSimilar(saslFailureString, saslFailure.toXML(StreamOpen.CLIENT_NAMESPACE));
}
@SuppressWarnings("ReferenceEquality")
@ -909,7 +916,7 @@ public class PacketParserUtilsTest {
.element("internal-server-error", StanzaError.ERROR_CONDITION_AND_TEXT_NAMESPACE).up()
.element("text", StanzaError.ERROR_CONDITION_AND_TEXT_NAMESPACE).t(text).up()
.asString();
XmlUnitUtils.assertSimilar(errorXml, error.toXML(StreamOpen.CLIENT_NAMESPACE));
assertXmlSimilar(errorXml, error.toXML(StreamOpen.CLIENT_NAMESPACE));
}
@Test

View file

@ -21,7 +21,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import org.junit.Test;
@ -31,11 +31,9 @@ import org.junit.Test;
public class StringUtilsTest {
@Test
public void testEscapeForXml() {
String input = null;
assertNull(StringUtils.escapeForXml(null));
input = "<b>";
String input = "<b>";
assertCharSequenceEquals("&lt;b&gt;", StringUtils.escapeForXml(input));
input = "\"";
@ -74,15 +72,15 @@ public class StringUtilsTest {
}
@Test
public void testEncodeHex() throws UnsupportedEncodingException {
public void testEncodeHex() {
String input = "";
String output = "";
assertEquals(new String(StringUtils.encodeHex(input.getBytes(StringUtils.UTF8))),
assertEquals(new String(StringUtils.encodeHex(input.getBytes(StandardCharsets.UTF_8))),
output);
input = "foo bar 123";
output = "666f6f2062617220313233";
assertEquals(new String(StringUtils.encodeHex(input.getBytes(StringUtils.UTF8))),
assertEquals(new String(StringUtils.encodeHex(input.getBytes(StandardCharsets.UTF_8))),
output);
}

View file

@ -0,0 +1,231 @@
/**
*
* Copyright 2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smack.xml;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.stream.Stream;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import org.jivesoftware.smack.test.util.SmackTestUtil;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
public class XmlPullParserTest {
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testSimpleEmptyElement(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
Reader reader = new StringReader("<empty-element/>");
XmlPullParser parser = parserKind.factory.newXmlPullParser(reader);
assertEquals(XmlPullParser.Event.START_DOCUMENT, parser.getEventType());
assertEquals(XmlPullParser.Event.START_ELEMENT, parser.next());
QName qname = parser.getQName();
assertEquals(qname.getLocalPart(), "empty-element");
assertEquals(qname.getPrefix(), XMLConstants.DEFAULT_NS_PREFIX);
assertEquals(qname.getNamespaceURI(), XMLConstants.NULL_NS_URI);
assertEquals(XmlPullParser.Event.END_ELEMENT, parser.next());
assertEquals(XmlPullParser.Event.END_DOCUMENT, parser.next());
}
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testQNameSimpleElement(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
String simpleElement = "<outer-element xmlns='outer-namespace'><inner-element/></outer-element>";
XmlPullParser parser = SmackTestUtil.getParserFor(simpleElement, parserKind);
QName qname = parser.getQName();
assertEquals("outer-element", qname.getLocalPart());
assertEquals("outer-namespace", qname.getNamespaceURI());
assertEquals(XmlPullParser.Event.START_ELEMENT, parser.next());
qname = parser.getQName();
assertEquals("inner-element", qname.getLocalPart());
assertEquals("outer-namespace", qname.getNamespaceURI());
}
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testQNamePrefixElement(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
String prefixElement = "<outer-element xmlns='outer-namespace' xmlns:inner-prefix='inner-namespace'><inner-prefix:inner-element></outer-element>";
XmlPullParser parser = SmackTestUtil.getParserFor(prefixElement, parserKind);
QName qname = parser.getQName();
assertEquals("outer-element", qname.getLocalPart());
assertEquals("outer-namespace", qname.getNamespaceURI());
assertEquals(XmlPullParser.Event.START_ELEMENT, parser.next());
qname = parser.getQName();
assertEquals("inner-element", qname.getLocalPart());
assertEquals("inner-namespace", qname.getNamespaceURI());
}
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testAttributesElementWithOneAttribute(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
String elementWithOneAttribute = "<element attribute-one='attribute-one-value'/>";
XmlPullParser parser = SmackTestUtil.getParserFor(elementWithOneAttribute, parserKind);
assertAttributeHolds(parser, 0, "attribute-one", "", "");
assertThrows(NullPointerException.class, () ->
assertAttributeHolds(parser, 1, "attribute-one", "", ""));
}
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testAttributesNamespacedElementWithOneAttribute(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
String namespacedElementWithOneAttribute = "<element xmlns='element-namespace' attribute-one='attribute-one-value'/>";
XmlPullParser parser = SmackTestUtil.getParserFor(namespacedElementWithOneAttribute, parserKind);
assertAttributeHolds(parser, 0, "attribute-one", "", "");
assertThrows(NullPointerException.class, () ->
assertAttributeHolds(parser, 1, "attribute-one", "", ""));
}
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testAttributesNamespacedElementWithOneNamespacedAttribute(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
String namespacedElementWithOneNamespacedAttribute = "<element xmlns='element-namespace' xmlns:attribute-namespace='attribute-namespace-value' attribute-namespace:attribute-one='attribute-one-value'/>";
XmlPullParser parser = SmackTestUtil.getParserFor(namespacedElementWithOneNamespacedAttribute, parserKind);
assertAttributeHolds(parser, 0, "attribute-one", "attribute-namespace", "attribute-namespace-value");
assertThrows(NullPointerException.class, () ->
assertAttributeHolds(parser, 1, "attribute-one", "", ""));
}
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testNamespacedAttributes(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
String element = "<element xmlns:attr='attribute-namespace' attr:attributeOneName='attributeOneValue'/>";
XmlPullParser parser = SmackTestUtil.getParserFor(element, parserKind);
assertEquals(1, parser.getAttributeCount());
assertEquals("attributeOneName", parser.getAttributeName(0));
assertEquals("attr", parser.getAttributePrefix(0));
assertEquals("attribute-namespace", parser.getAttributeNamespace(0));
QName attributeZeroQname = parser.getAttributeQName(0);
assertEquals("attributeOneName", attributeZeroQname.getLocalPart());
assertEquals("attr", attributeZeroQname.getPrefix());
assertEquals("attribute-namespace", attributeZeroQname.getNamespaceURI());
// Test how parser handle non-existent attributes.
assertNull(parser.getAttributeName(1));
assertNull(parser.getAttributePrefix(1));
assertNull(parser.getAttributeNamespace(1));
QName attributeOneQname = parser.getAttributeQName(1);
assertNull(attributeOneQname);
}
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testAttributeType(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
String element = "<element xmlns:attr='attribute-namespace' attr:attributeOneName='attributeOneValue'/>";
XmlPullParser parser = SmackTestUtil.getParserFor(element, parserKind);
assertEquals("CDATA", parser.getAttributeType(0));
assertNull(parser.getAttributeType(1));
}
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testNextText(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
XmlPullParser parser;
String simpleElement = "<element>Element text</element>";
parser = SmackTestUtil.getParserFor(simpleElement, parserKind);
assertEquals("Element text", parser.nextText());
String complexElement = "<outer-elment><element1>Element 1 &apos; text</element1><element2>Element 2 text</element2></outer-element>";
parser = SmackTestUtil.getParserFor(complexElement, parserKind);
assertEquals(XmlPullParser.Event.START_ELEMENT, parser.next());
assertEquals("element1", parser.getName());
assertEquals(0, parser.getAttributeCount());
assertEquals("Element 1 ' text", parser.nextText());
assertEquals(XmlPullParser.Event.START_ELEMENT, parser.next());
assertEquals("element2", parser.getName());
assertEquals(0, parser.getAttributeCount());
assertEquals("Element 2 text", parser.nextText());
}
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testNextTextMixedContent(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
String element = "<element>Mixed content element text<inner-element>Inner element text</inner-element></element>";
XmlPullParser parser = SmackTestUtil.getParserFor(element, parserKind);
assertThrows(XmlPullParserException.class, () -> parser.nextText());
}
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testNextTextOnEndElement(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
String element = "<element>Element text</element>";
XmlPullParser parser = SmackTestUtil.getParserFor(element, parserKind);
assertEquals(XmlPullParser.Event.START_ELEMENT, parser.getEventType());
assertEquals(XmlPullParser.Event.TEXT_CHARACTERS, parser.next());
assertEquals(XmlPullParser.Event.END_ELEMENT, parser.next());
assertThrows(XmlPullParserException.class, () -> parser.nextText());
}
@ParameterizedTest
@EnumSource(SmackTestUtil.XmlPullParserKind.class)
public void testNextTextOnEmptyElement(SmackTestUtil.XmlPullParserKind parserKind)
throws XmlPullParserException, IOException {
String[] emptyElementStream = Stream.of().toArray(String[]::new);
for (String emptyElement : emptyElementStream) {
XmlPullParser parser = SmackTestUtil.getParserFor(emptyElement, parserKind);
assertEquals(XmlPullParser.Event.START_ELEMENT, parser.getEventType());
assertEquals("", parser.nextText());
}
}
private static void assertAttributeHolds(XmlPullParser parser, int attributeIndex, String expectedLocalpart,
String expectedPrefix, String expectedNamespace) {
QName qname = parser.getAttributeQName(attributeIndex);
String qnameNamespaceUri = qname.getNamespaceURI();
assertEquals(expectedLocalpart, qname.getLocalPart());
assertEquals(expectedPrefix, qname.getPrefix());
assertEquals(expectedNamespace, qnameNamespaceUri);
assertEquals(qname.getLocalPart(), parser.getAttributeName(attributeIndex));
assertEquals(qname.getPrefix(), parser.getAttributePrefix(attributeIndex));
final String expectedGetAttributeNamespace;
if (qnameNamespaceUri.equals(XMLConstants.NULL_NS_URI)) {
expectedGetAttributeNamespace = null;
}
else {
expectedGetAttributeNamespace = qnameNamespaceUri;
}
assertEquals(expectedGetAttributeNamespace, parser.getAttributeNamespace(attributeIndex));
}
}

View file

@ -257,11 +257,9 @@ public class EnhancedDebugger extends SmackDebugger {
new DefaultTableModel(
new Object[] {"Hide", "Timestamp", "", "", "Message", "Id", "Type", "To", "From"},
0) {
// CHECKSTYLE:OFF
private static final long serialVersionUID = 8136121224474217264L;
@Override
private static final long serialVersionUID = 8136121224474217264L;
@Override
public boolean isCellEditable(int rowIndex, int mColIndex) {
// CHECKSTYLE:ON
return false;
}
@ -689,11 +687,9 @@ public class EnhancedDebugger extends SmackDebugger {
new DefaultTableModel(new Object[][] { {"IQ", 0, 0}, {"Message", 0, 0},
{"Presence", 0, 0}, {"Other", 0, 0}, {"Total", 0, 0}},
new Object[] {"Type", "Received", "Sent"}) {
// CHECKSTYLE:OFF
private static final long serialVersionUID = -6793886085109589269L;
@Override
private static final long serialVersionUID = -6793886085109589269L;
@Override
public boolean isCellEditable(int rowIndex, int mColIndex) {
// CHECKSTYLE:ON
return false;
}
};

View file

@ -346,6 +346,7 @@ public final class EnhancedDebuggerWindow {
*
* @param evt the event that indicates that the root window is closing
*/
@SuppressWarnings("UnusedVariable")
private synchronized void rootWindowClosing(WindowEvent evt) {
// Notify to all the debuggers to stop debugging
for (EnhancedDebugger debugger : debuggers) {

View file

@ -21,15 +21,14 @@ import java.io.IOException;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.parsing.SmackParsingException;
import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jivesoftware.smackx.carbons.packet.CarbonExtension;
import org.jivesoftware.smackx.carbons.packet.CarbonExtension.Direction;
import org.jivesoftware.smackx.forward.packet.Forwarded;
import org.jivesoftware.smackx.forward.provider.ForwardedProvider;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
/**
* This class implements the {@link ExtensionElementProvider} to parse
* carbon copied messages from a packet. It will return a {@link CarbonExtension} stanza extension.
@ -48,11 +47,11 @@ public class CarbonManagerProvider extends ExtensionElementProvider<CarbonExtens
boolean done = false;
while (!done) {
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG && parser.getName().equals("forwarded")) {
XmlPullParser.Event eventType = parser.next();
if (eventType == XmlPullParser.Event.START_ELEMENT && parser.getName().equals("forwarded")) {
fwd = FORWARDED_PROVIDER.parse(parser);
}
else if (eventType == XmlPullParser.END_TAG && dir == Direction.valueOf(parser.getName()))
else if (eventType == XmlPullParser.Event.END_ELEMENT && dir == Direction.valueOf(parser.getName()))
done = true;
}
if (fwd == null) {

View file

@ -42,6 +42,7 @@ import org.jivesoftware.smack.filter.StanzaExtensionFilter;
import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smackx.chat_markers.element.ChatMarkersElements;
import org.jivesoftware.smackx.chat_markers.filter.ChatMarkersFilter;
import org.jivesoftware.smackx.chat_markers.filter.EligibleForChatMarkerFilter;

View file

@ -20,6 +20,7 @@ import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smackx.chat_markers.ChatMarkersState;
/**

View file

@ -18,6 +18,7 @@ package org.jivesoftware.smackx.chat_markers.filter;
import org.jivesoftware.smack.filter.StanzaExtensionFilter;
import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smackx.chat_markers.element.ChatMarkersElements;
/**

View file

@ -19,6 +19,7 @@ package org.jivesoftware.smackx.chat_markers.filter;
import org.jivesoftware.smack.filter.StanzaExtensionFilter;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smackx.chatstates.ChatState;
import org.jivesoftware.smackx.chatstates.ChatStateManager;

Some files were not shown because too many files have changed in this diff Show more