From 1e5d34eacf9a84f6dc2b5e918274d587bd35c030 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 25 Sep 2024 11:43:47 +0200 Subject: [PATCH] Bump to Gradle 8.10.2, require Java 11 Bump Gradle from 6.8.3 to 8.10.2 and increase the minimum required Java version from 8 to 11 (SMACK-953). The switch from Java 8 to 11 caused some Bytecode portability issues regarding NIO Buffers. Java changed with version 9 the return type of some subclasses of Buffer to return the specific Buffer type instead of the Buffer superclass [JDK-4774077]. For example, ByteBuffer.filp() previously returned Buffer, while it does return ByteBuffer now. This sensible change was not reflected by the Android API [1], which means that AnimalSniffer rightfully started to complain that there is no method "ByteBuffer ByteBuffer.flip()" in Android, there is only "Buffer ByteBuffer.flip()", and those are incompatible methods on Java's Bytecode layer. As workaround, this changes return charBuffer.flip().toString(); to ((java.nio.Buffer) charBuffer).flip(); return charBuffer.toString(); to restore the Bytecode portability between Android and Java. Errorprone also got new checks, of which JavaUtilDate and JdkObsolete are wroth mentioning. JavaUtilData basically strongly recommends to use Java's newer time API over java.util.Date. But since Smack was Java 8 until now, j.u.Date is widely used. Similar JdkObsolete mentions obsolete JDK APIs, like data structures like Vector and Stack. But mostly LinkedList, which should usually be replaced by ArrayList. And this is what this commit largely does. JDK-4774077: https://bugs.openjdk.org/browse/JDK-4774077 1: https://issuetracker.google.com/issues/369219141 --- .github/workflows/ci.yml | 32 +- Makefile | 30 + build-logic/build.gradle | 16 + build-logic/settings.gradle | 1 + ....android-boot-classpath-conventions.gradle | 6 + ...erealtime.smack.android-conventions.gradle | 10 + ...ltime.smack.application-conventions.gradle | 12 + ...terealtime.smack.global-conventions.gradle | 37 + ...ltime.smack.java-common-conventions.gradle | 373 ++++++++++ ...erealtime.smack.javadoc-conventions.gradle | 30 + build.gradle | 690 +----------------- gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 297 +++++--- gradlew.bat | 37 +- repl | 11 +- resources/releasedocs/README.html | 221 ------ settings.gradle | 4 + smack-android-extensions/build.gradle | 8 +- smack-android/build.gradle | 20 +- smack-bosh/build.gradle | 5 + smack-core/build.gradle | 13 +- .../smack/AbstractXMPPConnection.java | 15 +- .../jivesoftware/smack/ScheduledAction.java | 4 +- .../org/jivesoftware/smack/SmackReactor.java | 3 +- .../jivesoftware/smack/StanzaCollector.java | 12 +- .../jivesoftware/smack/XMPPConnection.java | 2 + .../ModularXmppClientToServerConnection.java | 2 +- .../zlib/ZlibXmppCompressionFactory.java | 16 +- .../smack/debugger/ConsoleDebugger.java | 1 + .../smack/initializer/UrlInitializer.java | 6 +- .../smack/packet/AbstractError.java | 3 +- .../jivesoftware/smack/packet/Mechanisms.java | 6 +- .../packet/StandardExtensionElement.java | 4 +- .../jivesoftware/smack/packet/StanzaView.java | 6 +- .../smack/provider/ProviderFileLoader.java | 10 +- .../smack/provider/ProviderManager.java | 4 +- .../smack/sasl/core/ScramMechanism.java | 1 + .../org/jivesoftware/smack/util/MultiMap.java | 5 +- .../smack/util/PacketParserUtils.java | 7 +- .../jivesoftware/smack/util/PacketUtil.java | 4 +- .../org/jivesoftware/smack/util/Pair.java | 3 +- .../jivesoftware/smack/util/StringUtils.java | 5 +- .../smack/util/XmppElementUtil.java | 1 + .../jivesoftware/smack/DummyConnection.java | 4 +- smack-debug-slf4j/build.gradle | 4 + smack-debug/build.gradle | 4 + .../smackx/debugger/EnhancedDebugger.java | 3 + .../debugger/EnhancedDebuggerWindow.java | 2 +- smack-examples/build.gradle | 4 + .../smack/examples/XmppTools.java | 3 +- smack-experimental/build.gradle | 5 + .../iot/data/element/IoTFieldsExtension.java | 1 + .../element/JingleFileTransferChild.java | 3 +- .../jivesoftware/smackx/mam/MamManager.java | 4 +- .../spoiler/element/SpoilerElement.java | 1 + .../element/TimestampAffixElement.java | 1 + .../jivesoftware/smackx/mam/FiltersTest.java | 4 +- smack-extensions/build.gradle | 5 + .../ibb/InBandBytestreamManager.java | 6 +- .../socks5/Socks5BytestreamManager.java | 5 +- .../bytestreams/socks5/Socks5Proxy.java | 6 +- .../smackx/caps/EntityCapsManager.java | 6 +- .../smackx/disco/ServiceDiscoveryManager.java | 3 +- .../smackx/disco/packet/DiscoverInfo.java | 3 +- .../smackx/disco/packet/DiscoverItems.java | 4 +- .../provider/RegistrationProvider.java | 4 +- .../smackx/iqversion/packet/Version.java | 4 +- .../last_interaction/element/IdleElement.java | 1 + .../smackx/muc/MucEnterConfiguration.java | 2 - .../smackx/muc/MultiUserChat.java | 4 +- .../smackx/muc/MultiUserChatManager.java | 1 + .../smackx/pubsub/ItemPublishEvent.java | 1 + .../smackx/pubsub/packet/PubSub.java | 2 +- .../jivesoftware/smackx/rsm/RSMManager.java | 8 +- .../si/provider/StreamInitiationProvider.java | 1 + .../smackx/caps/EntityCapsManagerTest.java | 6 +- .../java/org/jivesoftware/util/Protocol.java | 1 + smack-im/build.gradle | 8 + .../jivesoftware/smack/roster/RosterUtil.java | 4 +- smack-integration-test/build.gradle | 16 +- .../smack/inttest/Configuration.java | 6 +- .../SmackIntegrationTestFramework.java | 9 +- .../java/org/jivesoftware/smack/ChatTest.java | 2 +- smack-java8-full/build.gradle | 5 + smack-java8/build.gradle | 8 +- .../smack/java7/XmppHostnameVerifier.java | 8 +- smack-jingle-old/build.gradle | 4 + .../sshare/api/OctTreeQuantizer.java | 1 + smack-legacy/build.gradle | 5 + .../smackx/workgroup/agent/AgentRoster.java | 2 +- .../smackx/workgroup/agent/AgentSession.java | 2 + .../ext/history/AgentChatHistory.java | 2 + .../smackx/workgroup/packet/QueueDetails.java | 1 + .../smackx/workgroup/util/MetaDataUtils.java | 5 +- .../build.gradle | 15 +- smack-omemo-signal/build.gradle | 8 + smack-omemo/build.gradle | 8 + .../smackx/omemo/FileBasedOmemoStore.java | 7 + .../smackx/omemo/OmemoService.java | 3 + .../jivesoftware/smackx/omemo/OmemoStore.java | 2 + .../smackx/omemo/OmemoServiceTest.java | 1 + .../smackx/omemo/OmemoStoreTest.java | 4 +- smack-openpgp/build.gradle | 8 + .../smackx/ox/OpenPgpContact.java | 1 + .../smackx/ox/OpenPgpManager.java | 1 + .../jivesoftware/smackx/ox/OpenPgpSelf.java | 1 + .../EncryptedOpenPgpContentElement.java | 3 +- .../ox/element/OpenPgpContentElement.java | 2 +- .../ox/element/PublicKeysListElement.java | 3 +- .../OpenPgpContentElementProvider.java | 6 +- .../FileBasedOpenPgpMetadataStore.java | 1 + .../smackx/ox/util/OpenPgpPubSubUtil.java | 4 +- .../smackx/ox/OpenPgpElementTest.java | 1 + .../smackx/ox/OpenPgpStoreTest.java | 2 + .../ox/PainlessOpenPgpProviderTest.java | 1 + .../smackx/ox/PublicKeysListElementTest.java | 1 + .../ox_im/OXInstantMessagingManagerTest.java | 1 + smack-repl/build.gradle | 11 +- smack-resolver-dnsjava/build.gradle | 5 + smack-resolver-javax/build.gradle | 4 + .../smack/util/dns/javax/JavaxResolver.java | 3 +- smack-resolver-minidns-dox/build.gradle | 5 + smack-resolver-minidns/build.gradle | 5 + smack-sasl-javax/build.gradle | 4 + smack-sasl-provided/build.gradle | 5 + smack-streammanagement/build.gradle | 5 + smack-tcp/build.gradle | 5 + .../smack/tcp/XMPPTCPConnection.java | 3 +- .../smack/tcp/XmppTcpTransportModule.java | 24 +- smack-websocket-java11/build.gradle | 4 + smack-websocket-okhttp/build.gradle | 5 + smack-websocket/build.gradle | 5 + smack-xmlparser-stax/build.gradle | 7 +- smack-xmlparser-xpp3/build.gradle | 8 +- smack-xmlparser/build.gradle | 8 +- 136 files changed, 1161 insertions(+), 1220 deletions(-) create mode 100644 Makefile create mode 100644 build-logic/build.gradle create mode 100644 build-logic/settings.gradle create mode 100644 build-logic/src/main/groovy/org.igniterealtime.smack.android-boot-classpath-conventions.gradle create mode 100644 build-logic/src/main/groovy/org.igniterealtime.smack.android-conventions.gradle create mode 100644 build-logic/src/main/groovy/org.igniterealtime.smack.application-conventions.gradle create mode 100644 build-logic/src/main/groovy/org.igniterealtime.smack.global-conventions.gradle create mode 100644 build-logic/src/main/groovy/org.igniterealtime.smack.java-common-conventions.gradle create mode 100644 build-logic/src/main/groovy/org.igniterealtime.smack.javadoc-conventions.gradle delete mode 100644 resources/releasedocs/README.html diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20c87d49e..5ddb006d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,13 +6,13 @@ jobs: build: name: Build Smack - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: java: - - 11 + - 17 env: - PRIMARY_JAVA_VERSION: 11 + PRIMARY_JAVA_VERSION: 17 steps: - name: Checkout @@ -57,6 +57,17 @@ jobs: run: | sdkmanager "platforms;android-21" + # Workaround + - name: Create gradle.properties + run: | + cat <<-EOF > gradle.properties + # Workaround for https://github.com/CycloneDX/cyclonedx-gradle-plugin/issues/349 + # suggested at https://docs.gradle.org/current/userguide/upgrading_version_8.html#xml_parsing_now_requires_recent_parsers + systemProp.javax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl + systemProp.javax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl + systemProp.javax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl + EOF + # Testing - name: Gradle Check run: ./gradlew check --stacktrace @@ -72,10 +83,19 @@ jobs: # Test Coverage Report - name: Jacoco Test Coverage - if: ${{ matrix.java == env.PRIMARY_JAVA_VERSION }} - run: ./gradlew jacocoRootReport coveralls env: - COVERALLS_REPO_TOKEN: S2ecSJja2cKJa9yv45C8ZFPohXuRrTXKd + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + if: | + ${{ matrix.java == env.PRIMARY_JAVA_VERSION }} && + ${{ env.COVERALLS_REPO_TOKEN != '' }} + run: | + if [[ -z ${COVERALLS_REPO_TOKEN} ]]; then + echo WARNING: COVERALLS_REPO_TOKEN is empty + else + echo COVERALLS_REPO_TOKEN is not empty + fi + ./gradlew smack-java8-full:testCodeCoverageReport + ./gradlew smack-java8-full:coveralls # Upload build artifacts - name: Upload build artifacts diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..0621bf85f --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +GRADLE ?= ./gradlew + +.PHONY: all +all: check jacocoRootReport javadocAll sinttest + +.PHONY: codecov +codecov: + $(GRADLE) smack-java8-full:testCodeCoverageReport + echo "Report available at smack-java8-full/build/reports/jacoco/testCodeCoverageReport/html/index.html" + +.PHONY: check +check: + $(GRADLE) $@ + +.PHONY: eclipse +eclipse: + $(GRADLE) $@ + +.PHONY: sinttest +sinttest: + $(GRADLE) $@ + +.PHONY: jacocoRootReport +jacocoRootReport: + $(GRADLE) $@ + +.PHONY: javadocAll +javadocAll: + $(GRADLE) $@ + echo "Smack javadoc available at build/javadoc/index.html" diff --git a/build-logic/build.gradle b/build-logic/build.gradle new file mode 100644 index 000000000..795d644bd --- /dev/null +++ b/build-logic/build.gradle @@ -0,0 +1,16 @@ +plugins { + id 'groovy-gradle-plugin' +} + +repositories { + gradlePluginPortal() +} + +dependencies { + implementation "biz.aQute.bnd:biz.aQute.bnd.gradle:7.0.0" + implementation "io.freefair.gradle:maven-plugin:8.10" // for io.freefair.agregate-javadoc + implementation "me.champeau.jmh:jmh-gradle-plugin:0.7.2" + implementation "net.ltgt.gradle:gradle-errorprone-plugin:4.0.1" + implementation "gradle.plugin.org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.12.2" + implementation "ru.vyarus:gradle-animalsniffer-plugin:1.7.1" +} diff --git a/build-logic/settings.gradle b/build-logic/settings.gradle new file mode 100644 index 000000000..d082ce7e0 --- /dev/null +++ b/build-logic/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'smack-build-logic' diff --git a/build-logic/src/main/groovy/org.igniterealtime.smack.android-boot-classpath-conventions.gradle b/build-logic/src/main/groovy/org.igniterealtime.smack.android-boot-classpath-conventions.gradle new file mode 100644 index 000000000..c14cb3199 --- /dev/null +++ b/build-logic/src/main/groovy/org.igniterealtime.smack.android-boot-classpath-conventions.gradle @@ -0,0 +1,6 @@ +compileJava { + options.bootstrapClasspath = files(androidBootClasspath) +} +javadoc { + classpath += files(androidBootClasspath) +} diff --git a/build-logic/src/main/groovy/org.igniterealtime.smack.android-conventions.gradle b/build-logic/src/main/groovy/org.igniterealtime.smack.android-conventions.gradle new file mode 100644 index 000000000..6f92548d3 --- /dev/null +++ b/build-logic/src/main/groovy/org.igniterealtime.smack.android-conventions.gradle @@ -0,0 +1,10 @@ +plugins { + id 'ru.vyarus.animalsniffer' + id 'org.igniterealtime.smack.global-conventions' +} +dependencies { + signature "net.sf.androidscents.signature:android-api-level-${smackMinAndroidSdk}:5.0.1_r2@signature" +} +animalsniffer { + sourceSets = [sourceSets.main] +} diff --git a/build-logic/src/main/groovy/org.igniterealtime.smack.application-conventions.gradle b/build-logic/src/main/groovy/org.igniterealtime.smack.application-conventions.gradle new file mode 100644 index 000000000..fa4c7011e --- /dev/null +++ b/build-logic/src/main/groovy/org.igniterealtime.smack.application-conventions.gradle @@ -0,0 +1,12 @@ +plugins { + id 'application' +} + +application { + applicationDefaultJvmArgs = ["-enableassertions"] +} + +run { + // Pass all system properties down to the "application" run + systemProperties System.getProperties() +} diff --git a/build-logic/src/main/groovy/org.igniterealtime.smack.global-conventions.gradle b/build-logic/src/main/groovy/org.igniterealtime.smack.global-conventions.gradle new file mode 100644 index 000000000..00fbff953 --- /dev/null +++ b/build-logic/src/main/groovy/org.igniterealtime.smack.global-conventions.gradle @@ -0,0 +1,37 @@ +ext { + javaVersion = JavaVersion.VERSION_11 + javaMajor = javaVersion.getMajorVersion() + smackMinAndroidSdk = 21 + + androidBootClasspath = { getAndroidRuntimeJar() } +} + +repositories { + mavenLocal() + mavenCentral() +} + +def getAndroidRuntimeJar() { + def androidApiLevel = ext.smackMinAndroidSdk + def androidHome = getAndroidHome() + def androidJar = new File("$androidHome/platforms/android-${androidApiLevel}/android.jar") + if (androidJar.isFile()) { + return androidJar + } else { + throw new Exception("Can't find android.jar for API level ${androidApiLevel}. Please install corresponding SDK platform package") + } +} +def getAndroidJavadocOffline() { + def androidHome = getAndroidHome() + return androidHome.toString() + "/docs/reference" +} + +def getAndroidHome() { + def androidHomeEnv = System.getenv("ANDROID_HOME") + if (androidHomeEnv == null) { + throw new Exception("ANDROID_HOME environment variable is not set") + } + def androidHome = new File(androidHomeEnv) + if (!androidHome.isDirectory()) throw new Exception("Environment variable ANDROID_HOME is not pointing to a directory") + return androidHome +} diff --git a/build-logic/src/main/groovy/org.igniterealtime.smack.java-common-conventions.gradle b/build-logic/src/main/groovy/org.igniterealtime.smack.java-common-conventions.gradle new file mode 100644 index 000000000..e6a9ecbbf --- /dev/null +++ b/build-logic/src/main/groovy/org.igniterealtime.smack.java-common-conventions.gradle @@ -0,0 +1,373 @@ +plugins { + id 'biz.aQute.bnd.builder' + id 'checkstyle' + id 'com.github.kt3k.coveralls' + id 'eclipse' + id 'idea' + id 'jacoco' + id 'java' + id 'java-library' + id 'java-test-fixtures' + id 'maven-publish' + id 'net.ltgt.errorprone' + id 'signing' + + id 'jacoco-report-aggregation' + id 'test-report-aggregation' + + id 'org.igniterealtime.smack.global-conventions' + id 'org.igniterealtime.smack.javadoc-conventions' +} + +version readVersionFile() + +ext { + isSnapshot = version.endsWith('-SNAPSHOT') + gitCommit = getGitCommit() + rootConfigDir = new File(rootDir, 'config') + sonatypeCredentialsAvailable = project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword') + isReleaseVersion = !isSnapshot + isContinuousIntegrationEnvironment = Boolean.parseBoolean(System.getenv('CI')) + signingRequired = !(isSnapshot || isContinuousIntegrationEnvironment) + sonatypeSnapshotUrl = 'https://oss.sonatype.org/content/repositories/snapshots' + sonatypeStagingUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2' + builtDate = (new java.text.SimpleDateFormat("yyyy-MM-dd")).format(new Date()) + oneLineDesc = 'An Open Source XMPP (Jabber) client library' + + jxmppVersion = '[1.1.0-beta1, 1.1.999]' + miniDnsVersion = '[1.1.0-alpha3, 1.1.999]' + junitVersion = '5.9.2' + commonsIoVersion = '2.6' + bouncyCastleVersion = '1.73' + guavaVersion = '30.1-jre' + mockitoVersion = '5.13.0' + orgReflectionsVersion = '0.9.11' + + if (project.hasProperty("useSonatype")) { + useSonatype = project.getProperty("useSonatype").toBoolean() + } else { + // Default to true + useSonatype = true + } + + gplLicensedProjects = [ + ':smack-examples', + ':smack-omemo-signal', + ':smack-omemo-signal-integration-test', + ':smack-repl' + ].collect{ project(it) } +} + +group = 'org.igniterealtime.smack' + +java { + sourceCompatibility = javaVersion + targetCompatibility = sourceCompatibility +} + +eclipse { + classpath { + downloadJavadoc = true + } +} + +// Make all project's 'test' target depend on javadoc, so that +// javadoc is also linted. +test.dependsOn javadoc + +tasks.withType(JavaCompile) { + // Some systems may not have set their platform default + // converter to 'utf8', but we use unicode in our source + // files. Therefore ensure that javac uses unicode + options.encoding = "utf8" + options.compilerArgs = [ + '-Xlint:all', + // Set '-options' because a non-java7 javac will emit a + // warning if source/target is set to 1.7 and + // bootclasspath is *not* set. + '-Xlint:-options', + // TODO: Enable xlint serial + '-Xlint:-serial', + '-Werror', + ] +} +if (JavaVersion.current().isJava8Compatible()) { + tasks.withType(Javadoc) { + // The '-quiet' as second argument is actually a hack, + // since the one parameter addStringOption doesn't seem to + // work, we extra add '-quiet', which is added anyway by + // gradle. + // We disable 'missing' as we do most of javadoc checking via checkstyle. + options.addStringOption('Xdoclint:all,-missing', '-quiet') + // 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') + } +} + +if (JavaVersion.current().isJava9Compatible()) { + tasks.withType(JavaCompile) { + options.compilerArgs.addAll([ + '--release', javaMajor, + ]) + } +} + +jacoco { + toolVersion = "0.8.12" +} + +jacocoTestReport { + dependsOn test + reports { + xml.required = true + } +} + +dependencies { + testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" + + testFixturesApi "org.junit.jupiter:junit-jupiter-api:$junitVersion" + testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" + // https://stackoverflow.com/a/77274251/194894 + testRuntimeOnly "org.junit.platform:junit-platform-launcher:1.11.0" + + // The smack-extensions subproject uses mockito in its fest + // fixtures, and we want to have mockito also available in + // test, so we use API here. + testFixturesApi "org.mockito:mockito-core:${mockitoVersion}" + + testImplementation 'com.jamesmurty.utils:java-xmlbuilder:1.2' + + errorprone 'com.google.errorprone:error_prone_core:2.9.0' + errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') +} + +test { + useJUnitPlatform() + + maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1 + + // Enable full stacktraces of failed tests. Especially handy + // for CI environments. + testLogging { + events "failed" + exceptionFormat "full" + } +} + +jar { + manifest { + attributes( + 'Implementation-Version': version, + 'Implementation-GitRevision': gitCommit, + 'Built-JDK': System.getProperty('java.version'), + 'Built-Gradle': gradle.gradleVersion, + 'Built-By': System.getProperty('user.name') + ) + } + + bundle { + bnd( + '-removeheaders': 'Tool, Bnd-*', + '-exportcontents': '*', + ) + } +} + +checkstyle { + toolVersion = '8.27' + + if (project in gplLicensedProjects) { + configProperties.checkstyleLicenseHeader = "${project.name}-gplv3-license-header" + } else { + configProperties.checkstyleLicenseHeader = "header" + } +} +task sourcesJar(type: Jar, dependsOn: classes) { + archiveClassifier = 'sources' + from sourceSets.main.allSource +} +task javadocJar(type: Jar, dependsOn: javadoc) { + archiveClassifier = 'javadoc' + from javadoc.destinationDir +} +task testsJar(type: Jar) { + archiveClassifier = 'tests' + from sourceSets.test.output +} +configurations { + testRuntime +} +artifacts { + // Add a 'testRuntime' configuration including the tests so that + // it can be consumed by other projects (smack-omemo-signal for + // example). See http://stackoverflow.com/a/21946676/194894 + testRuntime testsJar +} + +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + artifact sourcesJar + artifact javadocJar + artifact testsJar + pom { + name = 'Smack' + packaging = 'jar' + inceptionYear = '2003' + url = 'http://www.igniterealtime.org/projects/jxmpp/' + afterEvaluate { + description = project.description + } + + issueManagement { + system = 'JIRA' + url = 'http://issues.igniterealtime.org/browse/SMACK' + } + + scm { + url = 'https://github.com/igniterealtime/Smack' + connection = 'scm:git:https://github.com/igniterealtime/Smack.git' + developerConnection = 'scm:git:https://github.com/igniterealtime/Smack.git' + } + + licenses { + if (project in gplLicensedProjects) { + license { + name = 'GNU General Public License, version 3 or any later version' + url = 'https://www.gnu.org/licenses/gpl.txt' + distribution = 'repo' + } + } else { + license { + name = 'The Apache Software License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution = 'repo' + } + } + } + + developers { + developer { + id = 'flow' + name = 'Florian Schmaus' + email = 'flow@igniterealtime.org' + } + } + } + } + } + repositories { + if (sonatypeCredentialsAvailable && useSonatype) { + maven { + url isSnapshot ? sonatypeSnapshotUrl : sonatypeStagingUrl + credentials { + username = sonatypeUsername + password = sonatypePassword + } + } + } + // Use + // gradle publish -P customRepoUrl=https://www.igniterealtime.org/archiva/repository/maven -P customRepoUsername=bamboo -P customRepoPassword=hidden -P useSonatype=false + // to deploy to this repo. + if (project.hasProperty("customRepoUrl")) { + maven { + name 'customRepo' + url customRepoUrl + if (project.hasProperty("customRepoUsername")) { + credentials { + username customRepoUsername + password customRepoPassword + } + } + } + } + } +} + +// Workaround for gpg signatory not supporting the 'required' option +// See https://github.com/gradle/gradle/issues/5064#issuecomment-381924984 +// Note what we use 'signing.gnupg.keyName' instead of 'signing.keyId'. +tasks.withType(Sign) { + onlyIf { + project.hasProperty('signing.gnupg.keyName') + } +} +signing { + required { signingRequired } + useGpgCmd() + sign publishing.publications.mavenJava +} + +tasks.withType(JavaCompile) { + options.errorprone { + disableWarningsInGeneratedCode = true + excludedPaths = ".*/jmh_generated/.*" + error( + "UnusedVariable", + "UnusedMethod", + "MethodCanBeStatic", + ) + errorproneArgs = [ + // Disable MissingCasesInEnumSwitch error prone check + // because this check is already done by javac as incomplete-switch. + '-Xep:MissingCasesInEnumSwitch:OFF', + '-Xep:StringSplitter:OFF', + '-Xep:JavaTimeDefaultTimeZone:OFF', + '-Xep:InlineMeSuggester:OFF', + ] + } +} + +// Work around https://github.com/gradle/gradle/issues/4046 +task copyJavadocDocFiles(type: Copy) { + from('src/javadoc') + into 'build/docs/javadoc' + include '**/doc-files/*.*' +} +javadoc.dependsOn copyJavadocDocFiles + +coveralls { + jacocoReportPath 'build/reports/jacoco/testCodeCoverageReport/testCodeCoverageReport.xml' +} + +def getGitCommit() { + def projectDirFile = new File("$projectDir") + + def cmd = 'git describe --always --tags --dirty=+' + def proc = cmd.execute(null, projectDirFile) + + def exitStatus = proc.waitFor() + if (exitStatus != 0) return "non-git build" + + def gitCommit = proc.text.trim() + assert !gitCommit.isEmpty() + gitCommit +} + +def getAndroidRuntimeJar() { + def androidHome = new File("$System.env.ANDROID_HOME") + if (!androidHome.isDirectory()) throw new Exception("ANDROID_HOME not found or set") + def androidJar = new File("$androidHome/platforms/android-$smackMinAndroidSdk/android.jar") + if (androidJar.isFile()) { + return androidJar + } else { + throw new Exception("Can't find android.jar for $smackMinAndroidSdk API. Please install corresponding SDK platform package") + } +} + +def readVersionFile() { + def versionFile = new File(rootDir, 'version') + if (!versionFile.isFile()) { + throw new Exception("Could not find version file") + } + if (versionFile.text.isEmpty()) { + throw new Exception("Version file does not contain a version") + } + versionFile.text.trim() +} diff --git a/build-logic/src/main/groovy/org.igniterealtime.smack.javadoc-conventions.gradle b/build-logic/src/main/groovy/org.igniterealtime.smack.javadoc-conventions.gradle new file mode 100644 index 000000000..61cb8f3c6 --- /dev/null +++ b/build-logic/src/main/groovy/org.igniterealtime.smack.javadoc-conventions.gradle @@ -0,0 +1,30 @@ +plugins { + // Javadoc linking requires repositories to bet configured. And + // those are declared in global-conventions, hence we add it here. + id 'org.igniterealtime.smack.global-conventions' +} + +if (JavaVersion.current().isJava8Compatible()) { + tasks.withType(Javadoc) { + // The '-quiet' as second argument is actually a hack, + // since the one parameter addStringOption doesn't seem to + // work, we extra add '-quiet', which is added anyway by + // gradle. + // We disable 'missing' as we do most of javadoc checking via checkstyle. + options.addStringOption('Xdoclint:all,-missing', '-quiet') + // 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') + } +} + +if (JavaVersion.current().isJava9Compatible()) { + tasks.withType(Javadoc) { + options.addStringOption('-release', javaMajor) + } +} + +tasks.withType(Javadoc) { + options.charSet = "UTF-8" +} diff --git a/build.gradle b/build.gradle index 8570669b9..13f9b12d7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,346 +1,20 @@ -buildscript { - repositories { - gradlePluginPortal() - } -} - plugins { - id 'ru.vyarus.animalsniffer' version '1.5.0' - id 'net.ltgt.errorprone' version '1.3.0' - // Use e.g. "gradle taskTree" to show its dependency tree. - id 'com.dorongold.task-tree' version '1.5' - id 'com.github.kt3k.coveralls' version '2.10.2' - id 'biz.aQute.bnd.builder' version '6.4.0' + // The scalastyle plugin of smack-repl wants the root project to + // have a ideaProject task, so let's add one. + id 'idea' + + id 'org.igniterealtime.smack.javadoc-conventions' } ext { - java11Projects = [ - ':smack-examples', + javadocAllDir = new File(buildDir, 'javadoc') + integrationTestProjects = [ ':smack-integration-test', ':smack-omemo-signal-integration-test', - ':smack-repl', - ':smack-websocket-java11', - ].collect { project(it) } - java11Projects += getRootProject() - java8Projects = allprojects - java11Projects + ].collect{ project(it) } + javadocAllProjects = subprojects - integrationTestProjects } -configure (java8Projects) { - ext { - javaCompatilibity = JavaVersion.VERSION_1_8 - } -} - -configure (java11Projects) { - ext { - javaCompatilibity = JavaVersion.VERSION_11 - } -} - -allprojects { - apply plugin: 'java-library' - apply plugin: 'java-test-fixtures' - apply plugin: 'eclipse' - apply plugin: 'idea' - apply plugin: 'jacoco' - apply plugin: 'net.ltgt.errorprone' - - version readVersionFile() - - ext { - isSnapshot = version.endsWith('-SNAPSHOT') - gitCommit = getGitCommit() - javadocAllDir = new File(buildDir, 'javadoc') - documentationDir = new File(projectDir, 'documentation') - releasedocsDir = new File(buildDir, 'releasedocs') - rootConfigDir = new File(rootDir, 'config') - sonatypeCredentialsAvailable = project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword') - isReleaseVersion = !isSnapshot - isContinuousIntegrationEnvironment = Boolean.parseBoolean(System.getenv('CI')) - signingRequired = !(isSnapshot || isContinuousIntegrationEnvironment) - sonatypeSnapshotUrl = 'https://oss.sonatype.org/content/repositories/snapshots' - sonatypeStagingUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2' - // Returns only the date in yyyy-MM-dd format, as otherwise, with - // hh:mm:ss information, the manifest files would change with every - // build, causing unnecessary rebuilds. - builtDate = (new java.text.SimpleDateFormat("yyyy-MM-dd")).format(new Date()) - oneLineDesc = 'An Open Source XMPP (Jabber) client library' - integrationTestProjects = [ - ':smack-integration-test', - ':smack-omemo-signal-integration-test', - ].collect{ project(it) } - javadocAllProjects = subprojects - integrationTestProjects - // A dirty hack used for Gradle's jacoco plugin, since is not - // hable to handle the case when a (sub)project has no unit - // tests. :-( - projectsWithoutUnitTests = [ - ':smack-android', - ':smack-android-extensions', - ':smack-bosh', - ':smack-debug', - ':smack-debug-slf4j', - ':smack-java8', - ':smack-jingle-old', - ':smack-resolver-dnsjava', - ':smack-resolver-javax', - ':smack-resolver-minidns', - ':smack-omemo-signal-integration-test', - ].collect{ project(it) } - projectsWithUnitTests = subprojects - projectsWithoutUnitTests - androidProjects = [ - ':smack-tcp', - ':smack-bosh', - ':smack-core', - ':smack-im', - ':smack-resolver-minidns', - ':smack-sasl-provided', - ':smack-extensions', - ':smack-experimental', - ':smack-omemo', - ':smack-omemo-signal', - ':smack-openpgp', - ':smack-xmlparser', - ':smack-xmlparser-xpp3', - ].collect{ project(it) } - androidBootClasspathProjects = [ - ':smack-android', - ':smack-android-extensions', - ].collect{ project(it) } - androidOptionalProjects = [ - ':smack-tcp', - ':smack-extensions', - ':smack-experimental', - ':smack-bosh', - ':smack-omemo', - ':smack-omemo-signal', - ].collect{ project(it) } - gplLicensedProjects = [ - ':smack-examples', - ':smack-omemo-signal', - ':smack-omemo-signal-integration-test', - ':smack-repl' - ].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() } - junit4Projects = [ - ':smack-core', - ':smack-im', - ':smack-omemo', - ':smack-omemo-signal', - ':smack-openpgp', - ].collect { project(it) } - - // When using dynamic versions for those, do *not* use [1.0, - // 2.0), since this will also pull in 2.0-alpha1. Instead use - // [1.0, 1.0.99]. - // See also: - // - https://issues.apache.org/jira/browse/MNG-6232 - // - https://issues.igniterealtime.org/browse/SMACK-858 - jxmppVersion = '[1.1.0-beta1, 1.1.999]' - miniDnsVersion = '[1.1.0-alpha3, 1.1.999]' - smackMinAndroidSdk = 21 - junitVersion = '5.7.1' - commonsIoVersion = '2.6' - bouncyCastleVersion = '1.73' - guavaVersion = '30.1-jre' - mockitoVersion = '3.7.7' - orgReflectionsVersion = '0.9.11' - - if (project.hasProperty("useSonatype")) { - useSonatype = project.getProperty("useSonatype").toBoolean() - } else { - // Default to true - useSonatype = true - } - javaMajor = javaCompatilibity.getMajorVersion() - } - group = 'org.igniterealtime.smack' - sourceCompatibility = javaCompatilibity - targetCompatibility = sourceCompatibility - - test { - useJUnitPlatform() - - maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1 - - // Enable full stacktraces of failed tests. Especially handy - // for environments like Travis. - testLogging { - events "failed" - exceptionFormat "full" - } - } - - ext.sharedManifest = manifest { - attributes('Implementation-Version': version, - 'Implementation-GitRevision': ext.gitCommit, - 'Built-Date': ext.builtDate, - 'Built-JDK': System.getProperty('java.version'), - 'Built-Gradle': gradle.gradleVersion, - 'Built-By': System.getProperty('user.name') - ) - } - - eclipse { - classpath { - downloadJavadoc = true - } - } - - repositories { - mavenLocal() - mavenCentral() - } - - tasks.withType(JavaCompile) { - // Some systems may not have set their platform default - // converter to 'utf8', but we use unicode in our source - // files. Therefore ensure that javac uses unicode - options.encoding = 'UTF-8' - options.compilerArgs = [ - '-Xlint:all', - // Set '-options' because a non-java7 javac will emit a - // warning if source/target is set to 1.7 and - // bootclasspath is *not* set. - // TODO implement a sound heuristic to determine a java7 - // rt.jar on the build host. And if none is found, - // fallback to using a environment variable, - // e.g. JAVA7_HOME. See SMACK-651. - '-Xlint:-options', - '-Werror', - ] - options.errorprone { - error( - "UnusedVariable", - "UnusedMethod", - "MethodCanBeStatic", - ) - 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', - // TODO: Re-enable once Smack's minimum Android SDK level is 26 or higher. - '-Xep:JavaUtilDate:OFF', - ] - } - } - - tasks.withType(ScalaCompile) { - scalaCompileOptions.additionalParameters = [ - '-Xfatal-warnings', - '-feature', - ] - } - - jacoco { - toolVersion = "0.8.6" - } - - jacocoTestReport { - dependsOn test - getSourceDirectories().setFrom(project.files(sourceSets.main.allSource.srcDirs)) - getClassDirectories().setFrom(project.files(sourceSets.main.output)) - reports { - xml.enabled true - } - } - - if (JavaVersion.current().isJava8Compatible()) { - tasks.withType(Javadoc) { - // The '-quiet' as second argument is actually a hack, - // since the one parameter addStringOption doesn't seem to - // work, we extra add '-quiet', which is added anyway by - // gradle. - // TODO: This enables all doclint check but - // 'missing'. Re-enable 'missing' once every public API in - // Smack has a javadoc comment. - options.addStringOption('Xdoclint:accessibility,html,reference,syntax', '-quiet') - - // Treat warnings as errors. - // See also https://bugs.openjdk.java.net/browse/JDK-8200363 - options.addStringOption('Xwerror', '-quiet') - } - } - - if (JavaVersion.current().isJava9Compatible()) { - tasks.withType(Javadoc) { - options.addStringOption('-release', javaMajor) - - // The -no-modules-directories javadoc option was removed in Java 13 - // See https://bugs.openjdk.java.net/browse/JDK-8215582 - if (JavaVersion.current() < JavaVersion.VERSION_13) { - // Fix for javadoc search. If not set, the search result would direct to - // javadoc/undefined/org/jivesoftware/smack/altconnections/HttpLookupMethod.html - // instead of - // javadoc/org/jivesoftware/smack/altconnections/HttpLookupMethod.html - // https://stackoverflow.com/a/53732633/194894 - options.addBooleanOption("-no-module-directories", true) - } - } - tasks.withType(JavaCompile) { - options.compilerArgs.addAll([ - '--release', javaMajor, - ]) - } - } - -tasks.withType(Javadoc) { - options.charSet = "UTF-8" - options.encoding = 'UTF-8' - } - - dependencies { - testFixturesApi "org.junit.jupiter:junit-jupiter-api:$junitVersion" - testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion" - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" - // https://stackoverflow.com/a/77274251/194894 - testRuntimeOnly "org.junit.platform:junit-platform-launcher" - - // The smack-extensions subproject uses mockito in its fest - // fixtures, and we want to have mockito also available in - // test, so we use API here. - testFixturesApi "org.mockito:mockito-core:${mockitoVersion}" - - // To mock final classes - testImplementation "org.mockito:mockito-inline:${mockitoVersion}" - testImplementation 'com.jamesmurty.utils:java-xmlbuilder:1.2' - - errorprone 'com.google.errorprone:error_prone_core:2.5.1' - errorproneJavac('com.google.errorprone:javac:9+181-r4173-1') - } - - // Make all project's 'test' target depend on javadoc, so that - // javadoc is also linted. - test { dependsOn javadoc } -} - -configure (junit4Projects) { - dependencies { - testImplementation "org.junit.vintage:junit-vintage-engine:$junitVersion" - } -} - -// We need to evaluate the child projects first because -// - javadocAll needs the smack-core child to have already resolved -// the jXMPP/MiniDNS dependencies, so that we can the resolved -// version to link to those project's javadoc. -// - We use the child's project description as description for the -// Maven POM. evaluationDependsOnChildren() task javadocAll(type: Javadoc) { source javadocAllProjects.collect {project -> @@ -389,286 +63,6 @@ task javadocAll(type: Javadoc) { } } -import org.apache.tools.ant.filters.ReplaceTokens -task prepareReleasedocs(type: Copy) { - from 'resources/releasedocs' - into releasedocsDir - filter(ReplaceTokens, tokens: [version: version, releasedate: builtDate, targetCompatibility: targetCompatibility.toString()]) -} - -task distributionZip(type: Zip, dependsOn: [javadocAll, prepareReleasedocs]) { - classifier builtDate - into ('javadoc') { - from(javadocAllDir) - } - into ('releasedocs') { - from(releasedocsDir) - } - into ('releasedocs/documentation') { - from(documentationDir) - } -} - -task maybeCheckForSnapshotDependencies { - // Don't check for Snapshot dependencies if this is a snapshot. - onlyIf { isReleaseVersion } - // Run in the execution phase, not in configuration phase, as the - // 'each' forces the runtime configuration to be resolved, which - // causes "Cannot change dependencies of configuration after it - // has been included in dependency resolution." errors. - // See https://discuss.gradle.org/t/23153 - doLast { - allprojects { project -> - project.configurations.runtime.each { - if (it.toString().contains("-SNAPSHOT")) - throw new Exception("Release build contains snapshot dependencies: " + it) - } - } - } -} - -test { dependsOn maybeCheckForSnapshotDependencies } - -jar { - // Root project should not create empty jar artifact - enabled = false -} - -// Disable upload archives for the root project -uploadArchives.enabled = false - -description = """\ -Smack ${version} -${oneLineDesc}.""" - -subprojects { - apply plugin: 'maven-publish' - apply plugin: 'signing' - apply plugin: 'checkstyle' - apply plugin: 'biz.aQute.bnd.builder' - - checkstyle { - toolVersion = '8.27' - } - task sourcesJar(type: Jar, dependsOn: classes) { - classifier = 'sources' - from sourceSets.main.allSource - } - task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.destinationDir - } - task testsJar(type: Jar, dependsOn: testClasses) { - classifier = 'tests' - from sourceSets.test.output - } - - artifacts { - // See http://stackoverflow.com/a/21946676/194894 - testRuntime testsJar - } - - publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact sourcesJar - artifact javadocJar - artifact testsJar - pom { - name = 'Smack' - packaging = 'jar' - inceptionYear = '2003' - url = 'http://www.igniterealtime.org/projects/smack/' - description = project.description - - issueManagement { - system = 'JIRA' - url = 'https://igniterealtime.org/issues/browse/SMACK' - } - - scm { - url = 'https://github.com/igniterealtime/Smack' - connection = 'scm:git:https://github.com/igniterealtime/Smack.git' - developerConnection = 'scm:git:https://github.com/igniterealtime/Smack.git' - } - - developers { - developer { - id = 'flow' - name = 'Florian Schmaus' - email = 'flow@igniterealtime.org' - } - } - } - } - } - repositories { - if (sonatypeCredentialsAvailable && useSonatype) { - maven { - url isSnapshot ? sonatypeSnapshotUrl : sonatypeStagingUrl - credentials { - username = sonatypeUsername - password = sonatypePassword - } - } - } - // Use - // gradle publish -P customRepoUrl=https://www.igniterealtime.org/archiva/repository/maven -P customRepoUsername=bamboo -P customRepoPassword=hidden -P useSonatype=false - // to deploy to this repo. - if (project.hasProperty("customRepoUrl")) { - maven { - name 'customRepo' - url customRepoUrl - if (project.hasProperty("customRepoUsername")) { - credentials { - username customRepoUsername - password customRepoPassword - } - } - } - } - } - } - rootProject.distributionZip { - dependsOn build - from(buildDir) { - include "$libsDirName/*${version}.jar" - include "$libsDirName/*${version}-javadoc.jar" - include "$libsDirName/*${version}-sources.jar" - } - } - - // Workaround for gpg signatory not supporting the 'required' option - // See https://github.com/gradle/gradle/issues/5064#issuecomment-381924984 - // Note what we use 'signing.gnupg.keyName' instead of 'signing.keyId'. - tasks.withType(Sign) { - onlyIf { - project.hasProperty('signing.gnupg.keyName') - } - } - signing { - useGpgCmd() - required { signingRequired } - sign publishing.publications.mavenJava - } - - // Work around https://github.com/gradle/gradle/issues/4046 - task copyJavadocDocFiles(type: Copy) { - from('src/javadoc') - into 'build/docs/javadoc' - include '**/doc-files/*.*' - } - javadoc.dependsOn copyJavadocDocFiles - - // Make sure root projects 'javadocAll' depends on the - // subproject's javadoc, to ensure that all all doc-files/ are - // generated and up-to-date. Obviously this means that the - // javadocAll task will also create the individual javadoc's of the - // subprojects. - javadocAll.dependsOn javadoc -} - -// The smack-java8-full project generates the dot and png files of the -// current state graph. Ensure they are generated before copied. -configure (project(':smack-java8-full')) { - copyJavadocDocFiles.dependsOn convertModularXmppClientToServerConnectionStateGraphDotToPng -} - -configure (androidProjects + androidBootClasspathProjects) { - apply plugin: 'ru.vyarus.animalsniffer' - dependencies { - signature "net.sf.androidscents.signature:android-api-level-${smackMinAndroidSdk}:5.0.1_r2@signature" - } - animalsniffer { - sourceSets = [sourceSets.main] - } -} - -subprojects*.jar { - manifest { - from sharedManifest - } - bundle { - bnd( - '-removeheaders': 'Tool, Bnd-*', - '-exportcontents': '*', - ) - } -} - -configure(subprojects - gplLicensedProjects) { - checkstyle { - configProperties.checkstyleLicenseHeader = "header" - } - publishing { - publications { - mavenJava(MavenPublication) { - pom { - licenses { - license { - name = 'The Apache Software License, Version 2.0' - url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' - distribution = 'repo' - } - } - } - } - } - } -} - -configure(gplLicensedProjects) { - checkstyle { - configProperties.checkstyleLicenseHeader = "${project.name}-gplv3-license-header" - } - publishing { - publications { - mavenJava(MavenPublication) { - pom { - licenses { - license { - name = 'GNU General Public License, version 3 or any later version' - url = 'https://www.gnu.org/licenses/gpl.txt' - distribution = 'repo' - } - } - } - } - } - } -} - -configure(androidBootClasspathProjects) { - compileJava { - options.bootstrapClasspath = files(androidBootClasspath) - } - javadoc { - classpath += files(androidBootClasspath) - } -} - -apply plugin: "com.github.kt3k.coveralls" -coveralls { - sourceDirs = files(subprojects.sourceSets.main.allSource.srcDirs).files.absolutePath -} - -task jacocoRootReport(type: org.gradle.testing.jacoco.tasks.JacocoReport) { - dependsOn = projectsWithUnitTests.jacocoTestReport - getSourceDirectories().setFrom(files(projectsWithUnitTests.sourceSets.main.allSource.srcDirs)) - getClassDirectories().setFrom(files(projectsWithUnitTests.sourceSets.main.output)) - getExecutionData().setFrom(files(projectsWithUnitTests.jacocoTestReport.executionData)) - reports { - xml.enabled true - xml.destination file("${buildDir}/reports/jacoco/test/jacocoTestReport.xml") - } - // We could remove the following setOnlyIf line, but then - // jacocoRootReport would silently be SKIPPED if something with - // the projectsWithUnitTests is wrong (e.g. a project is missing - // in there). - setOnlyIf { true } -} - task integrationTest { description 'Verify correct functionality of Smack by running some integration tests.' dependsOn project(':smack-integration-test').tasks.run @@ -676,7 +70,7 @@ task integrationTest { task omemoSignalIntTest { description 'Run integration tests of the smack-omemo module in combination with smack-omemo-signal.' - dependsOn project(':smack-omemo-signal-integration-test').tasks.run + dependsOn 'smack-omemo-signal-integration-test:run' } task sinttestAll { @@ -687,70 +81,6 @@ task sinttestAll { ]} } -def getGitCommit() { - def projectDirFile = new File("$projectDir") - def dotGit = new File(projectDirFile, ".git") - if (!dotGit.isDirectory()) return 'non-git build' - - def cmd = 'git describe --always --tags --dirty=+' - def proc = cmd.execute(null, projectDirFile) - proc.waitForOrKill(10 * 1000) - - def gitCommit = proc.text.trim() - assert !gitCommit.isEmpty() - - def srCmd = 'git symbolic-ref --short HEAD' - def srProc = srCmd.execute(null, projectDirFile) - srProc.waitForOrKill(10 * 1000) - if (srProc.exitValue() == 0) { - // Only add the information if the git command was - // successful. There may be no symbolic reference for HEAD if - // e.g. in detached mode. - def symbolicReference = srProc.text.trim() - assert !symbolicReference.isEmpty() - gitCommit += "-$symbolicReference" - } - - gitCommit -} - -def getAndroidRuntimeJar() { - def androidApiLevel = ext.smackMinAndroidSdk - def androidHome = getAndroidHome() - def androidJar = new File("$androidHome/platforms/android-${androidApiLevel}/android.jar") - if (androidJar.isFile()) { - return androidJar - } else { - throw new Exception("Can't find android.jar for API level ${androidApiLevel}. Please install corresponding SDK platform package") - } -} - -def getAndroidJavadocOffline() { - def androidHome = getAndroidHome() - return androidHome.toString() + "/docs/reference" -} - -def getAndroidHome() { - def androidHomeEnv = System.getenv("ANDROID_HOME") - if (androidHomeEnv == null) { - throw new Exception("ANDROID_HOME environment variable is not set") - } - def androidHome = new File(androidHomeEnv) - if (!androidHome.isDirectory()) throw new Exception("Environment variable ANDROID_HOME is not pointing to a directory") - return androidHome -} - -def readVersionFile() { - def versionFile = new File(rootDir, 'version') - if (!versionFile.isFile()) { - throw new Exception("Could not find version file") - } - if (versionFile.text.isEmpty()) { - throw new Exception("Version file does not contain a version") - } - versionFile.text.trim() -} - def getResolvedVersion(queriedProject = 'smack-core', component) { def configuration = project(queriedProject) .configurations diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c023ec8b20f512888fe07c5bd3ff77bb8f..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 59203 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

K7UpUK$>l@ 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 E2O(~oYXATM diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 442d9132e..df97d72b8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0c8..f5feea6d6 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,69 +15,104 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +122,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,88 +133,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index ac1b06f93..9b42019c7 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,8 +13,10 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +27,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/repl b/repl index c6014bbb4..e31926a9d 100755 --- a/repl +++ b/repl @@ -1,7 +1,5 @@ #!/usr/bin/env bash -set -e -set -u -set -o pipefail +set -euo pipefail JDWP=false JDWP_PORT=8000 @@ -37,12 +35,13 @@ echo "Compiling and computing classpath (May take a while)" # /smack/smack-repl/build/classes/main:/smack/smack-repl/build/ # resources/main:/smack/smack-tcp/build/libs/smack-tcp-4.2.0-alpha4-SNAPSHOT.jar # So perform a "tail -n1" on the output of gradle -GRADLE_CLASSPATH="$(gradle :smack-repl:printClasspath --quiet |\ +GRADLE_CLASSPATH="$(${GRADLE_BIN:-./gradlew} :smack-repl:printClasspath --quiet |\ tail -n1)" echo "Finished, starting REPL" -java "${EXTRA_JAVA_ARGS[@]}" \ +exec java \ + "${EXTRA_JAVA_ARGS[@]}" \ -Dscala.usejavacp=true \ -classpath "${GRADLE_CLASSPATH}" \ ammonite.Main \ - --predef "smack-repl/scala.repl" + --predef smack-repl/scala.repl diff --git a/resources/releasedocs/README.html b/resources/releasedocs/README.html deleted file mode 100644 index d25eaf624..000000000 --- a/resources/releasedocs/README.html +++ /dev/null @@ -1,221 +0,0 @@ - - - - - Smack Readme - - - - -

- - - - -
- -

- - - - - - - - - -
version:@version@
released:@releasedate@
- -

-Thank you for downloading Smack! This version of Smack is compatible -with JVMs @targetCompatibility@ or higher. Using a build system which -is able to consume Maven artifacts, like gradle or Maven, is highly -recommended when using Smack. -

- -

- This is not the real README. Please visit -

- https://www.igniterealtime.org/projects/smack/readme -
- for the README of the current stable Smack version. -

- -

- Smack tries to depend on as few as possible libraries. The only - requirement is jXMPP. For DNS - resolution we recommend to - use MiniDNS. -

- -

-Start off by viewing the documentation -that can be found in the "documentation" directory included with this distribution. -

-Further information can be found on the -Smack website. If you need help using or would like to make contributions or -fixes to the code, please visit the -online forum. -

- -

Changelog and Upgrading

- -View the changelog for a list of changes since the -last release. - -

License Agreements

-

    -
  • Use of the Smack source code is governed by the Apache License Version 2.0: -
    - Copyright 2002-2008 Jive Software.
    -
    - Licensed under the Apache License, Version 2.0 (the "License");
    - you may not use this file except in compliance with the License.
    - You may obtain a copy of the License at
    -
    -     http://www.apache.org/licenses/LICENSE-2.0
    -
    - Unless required by applicable law or agreed to in writing, software
    - distributed under the License is distributed on an "AS IS" BASIS,
    - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    - See the License for the specific language governing permissions and
    - limitations under the License.
    - 
  • - -
  • Smack contains icons and images licensed from INCORS GmbH. You are not licensed -to use these icons outside of Smack.
  • - -
  • Third-party source code is licensed as noted in their source files. - -
-
-
- - diff --git a/settings.gradle b/settings.gradle index 8a7fececc..2ed68cff5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,7 @@ +pluginManagement { + includeBuild('build-logic') +} + // The name of the root project. // If we would not set the name, then gradle would use the directory // name of the root directory diff --git a/smack-android-extensions/build.gradle b/smack-android-extensions/build.gradle index 0cdad8bda..ce9a40fc4 100644 --- a/smack-android-extensions/build.gradle +++ b/smack-android-extensions/build.gradle @@ -1,3 +1,9 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' + id 'org.igniterealtime.smack.android-boot-classpath-conventions' +} + description = """\ Extra Smack extensions for Android.""" @@ -8,5 +14,5 @@ dependencies { api project(':smack-extensions') // Add the Android jar to the Eclipse .classpath. - compileClasspath files(androidBootClasspath) + implementation files(androidBootClasspath) } diff --git a/smack-android/build.gradle b/smack-android/build.gradle index 556a526eb..ef158e137 100644 --- a/smack-android/build.gradle +++ b/smack-android/build.gradle @@ -1,3 +1,9 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' + id 'org.igniterealtime.smack.android-boot-classpath-conventions' +} + description = """\ Smack for Android. All the required dependencies to run Smack on Android. @@ -16,13 +22,13 @@ dependencies { // used in non-Android projects. implementation "org.minidns:minidns-android21:$miniDnsVersion" - // androidProjects lists all projects that are checked to compile against android.jar - // Filter out the optional Smack dependencies from androidProjects - (androidProjects - androidOptionalProjects) - .each { project -> - api project - } + api project(':smack-core') + api project(':smack-im') + api project(':smack-resolver-minidns') + api project(':smack-sasl-provided') + api project(':smack-xmlparser') + api project(':smack-xmlparser-xpp3') // Add the Android jar to the Eclipse .classpath. - compileClasspath files(androidBootClasspath) + implementation files(androidBootClasspath) } diff --git a/smack-bosh/build.gradle b/smack-bosh/build.gradle index fcd3d5896..d939a9e46 100644 --- a/smack-bosh/build.gradle +++ b/smack-bosh/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description = """\ Smack BOSH API. This API is considered beta quality.""" diff --git a/smack-core/build.gradle b/smack-core/build.gradle index d29c04d80..1ffb92eb7 100644 --- a/smack-core/build.gradle +++ b/smack-core/build.gradle @@ -1,7 +1,7 @@ -// Note that this is also declared in the main build.gradle for -// subprojects, but since evaluationDependsOnChildren is enabled we -// need to declare it here too to have bundle{bnd{...}} available -apply plugin: 'biz.aQute.bnd.builder' +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} description = """\ Smack core components.""" @@ -16,6 +16,9 @@ dependencies { api "org.jxmpp:jxmpp-jid:$jxmppVersion" api "org.minidns:minidns-core:$miniDnsVersion" + // TODO: Migrate Junit4 tests to Junit5. + testImplementation "org.junit.vintage:junit-vintage-engine:$junitVersion" + testFixturesImplementation project(':smack-xmlparser-stax') testFixturesImplementation project(':smack-xmlparser-xpp3') @@ -59,7 +62,7 @@ task createVersionResource(type: CreateFileTask) { outputFile = new File(projectDir, 'src/main/resources/org.jivesoftware.smack/version') } -compileJava.dependsOn(createVersionResource) +processResources.dependsOn(createVersionResource) jar { bundle { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index 8e3e66828..e29ed25f8 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -1,6 +1,6 @@ /** * - * Copyright 2009 Jive Software, 2018-2022 Florian Schmaus. + * Copyright 2009 Jive Software, 2018-2024 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,6 +19,7 @@ package org.jivesoftware.smack; import java.io.IOException; import java.io.Reader; import java.io.Writer; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; @@ -1067,6 +1068,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { } @Override + @SuppressWarnings("TypeParameterUnusedInFormals") public I sendIqRequestAndWaitForResponse(IQ request) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { StanzaCollector collector = createStanzaCollectorAndSend(request); @@ -1214,7 +1216,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { } Stanza packet = (Stanza) sendTopLevelStreamElement; - final List listenersToNotify = new LinkedList<>(); + final List listenersToNotify = new ArrayList<>(); synchronized (sendListeners) { for (ListenerWrapper listenerWrapper : sendListeners.values()) { if (listenerWrapper.filterMatches(packet)) { @@ -1284,7 +1286,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { private static , MP extends MessageOrPresence> MP fireMessageOrPresenceInterceptors( MP messageOrPresence, Map, GenericInterceptorWrapper> interceptors) { - List> interceptorsToInvoke = new LinkedList<>(); + List> interceptorsToInvoke = new ArrayList<>(); synchronized (interceptors) { for (GenericInterceptorWrapper interceptorWrapper : interceptors.values()) { if (interceptorWrapper.filterMatches(messageOrPresence)) { @@ -1319,7 +1321,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { * @return the, potentially modified stanza, after the interceptors are run. */ private Stanza firePacketInterceptors(Stanza packet) { - List interceptorsToInvoke = new LinkedList<>(); + List interceptorsToInvoke = new ArrayList<>(); synchronized (interceptors) { for (InterceptorWrapper interceptorWrapper : interceptors.values()) { if (interceptorWrapper.filterMatches(packet)) { @@ -1604,7 +1606,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { // First handle the async recv listeners. Note that this code is very similar to what follows a few lines below, // the only difference is that asyncRecvListeners is used here and that the packet listeners are started in // their own thread. - final Collection listenersToNotify = new LinkedList<>(); + final Collection listenersToNotify = new ArrayList<>(); extractMatchingListeners(packet, asyncRecvListeners, listenersToNotify); for (final StanzaListener listener : listenersToNotify) { asyncGoLimited(new Runnable() { @@ -1930,7 +1932,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { // Default implementation does nothing } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) @Override public F getFeature(QName qname) { return (F) streamFeatures.get(qname); @@ -2175,6 +2177,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { * {@link #maxAsyncRunnables}. Note that we use a {@code LinkedList} in order to avoid space blowups in case the * list ever becomes very big and shrinks again. */ + @SuppressWarnings("JdkObsolete") private final Queue deferredAsyncRunnables = new LinkedList<>(); private int deferredAsyncRunnablesCount; diff --git a/smack-core/src/main/java/org/jivesoftware/smack/ScheduledAction.java b/smack-core/src/main/java/org/jivesoftware/smack/ScheduledAction.java index da0377fab..def612a19 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/ScheduledAction.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/ScheduledAction.java @@ -1,6 +1,6 @@ /** * - * Copyright 2018 Florian Schmaus + * Copyright 2018-2024 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,11 +50,13 @@ public class ScheduledAction implements Delayed { return smackReactor.cancel(this); } + @SuppressWarnings("JavaUtilDate") public boolean isDue() { Date now = new Date(); return now.after(releaseTime); } + @SuppressWarnings("JavaUtilDate") public long getTimeToDueMillis() { long now = System.currentTimeMillis(); return releaseTime.getTime() - now; diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackReactor.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackReactor.java index efc6ca602..8fc59ab3a 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SmackReactor.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackReactor.java @@ -1,6 +1,6 @@ /** * - * Copyright 2018-2023 Florian Schmaus + * Copyright 2018-2024 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -144,6 +144,7 @@ public class SmackReactor { } } + @SuppressWarnings("JavaUtilDate") ScheduledAction schedule(Runnable runnable, long delay, TimeUnit unit, ScheduledAction.Kind scheduledActionKind) { long releaseTimeEpoch = System.currentTimeMillis() + unit.toMillis(delay); Date releaseTimeDate = new Date(releaseTimeEpoch); diff --git a/smack-core/src/main/java/org/jivesoftware/smack/StanzaCollector.java b/smack-core/src/main/java/org/jivesoftware/smack/StanzaCollector.java index 2ceaaf19d..dfa0ec7d2 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/StanzaCollector.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/StanzaCollector.java @@ -1,6 +1,6 @@ /** * - * Copyright 2003-2007 Jive Software, 2016-2019 Florian Schmaus. + * Copyright 2003-2007 Jive Software, 2016-2024 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -117,7 +117,7 @@ public final class StanzaCollector implements AutoCloseable { * @return the next stanza result, or null if there are no more * results. */ - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) public synchronized

P pollResult() { return (P) resultQueue.poll(); } @@ -134,6 +134,7 @@ public final class StanzaCollector implements AutoCloseable { * @return the next available packet. * @throws XMPPErrorException in case an error response. */ + @SuppressWarnings("TypeParameterUnusedInFormals") public

P pollResultOrThrow() throws XMPPErrorException { P result = pollResult(); if (result != null) { @@ -150,7 +151,7 @@ public final class StanzaCollector implements AutoCloseable { * @return the next available packet. * @throws InterruptedException if the calling thread was interrupted. */ - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) // TODO: Consider removing this method as it is hardly ever useful. public synchronized

P nextResultBlockForever() throws InterruptedException { throwIfCancelled(); @@ -175,6 +176,7 @@ public final class StanzaCollector implements AutoCloseable { * @return the next available packet. * @throws InterruptedException if the calling thread was interrupted. */ + @SuppressWarnings("TypeParameterUnusedInFormals") public

P nextResult() throws InterruptedException { return nextResult(connection.getReplyTimeout()); } @@ -191,7 +193,7 @@ public final class StanzaCollector implements AutoCloseable { * @return the next available stanza or null on timeout or connection error. * @throws InterruptedException if the calling thread was interrupted. */ - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) public

P nextResult(long timeout) throws InterruptedException { throwIfCancelled(); P res = null; @@ -223,6 +225,7 @@ public final class StanzaCollector implements AutoCloseable { * @throws NotConnectedException if the XMPP connection is not connected. * @see #nextResultOrThrow(long) */ + @SuppressWarnings("TypeParameterUnusedInFormals") public

P nextResultOrThrow() throws NoResponseException, XMPPErrorException, InterruptedException, NotConnectedException { return nextResultOrThrow(connection.getReplyTimeout()); @@ -263,6 +266,7 @@ public final class StanzaCollector implements AutoCloseable { * @throws InterruptedException if the calling thread was interrupted. * @throws NotConnectedException if there was no response and the connection got disconnected. */ + @SuppressWarnings("TypeParameterUnusedInFormals") public

P nextResultOrThrow(long timeout) throws NoResponseException, XMPPErrorException, InterruptedException, NotConnectedException { P result; diff --git a/smack-core/src/main/java/org/jivesoftware/smack/XMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/XMPPConnection.java index c3bd2d414..45cd8328f 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/XMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/XMPPConnection.java @@ -318,6 +318,7 @@ public interface XMPPConnection { * @throws InterruptedException if the calling thread was interrupted. * @since 4.3 */ + @SuppressWarnings("TypeParameterUnusedInFormals") I sendIqRequestAndWaitForResponse(IQ request) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException; @@ -590,6 +591,7 @@ public interface XMPPConnection { * @return a stanza extensions of the feature or null * @since 4.4 */ + @SuppressWarnings("TypeParameterUnusedInFormals") F getFeature(QName qname); /** diff --git a/smack-core/src/main/java/org/jivesoftware/smack/c2s/ModularXmppClientToServerConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/c2s/ModularXmppClientToServerConnection.java index 495720deb..0ece95aa2 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/c2s/ModularXmppClientToServerConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/c2s/ModularXmppClientToServerConnection.java @@ -301,7 +301,7 @@ public final class ModularXmppClientToServerConnection extends AbstractXMPPConne currentStateVertex = StateDescriptorGraph.convertToStateGraph(initialStateDescriptorVertex, connectionInternal); } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) public > CM getConnectionModuleFor( Class descriptorClass) { return (CM) connectionModules.get(descriptorClass); diff --git a/smack-core/src/main/java/org/jivesoftware/smack/compression/zlib/ZlibXmppCompressionFactory.java b/smack-core/src/main/java/org/jivesoftware/smack/compression/zlib/ZlibXmppCompressionFactory.java index 096147931..d851b0c44 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/compression/zlib/ZlibXmppCompressionFactory.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/compression/zlib/ZlibXmppCompressionFactory.java @@ -143,7 +143,9 @@ public final class ZlibXmppCompressionFactory extends XmppCompressionFactory { int bytesWritten = compressor.deflate(buffer, initialOutputBufferPosition, length, flushMode); int newOutputBufferPosition = initialOutputBufferPosition + bytesWritten; - outputBuffer.position(newOutputBufferPosition); + // Workaround for Android API not matching Java >=9 API. + // See https://issuetracker.google.com/issues/369219141 + ((java.nio.Buffer) outputBuffer).position(newOutputBufferPosition); totalBytesWritten += bytesWritten; @@ -156,7 +158,9 @@ public final class ZlibXmppCompressionFactory extends XmppCompressionFactory { increasedBufferSize = MINIMUM_OUTPUT_BUFFER_INCREASE; } ByteBuffer newCurrentOutputBuffer = ByteBuffer.allocate(increasedBufferSize); - outputBuffer.flip(); + // Workaround for Android API not matching Java >=9 API. + // See https://issuetracker.google.com/issues/369219141 + ((java.nio.Buffer) outputBuffer).flip(); newCurrentOutputBuffer.put(outputBuffer); outputBuffer = newCurrentOutputBuffer; } @@ -202,7 +206,9 @@ public final class ZlibXmppCompressionFactory extends XmppCompressionFactory { throw new IOException(e); } - outputBuffer.position(inflateOutputBufferOffset + bytesInflated); + // Workaround for Android API not matching Java >=9 API. + // See https://issuetracker.google.com/issues/369219141 + ((java.nio.Buffer) outputBuffer).position(inflateOutputBufferOffset + bytesInflated); decompressorOutBytes += bytesInflated; @@ -212,7 +218,9 @@ public final class ZlibXmppCompressionFactory extends XmppCompressionFactory { int increasedBufferSize = outputBuffer.capacity() * 2; ByteBuffer increasedOutputBuffer = ByteBuffer.allocate(increasedBufferSize); - outputBuffer.flip(); + // Workaround for Android API not matching Java >=9 API. + // See https://issuetracker.google.com/issues/369219141 + ((java.nio.Buffer) outputBuffer).flip(); increasedOutputBuffer.put(outputBuffer); outputBuffer = increasedOutputBuffer; } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/debugger/ConsoleDebugger.java b/smack-core/src/main/java/org/jivesoftware/smack/debugger/ConsoleDebugger.java index 12d140aad..95c339a5d 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/debugger/ConsoleDebugger.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/debugger/ConsoleDebugger.java @@ -41,6 +41,7 @@ public class ConsoleDebugger extends AbstractDebugger { super(connection); } + @SuppressWarnings("JavaUtilDate") @Override protected void log(String logMessage) { String formatedDate; diff --git a/smack-core/src/main/java/org/jivesoftware/smack/initializer/UrlInitializer.java b/smack-core/src/main/java/org/jivesoftware/smack/initializer/UrlInitializer.java index ec7b047e7..33ced4f39 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/initializer/UrlInitializer.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/initializer/UrlInitializer.java @@ -1,6 +1,6 @@ /** * - * Copyright 2014-2018 Florian Schmaus + * Copyright 2014-2024 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ package org.jivesoftware.smack.initializer; import java.io.InputStream; import java.net.URI; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -42,7 +42,7 @@ public abstract class UrlInitializer implements SmackInitializer { public List initialize() { InputStream is = null; final ClassLoader classLoader = this.getClass().getClassLoader(); - final List exceptions = new LinkedList(); + final List exceptions = new ArrayList(); final String providerUriString = getProvidersUri(); if (providerUriString != null) { try { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/AbstractError.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/AbstractError.java index 147b4f031..50067fc14 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/packet/AbstractError.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/AbstractError.java @@ -1,6 +1,6 @@ /** * - * Copyright 2014-2021 Florian Schmaus + * Copyright 2014-2024 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -108,6 +108,7 @@ public class AbstractError { * @param type of the ExtensionElement. * @return the extension, or null if it doesn't exist. */ + @SuppressWarnings("TypeParameterUnusedInFormals") public PE getExtension(String elementName, String namespace) { return PacketUtil.extensionElementFrom(extensions, elementName, namespace); } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/Mechanisms.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/Mechanisms.java index a981589ee..2d36eb920 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/packet/Mechanisms.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/Mechanisms.java @@ -1,6 +1,6 @@ /** * - * Copyright © 2014-2020 Florian Schmaus + * Copyright © 2014-2024 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,9 @@ */ package org.jivesoftware.smack.packet; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.LinkedList; import java.util.List; import javax.xml.namespace.QName; @@ -31,7 +31,7 @@ public class Mechanisms implements ExtensionElement { public static final String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-sasl"; public static final QName QNAME = new QName(NAMESPACE, ELEMENT); - public final List mechanisms = new LinkedList(); + public final List mechanisms = new ArrayList(); public Mechanisms(String mechanism) { mechanisms.add(mechanism); diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/StandardExtensionElement.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/StandardExtensionElement.java index 8ae1f5a7a..9f1959460 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/packet/StandardExtensionElement.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/StandardExtensionElement.java @@ -1,6 +1,6 @@ /** * - * Copyright 2015-2021 Florian Schmaus. + * Copyright 2015-2024 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,9 +53,7 @@ public final class StandardExtensionElement implements XmlElement { /** * Constructs a new extension element with the given name and namespace and nothing else. - *

* This is meant to construct extension elements used as simple flags in Stanzas. - *

* * @param name the name of the extension element. * @param namespace the namespace of the extension element. diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/StanzaView.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/StanzaView.java index 85c4af1a9..e435d7159 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/packet/StanzaView.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/StanzaView.java @@ -1,6 +1,6 @@ /** * - * Copyright 2019-2021 Florian Schmaus + * Copyright 2019-2024 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ public interface StanzaView extends XmlLangElement { /** * Returns who the stanza is being sent "to", or null if * the value is not set. The XMPP protocol often makes the "to" - * attribute optional, so it does not always need to be set.

+ * attribute optional, so it does not always need to be set. * * @return who the stanza is being sent to, or null if the * value has not been set. @@ -46,7 +46,7 @@ public interface StanzaView extends XmlLangElement { /** * Returns who the stanza is being sent "from" or null if * the value is not set. The XMPP protocol often makes the "from" - * attribute optional, so it does not always need to be set.

+ * attribute optional, so it does not always need to be set. * * @return who the stanza is being sent from, or null if the * value has not been set. diff --git a/smack-core/src/main/java/org/jivesoftware/smack/provider/ProviderFileLoader.java b/smack-core/src/main/java/org/jivesoftware/smack/provider/ProviderFileLoader.java index 11da95318..2781fe0d9 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/provider/ProviderFileLoader.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/provider/ProviderFileLoader.java @@ -17,9 +17,9 @@ package org.jivesoftware.smack.provider; import java.io.InputStream; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -39,11 +39,11 @@ import org.jivesoftware.smack.xml.XmlPullParser; public class ProviderFileLoader implements ProviderLoader { private static final Logger LOGGER = Logger.getLogger(ProviderFileLoader.class.getName()); - private final Collection iqProviders = new LinkedList(); - private final Collection extProviders = new LinkedList(); - private final Collection sfProviders = new LinkedList(); + private final Collection iqProviders = new ArrayList(); + private final Collection extProviders = new ArrayList(); + private final Collection sfProviders = new ArrayList(); - private List exceptions = new LinkedList(); + private List exceptions = new ArrayList(); public ProviderFileLoader(InputStream providerStream) { this(providerStream, ProviderFileLoader.class.getClassLoader()); diff --git a/smack-core/src/main/java/org/jivesoftware/smack/provider/ProviderManager.java b/smack-core/src/main/java/org/jivesoftware/smack/provider/ProviderManager.java index 0943f31d6..b2f08cc3a 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/provider/ProviderManager.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/provider/ProviderManager.java @@ -97,6 +97,7 @@ import org.jivesoftware.smack.util.XmppElementUtil; * </extensionProvider> * </smackProviders> * + *

* If multiple provider entries attempt to register to handle the same element name and namespace, * the first entry loaded from the classpath will take precedence. Whenever a stanza extension * is found in a packet, parsing will be passed to the correct provider. Each provider @@ -106,7 +107,8 @@ import org.jivesoftware.smack.util.XmppElementUtil; * set the properties of th class using the values in the stanza extension sub-element. When an * extension provider is not registered for an element name and namespace combination, Smack will * store all top-level elements of the sub-packet in DefaultPacketExtension object and then - * attach it to the packet.

+ * attach it to the packet. + *

* * @author Matt Tucker */ diff --git a/smack-core/src/main/java/org/jivesoftware/smack/sasl/core/ScramMechanism.java b/smack-core/src/main/java/org/jivesoftware/smack/sasl/core/ScramMechanism.java index 8f4133c81..6dc482ce3 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/sasl/core/ScramMechanism.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/sasl/core/ScramMechanism.java @@ -271,6 +271,7 @@ public abstract class ScramMechanism extends SASLMechanism { return null; } + @SuppressWarnings("MixedMutabilityReturnType") private static Map parseAttributes(String string) throws SmackSaslException { if (string.length() == 0) { return Collections.emptyMap(); diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/MultiMap.java b/smack-core/src/main/java/org/jivesoftware/smack/util/MultiMap.java index 852e01bf7..7e9889e57 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/MultiMap.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/MultiMap.java @@ -1,6 +1,6 @@ /** * - * Copyright © 2015-2021 Florian Schmaus + * Copyright © 2015-2024 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -184,13 +184,14 @@ public class MultiMap { } /** - * Remove the given number of values for a given key. May return less values then requested. + * Remove the given number of values for a given key. May return less values than requested. * * @param key the key to remove from. * @param num the number of values to remove. * @return a list of the removed values. * @since 4.4.0 */ + @SuppressWarnings("MixedMutabilityReturnType") public List remove(K key, int num) { List values = map.get(key); if (values == null) { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java index c04514075..69f0aaca2 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java @@ -1,6 +1,6 @@ /** * - * Copyright 2003-2007 Jive Software, 2019-2023 Florian Schmaus. + * Copyright 2003-2007 Jive Software, 2019-2024 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,6 @@ 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; @@ -87,7 +86,7 @@ public class PacketParserUtils { return parser; } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) public static S parseStanza(String stanza) throws XmlPullParserException, SmackParsingException, IOException { return (S) parseStanza(getParserFor(stanza), XmlEnvironment.EMPTY); } @@ -644,7 +643,7 @@ public class PacketParserUtils { assert parser.getEventType() == XmlPullParser.Event.START_ELEMENT; String name; final int initialDepth = parser.getDepth(); - List methods = new LinkedList<>(); + List methods = new ArrayList<>(); outerloop: while (true) { XmlPullParser.Event eventType = parser.next(); switch (eventType) { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/PacketUtil.java b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketUtil.java index a68e91dd0..40da6f4d6 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/PacketUtil.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketUtil.java @@ -1,6 +1,6 @@ /** * - * Copyright © 2014-2021 Florian Schmaus + * Copyright © 2014-2024 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ public class PacketUtil { * * @return the extension element */ - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) public static PE extensionElementFrom(Collection collection, String element, String namespace) { for (XmlElement packetExtension : collection) { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/Pair.java b/smack-core/src/main/java/org/jivesoftware/smack/util/Pair.java index 08bf41234..76ebc1dc5 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/Pair.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/Pair.java @@ -1,6 +1,6 @@ /** * - * Copyright 2020 Florian Schmaus. + * Copyright 2020-2024 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ public final class Pair { return new Pair<>(first, second); } + @SuppressWarnings("ReturnValueIgnored") public static Pair createAndInitHashCode(F first, S second) { Pair pair = new Pair<>(first, second); pair.hashCode(); diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/StringUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/StringUtils.java index 1a66cc0f3..ffadbda00 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/StringUtils.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/StringUtils.java @@ -329,7 +329,10 @@ public class StringUtils { throw new AssertionError(e); } - return charBuffer.flip().toString(); + // Workaround for Android API not matching Java >=9 API. + // See https://issuetracker.google.com/issues/369219141 + ((java.nio.Buffer) charBuffer).flip(); + return charBuffer.toString(); } private static void randomString(Appendable appendable, Random random, char[] alphabet, int numRandomChars) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/XmppElementUtil.java b/smack-core/src/main/java/org/jivesoftware/smack/util/XmppElementUtil.java index 5639a7e5f..7ffe2f2eb 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/XmppElementUtil.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/XmppElementUtil.java @@ -71,6 +71,7 @@ public class XmppElementUtil { return qname; } + @SuppressWarnings("MixedMutabilityReturnType") public static List getElementsFrom( MultiMap elementMap, Class extensionElementClass) { QName qname = XmppElementUtil.getQNameFor(extensionElementClass); diff --git a/smack-core/src/testFixtures/java/org/jivesoftware/smack/DummyConnection.java b/smack-core/src/testFixtures/java/org/jivesoftware/smack/DummyConnection.java index 7df852975..2faca2ebc 100644 --- a/smack-core/src/testFixtures/java/org/jivesoftware/smack/DummyConnection.java +++ b/smack-core/src/testFixtures/java/org/jivesoftware/smack/DummyConnection.java @@ -91,6 +91,7 @@ public class DummyConnection extends AbstractXMPPConnection { user = getUserJid(); } + @SuppressWarnings("JavaUtilDate") @Override protected void connectInternal() { connected = true; @@ -162,6 +163,7 @@ public class DummyConnection extends AbstractXMPPConnection { * @param

the top level stream element class. * @return a sent packet. */ + @SuppressWarnings("TypeParameterUnusedInFormals") public

P getSentPacket() { return getSentPacket(5 * 60); } @@ -176,7 +178,7 @@ public class DummyConnection extends AbstractXMPPConnection { * @param

the top level stream element class. * @return a sent packet. */ - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) public

P getSentPacket(int wait) { try { return (P) queue.poll(wait, TimeUnit.SECONDS); diff --git a/smack-debug-slf4j/build.gradle b/smack-debug-slf4j/build.gradle index 35d904a7e..71eae05b4 100644 --- a/smack-debug-slf4j/build.gradle +++ b/smack-debug-slf4j/build.gradle @@ -1,3 +1,7 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' +} + description = """\ Smack slf4j debugger. Inspect the exchanged XMPP stanzas. diff --git a/smack-debug/build.gradle b/smack-debug/build.gradle index 959caff4f..7c9fdc0f1 100644 --- a/smack-debug/build.gradle +++ b/smack-debug/build.gradle @@ -1,3 +1,7 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' +} + description = """\ Smack GUI debugger. Inspect the exchanged XMPP stanzas.""" diff --git a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java index 40d2e5263..23eba68ec 100644 --- a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java +++ b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java @@ -160,6 +160,7 @@ public class EnhancedDebugger extends SmackDebugger { private ReaderListener readerListener; private WriterListener writerListener; + @SuppressWarnings("JavaUtilDate") private Date creationTime = new Date(); // Statistics variables @@ -756,6 +757,7 @@ public class EnhancedDebugger extends SmackDebugger { * @param dateFormatter the SimpleDateFormat to use to format Dates * @param packet the read stanza to add to the table */ + @SuppressWarnings("JavaUtilDate") private void addReadPacketToTable(final SimpleDateFormat dateFormatter, final TopLevelStreamElement packet) { SwingUtilities.invokeLater(new Runnable() { @Override @@ -827,6 +829,7 @@ public class EnhancedDebugger extends SmackDebugger { * @param dateFormatter the SimpleDateFormat to use to format Dates * @param packet the sent stanza to add to the table */ + @SuppressWarnings("JavaUtilDate") private void addSentPacketToTable(final SimpleDateFormat dateFormatter, final TopLevelStreamElement packet) { SwingUtilities.invokeLater(new Runnable() { @Override diff --git a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebuggerWindow.java b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebuggerWindow.java index 5755207d8..cadcb0b53 100644 --- a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebuggerWindow.java +++ b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebuggerWindow.java @@ -204,7 +204,7 @@ public final class EnhancedDebuggerWindow { * Creates the main debug window that provides information about Smack and also shows * a tab panel for each connection that is being debugged. */ - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({ "rawtypes", "unchecked", "JdkObsolete" }) private void createDebug() { frame = new JFrame("Smack Debug Window"); diff --git a/smack-examples/build.gradle b/smack-examples/build.gradle index 7592441a5..244040dd7 100644 --- a/smack-examples/build.gradle +++ b/smack-examples/build.gradle @@ -1,3 +1,7 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' +} + description = """\ Examples and test applications for Smack""" diff --git a/smack-examples/src/main/java/org/igniterealtime/smack/examples/XmppTools.java b/smack-examples/src/main/java/org/igniterealtime/smack/examples/XmppTools.java index f262102c2..70bb9f1f2 100644 --- a/smack-examples/src/main/java/org/igniterealtime/smack/examples/XmppTools.java +++ b/smack-examples/src/main/java/org/igniterealtime/smack/examples/XmppTools.java @@ -1,6 +1,6 @@ /** * - * Copyright 2016-2021 Florian Schmaus + * Copyright 2016-2024 Florian Schmaus * * This file is part of smack-examples. * @@ -136,6 +136,7 @@ public class XmppTools { // CHECKSTYLE:ON } + @SuppressWarnings("JavaUtilDate") public static void sendItsAlive(String to, XMPPConnection connection) throws XmppStringprepException, NotConnectedException, InterruptedException { if (to == null) { diff --git a/smack-experimental/build.gradle b/smack-experimental/build.gradle index 9e945e0d5..7484d56f8 100644 --- a/smack-experimental/build.gradle +++ b/smack-experimental/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description = """\ Smack experimental extensions. Classes and methods for XEPs that are in status 'experimental' or that should diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/iot/data/element/IoTFieldsExtension.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/iot/data/element/IoTFieldsExtension.java index cb280745f..721b1b657 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/iot/data/element/IoTFieldsExtension.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/iot/data/element/IoTFieldsExtension.java @@ -83,6 +83,7 @@ public class IoTFieldsExtension implements ExtensionElement { return xml; } + @SuppressWarnings("JavaUtilDate") public static IoTFieldsExtension buildFor(int seqNr, boolean done, NodeInfo nodeInfo, List data) { TimestampElement timestampElement = new TimestampElement(new Date(), data); diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/JingleFileTransferChild.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/JingleFileTransferChild.java index b4e9021ec..cab86e550 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/JingleFileTransferChild.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/JingleFileTransferChild.java @@ -1,6 +1,6 @@ /** * - * Copyright 2017 Paul Schaub, 2019 Florian Schmaus + * Copyright 2017 Paul Schaub, 2019-2024 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -167,6 +167,7 @@ public class JingleFileTransferChild implements JingleContentDescriptionChildEle return new JingleFileTransferChild(date, desc, hash, mediaType, name, size, range); } + @SuppressWarnings("JavaUtilDate") public Builder setFile(File file) { return setDate(new Date(file.lastModified())) .setName(file.getAbsolutePath().substring(file.getAbsolutePath().lastIndexOf("/") + 1)) diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java index 985ca8b48..6ce58bdea 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java @@ -1,6 +1,6 @@ /** * - * Copyright © 2017-2023 Florian Schmaus, 2016-2017 Fernando Ramirez + * Copyright © 2017-2024 Florian Schmaus, 2016-2017 Fernando Ramirez * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -387,6 +387,7 @@ public final class MamManager extends Manager { return this; } + @SuppressWarnings("JavaUtilDate") public Builder limitResultsSince(Date start) { if (start == null) { return this; @@ -415,6 +416,7 @@ public final class MamManager extends Manager { return this; } + @SuppressWarnings("JavaUtilDate") public Builder limitResultsBefore(Date end) { if (end == null) { return this; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/spoiler/element/SpoilerElement.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/spoiler/element/SpoilerElement.java index 6d5c02fd6..b18a5af5c 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/spoiler/element/SpoilerElement.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/spoiler/element/SpoilerElement.java @@ -114,6 +114,7 @@ public class SpoilerElement implements ExtensionElement { * @param message message * @return map of spoilers */ + @SuppressWarnings("MixedMutabilityReturnType") public static Map getSpoilers(Message message) { if (!containsSpoiler(message)) { return Collections.emptyMap(); diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/stanza_content_encryption/element/TimestampAffixElement.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/stanza_content_encryption/element/TimestampAffixElement.java index 0c48f7b7a..eee726085 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/stanza_content_encryption/element/TimestampAffixElement.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/stanza_content_encryption/element/TimestampAffixElement.java @@ -56,6 +56,7 @@ public class TimestampAffixElement implements NamedElement, AffixElement { return EqualsUtil.equals(this, obj, (e, o) -> e.append(getTimestamp(), o.getTimestamp())); } + @SuppressWarnings("JavaUtilDate") @Override public int hashCode() { return timestamp.hashCode(); diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/FiltersTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/FiltersTest.java index b5c974dce..df14ea279 100644 --- a/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/FiltersTest.java +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/FiltersTest.java @@ -1,6 +1,6 @@ /** * - * Copyright 2016 Fernando Ramirez, 2018-2020 Florian Schmaus + * Copyright 2016 Fernando Ramirez, 2018-2024 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,6 +46,7 @@ public class FiltersTest extends MamTest { return xml; } + @SuppressWarnings("JavaUtilDate") @Test public void checkStartDateFilter() throws Exception { Date date = new Date(); @@ -61,6 +62,7 @@ public class FiltersTest extends MamTest { assertEquals(getMamXMemberWith(fields, values), dataForm.toXML().toString()); } + @SuppressWarnings("JavaUtilDate") @Test public void checkEndDateFilter() throws Exception { Date date = new Date(); diff --git a/smack-extensions/build.gradle b/smack-extensions/build.gradle index 2489c9f87..0b62da32c 100644 --- a/smack-extensions/build.gradle +++ b/smack-extensions/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description = """\ Smack extensions. Classes and methods that implement support for the various XMPP XEPs diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java index 823df54e1..e527d416a 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java @@ -16,8 +16,8 @@ */ package org.jivesoftware.smackx.bytestreams.ibb; +import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.WeakHashMap; @@ -135,7 +135,7 @@ public final class InBandBytestreamManager extends Manager implements Bytestream * list of listeners that respond to all In-Band Bytestream requests if there are no user * specific listeners for that request */ - private final List allRequestListeners = Collections.synchronizedList(new LinkedList()); + private final List allRequestListeners = Collections.synchronizedList(new ArrayList()); /* listener that handles all incoming In-Band Bytestream requests */ private final InitiationListener initiationListener; @@ -162,7 +162,7 @@ public final class InBandBytestreamManager extends Manager implements Bytestream * list containing session IDs of In-Band Bytestream open packets that should be ignored by the * InitiationListener */ - private final List ignoredBytestreamRequests = Collections.synchronizedList(new LinkedList()); + private final List ignoredBytestreamRequests = Collections.synchronizedList(new ArrayList()); /** * Returns the InBandBytestreamManager to handle In-Band Bytestreams for a given diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java index a0dd45581..fac036a1d 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java @@ -22,7 +22,6 @@ import java.net.Socket; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -128,7 +127,7 @@ public final class Socks5BytestreamManager extends Manager implements Bytestream * list of listeners that respond to all bytestream requests if there are not user specific * listeners for that request */ - private final List allRequestListeners = Collections.synchronizedList(new LinkedList()); + private final List allRequestListeners = Collections.synchronizedList(new ArrayList()); /* listener that handles all incoming bytestream requests */ private final InitiationListener initiationListener; @@ -154,7 +153,7 @@ public final class Socks5BytestreamManager extends Manager implements Bytestream * list containing session IDs of SOCKS5 Bytestream initialization packets that should be * ignored by the InitiationListener */ - private final List ignoredBytestreamRequests = Collections.synchronizedList(new LinkedList()); + private final List ignoredBytestreamRequests = Collections.synchronizedList(new ArrayList()); /** * Returns the Socks5BytestreamManager to handle SOCKS5 Bytestreams for a given diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java index 88e7abfe2..9d1191b3e 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java @@ -26,12 +26,12 @@ import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.LinkedHashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -107,7 +107,7 @@ public class Socks5Proxy { private final Map connectionMap = new ConcurrentHashMap<>(); /* list of digests connections should be stored */ - private final List allowedConnections = Collections.synchronizedList(new LinkedList()); + private final List allowedConnections = Collections.synchronizedList(new ArrayList()); private final Set localAddresses = new LinkedHashSet<>(4); @@ -345,7 +345,7 @@ public class Socks5Proxy { */ public List getLocalAddresses() { synchronized (localAddresses) { - return new LinkedList<>(localAddresses); + return new ArrayList<>(localAddresses); } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java index c15cdf131..aaa87e2b0 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java @@ -1,6 +1,6 @@ /** * - * Copyright © 2009 Jonas Ådahl, 2011-2022 Florian Schmaus + * Copyright © 2009 Jonas Ådahl, 2011-2024 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,12 +19,12 @@ package org.jivesoftware.smackx.caps; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; @@ -555,7 +555,7 @@ public final class EntityCapsManager extends Manager { if (connection != null) JID_TO_NODEVER_CACHE.put(connection.getUser(), new NodeVerHash(entityNode, currentCapsVersion)); - final List identities = new LinkedList<>(ServiceDiscoveryManager.getInstanceFor(connection).getIdentities()); + final List identities = new ArrayList<>(ServiceDiscoveryManager.getInstanceFor(connection).getIdentities()); sdm.setNodeInformationProvider(localNodeVer, new AbstractNodeInformationProvider() { List features = sdm.getFeatures(); List packetExtensions = sdm.getExtendedInfo(); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java index 3953b9c63..e50f6d956 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java @@ -22,7 +22,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -772,7 +771,7 @@ public final class ServiceDiscoveryManager extends Manager { return serviceDiscoInfo; } } - serviceDiscoInfo = new LinkedList<>(); + serviceDiscoInfo = new ArrayList<>(); // Send the disco packet to the server itself DiscoverInfo info; try { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java index 08560bc25..9df5c64ac 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java @@ -19,7 +19,6 @@ package org.jivesoftware.smackx.disco.packet; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Set; @@ -184,7 +183,7 @@ public class DiscoverInfo extends IQ implements DiscoverInfoView { * @return true if duplicate identities where found, otherwise false */ public boolean containsDuplicateIdentities() { - List checkedIdentities = new LinkedList<>(); + List checkedIdentities = new ArrayList<>(identities.size()); for (Identity i : identities) { for (Identity i2 : checkedIdentities) { if (i.equals(i2)) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverItems.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverItems.java index 34c62a8a1..a6394716c 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverItems.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverItems.java @@ -16,9 +16,9 @@ */ package org.jivesoftware.smackx.disco.packet; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.LinkedList; import java.util.List; import org.jivesoftware.smack.packet.IQ; @@ -40,7 +40,7 @@ public class DiscoverItems extends IQ { public static final String ELEMENT = QUERY_ELEMENT; public static final String NAMESPACE = "http://jabber.org/protocol/disco#items"; - private final List items = new LinkedList<>(); + private final List items = new ArrayList<>(); private String node; public DiscoverItems() { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/provider/RegistrationProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/provider/RegistrationProvider.java index 67da11bbe..d087a5bf4 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/provider/RegistrationProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/provider/RegistrationProvider.java @@ -17,8 +17,8 @@ package org.jivesoftware.smackx.iqregister.provider; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -40,7 +40,7 @@ public class RegistrationProvider extends IqProvider { public Registration parse(XmlPullParser parser, int initialDepth, IqData iqData, XmlEnvironment xmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException { String instruction = null; Map fields = new HashMap<>(); - List packetExtensions = new LinkedList<>(); + List packetExtensions = new ArrayList<>(); outerloop: while (true) { XmlPullParser.Event eventType = parser.next(); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/packet/Version.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/packet/Version.java index b0dd5c1d0..fb0ca01fa 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/packet/Version.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/packet/Version.java @@ -1,6 +1,6 @@ /** * - * Copyright 2003-2007 Jive Software, 2021 Florian Schmaus. + * Copyright 2003-2007 Jive Software, 2021-2024 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import org.jivesoftware.smack.util.StringUtils; /** * A Version IQ packet, which is used by XMPP clients to discover version information - * about the software running at another entity's JID.

+ * about the software running at another entity's JID. * * @author Gaston Dombiak */ diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/last_interaction/element/IdleElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/last_interaction/element/IdleElement.java index 2799c1224..6603fe21b 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/last_interaction/element/IdleElement.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/last_interaction/element/IdleElement.java @@ -37,6 +37,7 @@ public class IdleElement implements ExtensionElement { /** * Create a new IdleElement with the current date as date of last user interaction. */ + @SuppressWarnings("JavaUtilDate") public IdleElement() { this(new Date()); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MucEnterConfiguration.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MucEnterConfiguration.java index e2a73dad1..58c0c4e26 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MucEnterConfiguration.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MucEnterConfiguration.java @@ -101,9 +101,7 @@ public final class MucEnterConfiguration { /** * Set the presence used to join the MUC room. - *

* The consumer must not modify the presence type, otherwise an {@link IllegalArgumentException} will be thrown. - *

* * @param presenceBuilderConsumer a consumer which will be passed the presence build. * @return a reference to this builder. diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java index 3c283adc5..e71f6b523 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java @@ -1842,7 +1842,7 @@ public class MultiUserChat { /** * Returns the presence info for a particular user, or null if the user - * is not in the room.

+ * is not in the room. * * @param user the room occupant to search for his presence. The format of user must * be: roomName@service/nickname (e.g. darkcave@macbeth.shakespeare.lit/thirdwitch). @@ -1856,7 +1856,7 @@ public class MultiUserChat { /** * Returns the Occupant information for a particular occupant, or null if the * user is not in the room. The Occupant object may include information such as full - * JID of the user as well as the role and affiliation of the user in the room.

+ * JID of the user as well as the role and affiliation of the user in the room. * * @param user the room occupant to search for his presence. The format of user must * be: roomName@service/nickname (e.g. darkcave@macbeth.shakespeare.lit/thirdwitch). diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java index 7ebfdfdc9..4d8c5c637 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java @@ -108,6 +108,7 @@ public final class MultiUserChatManager extends Manager { final WeakReference weakRefConnection = new WeakReference(connection); ServiceDiscoveryManager.getInstanceFor(connection).setNodeInformationProvider(DISCO_NODE, new AbstractNodeInformationProvider() { + @SuppressWarnings({"JavaUtilDate", "MixedMutabilityReturnType"}) @Override public List getNodeItems() { XMPPConnection connection = weakRefConnection.get(); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/ItemPublishEvent.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/ItemPublishEvent.java index 577dad4f7..7018b5934 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/ItemPublishEvent.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/ItemPublishEvent.java @@ -109,6 +109,7 @@ public class ItemPublishEvent extends SubscriptionEvent { return originalDate; } + @SuppressWarnings("JavaUtilDate") @Override public String toString() { return getClass().getName() + " [subscriptions: " + getSubscriptions() + "], [Delayed: " + diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/packet/PubSub.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/packet/PubSub.java index a2756d5ff..cf708afe9 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/packet/PubSub.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/packet/PubSub.java @@ -49,7 +49,7 @@ public class PubSub extends IQ { setType(type); } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) public PE getExtension(PubSubElementType elem) { return (PE) getExtensionElement(elem.getElementName(), elem.getNamespace().getXmlns()); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/rsm/RSMManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/rsm/RSMManager.java index ea6924fae..9f03c257a 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/rsm/RSMManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/rsm/RSMManager.java @@ -1,6 +1,6 @@ /** * - * Copyright © 2014-2021 Florian Schmaus + * Copyright © 2014-2024 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,8 +16,8 @@ */ package org.jivesoftware.smackx.rsm; +import java.util.ArrayList; import java.util.Collection; -import java.util.LinkedList; import java.util.List; import org.jivesoftware.smack.packet.XmlElement; @@ -29,7 +29,7 @@ import org.jivesoftware.smackx.rsm.packet.RSMSet.PageDirection; public class RSMManager { Collection page(int max) { - List packetExtensions = new LinkedList<>(); + List packetExtensions = new ArrayList<>(); packetExtensions.add(new RSMSet(max)); return packetExtensions; } @@ -45,7 +45,7 @@ public class RSMManager { throw new IllegalArgumentException("returnedExtensions must no be null"); } if (additionalExtensions == null) { - additionalExtensions = new LinkedList<>(); + additionalExtensions = new ArrayList<>(); } RSMSet resultRsmSet = PacketUtil.extensionElementFrom(returnedExtensions, RSMSet.ELEMENT, RSMSet.NAMESPACE); if (resultRsmSet == null) { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/si/provider/StreamInitiationProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/si/provider/StreamInitiationProvider.java index a4be338b5..d6333ed80 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/si/provider/StreamInitiationProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/si/provider/StreamInitiationProvider.java @@ -45,6 +45,7 @@ import org.jxmpp.util.XmppDateTime; public class StreamInitiationProvider extends IqProvider { private static final Logger LOGGER = Logger.getLogger(StreamInitiationProvider.class.getName()); + @SuppressWarnings("JavaUtilDate") @Override public StreamInitiation parse(XmlPullParser parser, int initialDepth, IqData iqData, XmlEnvironment xmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException { // si diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/caps/EntityCapsManagerTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/caps/EntityCapsManagerTest.java index 94f0fdaaa..d9a0666c3 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/caps/EntityCapsManagerTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/caps/EntityCapsManagerTest.java @@ -22,8 +22,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; -import java.util.LinkedList; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.test.util.SmackTestSuite; @@ -218,7 +218,7 @@ public class EntityCapsManagerTest extends SmackTestSuite { di.to(JidCreate.from("juliet@capulet.lit/chamber")); di.ofType(IQ.Type.result); - Collection identities = new LinkedList(); + Collection identities = new ArrayList(); DiscoverInfo.Identity i = new DiscoverInfo.Identity("client", "pc", "Psi 0.11", "en"); identities.add(i); i = new DiscoverInfo.Identity("client", "pc", "Ψ 0.11", "el"); @@ -241,7 +241,7 @@ public class EntityCapsManagerTest extends SmackTestSuite { di.to(")juliet@capulet.lit/chamber"); di.ofType(IQ.Type.result); - Collection identities = new LinkedList(); + Collection identities = new ArrayList(); DiscoverInfo.Identity i = new DiscoverInfo.Identity("client", "pc", "Psi 0.11", "en"); identities.add(i); i = new DiscoverInfo.Identity("client", "pc", "Ψ 0.11", "el"); diff --git a/smack-extensions/src/testFixtures/java/org/jivesoftware/util/Protocol.java b/smack-extensions/src/testFixtures/java/org/jivesoftware/util/Protocol.java index f256a9728..9e1bdc652 100644 --- a/smack-extensions/src/testFixtures/java/org/jivesoftware/util/Protocol.java +++ b/smack-extensions/src/testFixtures/java/org/jivesoftware/util/Protocol.java @@ -89,6 +89,7 @@ public class Protocol { public boolean printProtocol = false; // responses to requests are taken form this queue + @SuppressWarnings("JdkObsolete") private final Queue responses = new LinkedList<>(); // list of verifications diff --git a/smack-im/build.gradle b/smack-im/build.gradle index f3cb2d475..beb30a966 100644 --- a/smack-im/build.gradle +++ b/smack-im/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description = """\ Smack IM. Classes and methods for XMPP-IM (RFC 6121): @@ -8,4 +13,7 @@ Roster, Chat and other functionality.""" dependencies { api project(':smack-core') testImplementation(testFixtures(project(":smack-core"))) + + // TODO: Migrate Junit4 tests to Junit5. + testImplementation "org.junit.vintage:junit-vintage-engine:$junitVersion" } diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterUtil.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterUtil.java index 843b24bad..5f2093404 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterUtil.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterUtil.java @@ -1,6 +1,6 @@ /** * - * Copyright 2016 Florian Schmaus + * Copyright 2016-2024 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import org.jxmpp.jid.Jid; public class RosterUtil { + @SuppressWarnings("JavaUtilDate") public static void waitUntilOtherEntityIsSubscribed(Roster roster, BareJid otherEntity, long timeoutMillis) throws InterruptedException, TimeoutException { Date deadline = new Date(System.currentTimeMillis() + timeoutMillis); @@ -147,6 +148,7 @@ public class RosterUtil { ensureSubscribedTo(connectionTwo, connectionOne, timeout); } + @SuppressWarnings("JavaUtilDate") public static void ensureSubscribedTo(XMPPConnection connectionOne, XMPPConnection connectionTwo, long timeout) throws NotLoggedInException, NotConnectedException, InterruptedException, TimeoutException { Date deadline = new Date(System.currentTimeMillis() + timeout); diff --git a/smack-integration-test/build.gradle b/smack-integration-test/build.gradle index ea08655af..479ee0036 100644 --- a/smack-integration-test/build.gradle +++ b/smack-integration-test/build.gradle @@ -1,10 +1,15 @@ -apply plugin: 'application' +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.application-conventions' +} description = """\ Smack integration tests.""" -mainClassName = 'org.igniterealtime.smack.inttest.SmackIntegrationTestFramework' -applicationDefaultJvmArgs = ["-enableassertions"] + +application { + mainClass = 'org.igniterealtime.smack.inttest.SmackIntegrationTestFramework' +} dependencies { api project(':smack-java8-full') @@ -20,8 +25,3 @@ dependencies { testFixturesApi(testFixtures(project(":smack-core"))) testImplementation "org.jxmpp:jxmpp-jid:$jxmppVersion:tests" } - -run { - // Pass all system properties down to the "application" run - systemProperties System.getProperties() -} diff --git a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/Configuration.java b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/Configuration.java index 0616da38a..889f9bb9c 100644 --- a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/Configuration.java +++ b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/Configuration.java @@ -1,6 +1,6 @@ /** * - * Copyright 2015-2023 Florian Schmaus + * Copyright 2015-2024 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,11 +22,11 @@ import java.io.IOException; import java.lang.reflect.Method; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; @@ -587,7 +587,7 @@ public final class Configuration { } private static File findPropertiesFile() { - List possibleLocations = new LinkedList<>(); + List possibleLocations = new ArrayList<>(); possibleLocations.add("properties"); String userHome = System.getProperty("user.home"); if (userHome != null) { diff --git a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java index dd0f7fcac..3fb4edaae 100644 --- a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java +++ b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java @@ -1,6 +1,6 @@ /** * - * Copyright 2015-2023 Florian Schmaus + * Copyright 2015-2024 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,7 +39,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; @@ -698,9 +697,9 @@ public class SmackIntegrationTestFramework { */ public final String testRunId = StringUtils.insecureRandomString(5).toLowerCase(Locale.US); - private final List successfulIntegrationTests = Collections.synchronizedList(new LinkedList()); - private final List failedIntegrationTests = Collections.synchronizedList(new LinkedList()); - private final List impossibleIntegrationTests = Collections.synchronizedList(new LinkedList()); + private final List successfulIntegrationTests = Collections.synchronizedList(new ArrayList()); + private final List failedIntegrationTests = Collections.synchronizedList(new ArrayList()); + private final List impossibleIntegrationTests = Collections.synchronizedList(new ArrayList()); // TODO: Ideally three would only be a list of disabledTests, but since we do not process a disabled test class // any further, we can not determine the concrete disabled tests. diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smack/ChatTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smack/ChatTest.java index d956c92ee..56a5ec10e 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smack/ChatTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smack/ChatTest.java @@ -66,8 +66,8 @@ public class ChatTest extends AbstractSmackIntegrationTest { JivePropertiesManager.setJavaObjectEnabled(false); } - @SuppressWarnings("deprecation") @SmackIntegrationTest + @SuppressWarnings({"deprecation", "JavaUtilDate"}) public void testProperties() throws Exception { org.jivesoftware.smack.chat.Chat newChat = chatManagerOne.createChat(conTwo.getUser()); StanzaCollector collector = conTwo.createStanzaCollector(new ThreadFilter(newChat.getThreadID())); diff --git a/smack-java8-full/build.gradle b/smack-java8-full/build.gradle index 7607d3c02..61a4e00e0 100644 --- a/smack-java8-full/build.gradle +++ b/smack-java8-full/build.gradle @@ -1,3 +1,7 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' +} + description = """\ Full Smack library for Java SE.""" @@ -44,6 +48,7 @@ task convertModularXmppClientToServerConnectionStateGraphDotToPng(type: Exec) { executable 'dot' args "-Tpng", "-o", "${outputs.files.first()}", "${inputs.files.first()}" } +copyJavadocDocFiles.dependsOn convertModularXmppClientToServerConnectionStateGraphDotToPng task cleanGenerateFiles(type: Delete) { delete 'src/javadoc/org/jivesoftware/smack/full/doc-files/ModularXmppClientToServerConnectionStateGraph.dot', 'src/javadoc/org/jivesoftware/smack/full/doc-files/ModularXmppClientToServerConnectionStateGraph.png' diff --git a/smack-java8/build.gradle b/smack-java8/build.gradle index d26aa5ce3..d3d157ad1 100644 --- a/smack-java8/build.gradle +++ b/smack-java8/build.gradle @@ -1,7 +1,11 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' +} + description = """\ -Smack for Java7 (or higher). +Smack for Java 11 (or higher). This is a pseudo-artifact that pulls all the required dependencies to -run Smack on Java 7 (or higher) JVMs. Usually you want to add additional +run Smack on Java 11 (or higher) JVMs. Usually you want to add additional dependencies to smack-tcp, smack-extensions and smack-experimental.""" dependencies { diff --git a/smack-java8/src/main/java/org/jivesoftware/smack/java7/XmppHostnameVerifier.java b/smack-java8/src/main/java/org/jivesoftware/smack/java7/XmppHostnameVerifier.java index 16e1c5668..a03cd097a 100644 --- a/smack-java8/src/main/java/org/jivesoftware/smack/java7/XmppHostnameVerifier.java +++ b/smack-java8/src/main/java/org/jivesoftware/smack/java7/XmppHostnameVerifier.java @@ -1,6 +1,6 @@ /** * - * Copyright 2015 Florian Schmaus + * Copyright 2015-2024 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,8 +23,8 @@ import java.security.Principal; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.Collection; -import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.logging.Level; @@ -135,7 +135,7 @@ public class XmppHostnameVerifier implements HostnameVerifier { private static void matchDns(String name, X509Certificate cert) throws CertificateException { Collection> subjAltNames = cert.getSubjectAlternativeNames(); if (subjAltNames != null) { - List nonMatchingDnsAltnames = new LinkedList<>(); + List nonMatchingDnsAltnames = new ArrayList<>(); for (List san : subjAltNames) { if (((Integer) san.get(0)).intValue() != ALTNAME_DNS) { continue; @@ -253,7 +253,7 @@ public class XmppHostnameVerifier implements HostnameVerifier { if (subjectAlternativeNames == null) { throw new CertificateException("No subject alternative names present"); } - List nonMatchingIpAltnames = new LinkedList<>(); + List nonMatchingIpAltnames = new ArrayList<>(); for (List san : subjectAlternativeNames) { if (((Integer) san.get(0)).intValue() != ALTNAME_IP) { continue; diff --git a/smack-jingle-old/build.gradle b/smack-jingle-old/build.gradle index 5651864f2..63e732bee 100644 --- a/smack-jingle-old/build.gradle +++ b/smack-jingle-old/build.gradle @@ -1,3 +1,7 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' +} + description = """\ Smack Jingle API. Warning: This API is beta, outdated and currenlty unmaintained.""" diff --git a/smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/mediaimpl/sshare/api/OctTreeQuantizer.java b/smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/mediaimpl/sshare/api/OctTreeQuantizer.java index bb6e7ff27..91cdd7de0 100644 --- a/smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/mediaimpl/sshare/api/OctTreeQuantizer.java +++ b/smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/mediaimpl/sshare/api/OctTreeQuantizer.java @@ -76,6 +76,7 @@ public class OctTreeQuantizer implements Quantizer { private int colors = 0; private final List> colorList; + @SuppressWarnings("JdkObsolete") public OctTreeQuantizer() { setup(256); colorList = new ArrayList<>(MAX_LEVEL + 1); diff --git a/smack-legacy/build.gradle b/smack-legacy/build.gradle index 1ecec2720..12cb8b457 100644 --- a/smack-legacy/build.gradle +++ b/smack-legacy/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description = """\ Smack legacy extensions. Usually XEPs in the state 'retracted', 'rejected', 'deprecated', diff --git a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/agent/AgentRoster.java b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/agent/AgentRoster.java index 454221d70..c0f489e8b 100644 --- a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/agent/AgentRoster.java +++ b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/agent/AgentRoster.java @@ -203,7 +203,7 @@ public class AgentRoster { /** * Returns the presence info for a particular agent, or null if the agent - * is unavailable (offline) or if no presence information is available.

+ * is unavailable (offline) or if no presence information is available. * * @param user a fully qualified xmpp JID. The address could be in any valid format (e.g. * "domain/resource", "user@domain" or "user@domain/resource"). diff --git a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/agent/AgentSession.java b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/agent/AgentSession.java index 4c2e57c52..0767f7ea8 100644 --- a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/agent/AgentSession.java +++ b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/agent/AgentSession.java @@ -710,6 +710,7 @@ public class AgentSession { } } + @SuppressWarnings("JavaUtilDate") private void fireOfferRequestEvent(OfferRequestProvider.OfferRequestPacket requestPacket) { Offer offer = new Offer(this.connection, this, requestPacket.getUserID(), requestPacket.getUserJID(), this.getWorkgroupJID(), @@ -723,6 +724,7 @@ public class AgentSession { } } + @SuppressWarnings("JavaUtilDate") private void fireOfferRevokeEvent(OfferRevokeProvider.OfferRevokePacket orp) { RevokedOffer revokedOffer = new RevokedOffer(orp.getUserJID(), orp.getUserID(), this.getWorkgroupJID(), orp.getSessionID(), orp.getReason(), new Date()); diff --git a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/ext/history/AgentChatHistory.java b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/ext/history/AgentChatHistory.java index 87b03daf4..3fc5f4a1e 100644 --- a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/ext/history/AgentChatHistory.java +++ b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/ext/history/AgentChatHistory.java @@ -54,6 +54,7 @@ public class AgentChatHistory extends IQ { private final List agentChatSessions = new ArrayList<>(); + @SuppressWarnings("JavaUtilDate") public AgentChatHistory(EntityBareJid agentJID, int maxSessions, Date startDate) { this(); this.agentJID = agentJID; @@ -116,6 +117,7 @@ public class AgentChatHistory extends IQ { return agentChatHistory; } + @SuppressWarnings("JavaUtilDate") private static AgentChatSession parseChatSetting(XmlPullParser parser) throws XmlPullParserException, IOException { boolean done = false; diff --git a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/packet/QueueDetails.java b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/packet/QueueDetails.java index 19d7a0e3b..f29eb7738 100644 --- a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/packet/QueueDetails.java +++ b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/packet/QueueDetails.java @@ -145,6 +145,7 @@ public final class QueueDetails implements ExtensionElement { */ public static class Provider extends ExtensionElementProvider { + @SuppressWarnings("JavaUtilDate") @Override public QueueDetails parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) throws XmlPullParserException, diff --git a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/util/MetaDataUtils.java b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/util/MetaDataUtils.java index 29170b479..24370229f 100644 --- a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/util/MetaDataUtils.java +++ b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/util/MetaDataUtils.java @@ -19,7 +19,7 @@ package org.jivesoftware.smackx.workgroup.util; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; -import java.util.Hashtable; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -45,6 +45,7 @@ public class MetaDataUtils { * @throws XmlPullParserException if an error occurs while parsing the XML. * @throws IOException if an error occurs while parsing the XML. */ + @SuppressWarnings("MixedMutabilityReturnType") public static Map> parseMetaData(XmlPullParser parser) throws XmlPullParserException, IOException { XmlPullParser.Event eventType = parser.getEventType(); @@ -52,7 +53,7 @@ public class MetaDataUtils { if ((eventType == XmlPullParser.Event.START_ELEMENT) && parser.getName().equals(MetaData.ELEMENT_NAME) && parser.getNamespace().equals(MetaData.NAMESPACE)) { - Map> metaData = new Hashtable<>(); + Map> metaData = new LinkedHashMap<>(); eventType = parser.next(); diff --git a/smack-omemo-signal-integration-test/build.gradle b/smack-omemo-signal-integration-test/build.gradle index a499edc0c..58414a4d6 100644 --- a/smack-omemo-signal-integration-test/build.gradle +++ b/smack-omemo-signal-integration-test/build.gradle @@ -1,17 +1,16 @@ -apply plugin: 'application' +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.application-conventions' +} description = """\ Smack integration tests for OMEMO using libsignal.""" -mainClassName = 'org.igniterealtime.smack.inttest.smack_omemo_signal.SmackOmemoSignalIntegrationTestFramework' -applicationDefaultJvmArgs = ["-enableassertions"] +application { + mainClass = 'org.igniterealtime.smack.inttest.smack_omemo_signal.SmackOmemoSignalIntegrationTestFramework' +} dependencies { api project(':smack-integration-test') api project(':smack-omemo-signal') } - -run { - // Pass all system properties down to the "application" run - systemProperties System.getProperties() -} diff --git a/smack-omemo-signal/build.gradle b/smack-omemo-signal/build.gradle index f29374f10..aa0887f94 100644 --- a/smack-omemo-signal/build.gradle +++ b/smack-omemo-signal/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description=""" Smack API for XEP-0384: OMEMO Encryption using libsignal """ @@ -8,6 +13,9 @@ dependencies { api project(":smack-omemo") implementation 'org.whispersystems:signal-protocol-java:2.8.1' + // TODO: Migrate Junit4 tests to Junit5. + testImplementation "org.junit.vintage:junit-vintage-engine:$junitVersion" + testFixturesApi(testFixtures(project(":smack-core"))) testImplementation project(path: ":smack-omemo", configuration: "testRuntime") } diff --git a/smack-omemo/build.gradle b/smack-omemo/build.gradle index bee2d806c..ca38595a0 100644 --- a/smack-omemo/build.gradle +++ b/smack-omemo/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description=""" Smack API for XEP-0384: OMEMO Encryption """ @@ -7,5 +12,8 @@ dependencies { api project(":smack-extensions") api project(":smack-experimental") + // TODO: Migrate Junit4 tests to Junit5. + testImplementation "org.junit.vintage:junit-vintage-engine:$junitVersion" + testFixturesApi(testFixtures(project(":smack-core"))) } diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/FileBasedOmemoStore.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/FileBasedOmemoStore.java index 62b742db5..89faecafc 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/FileBasedOmemoStore.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/FileBasedOmemoStore.java @@ -125,12 +125,14 @@ public abstract class FileBasedOmemoStore stack = new Stack<>(); diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoService.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoService.java index d8e768e01..3f70ad7da 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoService.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoService.java @@ -914,6 +914,7 @@ public abstract class OmemoService to, List payload) { super(Objects.requireNonNullNorEmpty( to, "Encrypted OpenPGP content elements must have at least one 'to' attribute."), diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/element/OpenPgpContentElement.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/element/OpenPgpContentElement.java index 974185573..07d9327cb 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/element/OpenPgpContentElement.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/element/OpenPgpContentElement.java @@ -132,7 +132,7 @@ public abstract class OpenPgpContentElement implements ExtensionElement { * @param type of the ExtensionElement. * @return the extension, or null if it doesn't exist. */ - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) public PE getExtension(String elementName, String namespace) { if (namespace == null) { return null; diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/element/PublicKeysListElement.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/element/PublicKeysListElement.java index d4b9e81c7..780f67fc7 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/element/PublicKeysListElement.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/element/PublicKeysListElement.java @@ -133,12 +133,13 @@ public final class PublicKeysListElement implements ExtensionElement { return xml; } + @SuppressWarnings("JavaUtilDate") @Override public int hashCode() { return getV4Fingerprint().hashCode() + 3 * getDate().hashCode(); } - @SuppressWarnings("UndefinedEquals") + @SuppressWarnings({"UndefinedEquals", "JavaUtilDate"}) // TODO: Fix the UndefinedEquals due using Date.equals(Date) @Override public boolean equals(Object o) { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/provider/OpenPgpContentElementProvider.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/provider/OpenPgpContentElementProvider.java index 9bba1ef5e..616ac8779 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/provider/OpenPgpContentElementProvider.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/provider/OpenPgpContentElementProvider.java @@ -1,6 +1,6 @@ /** * - * Copyright 2017-2021 Florian Schmaus, 2018 Paul Schaub. + * Copyright 2017-2024 Florian Schmaus, 2018 Paul Schaub. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,9 @@ package org.jivesoftware.smackx.ox.provider; import java.io.IOException; import java.text.ParseException; +import java.util.ArrayList; import java.util.Date; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.logging.Level; @@ -87,7 +87,7 @@ public abstract class OpenPgpContentElementProvider to = new HashSet<>(); Date timestamp = null; String rpad = null; - List payload = new LinkedList<>(); + List payload = new ArrayList<>(); outerloop: while (true) { XmlPullParser.Event tag = parser.next(); diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpMetadataStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpMetadataStore.java index 9d20e2cfa..d1f0b2d6b 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpMetadataStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpMetadataStore.java @@ -118,6 +118,7 @@ public class FileBasedOpenPgpMetadataStore extends AbstractOpenPgpMetadataStore } } + @SuppressWarnings("JavaUtilDate") static void writeFingerprintsAndDates(Map data, File destination) throws IOException { if (data == null || data.isEmpty()) { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/OpenPgpPubSubUtil.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/OpenPgpPubSubUtil.java index 99caf10f9..1ba31495d 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/OpenPgpPubSubUtil.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/OpenPgpPubSubUtil.java @@ -124,6 +124,7 @@ public class OpenPgpPubSubUtil { * @throws SmackException.NotConnectedException if we are not connected. * @throws SmackException.NoResponseException if the server doesn't respond. */ + @SuppressWarnings("JavaUtilDate") public static void publishPublicKey(PepManager pepManager, PubkeyElement pubkeyElement, OpenPgpV4Fingerprint fingerprint) throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException { @@ -464,8 +465,7 @@ public class OpenPgpPubSubUtil { } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException | NoSuchFieldException e) { - LOGGER.log(Level.SEVERE, "Using reflections to create a LeafNode and put it into PubSubManagers nodeMap failed.", e); - throw new AssertionError(e); + throw new LinkageError("Using reflections to create a LeafNode and put it into PubSubManagers nodeMap failed.", e); } } } diff --git a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpElementTest.java b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpElementTest.java index 2c54a0d55..a958d1adb 100644 --- a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpElementTest.java +++ b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpElementTest.java @@ -51,6 +51,7 @@ public class OpenPgpElementTest extends SmackTestSuite { private final Set recipients; // 2014-07-10T15:06:00.000+00:00 + @SuppressWarnings("JavaUtilDate") private static final Date testDate = new Date(1405004760000L); public OpenPgpElementTest() throws XmppStringprepException { diff --git a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpStoreTest.java b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpStoreTest.java index d64c1522c..30e3f05af 100644 --- a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpStoreTest.java +++ b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpStoreTest.java @@ -300,6 +300,7 @@ public class OpenPgpStoreTest extends SmackTestSuite { */ @Test + @SuppressWarnings("JavaUtilDate") public void t10_meta_emptyStoreTest() throws IOException { assertNotNull(openPgpStoreInstance1.getAnnouncedFingerprintsOf(alice)); assertTrue(openPgpStoreInstance1.getAnnouncedFingerprintsOf(alice).isEmpty()); @@ -324,6 +325,7 @@ public class OpenPgpStoreTest extends SmackTestSuite { } @Test + @SuppressWarnings("JavaUtilDate") public void t11_key_fetchDateTest() throws IOException { Map fetchDates1 = openPgpStoreInstance1.getPublicKeyFetchDates(alice); diff --git a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PainlessOpenPgpProviderTest.java b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PainlessOpenPgpProviderTest.java index 5f1210367..41319bd6f 100644 --- a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PainlessOpenPgpProviderTest.java +++ b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PainlessOpenPgpProviderTest.java @@ -72,6 +72,7 @@ public class PainlessOpenPgpProviderTest extends SmackTestSuite { } @Test + @SuppressWarnings("JavaUtilDate") public void encryptDecryptTest() throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, IOException, MissingUserIdOnKeyException, XmlPullParserException { // Initialize diff --git a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PublicKeysListElementTest.java b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PublicKeysListElementTest.java index 319c60bcf..eb7f3922c 100644 --- a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PublicKeysListElementTest.java +++ b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PublicKeysListElementTest.java @@ -70,6 +70,7 @@ public class PublicKeysListElementTest extends SmackTestSuite { } @Test + @SuppressWarnings("JavaUtilDate") public void listBuilderRefusesDuplicatesTest() { PublicKeysListElement.Builder builder = PublicKeysListElement.builder(); String fp40 = "49545320414c4c2041424f555420444120484558"; diff --git a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox_im/OXInstantMessagingManagerTest.java b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox_im/OXInstantMessagingManagerTest.java index 7854aedce..668a14204 100644 --- a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox_im/OXInstantMessagingManagerTest.java +++ b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox_im/OXInstantMessagingManagerTest.java @@ -66,6 +66,7 @@ public class OXInstantMessagingManagerTest extends SmackTestSuite { } @Test + @SuppressWarnings("JavaUtilDate") public void test() throws IOException, PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, SmackException, MissingUserIdOnKeyException, InterruptedException, XMPPException, XmlPullParserException { diff --git a/smack-repl/build.gradle b/smack-repl/build.gradle index a7e1017d0..9b60cd9fb 100644 --- a/smack-repl/build.gradle +++ b/smack-repl/build.gradle @@ -1,12 +1,13 @@ plugins { - id "com.github.alisiikh.scalastyle_2.12" version "2.1.0" + id 'org.igniterealtime.smack.java-common-conventions' + id "com.github.alisiikh.scalastyle" version "3.5.0" } description = """\ A REPL (Read-Eval-Print-Loop) for Smack, or, in other words, a CLI (Command Line Interface) for Smack.""" apply plugin: 'scala' -apply plugin: 'com.github.alisiikh.scalastyle_2.12' +apply plugin: 'com.github.alisiikh.scalastyle' ext { scalaVersion = '2.13.13' @@ -19,13 +20,13 @@ dependencies { implementation "com.lihaoyi:ammonite_$scalaVersion:3.0.0-M1" } -scalaStyle { +scalastyle { config = new File(rootConfigDir, 'scalaStyle.xml') verbose = true - failOnViolation = true + failOnWarning = true } -check.dependsOn(scalaStyleCheck) +check.dependsOn(scalastyleCheck) task printClasspath(dependsOn: assemble) { doLast { diff --git a/smack-resolver-dnsjava/build.gradle b/smack-resolver-dnsjava/build.gradle index b17683ecc..b4e6b85cf 100644 --- a/smack-resolver-dnsjava/build.gradle +++ b/smack-resolver-dnsjava/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description = """\ DNS SRV with dnsjava Use dnsjava for DNS SRV lookups.""" diff --git a/smack-resolver-javax/build.gradle b/smack-resolver-javax/build.gradle index 4caefb6f5..f724be154 100644 --- a/smack-resolver-javax/build.gradle +++ b/smack-resolver-javax/build.gradle @@ -1,3 +1,7 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' +} + description = """\ DNS SRV with Java7 Use javax.naming for DNS SRV lookups. The javax.naming API is availabe in JavaSE diff --git a/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java b/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java index 9e78b34b8..96cd9771a 100644 --- a/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java +++ b/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java @@ -1,6 +1,6 @@ /** * - * Copyright 2013-2020 Florian Schmaus + * Copyright 2013-2024 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,6 +45,7 @@ import org.minidns.record.SRV; * @author Florian Schmaus * */ +@SuppressWarnings("JdkObsolete") public class JavaxResolver extends DNSResolver implements SmackInitializer { private static JavaxResolver instance; diff --git a/smack-resolver-minidns-dox/build.gradle b/smack-resolver-minidns-dox/build.gradle index de740cf84..f8ebf7d3b 100644 --- a/smack-resolver-minidns-dox/build.gradle +++ b/smack-resolver-minidns-dox/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description = """\ DNS over XMPP (DoX) support using MiniDNS.""" diff --git a/smack-resolver-minidns/build.gradle b/smack-resolver-minidns/build.gradle index 22809986c..c1fb68a28 100644 --- a/smack-resolver-minidns/build.gradle +++ b/smack-resolver-minidns/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description = """\ DNS SRV with minidns Use minidns for DNS SRV lookups. For platforms that don't provide the diff --git a/smack-sasl-javax/build.gradle b/smack-sasl-javax/build.gradle index e6fffd631..9f2eecc89 100644 --- a/smack-sasl-javax/build.gradle +++ b/smack-sasl-javax/build.gradle @@ -1,3 +1,7 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' +} + description = """\ SASL with javax.security.sasl Use javax.security.sasl for SASL.""" diff --git a/smack-sasl-provided/build.gradle b/smack-sasl-provided/build.gradle index a9f3724d0..65f10b3b1 100644 --- a/smack-sasl-provided/build.gradle +++ b/smack-sasl-provided/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description = """\ SASL with Smack provided code Use Smack provided code for SASL.""" diff --git a/smack-streammanagement/build.gradle b/smack-streammanagement/build.gradle index c06c423d9..73eb2139e 100644 --- a/smack-streammanagement/build.gradle +++ b/smack-streammanagement/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description = """\ Smack support for XMPP Stream Management (XEP-0198).""" diff --git a/smack-tcp/build.gradle b/smack-tcp/build.gradle index a0cffad6b..db2ee6bc2 100644 --- a/smack-tcp/build.gradle +++ b/smack-tcp/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description = """\ Smack for standard XMPP connections over TCP.""" diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java index 87ce7c647..aef1b27f0 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java @@ -31,7 +31,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -415,7 +414,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { // bind IQ may trigger a SM ack request, which would be invalid in the pre resource bound state. smEnabledSyncPoint = false; - List previouslyUnackedStanzas = new LinkedList(); + List previouslyUnackedStanzas = new ArrayList(); if (unacknowledgedStanzas != null) { // There was a previous connection with SM enabled but that was either not resumable or // failed to resume. Make sure that we (re-)send the unacknowledged stanzas. diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppTcpTransportModule.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppTcpTransportModule.java index 2feb626d3..fabfa4d6f 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppTcpTransportModule.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppTcpTransportModule.java @@ -1,6 +1,6 @@ /** * - * Copyright 2019-2021 Florian Schmaus + * Copyright 2019-2024 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -369,7 +369,7 @@ public class XmppTcpTransportModule extends ModularXmppClientToServerConnectionM newPendingOutputFilterData |= outputResult.pendingFilterData; outputFilterInputData = outputResult.filteredOutputData; if (outputFilterInputData != null) { - outputFilterInputData.flip(); + ((java.nio.Buffer) outputFilterInputData).flip(); } } @@ -459,7 +459,7 @@ public class XmppTcpTransportModule extends ModularXmppClientToServerConnectionM } int bytesRead; - incomingBuffer.clear(); + ((java.nio.Buffer) incomingBuffer).clear(); try { bytesRead = selectedSocketChannel.read(incomingBuffer); } catch (IOException e) { @@ -503,7 +503,7 @@ public class XmppTcpTransportModule extends ModularXmppClientToServerConnectionM ByteBuffer filteredIncomingBuffer = incomingBuffer; for (ListIterator it = connectionInternal.getXmppInputOutputFilterEndIterator(); it.hasPrevious();) { - filteredIncomingBuffer.flip(); + ((java.nio.Buffer) filteredIncomingBuffer).flip(); ByteBuffer newFilteredIncomingBuffer; try { @@ -518,7 +518,8 @@ public class XmppTcpTransportModule extends ModularXmppClientToServerConnectionM filteredIncomingBuffer = newFilteredIncomingBuffer; } - final int bytesReadAfterFilter = filteredIncomingBuffer.flip().remaining(); + ((java.nio.Buffer) filteredIncomingBuffer).flip(); + final int bytesReadAfterFilter = filteredIncomingBuffer.remaining(); totalBytesReadAfterFilter += bytesReadAfterFilter; @@ -980,7 +981,7 @@ public class XmppTcpTransportModule extends ModularXmppClientToServerConnectionM ByteBuffer[] outputDataArray = pendingOutputData.toArray(new ByteBuffer[pendingOutputData.size()]); - myNetData.clear(); + ((java.nio.Buffer) myNetData).clear(); while (true) { SSLEngineResult result; @@ -1037,7 +1038,7 @@ public class XmppTcpTransportModule extends ModularXmppClientToServerConnectionM newCapacity = 2 * myNetData.capacity(); } ByteBuffer newMyNetData = ByteBuffer.allocateDirect(newCapacity); - myNetData.flip(); + ((java.nio.Buffer) myNetData).flip(); newMyNetData.put(myNetData); myNetData = newMyNetData; continue; @@ -1060,12 +1061,12 @@ public class XmppTcpTransportModule extends ModularXmppClientToServerConnectionM int accumulatedDataBytes = pendingInputData.remaining() + inputData.remaining(); accumulatedData = ByteBuffer.allocate(accumulatedDataBytes); accumulatedData.put(pendingInputData) - .put(inputData) - .flip(); + .put(inputData); + ((java.nio.Buffer) accumulatedData).flip(); pendingInputData = null; } - peerAppData.clear(); + ((java.nio.Buffer) peerAppData).clear(); while (true) { SSLEngineResult result; @@ -1143,7 +1144,8 @@ public class XmppTcpTransportModule extends ModularXmppClientToServerConnectionM // higher layer. That is, here 'byteBuffer' is typically 'incomingBuffer', which is a direct buffer only // allocated once per connection for performance reasons and hence re-used for read() calls. pendingInputData = ByteBuffer.allocate(byteBuffer.remaining()); - pendingInputData.put(byteBuffer).flip(); + pendingInputData.put(byteBuffer); + ((java.nio.Buffer) pendingInputData).flip(); pendingInputFilterData = pendingInputData.hasRemaining(); } diff --git a/smack-websocket-java11/build.gradle b/smack-websocket-java11/build.gradle index 9439bad20..c019f214c 100644 --- a/smack-websocket-java11/build.gradle +++ b/smack-websocket-java11/build.gradle @@ -1,3 +1,7 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' +} + description = """\ Smack for XMPP connections over WebSocket (RFC 7395) using java.net.http.WebSocket.""" diff --git a/smack-websocket-okhttp/build.gradle b/smack-websocket-okhttp/build.gradle index 6f83f2c83..9e7b2fb46 100644 --- a/smack-websocket-okhttp/build.gradle +++ b/smack-websocket-okhttp/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description = """\ Smack for XMPP connections over WebSocket (RFC 7395) using OkHttp.""" diff --git a/smack-websocket/build.gradle b/smack-websocket/build.gradle index 1ef60c233..73dfab23b 100644 --- a/smack-websocket/build.gradle +++ b/smack-websocket/build.gradle @@ -1,3 +1,8 @@ +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} + description = """\ Smack for XMPP connections over WebSocket (RFC 7395).""" diff --git a/smack-xmlparser-stax/build.gradle b/smack-xmlparser-stax/build.gradle index b25ce2e9a..9cc67deda 100644 --- a/smack-xmlparser-stax/build.gradle +++ b/smack-xmlparser-stax/build.gradle @@ -1,7 +1,6 @@ -// Note that this is also declared in the main build.gradle for -// subprojects, but since evaluationDependsOnChildren is enabled we -// need to declare it here too to have bundle{bnd{...}} available -apply plugin: 'biz.aQute.bnd.builder' +plugins { + id 'org.igniterealtime.smack.java-common-conventions' +} description = """\ Smack XML parser using Stax.""" diff --git a/smack-xmlparser-xpp3/build.gradle b/smack-xmlparser-xpp3/build.gradle index f0a9f56c6..8c5063117 100644 --- a/smack-xmlparser-xpp3/build.gradle +++ b/smack-xmlparser-xpp3/build.gradle @@ -1,7 +1,7 @@ -// Note that this is also declared in the main build.gradle for -// subprojects, but since evaluationDependsOnChildren is enabled we -// need to declare it here too to have bundle{bnd{...}} available -apply plugin: 'biz.aQute.bnd.builder' +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} description = """\ Smack XML parser using XPP3.""" diff --git a/smack-xmlparser/build.gradle b/smack-xmlparser/build.gradle index 513a2b153..9686ae87b 100644 --- a/smack-xmlparser/build.gradle +++ b/smack-xmlparser/build.gradle @@ -1,7 +1,7 @@ -// Note that this is also declared in the main build.gradle for -// subprojects, but since evaluationDependsOnChildren is enabled we -// need to declare it here too to have bundle{bnd{...}} available -apply plugin: 'biz.aQute.bnd.builder' +plugins { + id 'org.igniterealtime.smack.java-common-conventions' + id 'org.igniterealtime.smack.android-conventions' +} description = """\ Smack XML parser fundamentals"""