From 5bf98b033b69ce9acc5d807fca49c668989ef634 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Mon, 2 Jun 2014 15:27:31 -0400 Subject: [PATCH] Remove spring-integration-mqtt from master --- spring-integration-mqtt/README.md | 92 +------ spring-integration-mqtt/build.gradle | 239 ------------------ spring-integration-mqtt/gradle.properties | 1 - .../gradle/wrapper/gradle-wrapper.jar | Bin 45502 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - spring-integration-mqtt/gradlew | 164 ------------ spring-integration-mqtt/gradlew.bat | 90 ------- spring-integration-mqtt/publish-maven.gradle | 61 ----- spring-integration-mqtt/src/api/overview.html | 22 -- .../src/dist/changelog.txt | 15 -- spring-integration-mqtt/src/dist/license.txt | 201 --------------- spring-integration-mqtt/src/dist/notice.txt | 21 -- spring-integration-mqtt/src/dist/readme.txt | 13 - ...MqttMessageDrivenChannelAdapterParser.java | 50 ---- ...qttMessageDrivenChannelAdapterParser.java~ | 49 ---- .../mqtt/config/xml/MqttNamespaceHandler.java | 36 --- .../xml/MqttOutboundChannelAdapterParser.java | 66 ----- .../mqtt/config/xml/MqttParserUtils.java | 53 ---- .../mqtt/config/xml/package-info.java | 4 - .../core/DefaultMqttPahoClientFactory.java | 165 ------------ .../mqtt/core/MqttPahoClientFactory.java | 32 --- .../integration/mqtt/core/package-info.java | 4 - ...stractMqttMessageDrivenChannelAdapter.java | 84 ------ .../MqttPahoMessageDrivenChannelAdapter.java | 175 ------------- .../MqttPahoMessageDrivenChannelAdapter.java~ | 174 ------------- .../mqtt/inbound/package-info.java | 4 - .../outbound/AbstractMqttMessageHandler.java | 160 ------------ .../mqtt/outbound/MqttPahoMessageHandler.java | 118 --------- .../mqtt/outbound/package-info.java | 4 - .../integration/mqtt/package-info.java | 4 - .../support/DefaultPahoMessageConverter.java | 104 -------- .../integration/mqtt/support/MqttHeaders.java | 38 --- .../mqtt/support/MqttMessageConverter.java | 33 --- .../integration/mqtt/support/MqttUtils.java | 33 --- .../mqtt/support/package-info.java | 4 - .../main/resources/META-INF/spring.handlers | 1 - .../main/resources/META-INF/spring.schemas | 2 - .../main/resources/META-INF/spring.tooling | 4 - .../xml/spring-integration-mqtt-1.0.xsd | 210 --------------- .../xml/spring-integration-mqtt-1.0.xsd~ | 200 --------------- .../xml/spring-integration-mqttadapter.gif | Bin 539 -> 0 bytes .../mqtt/BackTobackAdapterTests.java | 95 ------- .../integration/mqtt/BrokerRunning.java | 83 ------ .../integration/mqtt/BrokerRunning.java~ | 82 ------ .../mqtt/DownstreamExceptionTests-context.xml | 29 --- .../mqtt/DownstreamExceptionTests.java | 141 ----------- .../integration/mqtt/MqttAdapterTests.java | 238 ----------------- ...rivenChannelAdapterParserTests-context.xml | 40 --- ...essageDrivenChannelAdapterParserTests.java | 85 ------- ...boundChannelAdapterParserTests-context.xml | 39 --- ...MqttOutboundChannelAdapterParserTests.java | 85 ------- .../src/test/resources/log4j.properties | 8 - 52 files changed, 1 insertion(+), 3660 deletions(-) delete mode 100644 spring-integration-mqtt/build.gradle delete mode 100644 spring-integration-mqtt/gradle.properties delete mode 100644 spring-integration-mqtt/gradle/wrapper/gradle-wrapper.jar delete mode 100644 spring-integration-mqtt/gradle/wrapper/gradle-wrapper.properties delete mode 100755 spring-integration-mqtt/gradlew delete mode 100644 spring-integration-mqtt/gradlew.bat delete mode 100644 spring-integration-mqtt/publish-maven.gradle delete mode 100644 spring-integration-mqtt/src/api/overview.html delete mode 100644 spring-integration-mqtt/src/dist/changelog.txt delete mode 100644 spring-integration-mqtt/src/dist/license.txt delete mode 100644 spring-integration-mqtt/src/dist/notice.txt delete mode 100644 spring-integration-mqtt/src/dist/readme.txt delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParser.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParser.java~ delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttNamespaceHandler.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttOutboundChannelAdapterParser.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttParserUtils.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/package-info.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/core/DefaultMqttPahoClientFactory.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/core/MqttPahoClientFactory.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/core/package-info.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/AbstractMqttMessageDrivenChannelAdapter.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/MqttPahoMessageDrivenChannelAdapter.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/MqttPahoMessageDrivenChannelAdapter.java~ delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/package-info.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/outbound/AbstractMqttMessageHandler.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/outbound/MqttPahoMessageHandler.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/outbound/package-info.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/package-info.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/DefaultPahoMessageConverter.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/MqttHeaders.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/MqttMessageConverter.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/MqttUtils.java delete mode 100644 spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/package-info.java delete mode 100644 spring-integration-mqtt/src/main/resources/META-INF/spring.handlers delete mode 100644 spring-integration-mqtt/src/main/resources/META-INF/spring.schemas delete mode 100644 spring-integration-mqtt/src/main/resources/META-INF/spring.tooling delete mode 100644 spring-integration-mqtt/src/main/resources/org/springframework/integration/mqtt/config/xml/spring-integration-mqtt-1.0.xsd delete mode 100644 spring-integration-mqtt/src/main/resources/org/springframework/integration/mqtt/config/xml/spring-integration-mqtt-1.0.xsd~ delete mode 100644 spring-integration-mqtt/src/main/resources/org/springframework/integration/mqtt/config/xml/spring-integration-mqttadapter.gif delete mode 100644 spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/BackTobackAdapterTests.java delete mode 100644 spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/BrokerRunning.java delete mode 100644 spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/BrokerRunning.java~ delete mode 100644 spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/DownstreamExceptionTests-context.xml delete mode 100644 spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/DownstreamExceptionTests.java delete mode 100644 spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/MqttAdapterTests.java delete mode 100644 spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParserTests-context.xml delete mode 100644 spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParserTests.java delete mode 100644 spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttOutboundChannelAdapterParserTests-context.xml delete mode 100644 spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttOutboundChannelAdapterParserTests.java delete mode 100644 spring-integration-mqtt/src/test/resources/log4j.properties diff --git a/spring-integration-mqtt/README.md b/spring-integration-mqtt/README.md index 3fd8e81..c5e4d4c 100644 --- a/spring-integration-mqtt/README.md +++ b/spring-integration-mqtt/README.md @@ -4,95 +4,5 @@ Spring Integration MQTT Support ####Note: as of version 4.0.0, this extension has been moved to the main [Spring Integration Project](https://github.com/spring-projects/spring-integration) -`inbound` and `outbound` channel adapters are provided for [MQ Telemetry Transport (MQTT)][]. The current implementation uses the [Eclipse Paho][] client. +For a version of this extension that is compatible with Spring Integration 3.0.x/2.2.x, see the [SPR3.x branch](https://github.com/spring-projects/spring-integration-extensions/tree/SPR3.x/spring-integration-mqtt). -__Note:__ Starting with version 4.0.0, this module has been moved to the main [Spring Integration][] project. - -This extension project has essentially the same features, more fully documented in the [main project documentation][] and is compatible with Spring Integration 3.0.x and 2.2.x. - -Currently, the release candidate for the extension is 1.0.0.RC1 and will be released soon. - -[Spring Integration]:https://github.com/spring-projects/spring-integration -[main project documentation]:http://docs.spring.io/spring-integration/docs/4.0.0.BUILD-SNAPSHOT/reference/html/mqtt.html - -## Example Configurations - -```xml - - - -``` - -*Spring Integration* messages sent to the outbound adapter can have headers `mqtt_topic, mqtt_qos, mqtt_retained` which will override the defaults configured on the adapter. - -Inbound messages will have headers - - mqtt_topic - the topic from which the message was received - mqtt_duplicate - true if the message is a duplicate - mqtt_qos - the quality of service - -Both adapters use a `MqttPahoClientFactory` to get a client instance; the same factory also provides connection options from configured properties (such as user/password). The client factory bean (`DefaultMqttPahoClientFactory`) is provided to the adapter using the `client-factory` attribute. When not provided, a default factory instance is used. - -Currently tested with the RabbitMQ MQTT plugin. - -## Maven - -### Repository - - - repository.springframework.maven.milestone - Spring Framework Maven Milestone Repository - http://repo.springsource.org/milestone - - -### Artifact - - - org.springframework.integration - spring-integration-mqtt - 1.0.0.M1 - - -## Support - -Check out the [Spring Integration forums][] and the [spring-integration][spring-integration tag] tag -on [Stack Overflow][]. [Commercial support][] is available, too. - -## Resources - -* [Eclipse Paho][] - -## Related GitHub projects - -* [Spring Integration][] -* [Spring Integration Samples][] -* [Spring Integration Templates][] -* [Spring Integration Dsl Groovy][] -* [Spring Integration Dsl Scala][] -* [Spring Integration Pattern Catalog][] - -For more information, please also don't forget to visit the [Spring Integration][] website. - -[Spring Integration]: https://github.com/SpringSource/spring-integration -[Commercial support]: http://springsource.com/support/springsupport -[Spring Integration forums]: http://forum.springsource.org/forumdisplay.php?42-Integration -[spring-integration tag]: http://stackoverflow.com/questions/tagged/spring-integration -[Spring Integration Samples]: https://github.com/SpringSource/spring-integration-samples -[Spring Integration Templates]: https://github.com/SpringSource/spring-integration-templates/tree/master/si-sts-templates -[Spring Integration Dsl Groovy]: https://github.com/SpringSource/spring-integration-dsl-groovy -[Spring Integration Dsl Scala]: https://github.com/SpringSource/spring-integration-dsl-scala -[Spring Integration Pattern Catalog]: https://github.com/SpringSource/spring-integration-pattern-catalog -[Stack Overflow]: http://stackoverflow.com/faq -[Eclipse Paho]: http://www.eclipse.org/paho/ -[open paho bug]: https://bugs.eclipse.org/bugs/show_bug.cgi?id=382471 -[MQ Telemetry Transport (MQTT)]: http://mqtt.org/ diff --git a/spring-integration-mqtt/build.gradle b/spring-integration-mqtt/build.gradle deleted file mode 100644 index 01d4842..0000000 --- a/spring-integration-mqtt/build.gradle +++ /dev/null @@ -1,239 +0,0 @@ -description = 'Spring Integration MQTT Adapter' - -buildscript { - repositories { - maven { url 'https://repo.springsource.org/plugins-snapshot' } - } -} - -apply plugin: 'java' -apply from: "${rootProject.projectDir}/publish-maven.gradle" -apply plugin: 'eclipse' -apply plugin: 'idea' - -group = 'org.springframework.integration' - -repositories { - maven { url 'http://repo.spring.io/milestone' } - maven { url 'https://repo.eclipse.org/content/repositories/paho-releases/' } - maven { url 'http://repo.springsource.org/plugins-release' } -} - -sourceCompatibility=1.6 -targetCompatibility=1.6 - -ext { - junitVersion = '4.11' - log4jVersion = '1.2.17' - mockitoVersion = '1.9.5' - springVersion = '4.0.5.RELEASE' - springIntegrationVersion = '4.0.1.RELEASE' - idPrefix = 'mqtt' - - linkHomepage = 'https://github.com/SpringSource/spring-integration-extensions' - linkCi = 'https://build.springsource.org/browse/INTEXT' - linkIssue = 'https://jira.springsource.org/browse/INTEXT' - linkScmUrl = 'https://github.com/SpringSource/spring-integration-extensions' - linkScmConnection = 'https://github.com/SpringSource/spring-integration-extensions.git' - linkScmDevConnection = 'git@github.com:SpringSource/spring-integration-extensions.git' -} - -eclipse { - project { - natures += 'org.springframework.ide.eclipse.core.springnature' - } -} - -sourceSets { - test { - resources { - srcDirs = ['src/test/resources', 'src/test/java'] - } - } -} - -// See http://www.gradle.org/docs/current/userguide/dependency_management.html#sub:configurations -// and http://www.gradle.org/docs/current/dsl/org.gradle.api.artifacts.ConfigurationContainer.html -configurations { - jacoco //Configuration Group used by Sonar to provide Code Coverage using JaCoCo -} - -dependencies { - compile "org.springframework.integration:spring-integration-core:$springIntegrationVersion" - compile "org.eclipse.paho:mqtt-client:0.4.0" - testCompile "org.springframework.integration:spring-integration-test:$springIntegrationVersion" - testCompile "junit:junit-dep:$junitVersion" - testCompile "log4j:log4j:$log4jVersion" - testCompile "org.mockito:mockito-all:$mockitoVersion" - testCompile "org.springframework:spring-test:$springVersion" - jacoco group: "org.jacoco", name: "org.jacoco.agent", version: "0.6.2.201302030002", classifier: "runtime" -} - - -// enable all compiler warnings; individual projects may customize further -ext.xLintArg = '-Xlint:all' -[compileJava, compileTestJava]*.options*.compilerArgs = [xLintArg] - -test { - // suppress all console output during testing unless running `gradle -i` - logging.captureStandardOutput(LogLevel.INFO) - jvmArgs "-javaagent:${configurations.jacoco.asPath}=destfile=${buildDir}/jacoco.exec,includes=*" -} - -task sourcesJar(type: Jar) { - classifier = 'sources' - from sourceSets.main.allJava -} - -task javadocJar(type: Jar) { - classifier = 'javadoc' - from javadoc -} - -artifacts { - archives sourcesJar - archives javadocJar -} - -apply plugin: 'sonar-runner' - -sonarRunner { - sonarProperties { - property "sonar.jacoco.reportPath", "${buildDir.name}/jacoco.exec" - property "sonar.links.homepage", linkHomepage - property "sonar.links.ci", linkCi - property "sonar.links.issue", linkIssue - property "sonar.links.scm", linkScmUrl - property "sonar.links.scm_dev", linkScmDevConnection - property "sonar.java.coveragePlugin", "jacoco" - } -} - -task api(type: Javadoc) { - group = 'Documentation' - description = 'Generates the Javadoc API documentation.' - title = "${rootProject.description} ${version} API" - options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED - options.author = true - options.header = rootProject.description - options.overview = 'src/api/overview.html' - - source = sourceSets.main.allJava - classpath = project.sourceSets.main.compileClasspath - destinationDir = new File(buildDir, "api") -} - -task schemaZip(type: Zip) { - group = 'Distribution' - classifier = 'schema' - description = "Builds -${classifier} archive containing all " + - "XSDs for deployment at static.springframework.org/schema." - - def Properties schemas = new Properties(); - def shortName = idPrefix.replaceFirst("${idPrefix}-", '') - - project.sourceSets.main.resources.find { - it.path.endsWith('META-INF/spring.schemas') - }?.withInputStream { schemas.load(it) } - - for (def key : schemas.keySet()) { - File xsdFile = project.sourceSets.main.resources.find { - it.path.endsWith(schemas.get(key)) - } - assert xsdFile != null - into ("integration/${shortName}") { - from xsdFile.path - } - } - -} - -task docsZip(type: Zip) { - group = 'Distribution' - classifier = 'docs' - description = "Builds -${classifier} archive containing the api " + - "for deployment at static.springframework.org/spring-integration/docs." - - from('src/dist') { - include 'changelog.txt' - } - - from (api) { - into 'api' - } -} - -task distZip(type: Zip, dependsOn: [docsZip, schemaZip]) { - group = 'Distribution' - classifier = 'dist' - description = "Builds -${classifier} archive, containing all jars and docs, " + - "suitable for community download page." - - ext.baseDir = "${project.name}-${project.version}"; - - from('src/dist') { - include 'readme.txt' - include 'license.txt' - include 'notice.txt' - into "${baseDir}" - } - - from(zipTree(docsZip.archivePath)) { - into "${baseDir}/docs" - } - - from(zipTree(schemaZip.archivePath)) { - into "${baseDir}/schema" - } - - into ("${baseDir}/libs") { - from project.jar - from project.sourcesJar - from project.javadocJar - } -} - -// Create an optional "with dependencies" distribution. -// Not published by default; only for use when building from source. -task depsZip(type: Zip, dependsOn: distZip) { zipTask -> - group = 'Distribution' - classifier = 'dist-with-deps' - description = "Builds -${classifier} archive, containing everything " + - "in the -${distZip.classifier} archive plus all dependencies." - - from zipTree(distZip.archivePath) - - gradle.taskGraph.whenReady { taskGraph -> - if (taskGraph.hasTask(":${zipTask.name}")) { - def projectName = rootProject.name - def artifacts = new HashSet() - - rootProject.configurations.runtime.resolvedConfiguration.resolvedArtifacts.each { artifact -> - def dependency = artifact.moduleVersion.id - if (!projectName.equals(dependency.name)) { - artifacts << artifact.file - } - } - - zipTask.from(artifacts) { - into "${distZip.baseDir}/deps" - } - } - } -} - -artifacts { - archives distZip - archives docsZip - archives schemaZip -} - -task dist(dependsOn: assemble) { - group = 'Distribution' - description = 'Builds -dist, -docs and -schema distribution archives.' -} - -task wrapper(type: Wrapper) { - description = 'Generates gradlew[.bat] scripts' - gradleVersion = '1.6' -} diff --git a/spring-integration-mqtt/gradle.properties b/spring-integration-mqtt/gradle.properties deleted file mode 100644 index 2db7ae7..0000000 --- a/spring-integration-mqtt/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -version=4.0.0.BUILD-SNAPSHOT diff --git a/spring-integration-mqtt/gradle/wrapper/gradle-wrapper.jar b/spring-integration-mqtt/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7f1e239c8466c730b569575c494a89e6bb4c416a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45502 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 diff --git a/spring-integration-mqtt/gradle/wrapper/gradle-wrapper.properties b/spring-integration-mqtt/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 6281daf..0000000 --- a/spring-integration-mqtt/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Wed May 15 15:57:24 EDT 2013 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip diff --git a/spring-integration-mqtt/gradlew b/spring-integration-mqtt/gradlew deleted file mode 100755 index e61422d..0000000 --- a/spring-integration-mqtt/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/bin/bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# 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 -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" -APP_HOME="`pwd -P`" -cd "$SAVED" - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -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" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -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. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "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, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # 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=$((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" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/spring-integration-mqtt/gradlew.bat b/spring-integration-mqtt/gradlew.bat deleted file mode 100644 index aec9973..0000000 --- a/spring-integration-mqtt/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -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. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -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. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="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 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/spring-integration-mqtt/publish-maven.gradle b/spring-integration-mqtt/publish-maven.gradle deleted file mode 100644 index 113adda..0000000 --- a/spring-integration-mqtt/publish-maven.gradle +++ /dev/null @@ -1,61 +0,0 @@ -apply plugin: 'maven' - -ext.optionalDeps = [] -ext.providedDeps = [] - -ext.optional = { optionalDeps << it } -ext.provided = { providedDeps << it } - -install { - repositories.mavenInstaller { - customizePom(pom, project) - } -} - -def customizePom(pom, gradleProject) { - pom.whenConfigured { generatedPom -> - // respect 'optional' and 'provided' dependencies - gradleProject.optionalDeps.each { dep -> - generatedPom.dependencies.find { it.artifactId == dep.name }?.optional = true - } - gradleProject.providedDeps.each { dep -> - generatedPom.dependencies.find { it.artifactId == dep.name }?.scope = 'provided' - } - - // eliminate test-scoped dependencies (no need in maven central poms) - generatedPom.dependencies.removeAll { dep -> - dep.scope == 'test' - } - - // add all items necessary for maven central publication - generatedPom.project { - name = gradleProject.description - description = gradleProject.description - url = 'https://github.com/SpringSource/spring-integration-extensions' - organization { - name = 'SpringSource' - url = 'http://springsource.org' - } - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - distribution 'repo' - } - } - scm { - url = 'https://github.com/SpringSource/spring-integration-extensions' - connection = 'scm:git:git://github.com/SpringSource/spring-integration-extensions' - developerConnection = 'scm:git:git://github.com/SpringSource/spring-integration-extensions' - } - - developers { - developer { - id = 'not specified' - name = 'Gary Russell' - email = 'not specified' - } - } - } - } -} diff --git a/spring-integration-mqtt/src/api/overview.html b/spring-integration-mqtt/src/api/overview.html deleted file mode 100644 index fb0198b..0000000 --- a/spring-integration-mqtt/src/api/overview.html +++ /dev/null @@ -1,22 +0,0 @@ - - -This document is the API specification for Spring Integration -
-
-

- For further API reference and developer documentation, see the - Spring - Integration reference documentation. - That documentation contains more detailed, developer-targeted - descriptions, with conceptual overviews, definitions of terms, - workarounds, and working code examples. -

- -

- If you are interested in commercial training, consultancy, and - support for Spring Integration, please visit - http://www.springsource.com -

-
- - diff --git a/spring-integration-mqtt/src/dist/changelog.txt b/spring-integration-mqtt/src/dist/changelog.txt deleted file mode 100644 index 672b7ef..0000000 --- a/spring-integration-mqtt/src/dist/changelog.txt +++ /dev/null @@ -1,15 +0,0 @@ -Spring Integration MqttAdapter Adapter CHANGELOG -========================================= - -For the full detailed changelog, see: -https://.... - - -Changes in version 1.0 GA (insert date here) -https://.... - - -*** GENERAL *** - -Upgraded Spring Framework dependency to ... -... diff --git a/spring-integration-mqtt/src/dist/license.txt b/spring-integration-mqtt/src/dist/license.txt deleted file mode 100644 index 261eeb9..0000000 --- a/spring-integration-mqtt/src/dist/license.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/spring-integration-mqtt/src/dist/notice.txt b/spring-integration-mqtt/src/dist/notice.txt deleted file mode 100644 index f62045a..0000000 --- a/spring-integration-mqtt/src/dist/notice.txt +++ /dev/null @@ -1,21 +0,0 @@ - ======================================================================== - == NOTICE file corresponding to section 4 d of the Apache License, == - == Version 2.0, in this case for the Spring Integration distribution. == - ======================================================================== - - This product includes software developed by - the Apache Software Foundation (http://www.apache.org). - - The end-user documentation included with a redistribution, if any, - must include the following acknowledgement: - - "This product includes software developed by the Spring Framework - Project (http://www.springframework.org)." - - Alternatively, this acknowledgement may appear in the software itself, - if and wherever such third-party acknowledgements normally appear. - - The names "Spring", "Spring Framework", and "Spring Integration" must - not be used to endorse or promote products derived from this software - without prior written permission. For written permission, please contact - enquiries@springsource.com. diff --git a/spring-integration-mqtt/src/dist/readme.txt b/spring-integration-mqtt/src/dist/readme.txt deleted file mode 100644 index de9fd7e..0000000 --- a/spring-integration-mqtt/src/dist/readme.txt +++ /dev/null @@ -1,13 +0,0 @@ -Spring Integration Mqtt Adapters ------------------------------------ - -To find out what has changed since any earlier releases, see 'changelog.txt'. - -Please consult the documentation located within the 'docs/reference' directory -of this release and also visit the official Spring Integration home at -http://www.springsource.org/spring-integration - -There you will find links to the forum, issue tracker, and several other resources. - -See https://github.com/SpringSource/spring-integration#readme for additional -information including instructions on building from source. diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParser.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParser.java deleted file mode 100644 index 09e155b..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParser.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.config.xml; - -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.integration.config.xml.AbstractChannelAdapterParser; -import org.springframework.integration.config.xml.IntegrationNamespaceUtils; -import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; -import org.w3c.dom.Element; - -/** - * The MqttAdapter Message Driven Channel adapter parser - * - * @author Gary Russell - * @since 1.0 - * - */ -public class MqttMessageDrivenChannelAdapterParser extends AbstractChannelAdapterParser { - - - @Override - protected AbstractBeanDefinition doParse(Element element, ParserContext parserContext, String channelName) { - - BeanDefinitionBuilder builder = BeanDefinitionBuilder - .genericBeanDefinition(MqttPahoMessageDrivenChannelAdapter.class); - - MqttParserUtils.parseCommon(element, builder); - builder.addConstructorArgValue(element.getAttribute("topics")); - builder.addPropertyReference("outputChannel", channelName); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "error-channel"); - - return builder.getBeanDefinition(); - } - -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParser.java~ b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParser.java~ deleted file mode 100644 index b86b774..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParser.java~ +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.config.xml; - -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.integration.config.xml.AbstractChannelAdapterParser; -import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; -import org.w3c.dom.Element; - -/** - * The MqttAdapter Message Driven Channel adapter parser - * - * @author Gary Russell - * @since 1.0 - * - */ -public class MqttMessageDrivenChannelAdapterParser extends AbstractChannelAdapterParser { - - - @Override - protected AbstractBeanDefinition doParse(Element element, ParserContext parserContext, String channelName) { - - BeanDefinitionBuilder builder = BeanDefinitionBuilder - .genericBeanDefinition(MqttPahoMessageDrivenChannelAdapter.class); - - MqttParserUtils.parseCommon(element, builder); - builder.addConstructorArgValue(element.getAttribute("topics")); - builder.addPropertyReference("outputChannel", channelName); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "error-channel"); - - return builder.getBeanDefinition(); - } - -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttNamespaceHandler.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttNamespaceHandler.java deleted file mode 100644 index ea99d71..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttNamespaceHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.config.xml; - -import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHandler; - -/** - * The namespace handler for the MqttAdapter namespace - * - * @author Gary Russell - * @since 1.0 - * - */ -public class MqttNamespaceHandler extends AbstractIntegrationNamespaceHandler { - - /* (non-Javadoc) - * @see org.springframework.beans.factory.xml.NamespaceHandler#init() - */ - public void init() { - this.registerBeanDefinitionParser("message-driven-channel-adapter", new MqttMessageDrivenChannelAdapterParser()); - this.registerBeanDefinitionParser("outbound-channel-adapter", new MqttOutboundChannelAdapterParser()); - } -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttOutboundChannelAdapterParser.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttOutboundChannelAdapterParser.java deleted file mode 100644 index e9635c8..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttOutboundChannelAdapterParser.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.config.xml; - -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser; -import org.springframework.integration.config.xml.IntegrationNamespaceUtils; -import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler; -import org.springframework.util.StringUtils; -import org.w3c.dom.Element; - -/** - * The parser for the MqttAdapter Outbound Channel Adapter. - * - * @author Gary Russell - * @since 1.0 - * - */ -public class MqttOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser { - - @Override - protected boolean shouldGenerateId() { - return false; - } - - @Override - protected boolean shouldGenerateIdAsFallback() { - return true; - } - - @Override - protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) { - - final BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MqttPahoMessageHandler.class); - - MqttParserUtils.parseCommon(element, builder); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "default-topic"); - if (StringUtils.hasText(element.getAttribute("converter")) && - (StringUtils.hasText(element.getAttribute("default-qos")) || - StringUtils.hasText(element.getAttribute("default-retained")))) { - parserContext.getReaderContext().error("If a 'converter' is provided, you cannot provide " + - "'default-qos' or 'default-retained'", element); - } - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "default-qos"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "default-retained"); - - return builder.getBeanDefinition(); - - } - -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttParserUtils.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttParserUtils.java deleted file mode 100644 index 123cf5f..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/MqttParserUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.config.xml; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.integration.config.xml.IntegrationNamespaceUtils; -import org.springframework.util.StringUtils; -import org.w3c.dom.Element; - -/** - * Contains various utility methods for parsing Mqtt Adapter - * specific namesspace elements as well as for the generation of the the - * respective {@link BeanDefinition}s. - * - * @author Gary Russell - * @since 1.0 - * - */ -public final class MqttParserUtils { - - /** Prevent instantiation. */ - private MqttParserUtils() { - throw new AssertionError(); - } - - public static void parseCommon(Element element, BeanDefinitionBuilder builder) { - builder.addConstructorArgValue(element.getAttribute("url")); - builder.addConstructorArgValue(element.getAttribute("client-id")); - String clientFactory = element.getAttribute("client-factory"); - if (StringUtils.hasText(clientFactory)) { - builder.addConstructorArgReference(clientFactory); - } - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "converter"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-startup"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "phase"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "send-timeout"); - } - -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/package-info.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/package-info.java deleted file mode 100644 index 9c047f7..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/config/xml/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Provides parser classes to provide Xml namespace support for the MqttAdapter components. - */ -package org.springframework.integration.mqtt.config.xml; diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/core/DefaultMqttPahoClientFactory.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/core/DefaultMqttPahoClientFactory.java deleted file mode 100644 index 2445bb4..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/core/DefaultMqttPahoClientFactory.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.core; - -import java.util.Properties; - -import javax.net.SocketFactory; - -import org.eclipse.paho.client.mqttv3.MqttClient; -import org.eclipse.paho.client.mqttv3.MqttClientPersistence; -import org.eclipse.paho.client.mqttv3.MqttConnectOptions; -import org.eclipse.paho.client.mqttv3.MqttException; - -/** - * Creates a default {@link MqttClient} and a set of options as configured. - * @author Gary Russell - * @author Gunnar Hillert - * @since 1.0 - * - */ -public class DefaultMqttPahoClientFactory implements MqttPahoClientFactory { - - private volatile Boolean cleanSession; - - private volatile Integer connectionTimeout; - - private volatile Integer keepAliveInterval; - - private volatile String password; - - private volatile SocketFactory socketFactory; - - private volatile Properties sslProperties; - - private volatile String userName; - - private volatile MqttClientPersistence persistence; - - private volatile Will will; - - public void setCleanSession(Boolean cleanSession) { - this.cleanSession = cleanSession; - } - - public void setConnectionTimeout(Integer connectionTimeout) { - this.connectionTimeout = connectionTimeout; - } - - public void setKeepAliveInterval(Integer keepAliveInterval) { - this.keepAliveInterval = keepAliveInterval; - } - - public void setPassword(String password) { - this.password = password; - } - - public void setSocketFactory(SocketFactory socketFactory) { - this.socketFactory = socketFactory; - } - - public void setSslProperties(Properties sslProperties) { - this.sslProperties = sslProperties; - } - - public void setUserName(String userName) { - this.userName = userName; - } - - /** - * Will be used to set the "Last Will and Testament" (LWT) for the connection. - * - * @see MqttConnectOptions - */ - public void setWill(Will will) { - this.will = will; - } - - public void setPersistence(MqttClientPersistence persistence) { - this.persistence = persistence; - } - - @Override - public MqttClient getClientInstance(String url, String clientId) throws MqttException { - return new MqttClient(url, clientId, this.persistence); - } - - @Override - public MqttConnectOptions getConnectionOptions() { - MqttConnectOptions options = new MqttConnectOptions(); - if (this.cleanSession != null) { - options.setCleanSession(this.cleanSession); - } - if (this.connectionTimeout != null) { - options.setConnectionTimeout(this.connectionTimeout); - } - if (this.keepAliveInterval != null) { - options.setKeepAliveInterval(this.keepAliveInterval); - } - if (this.password != null) { - options.setPassword(this.password.toCharArray()); - } - if (this.socketFactory != null) { - options.setSocketFactory(this.socketFactory); - } - if (this.sslProperties != null) { - options.setSSLProperties(this.sslProperties); - } - if (this.userName != null) { - options.setUserName(this.userName); - } - if (this.will != null) { - options.setWill(this.will.getTopic(), this.will.getPayload(), this.will.getQos(), this.will.isRetained()); - } - return options; - } - - public static class Will { - - private final String topic; - - private final byte[] payload; - - private final int qos; - - private final boolean retained; - - public Will(String topic, byte[] payload, int qos, boolean retained) { - this.topic = topic; - this.payload = payload; - this.qos = qos; - this.retained = retained; - } - - protected String getTopic() { - return topic; - } - - protected byte[] getPayload() { - return payload; - } - - protected int getQos() { - return qos; - } - - protected boolean isRetained() { - return retained; - } - - } - -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/core/MqttPahoClientFactory.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/core/MqttPahoClientFactory.java deleted file mode 100644 index d7dcf74..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/core/MqttPahoClientFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.core; - -import org.eclipse.paho.client.mqttv3.MqttClient; -import org.eclipse.paho.client.mqttv3.MqttConnectOptions; -import org.eclipse.paho.client.mqttv3.MqttException; - -/** - * @author Gary Russell - * @since 1.0 - * - */ -public interface MqttPahoClientFactory { - - MqttClient getClientInstance(String url, String clientId) throws MqttException; - - MqttConnectOptions getConnectionOptions(); -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/core/package-info.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/core/package-info.java deleted file mode 100644 index 1488613..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/core/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Provides core classes of the MqttAdapter module. - */ -package org.springframework.integration.mqtt.core; diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/AbstractMqttMessageDrivenChannelAdapter.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/AbstractMqttMessageDrivenChannelAdapter.java deleted file mode 100644 index 5e21c72..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/AbstractMqttMessageDrivenChannelAdapter.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.inbound; - -import org.springframework.integration.endpoint.MessageProducerSupport; -import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter; -import org.springframework.integration.mqtt.support.MqttMessageConverter; -import org.springframework.util.Assert; - -/** - * Abstract class for MQTT Message-Driven Channel Adapters. - * @author Gary Russell - * @since 1.0 - * - */ -public abstract class AbstractMqttMessageDrivenChannelAdapter extends MessageProducerSupport { - - private final String url; - - private final String clientId; - - private final String[] topic; - - private volatile MqttMessageConverter converter; - - public AbstractMqttMessageDrivenChannelAdapter(String url, String clientId, String... topic) { - Assert.hasText(url, "'url' cannot be null or empty"); - Assert.hasText(clientId, "'clientId' cannot be null or empty"); - Assert.notNull(topic, "'topics' cannot be null"); - Assert.isTrue(topic.length > 0, "'topics' cannot be empty"); - Assert.noNullElements(topic, "'topics' cannot have null elements"); - this.url = url; - this.clientId = clientId; - this.topic = topic; - } - - public void setConverter(MqttMessageConverter converter) { - Assert.notNull(converter, "'converter' cannot be null"); - this.converter = converter; - } - - protected String getUrl() { - return url; - } - - protected String getClientId() { - return clientId; - } - - protected MqttMessageConverter getConverter() { - return converter; - } - - protected String[] getTopic() { - return topic; - } - - @Override - protected void onInit() { - super.onInit(); - if (this.converter == null) { - this.converter = new DefaultPahoMessageConverter(); - } - } - - @Override - public String getComponentType(){ - return "mqtt:inbound-channel-adapter"; - } - -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/MqttPahoMessageDrivenChannelAdapter.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/MqttPahoMessageDrivenChannelAdapter.java deleted file mode 100644 index 99be20b..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/MqttPahoMessageDrivenChannelAdapter.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.inbound; - -import java.util.Arrays; -import java.util.concurrent.ScheduledFuture; - -import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; -import org.eclipse.paho.client.mqttv3.MqttCallback; -import org.eclipse.paho.client.mqttv3.MqttClient; -import org.eclipse.paho.client.mqttv3.MqttException; -import org.eclipse.paho.client.mqttv3.MqttMessage; - -import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; -import org.springframework.integration.mqtt.core.MqttPahoClientFactory; -import org.springframework.messaging.Message; - -/** - * Eclipse Paho Implementation. - * - * @author Gary Russell - * @since 1.0 - * - */ -public class MqttPahoMessageDrivenChannelAdapter extends AbstractMqttMessageDrivenChannelAdapter - implements MqttCallback { - - private final MqttPahoClientFactory clientFactory; - - private volatile MqttClient client; - - private volatile ScheduledFuture reconnectFuture; - - private volatile boolean connected; - - - public MqttPahoMessageDrivenChannelAdapter(String url, String clientId, MqttPahoClientFactory clientFactory, - String... topic) { - super(url, clientId, topic); - this.clientFactory = clientFactory; - } - - public MqttPahoMessageDrivenChannelAdapter(String url, String clientId, String... topic) { - this(url, clientId, new DefaultMqttPahoClientFactory(), topic); - } - - @Override - protected void doStart() { - super.doStart(); - try { - this.connectAndSubscribe(); - } - catch (Exception e) { - logger.error("Exception while connecting and subscribing, retrying", e); - this.scheduleReconnect(); - } - } - - @Override - protected void doStop() { - this.cancelReconnect(); - super.doStop(); - try { - this.client.unsubscribe(this.getTopic()); - } - catch (MqttException e) { - logger.error("Exception while unsubscribing", e); - } - try { - this.client.disconnect(); - } - catch (MqttException e) { - logger.error("Exception while disconnecting", e); - } - try { - this.client.close(); - } - catch (MqttException e) { - logger.error("Exception while closing", e); - } - this.connected = false; - this.client = null; - } - - private void connectAndSubscribe() throws MqttException { - this.client = this.clientFactory.getClientInstance(this.getUrl(), this.getClientId()); - this.client.connect(this.clientFactory.getConnectionOptions()); - try { - this.client.subscribe(this.getTopic()); - } - catch (MqttException e) { - this.client.disconnect(); - throw e; - } - if (this.client.isConnected()) { - this.client.setCallback(this); - this.connected = true; - if (this.reconnectFuture != null) { - this.cancelReconnect(); - } - if (logger.isDebugEnabled()) { - logger.debug("Connected and subscribed to " + Arrays.asList(this.getTopic())); - } - } - } - - private synchronized void cancelReconnect() { - if (this.reconnectFuture != null) { - this.reconnectFuture.cancel(false); - this.reconnectFuture = null; - } - } - - private void scheduleReconnect() { - try { - this.reconnectFuture = this.getTaskScheduler().scheduleWithFixedDelay(new Runnable() { - - @Override - public void run() { - try { - if (logger.isDebugEnabled()) { - logger.debug("Attempting reconnect"); - } - if (!connected) { - connectAndSubscribe(); - } - } - catch (MqttException e) { - logger.error("Exception while connecting and subscribing", e); - } - } - }, 10000); - } - catch (Exception e) { - logger.error("Failed to schedule reconnect", e); - } - } - - @Override - public void connectionLost(Throwable cause) { - this.logger.error("Lost connection:" + cause.getMessage() + "; retrying..."); - this.connected = false; - this.scheduleReconnect(); - } - - @Override - public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception { - Message message = this.getConverter().toMessage(topic, mqttMessage); - try { - this.sendMessage(message); - } - catch (RuntimeException e) { - logger.error("Unhandled exception for " + message.toString(), e); - throw e; - } - } - - @Override - public void deliveryComplete(IMqttDeliveryToken token) { - } - -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/MqttPahoMessageDrivenChannelAdapter.java~ b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/MqttPahoMessageDrivenChannelAdapter.java~ deleted file mode 100644 index 55b760a..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/MqttPahoMessageDrivenChannelAdapter.java~ +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.inbound; - -import java.util.concurrent.ScheduledFuture; - -import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; -import org.eclipse.paho.client.mqttv3.MqttCallback; -import org.eclipse.paho.client.mqttv3.MqttClient; -import org.eclipse.paho.client.mqttv3.MqttException; -import org.eclipse.paho.client.mqttv3.MqttMessage; - -import org.springframework.integration.Message; -import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; -import org.springframework.integration.mqtt.core.MqttPahoClientFactory; - -/** - * Eclipse Paho Implementation. - * - * @author Gary Russell - * @since 1.0 - * - */ -public class MqttPahoMessageDrivenChannelAdapter extends AbstractMqttMessageDrivenChannelAdapter - implements MqttCallback { - - private final MqttPahoClientFactory clientFactory; - - private volatile MqttClient client; - - private volatile ScheduledFuture reconnectFuture; - - private volatile boolean connected; - - - public MqttPahoMessageDrivenChannelAdapter(String url, String clientId, MqttPahoClientFactory clientFactory, - String... topic) { - super(url, clientId, topic); - this.clientFactory = clientFactory; - } - - public MqttPahoMessageDrivenChannelAdapter(String url, String clientId, String... topic) { - this(url, clientId, new DefaultMqttPahoClientFactory(), topic); - } - - @Override - protected void doStart() { - super.doStart(); - try { - this.connectAndSubscribe(); - } - catch (Exception e) { - logger.error("Exception while connecting and subscribing, retrying", e); - this.scheduleReconnect(); - } - } - - @Override - protected void doStop() { - this.cancelReconnect(); - super.doStop(); - try { - this.client.unsubscribe(this.getTopic()); - } - catch (MqttException e) { - logger.error("Exception while unsubscribing", e); - } - try { - this.client.disconnect(); - } - catch (MqttException e) { - logger.error("Exception while disconnecting", e); - } - try { - this.client.close(); - } - catch (MqttException e) { - logger.error("Exception while closing", e); - } - this.connected = false; - this.client = null; - } - - private void connectAndSubscribe() throws MqttException { - this.client = this.clientFactory.getClientInstance(this.getUrl(), this.getClientId()); - this.client.connect(this.clientFactory.getConnectionOptions()); - try { - this.client.subscribe(this.getTopic()); - } - catch (MqttException e) { - this.client.disconnect(); - throw e; - } - if (this.client.isConnected()) { - this.client.setCallback(this); - this.connected = true; - if (this.reconnectFuture != null) { - this.cancelReconnect(); - } - if (logger.isDebugEnabled()) { - logger.debug("Connected and subscribed to " + Arrays.asList(this.getTopic())); - } - } - } - - private synchronized void cancelReconnect() { - if (this.reconnectFuture != null) { - this.reconnectFuture.cancel(false); - this.reconnectFuture = null; - } - } - - private void scheduleReconnect() { - try { - this.reconnectFuture = this.getTaskScheduler().scheduleWithFixedDelay(new Runnable() { - - @Override - public void run() { - try { - if (logger.isDebugEnabled()) { - logger.debug("Attempting reconnect"); - } - if (!connected) { - connectAndSubscribe(); - } - } - catch (MqttException e) { - logger.error("Exception while connecting and subscribing", e); - } - } - }, 10000); - } - catch (Exception e) { - logger.error("Failed to schedule reconnect", e); - } - } - - @Override - public void connectionLost(Throwable cause) { - this.logger.error("Lost connection:" + cause.getMessage() + "; retrying..."); - this.connected = false; - this.scheduleReconnect(); - } - - @Override - public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception { - Message message = this.getConverter().toMessage(topic, mqttMessage); - try { - this.sendMessage(message); - } - catch (RuntimeException e) { - logger.error("Unhandled exception for " + message.toString(), e); - throw e; - } - } - - @Override - public void deliveryComplete(IMqttDeliveryToken token) { - } - -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/package-info.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/package-info.java deleted file mode 100644 index 5dc35d5..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/inbound/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Provides inbound Spring Integration MqttAdapter components. - */ -package org.springframework.integration.mqtt.inbound; diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/outbound/AbstractMqttMessageHandler.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/outbound/AbstractMqttMessageHandler.java deleted file mode 100644 index 3dc7240..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/outbound/AbstractMqttMessageHandler.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.integration.mqtt.outbound; - -import org.eclipse.paho.client.mqttv3.MqttMessage; - -import org.springframework.context.SmartLifecycle; -import org.springframework.integration.MessageHandlingException; -import org.springframework.integration.handler.AbstractMessageHandler; -import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter; -import org.springframework.integration.mqtt.support.MqttHeaders; -import org.springframework.integration.mqtt.support.MqttMessageConverter; -import org.springframework.messaging.Message; -import org.springframework.util.Assert; - -/** - * Abstract class for MQTT outbound channel adapters. - * @author Gary Russell - * @since 1.0 - * - */ -public abstract class AbstractMqttMessageHandler extends AbstractMessageHandler implements SmartLifecycle { - - private final String url; - - private final String clientId; - - private volatile String defaultTopic; - - private volatile int defaultQos = 0; - - private volatile boolean defaultRetained = false; - - private volatile MqttMessageConverter converter; - - private boolean running; - - private volatile int phase; - - private volatile boolean autoStartup; - - public AbstractMqttMessageHandler(String url, String clientId) { - Assert.hasText(url, "'url' cannot be null or empty"); - Assert.hasText(clientId, "'clientId' cannot be null or empty"); - this.url = url; - this.clientId = clientId; - } - - public void setDefaultTopic(String defaultTopic) { - this.defaultTopic = defaultTopic; - } - - public void setDefaultQos(int defaultQos) { - this.defaultQos = defaultQos; - } - - public void setDefaultRetained(boolean defaultRetain) { - this.defaultRetained = defaultRetain; - } - - public void setConverter(MqttMessageConverter converter) { - Assert.notNull(converter, "'converter' cannot be null"); - this.converter = converter; - } - - protected String getUrl() { - return url; - } - - protected String getClientId() { - return clientId; - } - - @Override - protected void onInit() throws Exception { - super.onInit(); - if (this.converter == null) { - this.converter = new DefaultPahoMessageConverter(this.defaultQos, this.defaultRetained); - } - } - - @Override - public final void start() { - this.doStart(); - } - - protected abstract void doStart(); - - @Override - public final void stop() { - this.doStop(); - } - - protected abstract void doStop(); - - @Override - public boolean isRunning() { - return this.running; - } - - @Override - public int getPhase() { - return this.phase; - } - - public void setPhase(int phase) { - this.phase = phase; - } - - public void setAutoStartup(boolean autoStartup) { - this.autoStartup = autoStartup; - } - - @Override - public boolean isAutoStartup() { - return this.autoStartup; - } - - @Override - public void stop(Runnable callback) { - this.stop(); - callback.run(); - } - - @Override - protected void handleMessageInternal(Message message) throws Exception { - this.connectIfNeeded(); - String topic = (String) message.getHeaders().get(MqttHeaders.TOPIC); - MqttMessage mqttMessage = (MqttMessage) this.converter.fromMessage(message, MqttMessage.class); - if (topic == null && this.defaultTopic == null) { - throw new MessageHandlingException(message, - "No '" + MqttHeaders.TOPIC + "' header and no default topic defined"); - } - this.publish(topic == null ? this.defaultTopic : topic, mqttMessage); - } - - protected abstract void connectIfNeeded(); - - protected abstract void publish(String topic, Object mqttMessage) throws Exception; - - @Override - public String getComponentType() { - return "mqtt:outbound-channel-adapter"; - } - -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/outbound/MqttPahoMessageHandler.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/outbound/MqttPahoMessageHandler.java deleted file mode 100644 index e0570be..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/outbound/MqttPahoMessageHandler.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.outbound; - -import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; -import org.eclipse.paho.client.mqttv3.MqttCallback; -import org.eclipse.paho.client.mqttv3.MqttClient; -import org.eclipse.paho.client.mqttv3.MqttException; -import org.eclipse.paho.client.mqttv3.MqttMessage; - -import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; -import org.springframework.integration.mqtt.core.MqttPahoClientFactory; -import org.springframework.messaging.MessagingException; -import org.springframework.util.Assert; - -/** - * Eclipse Paho implementation. - * @author Gary Russell - * @since 1.0 - * - */ -public class MqttPahoMessageHandler extends AbstractMqttMessageHandler - implements MqttCallback { - - private final MqttPahoClientFactory clientFactory; - - private volatile MqttClient client; - - public MqttPahoMessageHandler(String url, String clientId, MqttPahoClientFactory factory) { - super(url, clientId); - this.clientFactory = factory; - } - - public MqttPahoMessageHandler(String url, String clientId) { - this(url, clientId, new DefaultMqttPahoClientFactory()); - } - - @Override - protected void doStart() { - } - - @Override - protected void doStop() { - try { - if (this.client != null) { - this.client.disconnect(); - this.client.close(); - this.client = null; - } - } - catch (MqttException e) { - logger.error("Failed to disconnect", e); - } - } - - private synchronized void doConnect() throws MqttException { - if (this.client != null && !this.client.isConnected()) { - this.client.close(); - this.client = null; - } - if (this.client == null) { - this.client = this.clientFactory.getClientInstance(this.getUrl(), this.getClientId()); - this.client.connect(this.clientFactory.getConnectionOptions()); - this.client.setCallback(this); - if (logger.isDebugEnabled()) { - logger.debug("Client connected"); - } - } - } - - @Override - protected void connectIfNeeded() { - if (this.client == null || !this.client.isConnected()) { - try { - this.doConnect(); - } - catch (MqttException e) { - throw new MessagingException("Failed to connect", e); - } - } - } - - @Override - protected void publish(String topic, Object mqttMessage) throws Exception { - Assert.isInstanceOf(MqttMessage.class, mqttMessage); - this.client.publish(topic, (MqttMessage) mqttMessage); - } - - @Override - public void connectionLost(Throwable cause) { - logger.error("Lost connection; will attempt reconnect on next request"); - this.client = null; - } - - @Override - public void messageArrived(String topic, MqttMessage message) throws Exception { - - } - - @Override - public void deliveryComplete(IMqttDeliveryToken token) { - - } - -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/outbound/package-info.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/outbound/package-info.java deleted file mode 100644 index 6b5d4e4..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/outbound/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Provides Spring Integration components for doing outbound operations. - */ -package org.springframework.integration.mqtt.outbound; diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/package-info.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/package-info.java deleted file mode 100644 index 79304d7..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Root package of the MqttAdapter Module. - */ -package org.springframework.integration.mqtt; diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/DefaultPahoMessageConverter.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/DefaultPahoMessageConverter.java deleted file mode 100644 index 5f4a5f0..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/DefaultPahoMessageConverter.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.support; - -import org.eclipse.paho.client.mqttv3.MqttMessage; - -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.converter.MessageConversionException; -import org.springframework.util.Assert; - - -/** - * Default implementation allowing most connection options to be configured. - * @author Gary Russell - * @since 1.0 - * - */ -public class DefaultPahoMessageConverter implements MqttMessageConverter { - - private final String charset; - - private final Integer defaultQos; - - private final Boolean defaultRetained; - - public DefaultPahoMessageConverter() { - this (0, false); - } - - public DefaultPahoMessageConverter(int defaultQos, boolean defaultRetain) { - this(defaultQos, defaultRetain, "UTF-8"); - } - - public DefaultPahoMessageConverter(int defaultQos, boolean defaultRetained, String charset) { - this.defaultQos = defaultQos; - this.defaultRetained = defaultRetained; - this.charset = charset; - } - - @Override - public Message toMessage(Object mqttMessage, MessageHeaders headers) { - Assert.isInstanceOf(MqttMessage.class, mqttMessage); - return toMessage(null, (MqttMessage) mqttMessage); - } - - @Override - public Message toMessage(String topic, MqttMessage mqttMessage) { - try { - MessageBuilder messageBuilder = MessageBuilder.withPayload(new String(mqttMessage.getPayload(), this.charset)) - .setHeader(MqttHeaders.QOS, mqttMessage.getQos()) - .setHeader(MqttHeaders.DUPLICATE, mqttMessage.isDuplicate()) - .setHeader(MqttHeaders.RETAINED, mqttMessage.isRetained()); - if (topic != null) { - messageBuilder.setHeader(MqttHeaders.TOPIC, topic); - } - return messageBuilder.build(); - } - catch (Exception e) { - throw new MessageConversionException("failed to convert object to Message", e); - } - } - - @Override - public MqttMessage fromMessage(Message message, Class targetClass) { - Object payload = message.getPayload(); - Assert.isTrue(payload instanceof byte[] || payload instanceof String); - byte[] payloadBytes; - if (payload instanceof String) { - try { - payloadBytes = ((String) payload).getBytes(this.charset); - } - catch (Exception e) { - throw new MessageConversionException("failed to convert Message to object", e); - } - } - else { - payloadBytes = (byte[]) payload; - } - MqttMessage mqttMessage = new MqttMessage(payloadBytes); - Object header = message.getHeaders().get(MqttHeaders.RETAINED); - Assert.isTrue(header == null || header instanceof Boolean, MqttHeaders.RETAINED + " header must be Boolean"); - mqttMessage.setRetained(header == null ? this.defaultRetained : (Boolean) header); - header = message.getHeaders().get(MqttHeaders.QOS); - Assert.isTrue(header == null || header instanceof Integer, MqttHeaders.QOS + " header must be Integer"); - mqttMessage.setQos(header == null ? this.defaultQos : (Integer) header); - return mqttMessage; - } - -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/MqttHeaders.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/MqttHeaders.java deleted file mode 100644 index b114ad6..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/MqttHeaders.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.support; - -/** - * Spring Integration headers. - * @author Gary Russell - * @since 3.0 - * - */ -public class MqttHeaders { - - private static final String prefix = "mqtt_"; - - public static final String QOS = prefix + "qos"; - - public static final String DUPLICATE = prefix + "duplicate"; - - public static final String RETAINED = prefix + "retained"; - - public static final String TOPIC = prefix + "topic"; - private MqttHeaders() { - throw new AssertionError(); - } -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/MqttMessageConverter.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/MqttMessageConverter.java deleted file mode 100644 index aefbff3..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/MqttMessageConverter.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.support; - -import org.eclipse.paho.client.mqttv3.MqttMessage; - -import org.springframework.messaging.Message; -import org.springframework.messaging.converter.MessageConverter; - -/** - * Extension of {@link MessageConverter} allowing the topic to be added as - * a header. - * @author Gary Russell - * @since 1.0 - * - */ -public interface MqttMessageConverter extends MessageConverter { - - Message toMessage(String topic, MqttMessage mqttMessage); -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/MqttUtils.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/MqttUtils.java deleted file mode 100644 index 1f69d23..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/MqttUtils.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.support; - - -/** - * Contains utility methods used by the MqttAdapter components. - * - * @author Gary Russell - * @since 1.0 - * - */ -public final class MqttUtils { - - /** Prevent instantiation. */ - private MqttUtils() { - throw new AssertionError(); - } - -} diff --git a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/package-info.java b/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/package-info.java deleted file mode 100644 index c711af2..0000000 --- a/spring-integration-mqtt/src/main/java/org/springframework/integration/mqtt/support/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Provides various support classes used across Spring Integration MqttAdapter Components. - */ -package org.springframework.integration.mqtt.support; diff --git a/spring-integration-mqtt/src/main/resources/META-INF/spring.handlers b/spring-integration-mqtt/src/main/resources/META-INF/spring.handlers deleted file mode 100644 index fdbf583..0000000 --- a/spring-integration-mqtt/src/main/resources/META-INF/spring.handlers +++ /dev/null @@ -1 +0,0 @@ -http\://www.springframework.org/schema/integration/mqtt=org.springframework.integration.mqtt.config.xml.MqttNamespaceHandler diff --git a/spring-integration-mqtt/src/main/resources/META-INF/spring.schemas b/spring-integration-mqtt/src/main/resources/META-INF/spring.schemas deleted file mode 100644 index f4273c5..0000000 --- a/spring-integration-mqtt/src/main/resources/META-INF/spring.schemas +++ /dev/null @@ -1,2 +0,0 @@ -http\://www.springframework.org/schema/integration/mqtt/spring-integration-mqtt-1.0.xsd=org/springframework/integration/mqtt/config/xml/spring-integration-mqtt-1.0.xsd -http\://www.springframework.org/schema/integration/mqtt/spring-integration-mqtt.xsd=org/springframework/integration/mqtt/config/xml/spring-integration-mqtt-1.0.xsd diff --git a/spring-integration-mqtt/src/main/resources/META-INF/spring.tooling b/spring-integration-mqtt/src/main/resources/META-INF/spring.tooling deleted file mode 100644 index a062077..0000000 --- a/spring-integration-mqtt/src/main/resources/META-INF/spring.tooling +++ /dev/null @@ -1,4 +0,0 @@ -# Tooling related information for the integration MqttAdapter namespace -http\://www.springframework.org/schema/integration/mqttadapter@name=integration MqttAdapter Namespace -http\://www.springframework.org/schema/integration/mqttadapter@prefix=int-mqttadapter -http\://www.springframework.org/schema/integration/mqttadapter@icon=org/springframework/integration/config/xml/spring-integration-mqttadapter.gif diff --git a/spring-integration-mqtt/src/main/resources/org/springframework/integration/mqtt/config/xml/spring-integration-mqtt-1.0.xsd b/spring-integration-mqtt/src/main/resources/org/springframework/integration/mqtt/config/xml/spring-integration-mqtt-1.0.xsd deleted file mode 100644 index 3f11fe6..0000000 --- a/spring-integration-mqtt/src/main/resources/org/springframework/integration/mqtt/config/xml/spring-integration-mqtt-1.0.xsd +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - - - - - - - - - The definition for the Spring Integration MqttAdapter - Inbound Channel Adapter. - - - - - - - - - - - - - - - - - Specifies one or more (comma-delimited) topics on which to listen for messages. - - - - - - - - - - - - - - - - - - If a downstream exception is thrown and an error-channel is specified, - the MessagingException will be sent to this channel. Otherwise, any such exception - will be logged. - - - - - - - - - - Defines an outbound Channel Adapter. - - - - - - - - - - - - Channel from which messages will be output. - When a message is sent to this channel it will - cause the query - to be executed. - - - - - - - - - - - Specifies the order for invocation when this endpoint is connected as a - subscriber to a SubscribableChannel. - - - - - - - Specifies the default topic to which messages will be sent. Required if an - outbound message does not have an 'mqtt_topic' header. - - - - - - - Specifies the default quality of service. Default 0. - - - - - - - Specifies the default value of the 'retained' flag. Default false. - - - - - - - - - - - Identifies the underlying Spring bean definition, which is an - instance of either 'EventDrivenConsumer' or 'PollingConsumer', - depending on whether the component's input channel is a - 'SubscribableChannel' or 'PollableChannel'. - - - - - - - Flag to indicate that the component should start automatically - on startup (default true). - - - - - - - - - - Flag to indicate the phase in which the component should start automatically - on startup. See SmartLifecycle. - - - - - - - - - - MQTT broker URL. - - - - - - - MQTT client ID. - - - - - - - to/from - a paho MqttMessage. Default is DefaultMqttMessageConverter. - ]]> - - - - - - - - - - - - - - - - - - - diff --git a/spring-integration-mqtt/src/main/resources/org/springframework/integration/mqtt/config/xml/spring-integration-mqtt-1.0.xsd~ b/spring-integration-mqtt/src/main/resources/org/springframework/integration/mqtt/config/xml/spring-integration-mqtt-1.0.xsd~ deleted file mode 100644 index ecf59a9..0000000 --- a/spring-integration-mqtt/src/main/resources/org/springframework/integration/mqtt/config/xml/spring-integration-mqtt-1.0.xsd~ +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - - - - - - - - - - The definition for the Spring Integration MqttAdapter - Inbound Channel Adapter. - - - - - - - - - - - - - - - - - Specifies one or more (comma-delimited) topics on which to listen for messages. - - - - - - - - - - - - - - - - Defines an outbound Channel Adapter. - - - - - - - - - - - - Channel from which messages will be output. - When a message is sent to this channel it will - cause the query - to be executed. - - - - - - - - - - - Specifies the order for invocation when this endpoint is connected as a - subscriber to a SubscribableChannel. - - - - - - - Specifies the default topic to which messages will be sent. Required if an - outbound message does not have an 'mqtt_topic' header. - - - - - - - Specifies the default quality of service. Default 0. - - - - - - - Specifies the default value of the 'retained' flag. Default false. - - - - - - - - - - - Identifies the underlying Spring bean definition, which is an - instance of either 'EventDrivenConsumer' or 'PollingConsumer', - depending on whether the component's input channel is a - 'SubscribableChannel' or 'PollableChannel'. - - - - - - - Flag to indicate that the component should start automatically - on startup (default true). - - - - - - - - - - Flag to indicate the phase in which the component should start automatically - on startup. See SmartLifecycle. - - - - - - - - - - MQTT broker URL. - - - - - - - MQTT client ID. - - - - - - - to/from - a paho MqttMessage. Default is DefaultMqttMessageConverter. - ]]> - - - - - - - - - - - - - - - - - - - diff --git a/spring-integration-mqtt/src/main/resources/org/springframework/integration/mqtt/config/xml/spring-integration-mqttadapter.gif b/spring-integration-mqtt/src/main/resources/org/springframework/integration/mqtt/config/xml/spring-integration-mqttadapter.gif deleted file mode 100644 index 210e0764fa4c1e5baebcdea156bc3f3e1f97a2c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 539 zcmZ?wbhEHb6krfwc*Xz%|NsB*n7VH6iaomzUp%y<^XRV5le@dm?CrjBr0?SXo|o4a z>{}Ri^GM%=bBkWz+y8vM?x%h3?+zusxj5zR@#^Jm-pe}!R`mow*jzjz+p;&)qBX&& zG1jmr&Ac*H`_zJhTu;?PU-d#?%_oZ!?=4DAaa1VqRO?H!xIQD{=A4w7g+5uX8WR(2 zrX<_tc8Bb5QRHvpiB8JU`8KTWP?thKQZD zFcaE=iuVx<>PO@dH?gn{*FclYXGfDn1BEP diff --git a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/BackTobackAdapterTests.java b/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/BackTobackAdapterTests.java deleted file mode 100644 index 45a17f8..0000000 --- a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/BackTobackAdapterTests.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import org.junit.Rule; -import org.junit.Test; - -import org.springframework.integration.channel.QueueChannel; -import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; -import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler; -import org.springframework.integration.mqtt.support.MqttHeaders; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.messaging.support.GenericMessage; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; - -/** - * @author Gary Russell - * @since 1.0 - * - */ -public class BackTobackAdapterTests { - - @Rule - public final BrokerRunning brokerRunning = BrokerRunning.isRunning(1883); - - @Test - public void testSingleTopic() { - MqttPahoMessageHandler adapter = new MqttPahoMessageHandler("tcp://localhost:1883", "si-test-out"); - adapter.setDefaultTopic("mqtt-foo"); - adapter.afterPropertiesSet(); - adapter.start(); - MqttPahoMessageDrivenChannelAdapter inbound = new MqttPahoMessageDrivenChannelAdapter("tcp://localhost:1883", "si-test-in", "mqtt-foo"); - QueueChannel outputChannel = new QueueChannel(); - inbound.setOutputChannel(outputChannel); - ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); - taskScheduler.initialize(); - inbound.setTaskScheduler(taskScheduler); - inbound.afterPropertiesSet(); - inbound.start(); - adapter.handleMessage(new GenericMessage("foo")); - adapter.stop(); - Message out = outputChannel.receive(1000); - assertNotNull(out); - inbound.stop(); - assertEquals("foo", out.getPayload()); - assertEquals("mqtt-foo", out.getHeaders().get(MqttHeaders.TOPIC)); - } - - @Test - public void testTwoTopics() { - MqttPahoMessageHandler adapter = new MqttPahoMessageHandler("tcp://localhost:1883", "si-test-out"); - adapter.setDefaultTopic("mqtt-foo"); - adapter.afterPropertiesSet(); - adapter.start(); - MqttPahoMessageDrivenChannelAdapter inbound = new MqttPahoMessageDrivenChannelAdapter("tcp://localhost:1883", "si-test-in", "mqtt-foo", "mqtt-bar"); - QueueChannel outputChannel = new QueueChannel(); - inbound.setOutputChannel(outputChannel); - ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); - taskScheduler.initialize(); - inbound.setTaskScheduler(taskScheduler); - inbound.afterPropertiesSet(); - inbound.start(); - adapter.handleMessage(new GenericMessage("foo")); - Message message = MessageBuilder.withPayload("bar").setHeader(MqttHeaders.TOPIC, "mqtt-bar").build(); - adapter.handleMessage(message); - adapter.stop(); - Message out = outputChannel.receive(1000); - assertNotNull(out); - inbound.stop(); - assertEquals("foo", out.getPayload()); - assertEquals("mqtt-foo", out.getHeaders().get(MqttHeaders.TOPIC)); - out = outputChannel.receive(1000); - assertNotNull(out); - inbound.stop(); - assertEquals("bar", out.getPayload()); - assertEquals("mqtt-bar", out.getHeaders().get(MqttHeaders.TOPIC)); } - -} diff --git a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/BrokerRunning.java b/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/BrokerRunning.java deleted file mode 100644 index 6c15e53..0000000 --- a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/BrokerRunning.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt; - -import static org.junit.Assume.assumeNoException; -import static org.junit.Assume.assumeTrue; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.eclipse.paho.client.mqttv3.MqttClient; -import org.eclipse.paho.client.mqttv3.MqttException; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; -import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; - -/** - * @author Gary Russell - * @since 1.0 - * - */ -public class BrokerRunning extends TestWatcher { - - private static Log logger = LogFactory.getLog(BrokerRunning.class); - - // Static so that we only test once on failure: speeds up test suite - private static Map brokerOnline = new HashMap(); - - private final int port; - - private BrokerRunning(int port) { - this.port = port; - brokerOnline.put(port, true); - } - - @Override - public Statement apply(Statement base, Description description) { - assumeTrue(brokerOnline.get(port)); - String url = "tcp://localhost:" + port; - MqttClient client = null; - try { - client = new DefaultMqttPahoClientFactory().getClientInstance(url, "junit-" + System.currentTimeMillis()); - client.connect(); - } - catch (MqttException e) { - logger.warn("Tests not running because no broker on " + url + ":", e); - assumeNoException(e); - } - finally { - if (client != null) { - try { - client.disconnect(); - client.close(); - } - catch (MqttException e) { - } - } - } - return super.apply(base, description); - } - - - - public static BrokerRunning isRunning(int port) { - return new BrokerRunning(port); - } -} diff --git a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/BrokerRunning.java~ b/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/BrokerRunning.java~ deleted file mode 100644 index 57587d8..0000000 --- a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/BrokerRunning.java~ +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt; - -import static org.junit.Assume.assumeNoException; -import static org.junit.Assume.assumeTrue; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.eclipse.paho.client.mqttv3.MqttClient; -import org.eclipse.paho.client.mqttv3.MqttException; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; -import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; - -/** - * @author Gary Russell - * @since 1.0 - * - */ -public class BrokerRunning extends TestWatcher { - - private static Log logger = LogFactory.getLog(BrokerRunning.class); - - // Static so that we only test once on failure: speeds up test suite - private static Map brokerOnline = new HashMap(); - - private final int port; - - private BrokerRunning(int port) { - this.port = port; - brokerOnline.put(port, true); - } - - @Override - public Statement apply(Statement base, Description description) { - assumeTrue(brokerOnline.get(port)); - String url = "tcp://localhost:" + port; - MqttClient client = null; - try { - client = new DefaultMqttPahoClientFactory().getClientInstance(url, "junit-" + System.currentTimeMillis()); - client.connect(); - } - catch (MqttException e) { - logger.warn("Tests not running because no broker on " + url + ":", e); - assumeNoException(e); - } - finally { - if (client != null) { - try { - client.close(); - } - catch (MqttException e) { - } - } - } - return super.apply(base, description); - } - - - - public static BrokerRunning isRunning(int port) { - return new BrokerRunning(port); - } -} diff --git a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/DownstreamExceptionTests-context.xml b/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/DownstreamExceptionTests-context.xml deleted file mode 100644 index 8576476..0000000 --- a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/DownstreamExceptionTests-context.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/DownstreamExceptionTests.java b/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/DownstreamExceptionTests.java deleted file mode 100644 index 847847d..0000000 --- a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/DownstreamExceptionTests.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.contains; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.logging.Log; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import org.springframework.beans.DirectFieldAccessor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; -import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler; -import org.springframework.integration.test.util.TestUtils; -import org.springframework.integration.core.PollableChannel; -import org.springframework.integration.message.GenericMessage; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -/** - * @author Gary Russell - * @since 4.0 - * - */ -@ContextConfiguration -@RunWith(SpringJUnit4ClassRunner.class) -@DirtiesContext -public class DownstreamExceptionTests { - - @ClassRule - public static final BrokerRunning brokerRunning = BrokerRunning.isRunning(1883); - - @Autowired - private Service service; - - @Autowired - private MqttPahoMessageDrivenChannelAdapter noErrorChannel; - - @Autowired - private MqttPahoMessageDrivenChannelAdapter withErrorChannel; - - @Autowired - private PollableChannel errors; - - @Test - public void testNoErrorChannel() throws Exception { - service.barrier.reset(); - service.n = 0; - Log logger = spy(TestUtils.getPropertyValue(noErrorChannel, "logger", Log.class)); - final CountDownLatch latch = new CountDownLatch(1); - doAnswer(new Answer() { - - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - if (((String) invocation.getArguments()[0]).contains("Unhandled")) { - latch.countDown(); - } - return null; - } - }).when(logger).error(anyString(), any(Throwable.class)); - new DirectFieldAccessor(noErrorChannel).setPropertyValue("logger", logger); - MqttPahoMessageHandler adapter = new MqttPahoMessageHandler("tcp://localhost:1883", "si-test-out"); - adapter.setDefaultTopic("mqtt-fooEx1"); - adapter.afterPropertiesSet(); - adapter.start(); - adapter.handleMessage(new GenericMessage("foo")); - service.barrier.await(10, TimeUnit.SECONDS); - service.barrier.reset(); - adapter.handleMessage(new GenericMessage("foo")); - service.barrier.await(10, TimeUnit.SECONDS); - assertTrue(latch.await(10, TimeUnit.SECONDS)); - verify(logger).error(contains("Unhandled exception for"), any(Throwable.class)); - service.barrier.reset(); - adapter.stop(); - } - - @Test - public void testWithErrorChannel() throws Exception { - service.barrier.reset(); - assertSame(this.errors, TestUtils.getPropertyValue(this.withErrorChannel, "errorChannel")); - service.n = 0; - MqttPahoMessageHandler adapter = new MqttPahoMessageHandler("tcp://localhost:1883", "si-test-out"); - adapter.setDefaultTopic("mqtt-fooEx2"); - adapter.afterPropertiesSet(); - adapter.start(); - adapter.handleMessage(new GenericMessage("foo")); - service.barrier.await(10, TimeUnit.SECONDS); - service.barrier.reset(); - adapter.handleMessage(new GenericMessage("foo")); - service.barrier.await(10, TimeUnit.SECONDS); - assertNotNull(errors.receive(10000)); - service.barrier.reset(); - adapter.stop(); - } - - public static class Service { - - public CyclicBarrier barrier = new CyclicBarrier(2); - - public int n; - - public void foo(String foo) throws Exception { - barrier.await(10, TimeUnit.SECONDS); - if (n++ > 0) { - throw new RuntimeException("bar"); - } - } - - } - -} diff --git a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/MqttAdapterTests.java b/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/MqttAdapterTests.java deleted file mode 100644 index e55800e..0000000 --- a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/MqttAdapterTests.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Properties; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import javax.net.SocketFactory; - -import org.eclipse.paho.client.mqttv3.MqttCallback; -import org.eclipse.paho.client.mqttv3.MqttClient; -import org.eclipse.paho.client.mqttv3.MqttConnectOptions; -import org.eclipse.paho.client.mqttv3.MqttMessage; -import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import org.springframework.integration.channel.QueueChannel; -import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; -import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory.Will; -import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; -import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler; -import org.springframework.messaging.Message; -import org.springframework.messaging.support.GenericMessage; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; - -/** - * @author Gary Russell - * @since 1.0 - * - */ -public class MqttAdapterTests { - - @Test - public void testPahoConnectOptions() { - DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory(); - factory.setCleanSession(false); - factory.setConnectionTimeout(23); - factory.setKeepAliveInterval(45); - factory.setPassword("pass"); - SocketFactory socketFactory = mock(SocketFactory.class); - factory.setSocketFactory(socketFactory); - Properties props = new Properties(); - factory.setSslProperties(props); - factory.setUserName("user"); - Will will = new Will("foo", "bar".getBytes(), 2, true); - factory.setWill(will); - - MqttConnectOptions options = factory.getConnectionOptions(); - - assertEquals(23, options.getConnectionTimeout()); - assertEquals(45, options.getKeepAliveInterval()); - assertEquals("pass", new String(options.getPassword())); - assertSame(socketFactory, options.getSocketFactory()); - assertSame(props, options.getSSLProperties()); - assertEquals("user", options.getUserName()); - assertEquals("foo", options.getWillDestination()); - assertEquals("bar", new String(options.getWillMessage().getPayload())); - assertEquals(2, options.getWillMessage().getQos()); - - } - - @Test - public void testOutboundOptionsApplied() throws Exception { - DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory(); - factory.setCleanSession(false); - factory.setConnectionTimeout(23); - factory.setKeepAliveInterval(45); - factory.setPassword("pass"); - MemoryPersistence persistence = new MemoryPersistence(); - factory.setPersistence(persistence); - final SocketFactory socketFactory = mock(SocketFactory.class); - factory.setSocketFactory(socketFactory); - final Properties props = new Properties(); - factory.setSslProperties(props); - factory.setUserName("user"); - Will will = new Will("foo", "bar".getBytes(), 2, true); - factory.setWill(will); - - factory = spy(factory); - final MqttClient client = mock(MqttClient.class); - doAnswer(new Answer() { - - @Override - public MqttClient answer(InvocationOnMock invocation) throws Throwable { - return client; - } - }).when(factory).getClientInstance(anyString(), anyString()); - - MqttPahoMessageHandler handler = new MqttPahoMessageHandler("foo", "bar", factory); - handler.setDefaultTopic("mqtt-foo"); - handler.afterPropertiesSet(); - handler.start(); - final AtomicBoolean connectCalled = new AtomicBoolean(); - doAnswer(new Answer(){ - - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - MqttConnectOptions options = (MqttConnectOptions) invocation.getArguments()[0]; - assertEquals(23, options.getConnectionTimeout()); - assertEquals(45, options.getKeepAliveInterval()); - assertEquals("pass", new String(options.getPassword())); - assertSame(socketFactory, options.getSocketFactory()); - assertSame(props, options.getSSLProperties()); - assertEquals("user", options.getUserName()); - assertEquals("foo", options.getWillDestination()); - assertEquals("bar", new String(options.getWillMessage().getPayload())); - assertEquals(2, options.getWillMessage().getQos()); - connectCalled.set(true); - return null; - } - }).when(client).connect(any(MqttConnectOptions.class)); - final AtomicBoolean publishCalled = new AtomicBoolean(); - doAnswer(new Answer() { - - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - assertEquals("mqtt-foo", invocation.getArguments()[0]); - MqttMessage message = (MqttMessage) invocation.getArguments()[1]; - assertEquals("Hello, world!", new String(message.getPayload())); - publishCalled.set(true); - return null; - } - }).when(client).publish(anyString(), any(MqttMessage.class)); - - handler.handleMessage(new GenericMessage("Hello, world!")); - - verify(client, times(1)).connect(any(MqttConnectOptions.class)); - assertTrue(connectCalled.get()); - } - - @Test - public void testInboundOptionsApplied() throws Exception { - DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory(); - factory.setCleanSession(false); - factory.setConnectionTimeout(23); - factory.setKeepAliveInterval(45); - factory.setPassword("pass"); - MemoryPersistence persistence = new MemoryPersistence(); - factory.setPersistence(persistence); - final SocketFactory socketFactory = mock(SocketFactory.class); - factory.setSocketFactory(socketFactory); - final Properties props = new Properties(); - factory.setSslProperties(props); - factory.setUserName("user"); - Will will = new Will("foo", "bar".getBytes(), 2, true); - factory.setWill(will); - - factory = spy(factory); - final MqttClient client = mock(MqttClient.class); - doAnswer(new Answer() { - - @Override - public MqttClient answer(InvocationOnMock invocation) throws Throwable { - return client; - } - }).when(factory).getClientInstance(anyString(), anyString()); - - final AtomicBoolean connectCalled = new AtomicBoolean(); - doAnswer(new Answer() { - - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - MqttConnectOptions options = (MqttConnectOptions) invocation.getArguments()[0]; - assertEquals(23, options.getConnectionTimeout()); - assertEquals(45, options.getKeepAliveInterval()); - assertEquals("pass", new String(options.getPassword())); - assertSame(socketFactory, options.getSocketFactory()); - assertSame(props, options.getSSLProperties()); - assertEquals("user", options.getUserName()); - assertEquals("foo", options.getWillDestination()); - assertEquals("bar", new String(options.getWillMessage().getPayload())); - assertEquals(2, options.getWillMessage().getQos()); - connectCalled.set(true); - return null; - } - }).when(client).connect(any(MqttConnectOptions.class)); - - final AtomicReference callback = new AtomicReference(); - doAnswer(new Answer() { - - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - callback.set((MqttCallback) invocation.getArguments()[0]); - return null; - } - }).when(client).setCallback(any(MqttCallback.class)); - - when(client.isConnected()).thenReturn(true); - - MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter("foo", "bar", factory, "baz"); - QueueChannel outputChannel = new QueueChannel(); - adapter.setOutputChannel(outputChannel); - ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); - taskScheduler.initialize(); - adapter.setTaskScheduler(taskScheduler); - adapter.afterPropertiesSet(); - adapter.start(); - - verify(client, times(1)).connect(any(MqttConnectOptions.class)); - assertTrue(connectCalled.get()); - - MqttMessage message = new MqttMessage("qux".getBytes()); - callback.get().messageArrived("baz", message); - Message outMessage = outputChannel.receive(0); - assertNotNull(outMessage); - assertEquals("qux", outMessage.getPayload()); - } - -} diff --git a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParserTests-context.xml b/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParserTests-context.xml deleted file mode 100644 index 9416250..0000000 --- a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParserTests-context.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParserTests.java b/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParserTests.java deleted file mode 100644 index 00d4fe5..0000000 --- a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttMessageDrivenChannelAdapterParserTests.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.config.xml; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; -import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; -import org.springframework.integration.mqtt.support.MqttMessageConverter; -import org.springframework.integration.test.util.TestUtils; -import org.springframework.messaging.MessageChannel; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -/** - * @author Gary Russell - * @since 1.0 - * - */ -@ContextConfiguration -@RunWith(SpringJUnit4ClassRunner.class) -public class MqttMessageDrivenChannelAdapterParserTests { - - @Autowired - private MqttPahoMessageDrivenChannelAdapter oneTopicAdapter; - - @Autowired - private MqttPahoMessageDrivenChannelAdapter twoTopicsAdapter; - - @Autowired - private MessageChannel out; - - @Autowired - private MqttMessageConverter converter; - - @Autowired - private DefaultMqttPahoClientFactory clientFactory; - - @Test - public void testOneTopic() { - assertEquals("tcp://localhost:1883", TestUtils.getPropertyValue(oneTopicAdapter, "url")); - assertFalse(TestUtils.getPropertyValue(oneTopicAdapter, "autoStartup", Boolean.class)); - assertEquals(25, TestUtils.getPropertyValue(oneTopicAdapter, "phase")); - assertEquals("foo", TestUtils.getPropertyValue(oneTopicAdapter, "clientId")); - assertEquals("bar", TestUtils.getPropertyValue(oneTopicAdapter, "topic", String[].class)[0]); - assertSame(converter, TestUtils.getPropertyValue(oneTopicAdapter, "converter")); - assertEquals(123L, TestUtils.getPropertyValue(oneTopicAdapter, "messagingTemplate.sendTimeout")); - assertSame(out, TestUtils.getPropertyValue(oneTopicAdapter, "outputChannel")); - assertSame(clientFactory, TestUtils.getPropertyValue(oneTopicAdapter, "clientFactory")); - } - - @Test - public void testTwoTopics() { - assertEquals("tcp://localhost:1883", TestUtils.getPropertyValue(oneTopicAdapter, "url")); - assertFalse(TestUtils.getPropertyValue(twoTopicsAdapter, "autoStartup", Boolean.class)); - assertEquals(25, TestUtils.getPropertyValue(twoTopicsAdapter, "phase")); - assertEquals("foo", TestUtils.getPropertyValue(twoTopicsAdapter, "clientId")); - assertEquals("bar", TestUtils.getPropertyValue(twoTopicsAdapter, "topic", String[].class)[0]); - assertEquals("baz", TestUtils.getPropertyValue(twoTopicsAdapter, "topic", String[].class)[1]); - assertSame(converter, TestUtils.getPropertyValue(twoTopicsAdapter, "converter")); - assertEquals(123L, TestUtils.getPropertyValue(twoTopicsAdapter, "messagingTemplate.sendTimeout")); - assertSame(out, TestUtils.getPropertyValue(twoTopicsAdapter, "outputChannel")); - assertSame(clientFactory, TestUtils.getPropertyValue(twoTopicsAdapter, "clientFactory")); - } - -} diff --git a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttOutboundChannelAdapterParserTests-context.xml b/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttOutboundChannelAdapterParserTests-context.xml deleted file mode 100644 index 203066d..0000000 --- a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttOutboundChannelAdapterParserTests-context.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - diff --git a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttOutboundChannelAdapterParserTests.java b/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttOutboundChannelAdapterParserTests.java deleted file mode 100644 index bea91f5..0000000 --- a/spring-integration-mqtt/src/test/java/org/springframework/integration/mqtt/config/xml/MqttOutboundChannelAdapterParserTests.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.integration.mqtt.config.xml; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; -import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler; -import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter; -import org.springframework.integration.mqtt.support.MqttMessageConverter; -import org.springframework.integration.test.util.TestUtils; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -/** - * @author Gary Russell - * @since 1.0 - * - */ -@ContextConfiguration -@RunWith(SpringJUnit4ClassRunner.class) -public class MqttOutboundChannelAdapterParserTests { - - @Autowired @Qualifier("withConverter.handler") - private MqttPahoMessageHandler withConverterHandler; - - @Autowired @Qualifier("withDefaultConverter.handler") - private MqttPahoMessageHandler withDefaultConverterHandler; - - @Autowired - private MqttMessageConverter converter; - - @Autowired - private DefaultMqttPahoClientFactory clientFactory; - - @Test - public void testWithConverter() { - assertEquals("tcp://localhost:1883", TestUtils.getPropertyValue(withConverterHandler, "url")); - assertFalse(TestUtils.getPropertyValue(withConverterHandler, "autoStartup", Boolean.class)); - assertEquals(25, TestUtils.getPropertyValue(withConverterHandler, "phase")); - assertEquals("foo", TestUtils.getPropertyValue(withConverterHandler, "clientId")); - assertEquals("bar", TestUtils.getPropertyValue(withConverterHandler, "defaultTopic")); - assertSame(converter, TestUtils.getPropertyValue(withConverterHandler, "converter")); - assertSame(clientFactory, TestUtils.getPropertyValue(withConverterHandler, "clientFactory")); - } - - @Test - public void testWithDefaultConverter() { - assertEquals("tcp://localhost:1883", TestUtils.getPropertyValue(withDefaultConverterHandler, "url")); - assertFalse(TestUtils.getPropertyValue(withDefaultConverterHandler, "autoStartup", Boolean.class)); - assertEquals(25, TestUtils.getPropertyValue(withDefaultConverterHandler, "phase")); - assertEquals("foo", TestUtils.getPropertyValue(withDefaultConverterHandler, "clientId")); - assertEquals("bar", TestUtils.getPropertyValue(withDefaultConverterHandler, "defaultTopic")); - assertEquals(1, TestUtils.getPropertyValue(withDefaultConverterHandler, "defaultQos")); - assertTrue(TestUtils.getPropertyValue(withDefaultConverterHandler, "defaultRetained", Boolean.class)); - MqttMessageConverter defaultConverter = TestUtils.getPropertyValue(withDefaultConverterHandler, "converter", - MqttMessageConverter.class); - assertTrue(defaultConverter instanceof DefaultPahoMessageConverter); - assertEquals(1, TestUtils.getPropertyValue(defaultConverter, "defaultQos")); - assertTrue(TestUtils.getPropertyValue(defaultConverter, "defaultRetained", Boolean.class)); - assertSame(clientFactory, TestUtils.getPropertyValue(withDefaultConverterHandler, "clientFactory")); - } - -} diff --git a/spring-integration-mqtt/src/test/resources/log4j.properties b/spring-integration-mqtt/src/test/resources/log4j.properties deleted file mode 100644 index 69750fc..0000000 --- a/spring-integration-mqtt/src/test/resources/log4j.properties +++ /dev/null @@ -1,8 +0,0 @@ -log4j.rootCategory=WARN, stdout - -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss.SSS} %-5p [%t][%c] %m%n - -log4j.category.org.springframework.integration=WARN -log4j.category.org.springframework.integration.mqtt=INFO