From 5bf4b9871e65a4616e2faa671dec4a4573cdf0f2 Mon Sep 17 00:00:00 2001 From: Gunnar Hillert Date: Mon, 3 Jun 2013 00:02:47 -0400 Subject: [PATCH] INTEXT-44 - Polishing * Upgrade to Gradle 1.6 * Upgrade Sonar plugin to SonarRunner * Upgrade a few dependencies (e.g. JUnit, Spring Integration) * Remove deprecations (e.g. JUnit) * Convert spaces to tabs * Add author tags * Add @since --- spring-integration-kafka/build.gradle | 146 +++--- .../gradle/wrapper/gradle-wrapper.jar | Bin 39770 -> 49875 bytes .../gradle/wrapper/gradle-wrapper.properties | 4 +- spring-integration-kafka/gradlew | 8 +- spring-integration-kafka/gradlew.bat | 180 +++---- spring-integration-kafka/publish-maven.gradle | 9 +- .../xml/KafkaConsumerContextParser.java | 119 ++--- .../xml/KafkaInboundChannelAdapterParser.java | 21 +- .../config/xml/KafkaNamespaceHandler.java | 11 +- .../KafkaOutboundChannelAdapterParser.java | 21 +- .../xml/KafkaProducerContextParser.java | 85 ++-- .../config/xml/ZookeeperConnectParser.java | 29 +- .../kafka/core/KafkaConsumerDefaults.java | 31 +- .../kafka/core/ZookeeperConnectDefaults.java | 15 +- .../KafkaHighLevelConsumerMessageSource.java | 25 +- .../outbound/KafkaProducerMessageHandler.java | 15 +- .../avro/AvroBackedKafkaDecoder.java | 35 +- .../avro/AvroBackedKafkaEncoder.java | 35 +- .../kafka/serializer/avro/AvroSerializer.java | 27 +- .../avro/AvroSpecificDatumSerializer.java | 27 +- .../serializer/common/StringEncoder.java | 23 +- .../support/ConsumerConfigFactoryBean.java | 53 +-- .../kafka/support/ConsumerConfiguration.java | 281 +++++------ .../support/ConsumerConnectionProvider.java | 15 +- .../kafka/support/ConsumerMetadata.java | 227 ++++----- .../kafka/support/DefaultPartitioner.java | 19 +- .../kafka/support/KafkaConsumerContext.java | 65 +-- .../kafka/support/KafkaProducerContext.java | 51 +- .../kafka/support/MessageLeftOverTracker.java | 27 +- .../kafka/support/ProducerConfiguration.java | 109 ++--- .../kafka/support/ProducerFactoryBean.java | 69 +-- .../kafka/support/ProducerMetadata.java | 175 +++---- .../kafka/support/ZookeeperConnect.java | 57 +-- .../config/xml/spring-integration-kafka.gif | Bin 572 -> 539 bytes .../docbook/SIAdapterLowerPrefix.xml | 72 --- .../src/reference/docbook/history.xml | 4 - .../src/reference/docbook/images/logo.png | Bin 9627 -> 0 bytes .../src/reference/docbook/index.xml | 67 --- .../src/reference/docbook/resources.xml | 15 - .../src/reference/docbook/whats-new.xml | 8 - .../xml/KafkaConsumerContextParserTests.java | 23 +- .../xml/KafkaInboundAdapterParserTests.java | 8 +- .../xml/KafkaOutboundAdapterParserTests.java | 30 +- .../xml/KafkaProducerContextParserTests.java | 64 +-- .../xml/ZookeeperConnectParserTests.java | 27 +- .../AvroBackedKafkaSerializerTest.java | 50 +- .../support/ConsumerConfigurationTests.java | 429 ++++++++--------- .../support/KafkaConsumerContextTest.java | 77 +-- .../support/ProducerConfigurationTests.java | 440 +++++++++--------- .../support/ProducerFactoryBeanTests.java | 63 +-- .../test/utils/NonSerializableTestKey.java | 28 +- .../utils/NonSerializableTestPayload.java | 28 +- .../integration/kafka/test/utils/TestKey.java | 30 +- .../kafka/test/utils/TestObject.java | 32 +- .../kafka/test/utils/TestPayload.java | 30 +- 55 files changed, 1706 insertions(+), 1833 deletions(-) delete mode 100644 spring-integration-kafka/src/reference/docbook/SIAdapterLowerPrefix.xml delete mode 100644 spring-integration-kafka/src/reference/docbook/history.xml delete mode 100644 spring-integration-kafka/src/reference/docbook/images/logo.png delete mode 100644 spring-integration-kafka/src/reference/docbook/index.xml delete mode 100644 spring-integration-kafka/src/reference/docbook/resources.xml delete mode 100644 spring-integration-kafka/src/reference/docbook/whats-new.xml diff --git a/spring-integration-kafka/build.gradle b/spring-integration-kafka/build.gradle index b4da5f7..fce4040 100644 --- a/spring-integration-kafka/build.gradle +++ b/spring-integration-kafka/build.gradle @@ -1,12 +1,9 @@ -description = 'Spring Integration Kafka Adapter' +description = 'Spring Integration Kafka Support' buildscript { repositories { maven { url 'https://repo.springsource.org/plugins-snapshot' } } - dependencies { - classpath 'org.springframework.build.gradle:docbook-reference-plugin:0.1.5' - } } apply plugin: 'java' @@ -17,24 +14,28 @@ apply plugin: 'idea' group = 'org.springframework.integration' repositories { - mavenLocal() - mavenCentral() - maven { url 'http://repo.springsource.org/libs-milestone' } - maven { url 'http://repo.springsource.org/plugins-release' } - maven { url 'https://repo.springsource.org/libs-snapshot' } + maven { url 'https://repo.springsource.org/libs-snapshot' } } sourceCompatibility=1.6 targetCompatibility=1.6 ext { - junitVersion = '4.10' + junitVersion = '4.11' log4jVersion = '1.2.12' - mockitoVersion = '1.9.0' + mockitoVersion = '1.9.5' springVersion = '3.1.3.RELEASE' - springIntegrationVersion = '2.2.0.RELEASE' + springIntegrationVersion = '2.2.3.RELEASE' idPrefix = 'kafka' + + 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 { @@ -61,47 +62,48 @@ dependencies { compile "org.springframework:spring-beans:$springVersion" compile "org.springframework:spring-context:$springVersion" compile "org.springframework:spring-expression:$springVersion" - compile "org.springframework.integration:spring-integration-core:$springIntegrationVersion" - compile("org.apache:kafka_2.9.2:0.8.0-SNAPSHOT") { - exclude module: 'log4j' - } - compile("org.apache.zookeeper:zookeeper:3.3.4") { - exclude module: 'log4j' - exclude module: 'jline' - } - compile "org.scala-lang:scala-library:2.9.2" - compile "org.scala-lang:scala-compiler:2.9.2" - compile("log4j:log4j:1.2.15") { - exclude module: 'jms' - exclude module: 'jmx' - exclude module: 'jmxtools' - exclude module: 'jmxri' + compile "org.springframework.integration:spring-integration-core:$springIntegrationVersion" + compile("org.apache:kafka_2.9.2:0.8.0-SNAPSHOT") { + exclude module: 'log4j' + } + compile("org.apache.zookeeper:zookeeper:3.3.4") { + exclude module: 'log4j' + exclude module: 'jline' + } + compile "org.scala-lang:scala-library:2.9.2" + compile "org.scala-lang:scala-compiler:2.9.2" + compile("log4j:log4j:1.2.15") { + exclude module: 'jms' + exclude module: 'jmx' + exclude module: 'jmxtools' + exclude module: 'jmxri' + } + compile "org.slf4j:slf4j-simple:1.6.4" + compile "net.sf.jopt-simple:jopt-simple:3.2" + compile "org.xerial.snappy:snappy-java:1.0.4.1" + //runtime "zkclient:zkclient:20120522" - } - compile "org.slf4j:slf4j-simple:1.6.4" - compile "net.sf.jopt-simple:jopt-simple:3.2" - compile "org.xerial.snappy:snappy-java:1.0.4.1" - //runtime "zkclient:zkclient:20120522" + runtime "com.101tec:zkclient:0.2" + runtime "com.yammer.metrics:metrics-core:2.2.0" + runtime "com.yammer.metrics:metrics-annotation:2.2.0" - runtime "com.101tec:zkclient:0.2" - runtime "com.yammer.metrics:metrics-core:2.2.0" - runtime "com.yammer.metrics:metrics-annotation:2.2.0" - - compile "org.apache.avro:avro:1.7.3" - compile "org.apache.avro:avro-compiler:1.7.3" + compile "org.apache.avro:avro:1.7.3" + compile "org.apache.avro:avro-compiler:1.7.3" testCompile "org.springframework.integration:spring-integration-test:$springIntegrationVersion" testCompile "junit:junit-dep:$junitVersion" testCompile("log4j:log4j:$log4jVersion") { - exclude module: 'jms' - exclude module: 'jmx' - exclude module: 'jmxtools' - exclude module: 'jmxri' -} + exclude module: 'jms' + exclude module: 'jmx' + exclude module: 'jmxtools' + exclude module: 'jmxri' + } + testCompile "org.mockito:mockito-all:$mockitoVersion" testCompile "org.springframework:spring-test:$springVersion" - testCompile "org.springframework.integration:spring-integration-stream:$springIntegrationVersion" - jacoco group: "org.jacoco", name: "org.jacoco.agent", version: "0.5.6.201201232323", classifier: "runtime" + testCompile "org.springframework.integration:spring-integration-stream:$springIntegrationVersion" + + jacoco group: "org.jacoco", name: "org.jacoco.agent", version: "0.6.2.201302030002", classifier: "runtime" } @@ -130,44 +132,18 @@ artifacts { archives javadocJar } -apply plugin: 'docbook-reference' +apply plugin: 'sonar-runner' -reference { - sourceDir = file('src/reference/docbook') -} - -apply plugin: 'sonar' - -sonar { - - if (rootProject.hasProperty('sonarHostUrl')) { - server.url = rootProject.sonarHostUrl +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" } - - database { - if (rootProject.hasProperty('sonarJdbcUrl')) { - url = rootProject.sonarJdbcUrl - } - if (rootProject.hasProperty('sonarJdbcDriver')) { - driverClassName = rootProject.sonarJdbcDriver - } - if (rootProject.hasProperty('sonarJdbcUsername')) { - username = rootProject.sonarJdbcUsername - } - if (rootProject.hasProperty('sonarJdbcPassword')) { - password = rootProject.sonarJdbcPassword - } - } - - project { - dynamicAnalysis = "reuseReports" - withProjectProperties { props -> - props["sonar.core.codeCoveragePlugin"] = "jacoco" - props["sonar.jacoco.reportPath"] = "${buildDir.name}/jacoco.exec" - } - } - - logger.info("Sonar parameters used: server.url='${server.url}'; database.url='${database.url}'; database.driverClassName='${database.driverClassName}'; database.username='${database.username}'") } task api(type: Javadoc) { @@ -212,7 +188,7 @@ task schemaZip(type: Zip) { task docsZip(type: Zip) { group = 'Distribution' classifier = 'docs' - description = "Builds -${classifier} archive containing api and reference " + + description = "Builds -${classifier} archive containing api " + "for deployment at static.springframework.org/spring-integration/docs." from('src/dist') { @@ -222,10 +198,6 @@ task docsZip(type: Zip) { from (api) { into 'api' } - - from (reference) { - into 'reference' - } } task distZip(type: Zip, dependsOn: [docsZip, schemaZip]) { @@ -300,5 +272,5 @@ task dist(dependsOn: assemble) { task wrapper(type: Wrapper) { description = 'Generates gradlew[.bat] scripts' - gradleVersion = '1.3' + gradleVersion = '1.6' } diff --git a/spring-integration-kafka/gradle/wrapper/gradle-wrapper.jar b/spring-integration-kafka/gradle/wrapper/gradle-wrapper.jar index 81dcde627d5cfbc12c96dc5113aac79b66a15118..a7634b071cb255e91a4572934e55b8cd8877b3e4 100644 GIT binary patch literal 49875 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 DCvKB) delta 34809 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 tUacb(E$p0}bI={E2)*7xC<^GF{C1<_&- APP_HOME="`pwd -P`" -cd "$SAVED" +cd "$SAVED" >&- CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -101,7 +101,7 @@ if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else - warn "Could not query businessSystem maximum file descriptor limit: $MAX_FD_LIMIT" + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi diff --git a/spring-integration-kafka/gradlew.bat b/spring-integration-kafka/gradlew.bat index 8a0b282..aec9973 100644 --- a/spring-integration-kafka/gradlew.bat +++ b/spring-integration-kafka/gradlew.bat @@ -1,90 +1,90 @@ -@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 +@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-kafka/publish-maven.gradle b/spring-integration-kafka/publish-maven.gradle index 5532ec4..9321d3b 100644 --- a/spring-integration-kafka/publish-maven.gradle +++ b/spring-integration-kafka/publish-maven.gradle @@ -31,7 +31,7 @@ def customizePom(pom, gradleProject) { generatedPom.project { name = gradleProject.description description = gradleProject.description - url = 'https://github.com/SpringSource/spring-integration-extensions' + url = linkHomepage organization { name = 'SpringSource' url = 'http://springsource.org' @@ -43,10 +43,11 @@ def customizePom(pom, gradleProject) { 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' + url = linkScmUrl + connection = 'scm:git:' + linkScmConnection + developerConnection = 'scm:git:' + linkScmDevConnection } developers { diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaConsumerContextParser.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaConsumerContextParser.java index 3eac811..0ac442b 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaConsumerContextParser.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaConsumerContextParser.java @@ -37,86 +37,87 @@ import java.util.Map; /** * @author Soby Chacko + * @since 0.5 */ public class KafkaConsumerContextParser extends AbstractSingleBeanDefinitionParser { - @Override - protected Class getBeanClass(final Element element) { - return KafkaConsumerContext.class; - } + @Override + protected Class getBeanClass(final Element element) { + return KafkaConsumerContext.class; + } - @Override - protected void doParse(final Element element, final ParserContext parserContext, final BeanDefinitionBuilder builder) { - super.doParse(element, parserContext, builder); + @Override + protected void doParse(final Element element, final ParserContext parserContext, final BeanDefinitionBuilder builder) { + super.doParse(element, parserContext, builder); - final Element consumerConfigurations = DomUtils.getChildElementByTagName(element, "consumer-configurations"); - parseConsumerConfigurations(consumerConfigurations, parserContext, builder, element); - } + final Element consumerConfigurations = DomUtils.getChildElementByTagName(element, "consumer-configurations"); + parseConsumerConfigurations(consumerConfigurations, parserContext, builder, element); + } - private void parseConsumerConfigurations(final Element consumerConfigurations, final ParserContext parserContext, - final BeanDefinitionBuilder builder, final Element parentElem) { - for (final Element consumerConfiguration : DomUtils.getChildElementsByTagName(consumerConfigurations, "consumer-configuration")) { - final BeanDefinitionBuilder consumerConfigurationBuilder = BeanDefinitionBuilder.genericBeanDefinition(ConsumerConfiguration.class); - final BeanDefinitionBuilder consumerMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition(ConsumerMetadata.class); + private void parseConsumerConfigurations(final Element consumerConfigurations, final ParserContext parserContext, + final BeanDefinitionBuilder builder, final Element parentElem) { + for (final Element consumerConfiguration : DomUtils.getChildElementsByTagName(consumerConfigurations, "consumer-configuration")) { + final BeanDefinitionBuilder consumerConfigurationBuilder = BeanDefinitionBuilder.genericBeanDefinition(ConsumerConfiguration.class); + final BeanDefinitionBuilder consumerMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition(ConsumerMetadata.class); - IntegrationNamespaceUtils.setValueIfAttributeDefined(consumerMetadataBuilder, consumerConfiguration, "group-id"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(consumerMetadataBuilder, consumerConfiguration, "group-id"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(consumerMetadataBuilder, consumerConfiguration, "value-decoder"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(consumerMetadataBuilder, consumerConfiguration, "key-decoder"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(consumerMetadataBuilder, consumerConfiguration, "key-class-type"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(consumerMetadataBuilder, consumerConfiguration, "value-class-type"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(consumerConfigurationBuilder, consumerConfiguration, "max-messages"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(consumerMetadataBuilder, parentElem, "consumer-timeout"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(consumerMetadataBuilder, consumerConfiguration, "value-decoder"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(consumerMetadataBuilder, consumerConfiguration, "key-decoder"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(consumerMetadataBuilder, consumerConfiguration, "key-class-type"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(consumerMetadataBuilder, consumerConfiguration, "value-class-type"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(consumerConfigurationBuilder, consumerConfiguration, "max-messages"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(consumerMetadataBuilder, parentElem, "consumer-timeout"); - final Map topicStreamsMap = new HashMap(); + final Map topicStreamsMap = new HashMap(); - for (final Element topicConfiguration : DomUtils.getChildElementsByTagName(consumerConfiguration, "topic")) { - final String topic = topicConfiguration.getAttribute("id"); - final String streams = topicConfiguration.getAttribute("streams"); - final Integer streamsInt = Integer.valueOf(streams); - topicStreamsMap.put(topic, streamsInt); - } + for (final Element topicConfiguration : DomUtils.getChildElementsByTagName(consumerConfiguration, "topic")) { + final String topic = topicConfiguration.getAttribute("id"); + final String streams = topicConfiguration.getAttribute("streams"); + final Integer streamsInt = Integer.valueOf(streams); + topicStreamsMap.put(topic, streamsInt); + } - consumerMetadataBuilder.addPropertyValue("topicStreamMap", topicStreamsMap); + consumerMetadataBuilder.addPropertyValue("topicStreamMap", topicStreamsMap); - final BeanDefinition consumerMetadataBeanDef = consumerMetadataBuilder.getBeanDefinition(); - registerBeanDefinition(new BeanDefinitionHolder(consumerMetadataBeanDef, "consumerMetadata_" + consumerConfiguration.getAttribute("group-id")), - parserContext.getRegistry()); + final BeanDefinition consumerMetadataBeanDef = consumerMetadataBuilder.getBeanDefinition(); + registerBeanDefinition(new BeanDefinitionHolder(consumerMetadataBeanDef, "consumerMetadata_" + consumerConfiguration.getAttribute("group-id")), + parserContext.getRegistry()); - final String zookeeperConnectBean = parentElem.getAttribute("zookeeper-connect"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, parentElem, zookeeperConnectBean); + final String zookeeperConnectBean = parentElem.getAttribute("zookeeper-connect"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, parentElem, zookeeperConnectBean); - final BeanDefinitionBuilder consumerConfigFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(ConsumerConfigFactoryBean.class); - consumerConfigFactoryBuilder.addConstructorArgReference("consumerMetadata_" + consumerConfiguration.getAttribute("group-id")); + final BeanDefinitionBuilder consumerConfigFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(ConsumerConfigFactoryBean.class); + consumerConfigFactoryBuilder.addConstructorArgReference("consumerMetadata_" + consumerConfiguration.getAttribute("group-id")); - if (StringUtils.hasText(zookeeperConnectBean)) { - consumerConfigFactoryBuilder.addConstructorArgReference(zookeeperConnectBean); - } + if (StringUtils.hasText(zookeeperConnectBean)) { + consumerConfigFactoryBuilder.addConstructorArgReference(zookeeperConnectBean); + } - final BeanDefinition consumerConfigFactoryBuilderBeanDefinition = consumerConfigFactoryBuilder.getBeanDefinition(); - registerBeanDefinition(new BeanDefinitionHolder(consumerConfigFactoryBuilderBeanDefinition, "consumerConfigFactory_" + consumerConfiguration.getAttribute("group-id")), parserContext.getRegistry()); + final BeanDefinition consumerConfigFactoryBuilderBeanDefinition = consumerConfigFactoryBuilder.getBeanDefinition(); + registerBeanDefinition(new BeanDefinitionHolder(consumerConfigFactoryBuilderBeanDefinition, "consumerConfigFactory_" + consumerConfiguration.getAttribute("group-id")), parserContext.getRegistry()); - final BeanDefinitionBuilder consumerConnectionProviderBuilder = BeanDefinitionBuilder.genericBeanDefinition(ConsumerConnectionProvider.class); - consumerConnectionProviderBuilder.addConstructorArgReference("consumerConfigFactory_" + consumerConfiguration.getAttribute("group-id")); + final BeanDefinitionBuilder consumerConnectionProviderBuilder = BeanDefinitionBuilder.genericBeanDefinition(ConsumerConnectionProvider.class); + consumerConnectionProviderBuilder.addConstructorArgReference("consumerConfigFactory_" + consumerConfiguration.getAttribute("group-id")); - final BeanDefinition consumerConnectionProviderBuilderBeanDefinition = consumerConnectionProviderBuilder.getBeanDefinition(); - registerBeanDefinition(new BeanDefinitionHolder(consumerConnectionProviderBuilderBeanDefinition, "consumerConnectionProvider_" + consumerConfiguration.getAttribute("group-id")), parserContext.getRegistry()); + final BeanDefinition consumerConnectionProviderBuilderBeanDefinition = consumerConnectionProviderBuilder.getBeanDefinition(); + registerBeanDefinition(new BeanDefinitionHolder(consumerConnectionProviderBuilderBeanDefinition, "consumerConnectionProvider_" + consumerConfiguration.getAttribute("group-id")), parserContext.getRegistry()); - final BeanDefinitionBuilder messageLeftOverBeanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MessageLeftOverTracker.class); - final BeanDefinition messageLeftOverBeanDefinition = messageLeftOverBeanDefinitionBuilder.getBeanDefinition(); - registerBeanDefinition(new BeanDefinitionHolder(messageLeftOverBeanDefinition, "messageLeftOver_" + consumerConfiguration.getAttribute("group-id")), - parserContext.getRegistry()); + final BeanDefinitionBuilder messageLeftOverBeanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MessageLeftOverTracker.class); + final BeanDefinition messageLeftOverBeanDefinition = messageLeftOverBeanDefinitionBuilder.getBeanDefinition(); + registerBeanDefinition(new BeanDefinitionHolder(messageLeftOverBeanDefinition, "messageLeftOver_" + consumerConfiguration.getAttribute("group-id")), + parserContext.getRegistry()); - consumerConfigurationBuilder.addConstructorArgReference("consumerMetadata_" + consumerConfiguration.getAttribute("group-id")); - consumerConfigurationBuilder.addConstructorArgReference("consumerConnectionProvider_" + consumerConfiguration.getAttribute("group-id")); - consumerConfigurationBuilder.addConstructorArgReference("messageLeftOver_" + consumerConfiguration.getAttribute("group-id")); + consumerConfigurationBuilder.addConstructorArgReference("consumerMetadata_" + consumerConfiguration.getAttribute("group-id")); + consumerConfigurationBuilder.addConstructorArgReference("consumerConnectionProvider_" + consumerConfiguration.getAttribute("group-id")); + consumerConfigurationBuilder.addConstructorArgReference("messageLeftOver_" + consumerConfiguration.getAttribute("group-id")); - final AbstractBeanDefinition consumerConfigurationBeanDefinition = consumerConfigurationBuilder.getBeanDefinition(); + final AbstractBeanDefinition consumerConfigurationBeanDefinition = consumerConfigurationBuilder.getBeanDefinition(); - final String consumerConfigurationBeanName = "consumerConfiguration_" + consumerConfiguration.getAttribute("group-id"); - registerBeanDefinition(new BeanDefinitionHolder(consumerConfigurationBeanDefinition, consumerConfigurationBeanName), - parserContext.getRegistry()); - } - } + final String consumerConfigurationBeanName = "consumerConfiguration_" + consumerConfiguration.getAttribute("group-id"); + registerBeanDefinition(new BeanDefinitionHolder(consumerConfigurationBeanDefinition, consumerConfigurationBeanName), + parserContext.getRegistry()); + } + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaInboundChannelAdapterParser.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaInboundChannelAdapterParser.java index cc52b1e..9b9735c 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaInboundChannelAdapterParser.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaInboundChannelAdapterParser.java @@ -28,22 +28,23 @@ import org.w3c.dom.Element; * The Kafka Inbound Channel adapter parser * * @author Soby Chacko + * @since 0.5 * */ public class KafkaInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser { - @Override - protected BeanMetadataElement parseSource(final Element element, final ParserContext parserContext) { - final BeanDefinitionBuilder highLevelConsumerMessageSourceBuilder = - BeanDefinitionBuilder.genericBeanDefinition(KafkaHighLevelConsumerMessageSource.class); + @Override + protected BeanMetadataElement parseSource(final Element element, final ParserContext parserContext) { + final BeanDefinitionBuilder highLevelConsumerMessageSourceBuilder = + BeanDefinitionBuilder.genericBeanDefinition(KafkaHighLevelConsumerMessageSource.class); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(highLevelConsumerMessageSourceBuilder, element, "kafka-decoder"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(highLevelConsumerMessageSourceBuilder, element, "kafka-decoder"); - final String kafkaConsumerContext = element.getAttribute("kafka-consumer-context-ref"); + final String kafkaConsumerContext = element.getAttribute("kafka-consumer-context-ref"); - if (StringUtils.hasText(kafkaConsumerContext)) { - highLevelConsumerMessageSourceBuilder.addConstructorArgReference(kafkaConsumerContext); - } + if (StringUtils.hasText(kafkaConsumerContext)) { + highLevelConsumerMessageSourceBuilder.addConstructorArgReference(kafkaConsumerContext); + } - return highLevelConsumerMessageSourceBuilder.getBeanDefinition(); + return highLevelConsumerMessageSourceBuilder.getBeanDefinition(); } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaNamespaceHandler.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaNamespaceHandler.java index 92d7823..3cc177b 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaNamespaceHandler.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaNamespaceHandler.java @@ -21,18 +21,19 @@ import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHa * The namespace handler for the Kafka namespace * * @author Soby Chacko + * @since 0.5 * */ public class KafkaNamespaceHandler extends AbstractIntegrationNamespaceHandler { /* (non-Javadoc) * @see org.springframework.beans.factory.xml.NamespaceHandler#init() */ - @Override + @Override public void init() { - registerBeanDefinitionParser("zookeeper-connect", new ZookeeperConnectParser()); + registerBeanDefinitionParser("zookeeper-connect", new ZookeeperConnectParser()); registerBeanDefinitionParser("inbound-channel-adapter", new KafkaInboundChannelAdapterParser()); - registerBeanDefinitionParser("outbound-channel-adapter", new KafkaOutboundChannelAdapterParser()); - registerBeanDefinitionParser("producer-context", new KafkaProducerContextParser()); - registerBeanDefinitionParser("consumer-context", new KafkaConsumerContextParser()); + registerBeanDefinitionParser("outbound-channel-adapter", new KafkaOutboundChannelAdapterParser()); + registerBeanDefinitionParser("producer-context", new KafkaProducerContextParser()); + registerBeanDefinitionParser("consumer-context", new KafkaConsumerContextParser()); } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaOutboundChannelAdapterParser.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaOutboundChannelAdapterParser.java index 714dad3..2df108f 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaOutboundChannelAdapterParser.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaOutboundChannelAdapterParser.java @@ -26,20 +26,21 @@ import org.w3c.dom.Element; /** * * @author Soby Chacko + * @since 0.5 * */ public class KafkaOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser { - @Override - protected AbstractBeanDefinition parseConsumer(final Element element, final ParserContext parserContext) { - final BeanDefinitionBuilder kafkaProducerMessageHandlerBuilder = - BeanDefinitionBuilder.genericBeanDefinition(KafkaProducerMessageHandler.class); + @Override + protected AbstractBeanDefinition parseConsumer(final Element element, final ParserContext parserContext) { + final BeanDefinitionBuilder kafkaProducerMessageHandlerBuilder = + BeanDefinitionBuilder.genericBeanDefinition(KafkaProducerMessageHandler.class); - final String kafkaServerBeanName = element.getAttribute("kafka-producer-context-ref"); + final String kafkaServerBeanName = element.getAttribute("kafka-producer-context-ref"); - if (StringUtils.hasText(kafkaServerBeanName)) { - kafkaProducerMessageHandlerBuilder.addConstructorArgReference(kafkaServerBeanName); - } + if (StringUtils.hasText(kafkaServerBeanName)) { + kafkaProducerMessageHandlerBuilder.addConstructorArgReference(kafkaServerBeanName); + } - return kafkaProducerMessageHandlerBuilder.getBeanDefinition(); - } + return kafkaProducerMessageHandlerBuilder.getBeanDefinition(); + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaProducerContextParser.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaProducerContextParser.java index 02ed893..5fc9937 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaProducerContextParser.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/KafkaProducerContextParser.java @@ -32,58 +32,59 @@ import org.w3c.dom.Element; /** * @author Soby Chacko + * @since 0.5 */ public class KafkaProducerContextParser extends AbstractSimpleBeanDefinitionParser { - @Override - protected Class getBeanClass(final Element element) { - return KafkaProducerContext.class; - } + @Override + protected Class getBeanClass(final Element element) { + return KafkaProducerContext.class; + } - @Override - protected void doParse(final Element element, final ParserContext parserContext, final BeanDefinitionBuilder builder) { - super.doParse(element, parserContext, builder); + @Override + protected void doParse(final Element element, final ParserContext parserContext, final BeanDefinitionBuilder builder) { + super.doParse(element, parserContext, builder); - final Element topics = DomUtils.getChildElementByTagName(element, "producer-configurations"); - parseProducerConfigurations(topics, parserContext); - } + final Element topics = DomUtils.getChildElementByTagName(element, "producer-configurations"); + parseProducerConfigurations(topics, parserContext); + } - private void parseProducerConfigurations(final Element topics, final ParserContext parserContext) { - for (final Element producerConfiguration : DomUtils.getChildElementsByTagName(topics, "producer-configuration")){ - final BeanDefinitionBuilder producerConfigurationBuilder = BeanDefinitionBuilder.genericBeanDefinition(ProducerConfiguration.class); + private void parseProducerConfigurations(final Element topics, final ParserContext parserContext) { + for (final Element producerConfiguration : DomUtils.getChildElementsByTagName(topics, "producer-configuration")){ + final BeanDefinitionBuilder producerConfigurationBuilder = BeanDefinitionBuilder.genericBeanDefinition(ProducerConfiguration.class); - final BeanDefinitionBuilder producerMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition(ProducerMetadata.class); - producerMetadataBuilder.addConstructorArgValue(producerConfiguration.getAttribute("topic")); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "value-encoder"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "key-encoder"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "key-class-type"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "value-class-type"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "partitioner"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "compression-codec"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "async"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "batch-num-messages"); + final BeanDefinitionBuilder producerMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition(ProducerMetadata.class); + producerMetadataBuilder.addConstructorArgValue(producerConfiguration.getAttribute("topic")); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "value-encoder"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "key-encoder"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "key-class-type"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "value-class-type"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "partitioner"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "compression-codec"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "async"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(producerMetadataBuilder, producerConfiguration, "batch-num-messages"); - final BeanDefinition producerMetadataBeanDef = producerMetadataBuilder.getBeanDefinition(); - registerBeanDefinition(new BeanDefinitionHolder(producerMetadataBeanDef, "producerMetadata_" + producerConfiguration.getAttribute("topic")), - parserContext.getRegistry()); + final BeanDefinition producerMetadataBeanDef = producerMetadataBuilder.getBeanDefinition(); + registerBeanDefinition(new BeanDefinitionHolder(producerMetadataBeanDef, "producerMetadata_" + producerConfiguration.getAttribute("topic")), + parserContext.getRegistry()); - final BeanDefinitionBuilder producerFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(ProducerFactoryBean.class); - producerFactoryBuilder.addConstructorArgReference("producerMetadata_" + producerConfiguration.getAttribute("topic")); + final BeanDefinitionBuilder producerFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(ProducerFactoryBean.class); + producerFactoryBuilder.addConstructorArgReference("producerMetadata_" + producerConfiguration.getAttribute("topic")); - final String brokerList = producerConfiguration.getAttribute("broker-list"); - if (StringUtils.hasText(brokerList)) { - producerFactoryBuilder.addConstructorArgValue(producerConfiguration.getAttribute("broker-list")); - } + final String brokerList = producerConfiguration.getAttribute("broker-list"); + if (StringUtils.hasText(brokerList)) { + producerFactoryBuilder.addConstructorArgValue(producerConfiguration.getAttribute("broker-list")); + } - final BeanDefinition producerfactoryBeanDefinition = producerFactoryBuilder.getBeanDefinition(); - registerBeanDefinition(new BeanDefinitionHolder(producerfactoryBeanDefinition, "prodFactory_" + producerConfiguration.getAttribute("topic")), parserContext.getRegistry()); + final BeanDefinition producerfactoryBeanDefinition = producerFactoryBuilder.getBeanDefinition(); + registerBeanDefinition(new BeanDefinitionHolder(producerfactoryBeanDefinition, "prodFactory_" + producerConfiguration.getAttribute("topic")), parserContext.getRegistry()); - producerConfigurationBuilder.addConstructorArgReference("producerMetadata_" + producerConfiguration.getAttribute("topic")); - producerConfigurationBuilder.addConstructorArgReference("prodFactory_" + producerConfiguration.getAttribute("topic")); + producerConfigurationBuilder.addConstructorArgReference("producerMetadata_" + producerConfiguration.getAttribute("topic")); + producerConfigurationBuilder.addConstructorArgReference("prodFactory_" + producerConfiguration.getAttribute("topic")); - final AbstractBeanDefinition producerConfigurationBeanDefinition = producerConfigurationBuilder.getBeanDefinition(); - final String producerConfigurationBeanName = "producerConfiguration_" + producerConfiguration.getAttribute("topic"); - registerBeanDefinition(new BeanDefinitionHolder(producerConfigurationBeanDefinition, producerConfigurationBeanName), - parserContext.getRegistry()); - } - } + final AbstractBeanDefinition producerConfigurationBeanDefinition = producerConfigurationBuilder.getBeanDefinition(); + final String producerConfigurationBeanName = "producerConfiguration_" + producerConfiguration.getAttribute("topic"); + registerBeanDefinition(new BeanDefinitionHolder(producerConfigurationBeanDefinition, producerConfigurationBeanName), + parserContext.getRegistry()); + } + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/ZookeeperConnectParser.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/ZookeeperConnectParser.java index cac01e9..3cda6c3 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/ZookeeperConnectParser.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/config/xml/ZookeeperConnectParser.java @@ -25,22 +25,23 @@ import org.w3c.dom.Element; /** * @author Soby Chacko + * @since 0.5 */ public class ZookeeperConnectParser extends AbstractSimpleBeanDefinitionParser { - @Override - protected Class getBeanClass(final Element element) { - return ZookeeperConnect.class; - } + @Override + protected Class getBeanClass(final Element element) { + return ZookeeperConnect.class; + } - @Override - protected void doParse(final Element element, final ParserContext parserContext, final BeanDefinitionBuilder builder) { - super.doParse(element, parserContext, builder); + @Override + protected void doParse(final Element element, final ParserContext parserContext, final BeanDefinitionBuilder builder) { + super.doParse(element, parserContext, builder); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, - BeanDefinitionParserDelegate.SCOPE_ATTRIBUTE); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "zk-connect"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "zk-connection-timeout"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "zk-session-timeout"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "zk-sync-time"); - } + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, + BeanDefinitionParserDelegate.SCOPE_ATTRIBUTE); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "zk-connect"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "zk-connection-timeout"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "zk-session-timeout"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "zk-sync-time"); + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/core/KafkaConsumerDefaults.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/core/KafkaConsumerDefaults.java index 212678f..e258f90 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/core/KafkaConsumerDefaults.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/core/KafkaConsumerDefaults.java @@ -19,22 +19,23 @@ package org.springframework.integration.kafka.core; * Kafka adapter specific message headers. * * @author Soby Chacko + * @since 0.5 */ -public class KafkaConsumerDefaults { - //High level consumer - public static final String GROUP_ID = "groupid"; - public static final String SOCKET_TIMEOUT = "30000"; - public static final String SOCKET_BUFFER_SIZE = "64*1024"; - public static final String FETCH_SIZE = "300 * 1024"; - public static final String BACKOFF_INCREMENT = "1000"; - public static final String QUEUED_CHUNKS_MAX = "100"; - public static final String AUTO_COMMIT_ENABLE = "true"; - public static final String AUTO_COMMIT_INTERVAL = "10000"; - public static final String AUTO_OFFSET_RESET = "smallest"; - //Overriding the default value of -1, which will make the consumer to wait indefinitely - public static final String CONSUMER_TIMEOUT = "5000"; - public static final String REBALANCE_RETRIES_MAX = "4"; +public final class KafkaConsumerDefaults { + //High level consumer + public static final String GROUP_ID = "groupid"; + public static final String SOCKET_TIMEOUT = "30000"; + public static final String SOCKET_BUFFER_SIZE = "64*1024"; + public static final String FETCH_SIZE = "300 * 1024"; + public static final String BACKOFF_INCREMENT = "1000"; + public static final String QUEUED_CHUNKS_MAX = "100"; + public static final String AUTO_COMMIT_ENABLE = "true"; + public static final String AUTO_COMMIT_INTERVAL = "10000"; + public static final String AUTO_OFFSET_RESET = "smallest"; + //Overriding the default value of -1, which will make the consumer to wait indefinitely + public static final String CONSUMER_TIMEOUT = "5000"; + public static final String REBALANCE_RETRIES_MAX = "4"; private KafkaConsumerDefaults() { - } + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/core/ZookeeperConnectDefaults.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/core/ZookeeperConnectDefaults.java index 11138d1..03428d7 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/core/ZookeeperConnectDefaults.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/core/ZookeeperConnectDefaults.java @@ -18,14 +18,15 @@ package org.springframework.integration.kafka.core; /** * * @author Soby Chacko + * @since 0.5 * */ -public class ZookeeperConnectDefaults { - public static final String ZK_CONNECT = "localhost:2181"; - public static final String ZK_CONNECTION_TIMEOUT = "6000"; - public static final String ZK_SESSION_TIMEOUT = "6000"; - public static final String ZK_SYNC_TIME = "2000"; +public final class ZookeeperConnectDefaults { + public static final String ZK_CONNECT = "localhost:2181"; + public static final String ZK_CONNECTION_TIMEOUT = "6000"; + public static final String ZK_SESSION_TIMEOUT = "6000"; + public static final String ZK_SYNC_TIME = "2000"; - private ZookeeperConnectDefaults() { - } + private ZookeeperConnectDefaults() { + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/inbound/KafkaHighLevelConsumerMessageSource.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/inbound/KafkaHighLevelConsumerMessageSource.java index acab37b..83e225e 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/inbound/KafkaHighLevelConsumerMessageSource.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/inbound/KafkaHighLevelConsumerMessageSource.java @@ -25,23 +25,24 @@ import java.util.Map; /** * @author Soby Chacko + * @since 0.5 * */ public class KafkaHighLevelConsumerMessageSource extends IntegrationObjectSupport implements MessageSource>>> { - private final KafkaConsumerContext kafkaConsumerContext; + private final KafkaConsumerContext kafkaConsumerContext; - public KafkaHighLevelConsumerMessageSource(final KafkaConsumerContext kafkaConsumerContext) { - this.kafkaConsumerContext = kafkaConsumerContext; - } + public KafkaHighLevelConsumerMessageSource(final KafkaConsumerContext kafkaConsumerContext) { + this.kafkaConsumerContext = kafkaConsumerContext; + } - @Override - public Message>>> receive() { - return kafkaConsumerContext.receive(); - } + @Override + public Message>>> receive() { + return kafkaConsumerContext.receive(); + } - @Override - public String getComponentType() { - return "kafka:inbound-channel-adapter"; - } + @Override + public String getComponentType() { + return "kafka:inbound-channel-adapter"; + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/outbound/KafkaProducerMessageHandler.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/outbound/KafkaProducerMessageHandler.java index ee4923b..fdf918c 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/outbound/KafkaProducerMessageHandler.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/outbound/KafkaProducerMessageHandler.java @@ -21,21 +21,22 @@ import org.springframework.integration.kafka.support.KafkaProducerContext; /** * @author Soby Chacko + * @since 0.5 */ public class KafkaProducerMessageHandler extends AbstractMessageHandler { - private final KafkaProducerContext kafkaProducerContext; + private final KafkaProducerContext kafkaProducerContext; - public KafkaProducerMessageHandler(final KafkaProducerContext kafkaProducerContext) { - this.kafkaProducerContext = kafkaProducerContext; - } + public KafkaProducerMessageHandler(final KafkaProducerContext kafkaProducerContext) { + this.kafkaProducerContext = kafkaProducerContext; + } public KafkaProducerContext getKafkaProducerContext() { return kafkaProducerContext; } @Override - protected void handleMessageInternal(final Message message) throws Exception { - kafkaProducerContext.send(message); - } + protected void handleMessageInternal(final Message message) throws Exception { + kafkaProducerContext.send(message); + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroBackedKafkaDecoder.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroBackedKafkaDecoder.java index f131659..d702492 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroBackedKafkaDecoder.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroBackedKafkaDecoder.java @@ -26,29 +26,30 @@ import org.apache.commons.logging.LogFactory; /** * @author Soby Chacko + * @since 0.5 */ public class AvroBackedKafkaDecoder implements Decoder { - private static final Log LOG = LogFactory.getLog(AvroBackedKafkaDecoder.class); + private static final Log LOG = LogFactory.getLog(AvroBackedKafkaDecoder.class); - private final Class clazz; + private final Class clazz; - public AvroBackedKafkaDecoder(final Class clazz) { - this.clazz = clazz; - } + public AvroBackedKafkaDecoder(final Class clazz) { + this.clazz = clazz; + } - @Override - @SuppressWarnings("unchecked") - public T fromBytes(final byte[] bytes) { - final Schema schema = ReflectData.get().getSchema(clazz); - final AvroSerializer avroSerializer = new AvroSerializer(); + @Override + @SuppressWarnings("unchecked") + public T fromBytes(final byte[] bytes) { + final Schema schema = ReflectData.get().getSchema(clazz); + final AvroSerializer avroSerializer = new AvroSerializer(); - try { - return (T) avroSerializer.deserialize(bytes, schema); - } catch (IOException e) { - LOG.error("Failed to decode byte array for schema: " + schema.getFullName(), e); - } + try { + return (T) avroSerializer.deserialize(bytes, schema); + } catch (IOException e) { + LOG.error("Failed to decode byte array for schema: " + schema.getFullName(), e); + } - return null; - } + return null; + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroBackedKafkaEncoder.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroBackedKafkaEncoder.java index 8bc426b..6ec8bfe 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroBackedKafkaEncoder.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroBackedKafkaEncoder.java @@ -25,28 +25,29 @@ import org.apache.commons.logging.LogFactory; /** * @author Soby Chacko + * @since 0.5 */ public class AvroBackedKafkaEncoder implements Encoder { - private static final Log LOG = LogFactory.getLog(AvroBackedKafkaEncoder.class); + private static final Log LOG = LogFactory.getLog(AvroBackedKafkaEncoder.class); - private final Class clazz; + private final Class clazz; - public AvroBackedKafkaEncoder(final Class clazz) { - this.clazz = clazz; - } + public AvroBackedKafkaEncoder(final Class clazz) { + this.clazz = clazz; + } - @Override - @SuppressWarnings("unchecked") - public byte[] toBytes(final T source) { - final Schema schema = ReflectData.get().getSchema(clazz); - final AvroSerializer avroSerializer = new AvroSerializer(); + @Override + @SuppressWarnings("unchecked") + public byte[] toBytes(final T source) { + final Schema schema = ReflectData.get().getSchema(clazz); + final AvroSerializer avroSerializer = new AvroSerializer(); - try { - return avroSerializer.serialize(source, schema); - } catch (IOException e) { - LOG.error("Failed to encode source for schema: " + schema.getFullName()); - } + try { + return avroSerializer.serialize(source, schema); + } catch (IOException e) { + LOG.error("Failed to encode source for schema: " + schema.getFullName()); + } - return null; - } + return null; + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroSerializer.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroSerializer.java index c3e751c..7bc08f8 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroSerializer.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroSerializer.java @@ -30,23 +30,24 @@ import java.io.IOException; /** * @author Soby Chacko + * @since 0.5 */ public class AvroSerializer { - public T deserialize(final byte[] bytes, final Schema schema) throws IOException { - final Decoder decoder = DecoderFactory.get().binaryDecoder(bytes, null); - final DatumReader reader = new ReflectDatumReader(schema); + public T deserialize(final byte[] bytes, final Schema schema) throws IOException { + final Decoder decoder = DecoderFactory.get().binaryDecoder(bytes, null); + final DatumReader reader = new ReflectDatumReader(schema); - return reader.read(null, decoder); - } + return reader.read(null, decoder); + } - public byte[] serialize(final T input, final Schema schema) throws IOException { - final DatumWriter writer = new ReflectDatumWriter(schema); - final ByteArrayOutputStream stream = new ByteArrayOutputStream(); + public byte[] serialize(final T input, final Schema schema) throws IOException { + final DatumWriter writer = new ReflectDatumWriter(schema); + final ByteArrayOutputStream stream = new ByteArrayOutputStream(); - final Encoder encoder = EncoderFactory.get().binaryEncoder(stream, null); - writer.write(input, encoder); - encoder.flush(); + final Encoder encoder = EncoderFactory.get().binaryEncoder(stream, null); + writer.write(input, encoder); + encoder.flush(); - return stream.toByteArray(); - } + return stream.toByteArray(); + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroSpecificDatumSerializer.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroSpecificDatumSerializer.java index 12fb60d..b7b6064 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroSpecificDatumSerializer.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/avro/AvroSpecificDatumSerializer.java @@ -30,23 +30,24 @@ import java.io.IOException; /** * @author Soby Chacko + * @since 0.5 */ public class AvroSpecificDatumSerializer { - public T deserialize(final byte[] bytes, final Schema schema) throws IOException { - final Decoder decoder = DecoderFactory.get().binaryDecoder(bytes, null); - final DatumReader reader = new SpecificDatumReader(schema); + public T deserialize(final byte[] bytes, final Schema schema) throws IOException { + final Decoder decoder = DecoderFactory.get().binaryDecoder(bytes, null); + final DatumReader reader = new SpecificDatumReader(schema); - return reader.read(null, decoder); - } + return reader.read(null, decoder); + } - public byte[] serialize(final T input, final Schema schema) throws IOException { - final DatumWriter writer = new SpecificDatumWriter(schema); - final ByteArrayOutputStream stream = new ByteArrayOutputStream(); + public byte[] serialize(final T input, final Schema schema) throws IOException { + final DatumWriter writer = new SpecificDatumWriter(schema); + final ByteArrayOutputStream stream = new ByteArrayOutputStream(); - final Encoder encoder = EncoderFactory.get().binaryEncoder(stream, null); - writer.write(input, encoder); - encoder.flush(); + final Encoder encoder = EncoderFactory.get().binaryEncoder(stream, null); + writer.write(input, encoder); + encoder.flush(); - return stream.toByteArray(); - } + return stream.toByteArray(); + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/common/StringEncoder.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/common/StringEncoder.java index ce5e0f3..7dc5105 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/common/StringEncoder.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/serializer/common/StringEncoder.java @@ -22,20 +22,21 @@ import java.util.Properties; /** * @author Soby Chacko + * @since 0.5 */ public class StringEncoder implements Encoder { - private String encoding = "UTF8"; + private String encoding = "UTF8"; - public void setEncoding(final String encoding){ - this.encoding = encoding; - } + public void setEncoding(final String encoding){ + this.encoding = encoding; + } - @Override - public byte[] toBytes(final Object o) { - final Properties props = new Properties(); - props.put("serializer.encoding", encoding); + @Override + public byte[] toBytes(final Object o) { + final Properties props = new Properties(); + props.put("serializer.encoding", encoding); - final VerifiableProperties verifiableProperties = new VerifiableProperties(props); - return new kafka.serializer.StringEncoder(verifiableProperties).toBytes((String)o); - } + final VerifiableProperties verifiableProperties = new VerifiableProperties(props); + return new kafka.serializer.StringEncoder(verifiableProperties).toBytes((String)o); + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerConfigFactoryBean.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerConfigFactoryBean.java index bd27da7..793162f 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerConfigFactoryBean.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerConfigFactoryBean.java @@ -22,38 +22,39 @@ import java.util.Properties; /** * @author Soby Chacko + * @since 0.5 */ public class ConsumerConfigFactoryBean implements FactoryBean { - private final ConsumerMetadata consumerMetadata; - private final ZookeeperConnect zookeeperConnect; + private final ConsumerMetadata consumerMetadata; + private final ZookeeperConnect zookeeperConnect; - public ConsumerConfigFactoryBean(final ConsumerMetadata consumerMetadata, - final ZookeeperConnect zookeeperConnect){ - this.consumerMetadata = consumerMetadata; - this.zookeeperConnect = zookeeperConnect; - } + public ConsumerConfigFactoryBean(final ConsumerMetadata consumerMetadata, + final ZookeeperConnect zookeeperConnect){ + this.consumerMetadata = consumerMetadata; + this.zookeeperConnect = zookeeperConnect; + } - @Override - public ConsumerConfig getObject() throws Exception { - final Properties properties = new Properties(); - properties.put("zookeeper.connect", zookeeperConnect.getZkConnect()); - properties.put("zookeeper.session.timeout.ms", zookeeperConnect.getZkSessionTimeout()); - properties.put("zookeeper.sync.time.ms", zookeeperConnect.getZkSyncTime()); - properties.put("auto.commit.interval.ms", consumerMetadata.getAutoCommitInterval()); - properties.put("consumer.timeout.ms", consumerMetadata.getConsumerTimeout()); - properties.put("group.id", consumerMetadata.getGroupId()); + @Override + public ConsumerConfig getObject() throws Exception { + final Properties properties = new Properties(); + properties.put("zookeeper.connect", zookeeperConnect.getZkConnect()); + properties.put("zookeeper.session.timeout.ms", zookeeperConnect.getZkSessionTimeout()); + properties.put("zookeeper.sync.time.ms", zookeeperConnect.getZkSyncTime()); + properties.put("auto.commit.interval.ms", consumerMetadata.getAutoCommitInterval()); + properties.put("consumer.timeout.ms", consumerMetadata.getConsumerTimeout()); + properties.put("group.id", consumerMetadata.getGroupId()); - return new ConsumerConfig(properties); - } + return new ConsumerConfig(properties); + } - @Override - public Class getObjectType() { - return ConsumerConfig.class; - } + @Override + public Class getObjectType() { + return ConsumerConfig.class; + } - @Override - public boolean isSingleton() { - return true; - } + @Override + public boolean isSingleton() { + return true; + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerConfiguration.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerConfiguration.java index c7bb878..047ba70 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerConfiguration.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerConfiguration.java @@ -35,175 +35,176 @@ import java.util.concurrent.Future; /** * @author Soby Chacko + * @since 0.5 */ public class ConsumerConfiguration { - private static final Log LOGGER = LogFactory.getLog(ConsumerConfiguration.class); + private static final Log LOGGER = LogFactory.getLog(ConsumerConfiguration.class); - private final ConsumerMetadata consumerMetadata; - private final ConsumerConnectionProvider consumerConnectionProvider; - private final MessageLeftOverTracker messageLeftOverTracker; - private ConsumerConnector consumerConnector; - private volatile int count = 0; - private int maxMessages = 1; + private final ConsumerMetadata consumerMetadata; + private final ConsumerConnectionProvider consumerConnectionProvider; + private final MessageLeftOverTracker messageLeftOverTracker; + private ConsumerConnector consumerConnector; + private volatile int count = 0; + private int maxMessages = 1; - private ExecutorService executorService = Executors.newCachedThreadPool(); + private ExecutorService executorService = Executors.newCachedThreadPool(); - public ConsumerConfiguration(final ConsumerMetadata consumerMetadata, - final ConsumerConnectionProvider consumerConnectionProvider, - final MessageLeftOverTracker messageLeftOverTracker) { - this.consumerMetadata = consumerMetadata; - this.consumerConnectionProvider = consumerConnectionProvider; - this.messageLeftOverTracker = messageLeftOverTracker; - } + public ConsumerConfiguration(final ConsumerMetadata consumerMetadata, + final ConsumerConnectionProvider consumerConnectionProvider, + final MessageLeftOverTracker messageLeftOverTracker) { + this.consumerMetadata = consumerMetadata; + this.consumerConnectionProvider = consumerConnectionProvider; + this.messageLeftOverTracker = messageLeftOverTracker; + } - public ConsumerMetadata getConsumerMetadata() { - return consumerMetadata; - } + public ConsumerMetadata getConsumerMetadata() { + return consumerMetadata; + } - public Map>> receive() { - count = messageLeftOverTracker.getCurrentCount(); + public Map>> receive() { + count = messageLeftOverTracker.getCurrentCount(); - final List>> tasks = new LinkedList>>(); - final Object lock = new Object(); + final List>> tasks = new LinkedList>>(); + final Object lock = new Object(); - final Map>> consumerMap = getConsumerMapWithMessageStreams(); - for (final List> streams : consumerMap.values()) { - for (final KafkaStream stream : streams) { - tasks.add(new Callable>() { - @Override - public List call() throws Exception { - final List rawMessages = new ArrayList(); - try { - while (count < maxMessages) { - final MessageAndMetadata messageAndMetadata = stream.iterator().next(); - synchronized (lock) { - if (count < maxMessages) { - rawMessages.add(messageAndMetadata); - count++; - } else { - messageLeftOverTracker.addMessageAndMetadata(messageAndMetadata); - } - } - } - } catch (ConsumerTimeoutException cte) { - LOGGER.info("Consumer timed out"); - } - return rawMessages; - } - }); - } - } + final Map>> consumerMap = getConsumerMapWithMessageStreams(); + for (final List> streams : consumerMap.values()) { + for (final KafkaStream stream : streams) { + tasks.add(new Callable>() { + @Override + public List call() throws Exception { + final List rawMessages = new ArrayList(); + try { + while (count < maxMessages) { + final MessageAndMetadata messageAndMetadata = stream.iterator().next(); + synchronized (lock) { + if (count < maxMessages) { + rawMessages.add(messageAndMetadata); + count++; + } else { + messageLeftOverTracker.addMessageAndMetadata(messageAndMetadata); + } + } + } + } catch (ConsumerTimeoutException cte) { + LOGGER.info("Consumer timed out"); + } + return rawMessages; + } + }); + } + } - return executeTasks(tasks); - } + return executeTasks(tasks); + } - private Map>> executeTasks(final List>> tasks) { + private Map>> executeTasks(final List>> tasks) { - final Map>> messages = new ConcurrentHashMap>>(); - messages.putAll(getLeftOverMessageMap()); + final Map>> messages = new ConcurrentHashMap>>(); + messages.putAll(getLeftOverMessageMap()); - try { - for (final Future> result : executorService.invokeAll(tasks)) { - if (!result.get().isEmpty()) { - final String topic = result.get().get(0).topic(); - if (!messages.containsKey(topic)) { - messages.put(topic, getPayload(result.get())); - } else { + try { + for (final Future> result : executorService.invokeAll(tasks)) { + if (!result.get().isEmpty()) { + final String topic = result.get().get(0).topic(); + if (!messages.containsKey(topic)) { + messages.put(topic, getPayload(result.get())); + } else { - final Map> existingPayloadMap = messages.get(topic); - getPayload(result.get(), existingPayloadMap); - } - } - } - } catch (Exception e) { - throw new MessagingException("Consuming from Kafka failed", e); - } + final Map> existingPayloadMap = messages.get(topic); + getPayload(result.get(), existingPayloadMap); + } + } + } + } catch (Exception e) { + throw new MessagingException("Consuming from Kafka failed", e); + } - if (messages.isEmpty()) { - return null; - } + if (messages.isEmpty()) { + return null; + } - return messages; - } + return messages; + } - private Map>> getLeftOverMessageMap() { + private Map>> getLeftOverMessageMap() { - final Map>> messages = new ConcurrentHashMap>>(); + final Map>> messages = new ConcurrentHashMap>>(); - for (final MessageAndMetadata mamd : messageLeftOverTracker.getMessageLeftOverFromPreviousPoll()) { - final String topic = mamd.topic(); + for (final MessageAndMetadata mamd : messageLeftOverTracker.getMessageLeftOverFromPreviousPoll()) { + final String topic = mamd.topic(); - if (!messages.containsKey(topic)) { - final List l = new ArrayList(); - l.add(mamd); - messages.put(topic, getPayload(l)); - } else { - final Map> existingPayloadMap = messages.get(topic); - final List l = new ArrayList(); - l.add(mamd); - getPayload(l, existingPayloadMap); - } - } - messageLeftOverTracker.clearMessagesLeftOver(); - return messages; - } + if (!messages.containsKey(topic)) { + final List l = new ArrayList(); + l.add(mamd); + messages.put(topic, getPayload(l)); + } else { + final Map> existingPayloadMap = messages.get(topic); + final List l = new ArrayList(); + l.add(mamd); + getPayload(l, existingPayloadMap); + } + } + messageLeftOverTracker.clearMessagesLeftOver(); + return messages; + } - private Map> getPayload(final List messageAndMetadatas) { - final Map> payloadMap = new ConcurrentHashMap>(); + private Map> getPayload(final List messageAndMetadatas) { + final Map> payloadMap = new ConcurrentHashMap>(); - for (final MessageAndMetadata messageAndMetadata : messageAndMetadatas) { - if (!payloadMap.containsKey(messageAndMetadata.partition())) { - final List payload = new ArrayList(); - payload.add(messageAndMetadata.message()); - payloadMap.put(messageAndMetadata.partition(), payload); - } else { - final List payload = payloadMap.get(messageAndMetadata.partition()); - payload.add(messageAndMetadata.message()); - } + for (final MessageAndMetadata messageAndMetadata : messageAndMetadatas) { + if (!payloadMap.containsKey(messageAndMetadata.partition())) { + final List payload = new ArrayList(); + payload.add(messageAndMetadata.message()); + payloadMap.put(messageAndMetadata.partition(), payload); + } else { + final List payload = payloadMap.get(messageAndMetadata.partition()); + payload.add(messageAndMetadata.message()); + } - } + } - return payloadMap; - } + return payloadMap; + } - private void getPayload(final List messageAndMetadatas, final Map> existingPayloadMap) { - for (final MessageAndMetadata messageAndMetadata : messageAndMetadatas) { - if (!existingPayloadMap.containsKey(messageAndMetadata.partition())) { - final List payload = new ArrayList(); - payload.add(messageAndMetadata.message()); - existingPayloadMap.put(messageAndMetadata.partition(), payload); - } else { - final List payload = existingPayloadMap.get(messageAndMetadata.partition()); - payload.add(messageAndMetadata.message()); - } - } - } + private void getPayload(final List messageAndMetadatas, final Map> existingPayloadMap) { + for (final MessageAndMetadata messageAndMetadata : messageAndMetadatas) { + if (!existingPayloadMap.containsKey(messageAndMetadata.partition())) { + final List payload = new ArrayList(); + payload.add(messageAndMetadata.message()); + existingPayloadMap.put(messageAndMetadata.partition(), payload); + } else { + final List payload = existingPayloadMap.get(messageAndMetadata.partition()); + payload.add(messageAndMetadata.message()); + } + } + } - @SuppressWarnings("unchecked") - public Map>> getConsumerMapWithMessageStreams() { - if (consumerMetadata.getValueDecoder() != null) { - return getConsumerConnector().createMessageStreams( - consumerMetadata.getTopicStreamMap(), - consumerMetadata.getValueDecoder(), - consumerMetadata.getValueDecoder()); - } + @SuppressWarnings("unchecked") + public Map>> getConsumerMapWithMessageStreams() { + if (consumerMetadata.getValueDecoder() != null) { + return getConsumerConnector().createMessageStreams( + consumerMetadata.getTopicStreamMap(), + consumerMetadata.getValueDecoder(), + consumerMetadata.getValueDecoder()); + } - return getConsumerConnector().createMessageStreams(consumerMetadata.getTopicStreamMap()); - } + return getConsumerConnector().createMessageStreams(consumerMetadata.getTopicStreamMap()); + } - public int getMaxMessages() { - return maxMessages; - } + public int getMaxMessages() { + return maxMessages; + } - public void setMaxMessages(final int maxMessages) { - this.maxMessages = maxMessages; - } + public void setMaxMessages(final int maxMessages) { + this.maxMessages = maxMessages; + } - public ConsumerConnector getConsumerConnector() { - if (consumerConnector == null) { - consumerConnector = consumerConnectionProvider.getConsumerConnector(); - } + public ConsumerConnector getConsumerConnector() { + if (consumerConnector == null) { + consumerConnector = consumerConnectionProvider.getConsumerConnector(); + } - return consumerConnector; - } + return consumerConnector; + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerConnectionProvider.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerConnectionProvider.java index d2287fd..6b542a4 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerConnectionProvider.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerConnectionProvider.java @@ -20,16 +20,17 @@ import kafka.javaapi.consumer.ConsumerConnector; /** * @author Soby Chacko + * @since 0.5 */ public class ConsumerConnectionProvider { - private final ConsumerConfig consumerConfig; + private final ConsumerConfig consumerConfig; - public ConsumerConnectionProvider(final ConsumerConfig consumerConfig) { - this.consumerConfig = consumerConfig; - } + public ConsumerConnectionProvider(final ConsumerConfig consumerConfig) { + this.consumerConfig = consumerConfig; + } - public ConsumerConnector getConsumerConnector() { - return kafka.consumer.Consumer.createJavaConsumerConnector(consumerConfig); - } + public ConsumerConnector getConsumerConnector() { + return kafka.consumer.Consumer.createJavaConsumerConnector(consumerConfig); + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerMetadata.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerMetadata.java index eb4cac5..d906bd7 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerMetadata.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ConsumerMetadata.java @@ -22,153 +22,154 @@ import java.util.Map; /** * @author Soby Chacko + * @since 0.5 */ public class ConsumerMetadata { - //High level consumer defaults - private String groupId = KafkaConsumerDefaults.GROUP_ID; - private String socketTimeout = KafkaConsumerDefaults.SOCKET_TIMEOUT; - private String socketBufferSize = KafkaConsumerDefaults.SOCKET_BUFFER_SIZE; - private String fetchSize = KafkaConsumerDefaults.FETCH_SIZE; - private String backoffIncrement = KafkaConsumerDefaults.BACKOFF_INCREMENT; - private String queuedChunksMax = KafkaConsumerDefaults.QUEUED_CHUNKS_MAX; - private String autoCommitEnable = KafkaConsumerDefaults.AUTO_COMMIT_ENABLE; - private String autoCommitInterval = KafkaConsumerDefaults.AUTO_COMMIT_INTERVAL; - private String autoOffsetReset = KafkaConsumerDefaults.AUTO_OFFSET_RESET; - private String rebalanceRetriesMax = KafkaConsumerDefaults.REBALANCE_RETRIES_MAX; - private String consumerTimeout = KafkaConsumerDefaults.CONSUMER_TIMEOUT; + //High level consumer defaults + private String groupId = KafkaConsumerDefaults.GROUP_ID; + private String socketTimeout = KafkaConsumerDefaults.SOCKET_TIMEOUT; + private String socketBufferSize = KafkaConsumerDefaults.SOCKET_BUFFER_SIZE; + private String fetchSize = KafkaConsumerDefaults.FETCH_SIZE; + private String backoffIncrement = KafkaConsumerDefaults.BACKOFF_INCREMENT; + private String queuedChunksMax = KafkaConsumerDefaults.QUEUED_CHUNKS_MAX; + private String autoCommitEnable = KafkaConsumerDefaults.AUTO_COMMIT_ENABLE; + private String autoCommitInterval = KafkaConsumerDefaults.AUTO_COMMIT_INTERVAL; + private String autoOffsetReset = KafkaConsumerDefaults.AUTO_OFFSET_RESET; + private String rebalanceRetriesMax = KafkaConsumerDefaults.REBALANCE_RETRIES_MAX; + private String consumerTimeout = KafkaConsumerDefaults.CONSUMER_TIMEOUT; - private String topic; - private int streams; - private Decoder valueDecoder; - private Decoder keyDecoder; - private Map topicStreamMap; + private String topic; + private int streams; + private Decoder valueDecoder; + private Decoder keyDecoder; + private Map topicStreamMap; - public String getGroupId() { - return groupId; - } + public String getGroupId() { + return groupId; + } - public void setGroupId(final String groupId) { - this.groupId = groupId; - } + public void setGroupId(final String groupId) { + this.groupId = groupId; + } - public String getSocketTimeout() { - return socketTimeout; - } + public String getSocketTimeout() { + return socketTimeout; + } - public void setSocketTimeout(final String socketTimeout) { - this.socketTimeout = socketTimeout; - } + public void setSocketTimeout(final String socketTimeout) { + this.socketTimeout = socketTimeout; + } - public String getSocketBufferSize() { - return socketBufferSize; - } + public String getSocketBufferSize() { + return socketBufferSize; + } - public void setSocketBufferSize(final String socketBufferSize) { - this.socketBufferSize = socketBufferSize; - } + public void setSocketBufferSize(final String socketBufferSize) { + this.socketBufferSize = socketBufferSize; + } - public String getFetchSize() { - return fetchSize; - } + public String getFetchSize() { + return fetchSize; + } - public void setFetchSize(final String fetchSize) { - this.fetchSize = fetchSize; - } + public void setFetchSize(final String fetchSize) { + this.fetchSize = fetchSize; + } - public String getBackoffIncrement() { - return backoffIncrement; - } + public String getBackoffIncrement() { + return backoffIncrement; + } - public void setBackoffIncrement(final String backoffIncrement) { - this.backoffIncrement = backoffIncrement; - } + public void setBackoffIncrement(final String backoffIncrement) { + this.backoffIncrement = backoffIncrement; + } - public String getQueuedChunksMax() { - return queuedChunksMax; - } + public String getQueuedChunksMax() { + return queuedChunksMax; + } - public void setQueuedChunksMax(final String queuedChunksMax) { - this.queuedChunksMax = queuedChunksMax; - } + public void setQueuedChunksMax(final String queuedChunksMax) { + this.queuedChunksMax = queuedChunksMax; + } - public String getAutoCommitEnable() { - return autoCommitEnable; - } + public String getAutoCommitEnable() { + return autoCommitEnable; + } - public void setAutoCommitEnable(final String autoCommitEnable) { - this.autoCommitEnable = autoCommitEnable; - } + public void setAutoCommitEnable(final String autoCommitEnable) { + this.autoCommitEnable = autoCommitEnable; + } - public String getAutoCommitInterval() { - return autoCommitInterval; - } + public String getAutoCommitInterval() { + return autoCommitInterval; + } - public void setAutoCommitInterval(final String autoCommitInterval) { - this.autoCommitInterval = autoCommitInterval; - } + public void setAutoCommitInterval(final String autoCommitInterval) { + this.autoCommitInterval = autoCommitInterval; + } - public String getAutoOffsetReset() { - return autoOffsetReset; - } + public String getAutoOffsetReset() { + return autoOffsetReset; + } - public void setAutoOffsetReset(final String autoOffsetReset) { - this.autoOffsetReset = autoOffsetReset; - } + public void setAutoOffsetReset(final String autoOffsetReset) { + this.autoOffsetReset = autoOffsetReset; + } - public String getRebalanceRetriesMax() { - return rebalanceRetriesMax; - } + public String getRebalanceRetriesMax() { + return rebalanceRetriesMax; + } - public void setRebalanceRetriesMax(final String rebalanceRetriesMax) { - this.rebalanceRetriesMax = rebalanceRetriesMax; - } + public void setRebalanceRetriesMax(final String rebalanceRetriesMax) { + this.rebalanceRetriesMax = rebalanceRetriesMax; + } - public String getConsumerTimeout() { - return consumerTimeout; - } + public String getConsumerTimeout() { + return consumerTimeout; + } - public void setConsumerTimeout(final String consumerTimeout) { - this.consumerTimeout = consumerTimeout; - } + public void setConsumerTimeout(final String consumerTimeout) { + this.consumerTimeout = consumerTimeout; + } - public String getTopic() { - return topic; - } + public String getTopic() { + return topic; + } - public void setTopic(final String topic) { - this.topic = topic; - } + public void setTopic(final String topic) { + this.topic = topic; + } - public int getStreams() { - return streams; - } + public int getStreams() { + return streams; + } - public void setStreams(final int streams) { - this.streams = streams; - } + public void setStreams(final int streams) { + this.streams = streams; + } - public Decoder getValueDecoder() { - return valueDecoder; - } + public Decoder getValueDecoder() { + return valueDecoder; + } - public void setValueDecoder(final Decoder valueDecoder) { - this.valueDecoder = valueDecoder; - } + public void setValueDecoder(final Decoder valueDecoder) { + this.valueDecoder = valueDecoder; + } - public Decoder getKeyDecoder() { - return keyDecoder; - } + public Decoder getKeyDecoder() { + return keyDecoder; + } - public void setKeyDecoder(final Decoder keyDecoder) { - this.keyDecoder = keyDecoder; - } + public void setKeyDecoder(final Decoder keyDecoder) { + this.keyDecoder = keyDecoder; + } - public Map getTopicStreamMap() { - return topicStreamMap; - } + public Map getTopicStreamMap() { + return topicStreamMap; + } - public void setTopicStreamMap(final Map topicStreamMap) { - this.topicStreamMap = topicStreamMap; - } + public void setTopicStreamMap(final Map topicStreamMap) { + this.topicStreamMap = topicStreamMap; + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/DefaultPartitioner.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/DefaultPartitioner.java index 3147b9d..929ef89 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/DefaultPartitioner.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/DefaultPartitioner.java @@ -20,17 +20,18 @@ import kafka.utils.Utils; /** * @author Soby Chacko + * @since 0.5 * * This class is for internal use only and therefore is at default access level */ class DefaultPartitioner implements Partitioner { - /** - * Uses the key to calculate a partition bucket id for routing - * the data to the appropriate broker partition - * @return an integer between 0 and numPartitions-1 - */ - @Override - public int partition(final T key, final int numPartitions) { - return Utils.abs(key.hashCode()) % numPartitions; - } + /** + * Uses the key to calculate a partition bucket id for routing + * the data to the appropriate broker partition + * @return an integer between 0 and numPartitions-1 + */ + @Override + public int partition(final T key, final int numPartitions) { + return Utils.abs(key.hashCode()) % numPartitions; + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/KafkaConsumerContext.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/KafkaConsumerContext.java index a42e458..a75b6ab 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/KafkaConsumerContext.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/KafkaConsumerContext.java @@ -30,47 +30,48 @@ import java.util.Map; /** * @author Soby Chacko + * @since 0.5 */ public class KafkaConsumerContext implements BeanFactoryAware { - private Map consumerConfigurations; - private String consumerTimeout = KafkaConsumerDefaults.CONSUMER_TIMEOUT; - private ZookeeperConnect zookeeperConnect; + private Map consumerConfigurations; + private String consumerTimeout = KafkaConsumerDefaults.CONSUMER_TIMEOUT; + private ZookeeperConnect zookeeperConnect; - public Collection getConsumerConfigurations() { - return consumerConfigurations.values(); - } + public Collection getConsumerConfigurations() { + return consumerConfigurations.values(); + } - @Override - public void setBeanFactory(final BeanFactory beanFactory) throws BeansException { - consumerConfigurations = ((ListableBeanFactory) beanFactory).getBeansOfType(ConsumerConfiguration.class); - } + @Override + public void setBeanFactory(final BeanFactory beanFactory) throws BeansException { + consumerConfigurations = ((ListableBeanFactory) beanFactory).getBeansOfType(ConsumerConfiguration.class); + } - public Message>>> receive() { - final Map>> consumedData = new HashMap>>(); + public Message>>> receive() { + final Map>> consumedData = new HashMap>>(); - for (final ConsumerConfiguration consumerConfiguration : getConsumerConfigurations()) { - final Map>> messages = consumerConfiguration.receive(); + for (final ConsumerConfiguration consumerConfiguration : getConsumerConfigurations()) { + final Map>> messages = consumerConfiguration.receive(); - if (messages != null){ - consumedData.putAll(messages); - } - } - return MessageBuilder.withPayload(consumedData).build(); - } + if (messages != null){ + consumedData.putAll(messages); + } + } + return MessageBuilder.withPayload(consumedData).build(); + } - public String getConsumerTimeout() { - return consumerTimeout; - } + public String getConsumerTimeout() { + return consumerTimeout; + } - public void setConsumerTimeout(final String consumerTimeout) { - this.consumerTimeout = consumerTimeout; - } + public void setConsumerTimeout(final String consumerTimeout) { + this.consumerTimeout = consumerTimeout; + } - public ZookeeperConnect getZookeeperConnect() { - return zookeeperConnect; - } + public ZookeeperConnect getZookeeperConnect() { + return zookeeperConnect; + } - public void setZookeeperConnect(final ZookeeperConnect zookeeperConnect) { - this.zookeeperConnect = zookeeperConnect; - } + public void setZookeeperConnect(final ZookeeperConnect zookeeperConnect) { + this.zookeeperConnect = zookeeperConnect; + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/KafkaProducerContext.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/KafkaProducerContext.java index 8a815d5..f85207d 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/KafkaProducerContext.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/KafkaProducerContext.java @@ -26,38 +26,39 @@ import java.util.Map; /** * @author Soby Chacko + * @since 0.5 */ public class KafkaProducerContext implements BeanFactoryAware { - private Map topicsConfiguration; + private Map topicsConfiguration; - @SuppressWarnings("unchecked") - public void send(final Message message) throws Exception { - final ProducerConfiguration producerConfiguration = - getTopicConfiguration(message.getHeaders().get("topic", String.class)); + @SuppressWarnings("unchecked") + public void send(final Message message) throws Exception { + final ProducerConfiguration producerConfiguration = + getTopicConfiguration(message.getHeaders().get("topic", String.class)); - if (producerConfiguration != null) { - producerConfiguration.send(message); - } - } + if (producerConfiguration != null) { + producerConfiguration.send(message); + } + } - private ProducerConfiguration getTopicConfiguration(final String topic){ - final Collection topics = topicsConfiguration.values(); + private ProducerConfiguration getTopicConfiguration(final String topic){ + final Collection topics = topicsConfiguration.values(); - for (final ProducerConfiguration producerConfiguration : topics){ - if (producerConfiguration.getProducerMetadata().getTopic().equals(topic)){ - return producerConfiguration; - } - } + for (final ProducerConfiguration producerConfiguration : topics){ + if (producerConfiguration.getProducerMetadata().getTopic().equals(topic)){ + return producerConfiguration; + } + } - return null; - } + return null; + } - public Map getTopicsConfiguration() { - return topicsConfiguration; - } + public Map getTopicsConfiguration() { + return topicsConfiguration; + } - @Override - public void setBeanFactory(final BeanFactory beanFactory) throws BeansException { - topicsConfiguration = ((ListableBeanFactory)beanFactory).getBeansOfType(ProducerConfiguration.class); - } + @Override + public void setBeanFactory(final BeanFactory beanFactory) throws BeansException { + topicsConfiguration = ((ListableBeanFactory)beanFactory).getBeansOfType(ProducerConfiguration.class); + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/MessageLeftOverTracker.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/MessageLeftOverTracker.java index a7d23e0..82f3461 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/MessageLeftOverTracker.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/MessageLeftOverTracker.java @@ -22,23 +22,24 @@ import java.util.List; /** * @author Soby Chacko + * @since 0.5 */ public class MessageLeftOverTracker { - private final List messageLeftOverFromPreviousPoll = new ArrayList(); + private final List messageLeftOverFromPreviousPoll = new ArrayList(); - public void addMessageAndMetadata(final MessageAndMetadata messageAndMetadata){ - messageLeftOverFromPreviousPoll.add(messageAndMetadata); - } + public void addMessageAndMetadata(final MessageAndMetadata messageAndMetadata){ + messageLeftOverFromPreviousPoll.add(messageAndMetadata); + } - public List getMessageLeftOverFromPreviousPoll(){ - return messageLeftOverFromPreviousPoll; - } + public List getMessageLeftOverFromPreviousPoll(){ + return messageLeftOverFromPreviousPoll; + } - public void clearMessagesLeftOver(){ - messageLeftOverFromPreviousPoll.clear(); - } + public void clearMessagesLeftOver(){ + messageLeftOverFromPreviousPoll.clear(); + } - public int getCurrentCount() { - return messageLeftOverFromPreviousPoll.size(); - } + public int getCurrentCount() { + return messageLeftOverFromPreviousPoll.size(); + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ProducerConfiguration.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ProducerConfiguration.java index 93e5c66..71026ae 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ProducerConfiguration.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ProducerConfiguration.java @@ -28,75 +28,76 @@ import java.io.ObjectOutputStream; /** * @author Soby Chacko + * @since 0.5 */ public class ProducerConfiguration { - private final Producer producer; - private final ProducerMetadata producerMetadata; + private final Producer producer; + private final ProducerMetadata producerMetadata; - public ProducerConfiguration(final ProducerMetadata producerMetadata, final Producer producer){ - this.producerMetadata = producerMetadata; - this.producer = producer; - } + public ProducerConfiguration(final ProducerMetadata producerMetadata, final Producer producer){ + this.producerMetadata = producerMetadata; + this.producer = producer; + } - public ProducerMetadata getProducerMetadata() { - return producerMetadata; - } + public ProducerMetadata getProducerMetadata() { + return producerMetadata; + } - public void send(final Message message) throws Exception { - final V v = getPayload(message); + public void send(final Message message) throws Exception { + final V v = getPayload(message); - if (message.getHeaders().containsKey("messageKey")) { - producer.send(new KeyedMessage(producerMetadata.getTopic(), getKey(message), v)); - } else { - producer.send(new KeyedMessage(producerMetadata.getTopic(), v)); - } - } + if (message.getHeaders().containsKey("messageKey")) { + producer.send(new KeyedMessage(producerMetadata.getTopic(), getKey(message), v)); + } else { + producer.send(new KeyedMessage(producerMetadata.getTopic(), v)); + } + } - @SuppressWarnings("unchecked") - private V getPayload(final Message message) throws Exception { - if (producerMetadata.getValueEncoder().getClass().isAssignableFrom(DefaultEncoder.class)) { - return (V) getByteStream(message.getPayload()); - } else if (message.getPayload().getClass().isAssignableFrom(producerMetadata.getValueClassType())) { - return producerMetadata.getValueClassType().cast(message.getPayload()); - } + @SuppressWarnings("unchecked") + private V getPayload(final Message message) throws Exception { + if (producerMetadata.getValueEncoder().getClass().isAssignableFrom(DefaultEncoder.class)) { + return (V) getByteStream(message.getPayload()); + } else if (message.getPayload().getClass().isAssignableFrom(producerMetadata.getValueClassType())) { + return producerMetadata.getValueClassType().cast(message.getPayload()); + } - throw new Exception("Message payload type is not matching with what is configured"); - } + throw new Exception("Message payload type is not matching with what is configured"); + } - @SuppressWarnings("unchecked") - private K getKey(final Message message) throws Exception { - final Object key = message.getHeaders().get("messageKey"); + @SuppressWarnings("unchecked") + private K getKey(final Message message) throws Exception { + final Object key = message.getHeaders().get("messageKey"); - if (producerMetadata.getKeyEncoder().getClass().isAssignableFrom(DefaultEncoder.class)) { - return (K) getByteStream(key); - } + if (producerMetadata.getKeyEncoder().getClass().isAssignableFrom(DefaultEncoder.class)) { + return (K) getByteStream(key); + } - return message.getHeaders().get("messageKey", producerMetadata.getKeyClassType()); - } + return message.getHeaders().get("messageKey", producerMetadata.getKeyClassType()); + } - private static boolean isRawByteArray(final Object obj){ - return obj instanceof byte[]; - } + private static boolean isRawByteArray(final Object obj){ + return obj instanceof byte[]; + } - private static byte[] getByteStream(final Object obj) throws IOException { - if (isRawByteArray(obj)){ - return (byte[])obj; - } + private static byte[] getByteStream(final Object obj) throws IOException { + if (isRawByteArray(obj)){ + return (byte[])obj; + } - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - final ObjectOutputStream os = new ObjectOutputStream(out); - os.writeObject(obj); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final ObjectOutputStream os = new ObjectOutputStream(out); + os.writeObject(obj); - return out.toByteArray(); - } + return out.toByteArray(); + } - @Override - public boolean equals(final Object obj){ - return EqualsBuilder.reflectionEquals(this, obj); - } + @Override + public boolean equals(final Object obj){ + return EqualsBuilder.reflectionEquals(this, obj); + } - @Override - public int hashCode() { - return HashCodeBuilder.reflectionHashCode(this); - } + @Override + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this); + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ProducerFactoryBean.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ProducerFactoryBean.java index 801c8e5..d49fa2c 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ProducerFactoryBean.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ProducerFactoryBean.java @@ -27,48 +27,49 @@ import java.util.Properties; /** * @author Soby Chacko + * @since 0.5 */ public class ProducerFactoryBean implements FactoryBean> { - private final String brokerList; - private final ProducerMetadata producerMetadata; + private final String brokerList; + private final ProducerMetadata producerMetadata; - public ProducerFactoryBean(final ProducerMetadata producerMetadata, final String brokerList){ - this.producerMetadata = producerMetadata; - this.brokerList = brokerList; - } + public ProducerFactoryBean(final ProducerMetadata producerMetadata, final String brokerList){ + this.producerMetadata = producerMetadata; + this.brokerList = brokerList; + } - @Override - public Producer getObject() throws Exception { - final Properties props = new Properties(); - props.put("metadata.broker.list", brokerList); - props.put("compression.codec", producerMetadata.getCompressionCodec()); + @Override + public Producer getObject() throws Exception { + final Properties props = new Properties(); + props.put("metadata.broker.list", brokerList); + props.put("compression.codec", producerMetadata.getCompressionCodec()); - if (producerMetadata.isAsync()){ - props.put("producer.type", "async"); - if (producerMetadata.getBatchNumMessages() != null){ - props.put("batch.num.messages", producerMetadata.getBatchNumMessages()); - } - } + if (producerMetadata.isAsync()){ + props.put("producer.type", "async"); + if (producerMetadata.getBatchNumMessages() != null){ + props.put("batch.num.messages", producerMetadata.getBatchNumMessages()); + } + } - final ProducerConfig config = new ProducerConfig(props); - final EventHandler eventHandler = new DefaultEventHandler(config, - producerMetadata.getPartitioner() == null ? new DefaultPartitioner() : producerMetadata.getPartitioner(), - producerMetadata.getValueEncoder(), producerMetadata.getKeyEncoder(), - new ProducerPool(config), new HashMap()); + final ProducerConfig config = new ProducerConfig(props); + final EventHandler eventHandler = new DefaultEventHandler(config, + producerMetadata.getPartitioner() == null ? new DefaultPartitioner() : producerMetadata.getPartitioner(), + producerMetadata.getValueEncoder(), producerMetadata.getKeyEncoder(), + new ProducerPool(config), new HashMap()); - final kafka.producer.Producer prod = new kafka.producer.Producer(config, - eventHandler); - return new Producer(prod); - } + final kafka.producer.Producer prod = new kafka.producer.Producer(config, + eventHandler); + return new Producer(prod); + } - @Override - public Class getObjectType() { - return Producer.class; - } + @Override + public Class getObjectType() { + return Producer.class; + } - @Override - public boolean isSingleton() { - return true; - } + @Override + public boolean isSingleton() { + return true; + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ProducerMetadata.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ProducerMetadata.java index a10a4fa..69b432e 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ProducerMetadata.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ProducerMetadata.java @@ -24,116 +24,117 @@ import org.springframework.beans.factory.InitializingBean; /** * @author Soby Chacko + * @since 0.5 */ public class ProducerMetadata implements InitializingBean { - private Encoder keyEncoder; - private Encoder valueEncoder; - private Class keyClassType; - private Class valueClassType; - private final String topic; - private String compressionCodec = "default"; - private Partitioner partitioner; - private boolean async = false; - private String batchNumMessages; + private Encoder keyEncoder; + private Encoder valueEncoder; + private Class keyClassType; + private Class valueClassType; + private final String topic; + private String compressionCodec = "default"; + private Partitioner partitioner; + private boolean async = false; + private String batchNumMessages; - public ProducerMetadata(final String topic) { - this.topic = topic; - } + public ProducerMetadata(final String topic) { + this.topic = topic; + } - public String getTopic() { - return topic; - } + public String getTopic() { + return topic; + } - public Encoder getKeyEncoder() { - return keyEncoder; - } + public Encoder getKeyEncoder() { + return keyEncoder; + } - public void setKeyEncoder(final Encoder keyEncoder) { - this.keyEncoder = keyEncoder; - } + public void setKeyEncoder(final Encoder keyEncoder) { + this.keyEncoder = keyEncoder; + } - public Encoder getValueEncoder() { - return valueEncoder; - } + public Encoder getValueEncoder() { + return valueEncoder; + } - public void setValueEncoder(final Encoder valueEncoder) { - this.valueEncoder = valueEncoder; - } + public void setValueEncoder(final Encoder valueEncoder) { + this.valueEncoder = valueEncoder; + } - public Class getKeyClassType() { - return keyClassType; - } + public Class getKeyClassType() { + return keyClassType; + } - public void setKeyClassType(final Class keyClassType) { - this.keyClassType = keyClassType; - } + public void setKeyClassType(final Class keyClassType) { + this.keyClassType = keyClassType; + } - public Class getValueClassType() { - return valueClassType; - } + public Class getValueClassType() { + return valueClassType; + } - public void setValueClassType(final Class valueClassType) { - this.valueClassType = valueClassType; - } + public void setValueClassType(final Class valueClassType) { + this.valueClassType = valueClassType; + } - //TODO: Use an enum - public String getCompressionCodec() { - if (compressionCodec.equalsIgnoreCase("gzip")) { - return "1"; - } else if (compressionCodec.equalsIgnoreCase("snappy")) { - return "2"; - } + //TODO: Use an enum + public String getCompressionCodec() { + if (compressionCodec.equalsIgnoreCase("gzip")) { + return "1"; + } else if (compressionCodec.equalsIgnoreCase("snappy")) { + return "2"; + } - return "0"; - } + return "0"; + } - public void setCompressionCodec(final String compressionCodec) { - this.compressionCodec = compressionCodec; - } + public void setCompressionCodec(final String compressionCodec) { + this.compressionCodec = compressionCodec; + } - public Partitioner getPartitioner() { - return partitioner; - } + public Partitioner getPartitioner() { + return partitioner; + } - public void setPartitioner(final Partitioner partitioner) { - this.partitioner = partitioner; - } + public void setPartitioner(final Partitioner partitioner) { + this.partitioner = partitioner; + } - @Override - @SuppressWarnings("unchecked") - public void afterPropertiesSet() throws Exception { - if (valueEncoder == null) { - setValueEncoder((Encoder) new DefaultEncoder(null)); - } + @Override + @SuppressWarnings("unchecked") + public void afterPropertiesSet() throws Exception { + if (valueEncoder == null) { + setValueEncoder((Encoder) new DefaultEncoder(null)); + } - if (keyEncoder == null) { - setKeyEncoder((Encoder) getValueEncoder()); - } - } + if (keyEncoder == null) { + setKeyEncoder((Encoder) getValueEncoder()); + } + } - public boolean isAsync() { - return async; - } + public boolean isAsync() { + return async; + } - public void setAsync(final boolean async) { - this.async = async; - } + public void setAsync(final boolean async) { + this.async = async; + } - public String getBatchNumMessages() { - return batchNumMessages; - } + public String getBatchNumMessages() { + return batchNumMessages; + } - public void setBatchNumMessages(final String batchNumMessages) { - this.batchNumMessages = batchNumMessages; - } + public void setBatchNumMessages(final String batchNumMessages) { + this.batchNumMessages = batchNumMessages; + } - @Override - public boolean equals(final Object obj){ - return EqualsBuilder.reflectionEquals(this, obj); - } + @Override + public boolean equals(final Object obj){ + return EqualsBuilder.reflectionEquals(this, obj); + } - @Override - public int hashCode() { - return HashCodeBuilder.reflectionHashCode(this); - } + @Override + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this); + } } diff --git a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ZookeeperConnect.java b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ZookeeperConnect.java index aa31a4d..99c304b 100644 --- a/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ZookeeperConnect.java +++ b/spring-integration-kafka/src/main/java/org/springframework/integration/kafka/support/ZookeeperConnect.java @@ -19,42 +19,43 @@ import org.springframework.integration.kafka.core.ZookeeperConnectDefaults; /** * @author Soby Chacko + * @since 0.5 */ public class ZookeeperConnect { - private String zkConnect = ZookeeperConnectDefaults.ZK_CONNECT; - private String zkConnectionTimeout = ZookeeperConnectDefaults.ZK_CONNECTION_TIMEOUT; - private String zkSessionTimeout = ZookeeperConnectDefaults.ZK_SESSION_TIMEOUT; - private String zkSyncTime = ZookeeperConnectDefaults.ZK_SYNC_TIME; + private String zkConnect = ZookeeperConnectDefaults.ZK_CONNECT; + private String zkConnectionTimeout = ZookeeperConnectDefaults.ZK_CONNECTION_TIMEOUT; + private String zkSessionTimeout = ZookeeperConnectDefaults.ZK_SESSION_TIMEOUT; + private String zkSyncTime = ZookeeperConnectDefaults.ZK_SYNC_TIME; - public String getZkConnect() { - return zkConnect; - } + public String getZkConnect() { + return zkConnect; + } - public void setZkConnect(final String zkConnect) { - this.zkConnect = zkConnect; - } + public void setZkConnect(final String zkConnect) { + this.zkConnect = zkConnect; + } - public String getZkConnectionTimeout() { - return zkConnectionTimeout; - } + public String getZkConnectionTimeout() { + return zkConnectionTimeout; + } - public void setZkConnectionTimeout(final String zkConnectionTimeout) { - this.zkConnectionTimeout = zkConnectionTimeout; - } + public void setZkConnectionTimeout(final String zkConnectionTimeout) { + this.zkConnectionTimeout = zkConnectionTimeout; + } - public String getZkSessionTimeout() { - return zkSessionTimeout; - } + public String getZkSessionTimeout() { + return zkSessionTimeout; + } - public void setZkSessionTimeout(final String zkSessionTimeout) { - this.zkSessionTimeout = zkSessionTimeout; - } + public void setZkSessionTimeout(final String zkSessionTimeout) { + this.zkSessionTimeout = zkSessionTimeout; + } - public String getZkSyncTime() { - return zkSyncTime; - } + public String getZkSyncTime() { + return zkSyncTime; + } - public void setZkSyncTime(final String zkSyncTime) { - this.zkSyncTime = zkSyncTime; - } + public void setZkSyncTime(final String zkSyncTime) { + this.zkSyncTime = zkSyncTime; + } } diff --git a/spring-integration-kafka/src/main/resources/org/springframework/integration/config/xml/spring-integration-kafka.gif b/spring-integration-kafka/src/main/resources/org/springframework/integration/config/xml/spring-integration-kafka.gif index 41b369fece0e576ecd920400b221fd33abbaf5c4..210e0764fa4c1e5baebcdea156bc3f3e1f97a2c9 100644 GIT binary patch delta 223 zcmdnPGMh!l-P6s&GEsm*fZ-Vf2>k#5zhmmUxhwYUK74UvakX5Ir{2{`v3t9c*EPl; zZwV<4FrV96vUzsb(T31G2ldI!j9rrh7;S-AuwL;e3nK%A7lRJS9FU0&>=g}OP0cN> zZS5UiVp7tgolUwb+!B^bo#NbDF7g`I3LTQl!ZL;i`c@|Gvd)?!YVNi++U-0ZMrJ~G zt`5c>ays@-f{qq?or>z7ZUW|}{YulyTioH(#+4t%gM#T&cV;c S$;-#zeDnV2hy5Lm4AuZLRYElY delta 337 zcmV-X0j~a=1iS=)M@dFFIbje05CG-?00000|Ns9kO_eoPm57zD8BM31sJy$w(NA!l zP#PA_Qat j7a - - Kafka Adapter - - The Spring Integration Kafka Adapter provides... - - - - Outbound Channel adapter - - - Outbound Gateway - - - Inbound Channel Adapter - - - -
- Java Implementation - Each of the provided components will use the - org.springframework.integration.kafka.core.KafkaExecutor - class... - -
-
- Common Configuration Attributes - - Certain configuration parameters are shared amongst all Kafka - components and are described below: - - - auto-startup - - Lifecycle attribute signaling if this component should - be started during Application Context startup. - Defaults to true. - Optional. - - - id - - Identifies the underlying Spring bean definition, which - is an instance of either EventDrivenConsumer - or PollingConsumer. - Optional. - - -
- -
- Outbound Channel Adapter - - The Kafka Outbound channel adapter allows you to... - -
-
- Outbound Gateway - - Outbound gateways are similar to outbound channel adapters except that it can also be used to - get a result on the reply channel after performing - the given... - -
-
- Inbound Channel Adapter - - An inbound channel adapter is used to execute... - -
- -
diff --git a/spring-integration-kafka/src/reference/docbook/history.xml b/spring-integration-kafka/src/reference/docbook/history.xml deleted file mode 100644 index 71b4f74..0000000 --- a/spring-integration-kafka/src/reference/docbook/history.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - Change History - diff --git a/spring-integration-kafka/src/reference/docbook/images/logo.png b/spring-integration-kafka/src/reference/docbook/images/logo.png deleted file mode 100644 index e1c2a0e3c7864b4c2495fa75fed9733af2558ff9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9627 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 R@&Et;07*qoM6N<$f(p*0Lx diff --git a/spring-integration-kafka/src/reference/docbook/index.xml b/spring-integration-kafka/src/reference/docbook/index.xml deleted file mode 100644 index bdb072f..0000000 --- a/spring-integration-kafka/src/reference/docbook/index.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - Spring Integration Kafka Adapter - Kafka Adapter ${version} - Spring Integration - ${version} - - - - - - - - - - - - - - Soby Chacko - - - © SpringSource Inc., 2012 - - - - - - - What's new? - - - For those who are already familiar with Spring Integration, this - chapter - provides a brief overview of the new features of version 2.2. If you are - interested in the changes and features, that were introduced in - earlier - versions, please take a look at chapter: - - - - - - - - - - Integration Adapters - - This section covers the various Channel Adapters and Messaging - Gateways provided - by Spring Integration to support Message-based communication with - external systems. - - - - - - Appendices - - Advanced Topics and Additional Resources - - - - diff --git a/spring-integration-kafka/src/reference/docbook/resources.xml b/spring-integration-kafka/src/reference/docbook/resources.xml deleted file mode 100644 index 456ebba..0000000 --- a/spring-integration-kafka/src/reference/docbook/resources.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - Additional Resources - -
- Spring Integration Home - - The definitive source of information about Spring Integration is the - Spring Integration Home at - http://www.springsource.org. That site serves as a hub of - information and is the best place to find up-to-date announcements about the project as well as links to - articles, blogs, and new sample applications. - -
-
diff --git a/spring-integration-kafka/src/reference/docbook/whats-new.xml b/spring-integration-kafka/src/reference/docbook/whats-new.xml deleted file mode 100644 index ddf2480..0000000 --- a/spring-integration-kafka/src/reference/docbook/whats-new.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - What's new? - - This chapter provides an overview of the new features and improvements - that have been added to the Kafka Adapter: - - diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaConsumerContextParserTests.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaConsumerContextParserTests.java index 50ae6fc..4b46b4e 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaConsumerContextParserTests.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaConsumerContextParserTests.java @@ -15,7 +15,7 @@ */ package org.springframework.integration.kafka.config.xml; -import junit.framework.Assert; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -27,21 +27,22 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author Soby Chacko + * @since 0.5 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class KafkaConsumerContextParserTests { - @Autowired - private ApplicationContext appContext; + @Autowired + private ApplicationContext appContext; - @Test - @SuppressWarnings("unchecked") - public void testConsumerContextConfiguration() { - final KafkaConsumerContext consumerContext = appContext.getBean("consumerContext", KafkaConsumerContext.class); - Assert.assertNotNull(consumerContext); + @Test + @SuppressWarnings("unchecked") + public void testConsumerContextConfiguration() { + final KafkaConsumerContext consumerContext = appContext.getBean("consumerContext", KafkaConsumerContext.class); + Assert.assertNotNull(consumerContext); - final ConsumerMetadata cm = appContext.getBean("consumerMetadata_default1", ConsumerMetadata.class); - Assert.assertNotNull(cm); - } + final ConsumerMetadata cm = appContext.getBean("consumerMetadata_default1", ConsumerMetadata.class); + Assert.assertNotNull(cm); + } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaInboundAdapterParserTests.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaInboundAdapterParserTests.java index e7525b9..f5e9486 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaInboundAdapterParserTests.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaInboundAdapterParserTests.java @@ -15,7 +15,7 @@ */ package org.springframework.integration.kafka.config.xml; -import junit.framework.Assert; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -24,6 +24,10 @@ import org.springframework.integration.endpoint.SourcePollingChannelAdapter; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +/** + * @author Soby Chacko + * @since 0.5 + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class KafkaInboundAdapterParserTests { @@ -39,7 +43,7 @@ public class KafkaInboundAdapterParserTests { final SourcePollingChannelAdapter adapter = appContext.getBean("kafkaInboundChannelAdapter", SourcePollingChannelAdapter.class); - Assert.assertNotNull(adapter); + Assert.assertNotNull(adapter); Assert.assertFalse(adapter.isAutoStartup()); } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaOutboundAdapterParserTests.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaOutboundAdapterParserTests.java index 3c69fcf..504e298 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaOutboundAdapterParserTests.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaOutboundAdapterParserTests.java @@ -15,7 +15,7 @@ */ package org.springframework.integration.kafka.config.xml; -import junit.framework.Assert; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -26,21 +26,25 @@ import org.springframework.integration.kafka.support.KafkaProducerContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +/** + * @author Soby Chacko + * @since 0.5 + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class KafkaOutboundAdapterParserTests { - @Autowired - private ApplicationContext appContext; + @Autowired + private ApplicationContext appContext; - @Test - public void testOutboundAdapterConfiguration(){ - final PollingConsumer pollingConsumer = appContext.getBean("kafkaOutboundChannelAdapter", PollingConsumer.class); - final KafkaProducerMessageHandler messageHandler = appContext.getBean(KafkaProducerMessageHandler.class); - Assert.assertNotNull(pollingConsumer); - Assert.assertNotNull(messageHandler); - final KafkaProducerContext producerContext = messageHandler.getKafkaProducerContext(); - Assert.assertNotNull(producerContext); - Assert.assertEquals(producerContext.getTopicsConfiguration().size(), 2); - } + @Test + public void testOutboundAdapterConfiguration(){ + final PollingConsumer pollingConsumer = appContext.getBean("kafkaOutboundChannelAdapter", PollingConsumer.class); + final KafkaProducerMessageHandler messageHandler = appContext.getBean(KafkaProducerMessageHandler.class); + Assert.assertNotNull(pollingConsumer); + Assert.assertNotNull(messageHandler); + final KafkaProducerContext producerContext = messageHandler.getKafkaProducerContext(); + Assert.assertNotNull(producerContext); + Assert.assertEquals(producerContext.getTopicsConfiguration().size(), 2); + } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaProducerContextParserTests.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaProducerContextParserTests.java index ddf9718..411d02d 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaProducerContextParserTests.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/KafkaProducerContextParserTests.java @@ -15,7 +15,7 @@ */ package org.springframework.integration.kafka.config.xml; -import junit.framework.Assert; +import org.junit.Assert; import kafka.javaapi.producer.Producer; import kafka.serializer.Encoder; import org.junit.Test; @@ -30,44 +30,48 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.Map; +/** + * @author Soby Chacko + * @since 0.5 + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class KafkaProducerContextParserTests { - @Autowired - private ApplicationContext appContext; + @Autowired + private ApplicationContext appContext; - @Test - @SuppressWarnings("unchecked") - public void testProducerContextConfiguration(){ - final KafkaProducerContext producerContext = appContext.getBean("producerContext", KafkaProducerContext.class); - Assert.assertNotNull(producerContext); + @Test + @SuppressWarnings("unchecked") + public void testProducerContextConfiguration(){ + final KafkaProducerContext producerContext = appContext.getBean("producerContext", KafkaProducerContext.class); + Assert.assertNotNull(producerContext); - final Map topicConfigurations = producerContext.getTopicsConfiguration(); - Assert.assertEquals(topicConfigurations.size(), 2); + final Map topicConfigurations = producerContext.getTopicsConfiguration(); + Assert.assertEquals(topicConfigurations.size(), 2); - final ProducerConfiguration producerConfigurationTest1 = topicConfigurations.get("producerConfiguration_test1"); - Assert.assertNotNull(producerConfigurationTest1); - final ProducerMetadata producerMetadataTest1 = producerConfigurationTest1.getProducerMetadata(); - Assert.assertEquals(producerMetadataTest1.getTopic(), "test1"); - Assert.assertEquals(producerMetadataTest1.getCompressionCodec(), "0"); - Assert.assertEquals(producerMetadataTest1.getKeyClassType(), java.lang.String.class); - Assert.assertEquals(producerMetadataTest1.getValueClassType(), java.lang.String.class); + final ProducerConfiguration producerConfigurationTest1 = topicConfigurations.get("producerConfiguration_test1"); + Assert.assertNotNull(producerConfigurationTest1); + final ProducerMetadata producerMetadataTest1 = producerConfigurationTest1.getProducerMetadata(); + Assert.assertEquals(producerMetadataTest1.getTopic(), "test1"); + Assert.assertEquals(producerMetadataTest1.getCompressionCodec(), "0"); + Assert.assertEquals(producerMetadataTest1.getKeyClassType(), java.lang.String.class); + Assert.assertEquals(producerMetadataTest1.getValueClassType(), java.lang.String.class); - final Encoder valueEncoder = appContext.getBean("valueEncoder", Encoder.class); - Assert.assertEquals(producerMetadataTest1.getValueEncoder(), valueEncoder); - Assert.assertEquals(producerMetadataTest1.getKeyEncoder(), valueEncoder); + final Encoder valueEncoder = appContext.getBean("valueEncoder", Encoder.class); + Assert.assertEquals(producerMetadataTest1.getValueEncoder(), valueEncoder); + Assert.assertEquals(producerMetadataTest1.getKeyEncoder(), valueEncoder); - final Producer producerTest1 = appContext.getBean("prodFactory_test1", Producer.class); - Assert.assertEquals(producerConfigurationTest1, new ProducerConfiguration(producerMetadataTest1, producerTest1)); + final Producer producerTest1 = appContext.getBean("prodFactory_test1", Producer.class); + Assert.assertEquals(producerConfigurationTest1, new ProducerConfiguration(producerMetadataTest1, producerTest1)); - final ProducerConfiguration producerConfigurationTest2 = topicConfigurations.get("producerConfiguration_" + "test2"); - Assert.assertNotNull(producerConfigurationTest2); - final ProducerMetadata producerMetadataTest2 = producerConfigurationTest2.getProducerMetadata(); - Assert.assertEquals(producerMetadataTest2.getTopic(), "test2"); - Assert.assertEquals(producerMetadataTest2.getCompressionCodec(), "0"); + final ProducerConfiguration producerConfigurationTest2 = topicConfigurations.get("producerConfiguration_" + "test2"); + Assert.assertNotNull(producerConfigurationTest2); + final ProducerMetadata producerMetadataTest2 = producerConfigurationTest2.getProducerMetadata(); + Assert.assertEquals(producerMetadataTest2.getTopic(), "test2"); + Assert.assertEquals(producerMetadataTest2.getCompressionCodec(), "0"); - final Producer producerTest2 = appContext.getBean("prodFactory_test2", Producer.class); - Assert.assertEquals(producerConfigurationTest2, new ProducerConfiguration(producerMetadataTest2, producerTest2)); - } + final Producer producerTest2 = appContext.getBean("prodFactory_test2", Producer.class); + Assert.assertEquals(producerConfigurationTest2, new ProducerConfiguration(producerMetadataTest2, producerTest2)); + } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/ZookeeperConnectParserTests.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/ZookeeperConnectParserTests.java index 6acfa87..f520fbb 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/ZookeeperConnectParserTests.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/config/xml/ZookeeperConnectParserTests.java @@ -15,7 +15,7 @@ */ package org.springframework.integration.kafka.config.xml; -import junit.framework.Assert; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -27,8 +27,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author Soby Chacko - * @since 1.0 - * + * @since 0.5 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @@ -42,18 +41,18 @@ public class ZookeeperConnectParserTests { final ZookeeperConnect broker = appContext.getBean("zookeeperConnect", ZookeeperConnect.class); Assert.assertEquals("localhost:2181", broker.getZkConnect()); - Assert.assertEquals("10000", broker.getZkConnectionTimeout()); - Assert.assertEquals("10000", broker.getZkSessionTimeout()); - Assert.assertEquals("200", broker.getZkSyncTime()); + Assert.assertEquals("10000", broker.getZkConnectionTimeout()); + Assert.assertEquals("10000", broker.getZkSessionTimeout()); + Assert.assertEquals("200", broker.getZkSyncTime()); } - @Test - public void testDefaultKafkaBrokerConfiguration() { - final ZookeeperConnect broker = appContext.getBean("defaultZookeeperConnect", ZookeeperConnect.class); + @Test + public void testDefaultKafkaBrokerConfiguration() { + final ZookeeperConnect broker = appContext.getBean("defaultZookeeperConnect", ZookeeperConnect.class); - Assert.assertEquals(ZookeeperConnectDefaults.ZK_CONNECT, broker.getZkConnect()); - Assert.assertEquals(ZookeeperConnectDefaults.ZK_CONNECTION_TIMEOUT, broker.getZkConnectionTimeout()); - Assert.assertEquals(ZookeeperConnectDefaults.ZK_SESSION_TIMEOUT, broker.getZkSessionTimeout()); - Assert.assertEquals(ZookeeperConnectDefaults.ZK_SYNC_TIME, broker.getZkSyncTime()); - } + Assert.assertEquals(ZookeeperConnectDefaults.ZK_CONNECT, broker.getZkConnect()); + Assert.assertEquals(ZookeeperConnectDefaults.ZK_CONNECTION_TIMEOUT, broker.getZkConnectionTimeout()); + Assert.assertEquals(ZookeeperConnectDefaults.ZK_SESSION_TIMEOUT, broker.getZkSessionTimeout()); + Assert.assertEquals(ZookeeperConnectDefaults.ZK_SYNC_TIME, broker.getZkSyncTime()); + } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/serializer/AvroBackedKafkaSerializerTest.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/serializer/AvroBackedKafkaSerializerTest.java index a12e908..6afea82 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/serializer/AvroBackedKafkaSerializerTest.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/serializer/AvroBackedKafkaSerializerTest.java @@ -15,7 +15,7 @@ */ package org.springframework.integration.kafka.serializer; -import junit.framework.Assert; +import org.junit.Assert; import org.junit.Test; import org.springframework.integration.kafka.serializer.avro.AvroBackedKafkaDecoder; import org.springframework.integration.kafka.serializer.avro.AvroBackedKafkaEncoder; @@ -23,37 +23,37 @@ import org.springframework.integration.kafka.test.utils.TestObject; /** * @author Soby Chacko - * @since 1.0 + * @since 0.5 */ public class AvroBackedKafkaSerializerTest { - @Test - @SuppressWarnings("unchecked") - public void testDecodePlainSchema() { - final AvroBackedKafkaEncoder avroBackedKafkaEncoder = new AvroBackedKafkaEncoder(TestObject.class); + @Test + @SuppressWarnings("unchecked") + public void testDecodePlainSchema() { + final AvroBackedKafkaEncoder avroBackedKafkaEncoder = new AvroBackedKafkaEncoder(TestObject.class); - final TestObject testObject = new TestObject(); - testObject.setTestData1("\"Test Data1\""); - testObject.setTestData2(1); + final TestObject testObject = new TestObject(); + testObject.setTestData1("\"Test Data1\""); + testObject.setTestData2(1); - final byte[] data = avroBackedKafkaEncoder.toBytes(testObject); + final byte[] data = avroBackedKafkaEncoder.toBytes(testObject); - final AvroBackedKafkaDecoder avroBackedKafkaDecoder = new AvroBackedKafkaDecoder(TestObject.class); - final TestObject decodedFbu = (TestObject) avroBackedKafkaDecoder.fromBytes(data); + final AvroBackedKafkaDecoder avroBackedKafkaDecoder = new AvroBackedKafkaDecoder(TestObject.class); + final TestObject decodedFbu = (TestObject) avroBackedKafkaDecoder.fromBytes(data); - Assert.assertEquals(testObject.getTestData1(), decodedFbu.getTestData1()); - Assert.assertEquals(testObject.getTestData2(), decodedFbu.getTestData2()); - } + Assert.assertEquals(testObject.getTestData1(), decodedFbu.getTestData1()); + Assert.assertEquals(testObject.getTestData2(), decodedFbu.getTestData2()); + } - @Test - @SuppressWarnings("unchecked") - public void anotherTest() { - final AvroBackedKafkaEncoder avroBackedKafkaEncoder = new AvroBackedKafkaEncoder(java.lang.String.class); - final String testString = "Testing Avro"; - final byte[] data = avroBackedKafkaEncoder.toBytes(testString); + @Test + @SuppressWarnings("unchecked") + public void anotherTest() { + final AvroBackedKafkaEncoder avroBackedKafkaEncoder = new AvroBackedKafkaEncoder(java.lang.String.class); + final String testString = "Testing Avro"; + final byte[] data = avroBackedKafkaEncoder.toBytes(testString); - final AvroBackedKafkaDecoder avroBackedKafkaDecoder = new AvroBackedKafkaDecoder(java.lang.String.class); - final String decodedS = (String) avroBackedKafkaDecoder.fromBytes(data); + final AvroBackedKafkaDecoder avroBackedKafkaDecoder = new AvroBackedKafkaDecoder(java.lang.String.class); + final String decodedS = (String) avroBackedKafkaDecoder.fromBytes(data); - Assert.assertEquals(testString, decodedS); - } + Assert.assertEquals(testString, decodedS); + } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/ConsumerConfigurationTests.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/ConsumerConfigurationTests.java index f41f18f..d4583dc 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/ConsumerConfigurationTests.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/ConsumerConfigurationTests.java @@ -15,7 +15,7 @@ */ package org.springframework.integration.kafka.support; -import junit.framework.Assert; +import org.junit.Assert; import kafka.consumer.ConsumerIterator; import kafka.consumer.KafkaStream; import kafka.javaapi.consumer.ConsumerConnector; @@ -33,274 +33,275 @@ import java.util.Map; /** * @author Soby Chacko + * @since 0.5 */ public class ConsumerConfigurationTests { - @Test - @SuppressWarnings("unchecked") - public void testReceiveMessageForSingleTopicFromSingleStream() { - final ConsumerMetadata consumerMetadata = Mockito.mock(ConsumerMetadata.class); - final ConsumerConnectionProvider consumerConnectionProvider = - Mockito.mock(ConsumerConnectionProvider.class); - final MessageLeftOverTracker messageLeftOverTracker = Mockito.mock(MessageLeftOverTracker.class); - final ConsumerConnector consumerConnector = Mockito.mock(ConsumerConnector.class); + @Test + @SuppressWarnings("unchecked") + public void testReceiveMessageForSingleTopicFromSingleStream() { + final ConsumerMetadata consumerMetadata = Mockito.mock(ConsumerMetadata.class); + final ConsumerConnectionProvider consumerConnectionProvider = + Mockito.mock(ConsumerConnectionProvider.class); + final MessageLeftOverTracker messageLeftOverTracker = Mockito.mock(MessageLeftOverTracker.class); + final ConsumerConnector consumerConnector = Mockito.mock(ConsumerConnector.class); - Mockito.when(consumerConnectionProvider.getConsumerConnector()).thenReturn(consumerConnector); + Mockito.when(consumerConnectionProvider.getConsumerConnector()).thenReturn(consumerConnector); - final ConsumerConfiguration consumerConfiguration = new ConsumerConfiguration(consumerMetadata, - consumerConnectionProvider, messageLeftOverTracker); - consumerConfiguration.setMaxMessages(1); + final ConsumerConfiguration consumerConfiguration = new ConsumerConfiguration(consumerMetadata, + consumerConnectionProvider, messageLeftOverTracker); + consumerConfiguration.setMaxMessages(1); - final KafkaStream stream = Mockito.mock(KafkaStream.class); - final List> streams = new ArrayList>(); - streams.add(stream); - final Map>> messageStreams = new HashMap>>(); - messageStreams.put("topic", streams); + final KafkaStream stream = Mockito.mock(KafkaStream.class); + final List> streams = new ArrayList>(); + streams.add(stream); + final Map>> messageStreams = new HashMap>>(); + messageStreams.put("topic", streams); - Mockito.when(consumerConfiguration.getConsumerMapWithMessageStreams()).thenReturn(messageStreams); - final ConsumerIterator iterator = Mockito.mock(ConsumerIterator.class); - Mockito.when(stream.iterator()).thenReturn(iterator); - final MessageAndMetadata messageAndMetadata = Mockito.mock(MessageAndMetadata.class); - Mockito.when(iterator.next()).thenReturn(messageAndMetadata); - Mockito.when(messageAndMetadata.message()).thenReturn("got message"); - Mockito.when(messageAndMetadata.topic()).thenReturn("topic"); - Mockito.when(messageAndMetadata.partition()).thenReturn(1); + Mockito.when(consumerConfiguration.getConsumerMapWithMessageStreams()).thenReturn(messageStreams); + final ConsumerIterator iterator = Mockito.mock(ConsumerIterator.class); + Mockito.when(stream.iterator()).thenReturn(iterator); + final MessageAndMetadata messageAndMetadata = Mockito.mock(MessageAndMetadata.class); + Mockito.when(iterator.next()).thenReturn(messageAndMetadata); + Mockito.when(messageAndMetadata.message()).thenReturn("got message"); + Mockito.when(messageAndMetadata.topic()).thenReturn("topic"); + Mockito.when(messageAndMetadata.partition()).thenReturn(1); - final Map>> messages = consumerConfiguration.receive(); - Assert.assertEquals(messages.size(), 1); - Assert.assertEquals(messages.get("topic").size(), 1); - Assert.assertEquals(messages.get("topic").get(1).get(0), "got message"); + final Map>> messages = consumerConfiguration.receive(); + Assert.assertEquals(messages.size(), 1); + Assert.assertEquals(messages.get("topic").size(), 1); + Assert.assertEquals(messages.get("topic").get(1).get(0), "got message"); - Mockito.verify(stream, Mockito.times(1)).iterator(); - Mockito.verify(iterator, Mockito.times(1)).next(); - Mockito.verify(messageAndMetadata, Mockito.times(1)).message(); - Mockito.verify(messageAndMetadata, Mockito.times(1)).topic(); - } + Mockito.verify(stream, Mockito.times(1)).iterator(); + Mockito.verify(iterator, Mockito.times(1)).next(); + Mockito.verify(messageAndMetadata, Mockito.times(1)).message(); + Mockito.verify(messageAndMetadata, Mockito.times(1)).topic(); + } - @Test - @SuppressWarnings("unchecked") - public void testReceiveMessageForSingleTopicFromMultipleStreams() { - final ConsumerMetadata consumerMetadata = Mockito.mock(ConsumerMetadata.class); - final ConsumerConnectionProvider consumerConnectionProvider = - Mockito.mock(ConsumerConnectionProvider.class); - final MessageLeftOverTracker messageLeftOverTracker = Mockito.mock(MessageLeftOverTracker.class); + @Test + @SuppressWarnings("unchecked") + public void testReceiveMessageForSingleTopicFromMultipleStreams() { + final ConsumerMetadata consumerMetadata = Mockito.mock(ConsumerMetadata.class); + final ConsumerConnectionProvider consumerConnectionProvider = + Mockito.mock(ConsumerConnectionProvider.class); + final MessageLeftOverTracker messageLeftOverTracker = Mockito.mock(MessageLeftOverTracker.class); - final ConsumerConnector consumerConnector = Mockito.mock(ConsumerConnector.class); + final ConsumerConnector consumerConnector = Mockito.mock(ConsumerConnector.class); - Mockito.when(consumerConnectionProvider.getConsumerConnector()).thenReturn(consumerConnector); + Mockito.when(consumerConnectionProvider.getConsumerConnector()).thenReturn(consumerConnector); - final ConsumerConfiguration consumerConfiguration = new ConsumerConfiguration(consumerMetadata, - consumerConnectionProvider, messageLeftOverTracker); - consumerConfiguration.setMaxMessages(3); + final ConsumerConfiguration consumerConfiguration = new ConsumerConfiguration(consumerMetadata, + consumerConnectionProvider, messageLeftOverTracker); + consumerConfiguration.setMaxMessages(3); - final KafkaStream stream1 = Mockito.mock(KafkaStream.class); - final KafkaStream stream2 = Mockito.mock(KafkaStream.class); - final KafkaStream stream3 = Mockito.mock(KafkaStream.class); - final List> streams = new ArrayList>(); - streams.add(stream1); - streams.add(stream2); - streams.add(stream3); - final Map>> messageStreams = new HashMap>>(); - messageStreams.put("topic", streams); + final KafkaStream stream1 = Mockito.mock(KafkaStream.class); + final KafkaStream stream2 = Mockito.mock(KafkaStream.class); + final KafkaStream stream3 = Mockito.mock(KafkaStream.class); + final List> streams = new ArrayList>(); + streams.add(stream1); + streams.add(stream2); + streams.add(stream3); + final Map>> messageStreams = new HashMap>>(); + messageStreams.put("topic", streams); - Mockito.when(consumerConfiguration.getConsumerMapWithMessageStreams()).thenReturn(messageStreams); - final ConsumerIterator iterator1 = Mockito.mock(ConsumerIterator.class); - final ConsumerIterator iterator2 = Mockito.mock(ConsumerIterator.class); - final ConsumerIterator iterator3 = Mockito.mock(ConsumerIterator.class); + Mockito.when(consumerConfiguration.getConsumerMapWithMessageStreams()).thenReturn(messageStreams); + final ConsumerIterator iterator1 = Mockito.mock(ConsumerIterator.class); + final ConsumerIterator iterator2 = Mockito.mock(ConsumerIterator.class); + final ConsumerIterator iterator3 = Mockito.mock(ConsumerIterator.class); - Mockito.when(stream1.iterator()).thenReturn(iterator1); - Mockito.when(stream2.iterator()).thenReturn(iterator2); - Mockito.when(stream3.iterator()).thenReturn(iterator3); - final MessageAndMetadata messageAndMetadata1 = Mockito.mock(MessageAndMetadata.class); - final MessageAndMetadata messageAndMetadata2 = Mockito.mock(MessageAndMetadata.class); - final MessageAndMetadata messageAndMetadata3 = Mockito.mock(MessageAndMetadata.class); + Mockito.when(stream1.iterator()).thenReturn(iterator1); + Mockito.when(stream2.iterator()).thenReturn(iterator2); + Mockito.when(stream3.iterator()).thenReturn(iterator3); + final MessageAndMetadata messageAndMetadata1 = Mockito.mock(MessageAndMetadata.class); + final MessageAndMetadata messageAndMetadata2 = Mockito.mock(MessageAndMetadata.class); + final MessageAndMetadata messageAndMetadata3 = Mockito.mock(MessageAndMetadata.class); - Mockito.when(iterator1.next()).thenReturn(messageAndMetadata1); - Mockito.when(iterator2.next()).thenReturn(messageAndMetadata2); - Mockito.when(iterator3.next()).thenReturn(messageAndMetadata3); + Mockito.when(iterator1.next()).thenReturn(messageAndMetadata1); + Mockito.when(iterator2.next()).thenReturn(messageAndMetadata2); + Mockito.when(iterator3.next()).thenReturn(messageAndMetadata3); - Mockito.when(messageAndMetadata1.message()).thenReturn("got message"); - Mockito.when(messageAndMetadata1.topic()).thenReturn("topic"); - Mockito.when(messageAndMetadata1.partition()).thenReturn(1); + Mockito.when(messageAndMetadata1.message()).thenReturn("got message"); + Mockito.when(messageAndMetadata1.topic()).thenReturn("topic"); + Mockito.when(messageAndMetadata1.partition()).thenReturn(1); - Mockito.when(messageAndMetadata2.message()).thenReturn("got message"); - Mockito.when(messageAndMetadata2.topic()).thenReturn("topic"); - Mockito.when(messageAndMetadata2.partition()).thenReturn(2); + Mockito.when(messageAndMetadata2.message()).thenReturn("got message"); + Mockito.when(messageAndMetadata2.topic()).thenReturn("topic"); + Mockito.when(messageAndMetadata2.partition()).thenReturn(2); - Mockito.when(messageAndMetadata3.message()).thenReturn("got message"); - Mockito.when(messageAndMetadata3.topic()).thenReturn("topic"); - Mockito.when(messageAndMetadata3.partition()).thenReturn(3); + Mockito.when(messageAndMetadata3.message()).thenReturn("got message"); + Mockito.when(messageAndMetadata3.topic()).thenReturn("topic"); + Mockito.when(messageAndMetadata3.partition()).thenReturn(3); - final Map>> messages = consumerConfiguration.receive(); - Assert.assertEquals(messages.size(), 1); - int sum = 0; + final Map>> messages = consumerConfiguration.receive(); + Assert.assertEquals(messages.size(), 1); + int sum = 0; - final Map> values = messages.get("topic"); + final Map> values = messages.get("topic"); - for (final List l : values.values()) { - sum += l.size(); - } + for (final List l : values.values()) { + sum += l.size(); + } - Assert.assertEquals(sum, 3); - } + Assert.assertEquals(sum, 3); + } - @Test - @SuppressWarnings("unchecked") - public void testReceiveMessageForMultipleTopicsFromMultipleStreams() { - final ConsumerMetadata consumerMetadata = Mockito.mock(ConsumerMetadata.class); - final ConsumerConnectionProvider consumerConnectionProvider = - Mockito.mock(ConsumerConnectionProvider.class); - final MessageLeftOverTracker messageLeftOverTracker = Mockito.mock(MessageLeftOverTracker.class); + @Test + @SuppressWarnings("unchecked") + public void testReceiveMessageForMultipleTopicsFromMultipleStreams() { + final ConsumerMetadata consumerMetadata = Mockito.mock(ConsumerMetadata.class); + final ConsumerConnectionProvider consumerConnectionProvider = + Mockito.mock(ConsumerConnectionProvider.class); + final MessageLeftOverTracker messageLeftOverTracker = Mockito.mock(MessageLeftOverTracker.class); - final ConsumerConnector consumerConnector = Mockito.mock(ConsumerConnector.class); + final ConsumerConnector consumerConnector = Mockito.mock(ConsumerConnector.class); - Mockito.when(consumerConnectionProvider.getConsumerConnector()).thenReturn(consumerConnector); + Mockito.when(consumerConnectionProvider.getConsumerConnector()).thenReturn(consumerConnector); - final ConsumerConfiguration consumerConfiguration = new ConsumerConfiguration(consumerMetadata, - consumerConnectionProvider, messageLeftOverTracker); - consumerConfiguration.setMaxMessages(9); + final ConsumerConfiguration consumerConfiguration = new ConsumerConfiguration(consumerMetadata, + consumerConnectionProvider, messageLeftOverTracker); + consumerConfiguration.setMaxMessages(9); - final KafkaStream stream1 = Mockito.mock(KafkaStream.class); - final KafkaStream stream2 = Mockito.mock(KafkaStream.class); - final KafkaStream stream3 = Mockito.mock(KafkaStream.class); - final List> streams = new ArrayList>(); - streams.add(stream1); - streams.add(stream2); - streams.add(stream3); - final Map>> messageStreams = new HashMap>>(); - messageStreams.put("topic1", streams); - messageStreams.put("topic2", streams); - messageStreams.put("topic3", streams); + final KafkaStream stream1 = Mockito.mock(KafkaStream.class); + final KafkaStream stream2 = Mockito.mock(KafkaStream.class); + final KafkaStream stream3 = Mockito.mock(KafkaStream.class); + final List> streams = new ArrayList>(); + streams.add(stream1); + streams.add(stream2); + streams.add(stream3); + final Map>> messageStreams = new HashMap>>(); + messageStreams.put("topic1", streams); + messageStreams.put("topic2", streams); + messageStreams.put("topic3", streams); - Mockito.when(consumerConfiguration.getConsumerMapWithMessageStreams()).thenReturn(messageStreams); - final ConsumerIterator iterator1 = Mockito.mock(ConsumerIterator.class); - final ConsumerIterator iterator2 = Mockito.mock(ConsumerIterator.class); - final ConsumerIterator iterator3 = Mockito.mock(ConsumerIterator.class); + Mockito.when(consumerConfiguration.getConsumerMapWithMessageStreams()).thenReturn(messageStreams); + final ConsumerIterator iterator1 = Mockito.mock(ConsumerIterator.class); + final ConsumerIterator iterator2 = Mockito.mock(ConsumerIterator.class); + final ConsumerIterator iterator3 = Mockito.mock(ConsumerIterator.class); - Mockito.when(stream1.iterator()).thenReturn(iterator1); - Mockito.when(stream2.iterator()).thenReturn(iterator2); - Mockito.when(stream3.iterator()).thenReturn(iterator3); - final MessageAndMetadata messageAndMetadata1 = Mockito.mock(MessageAndMetadata.class); - final MessageAndMetadata messageAndMetadata2 = Mockito.mock(MessageAndMetadata.class); - final MessageAndMetadata messageAndMetadata3 = Mockito.mock(MessageAndMetadata.class); + Mockito.when(stream1.iterator()).thenReturn(iterator1); + Mockito.when(stream2.iterator()).thenReturn(iterator2); + Mockito.when(stream3.iterator()).thenReturn(iterator3); + final MessageAndMetadata messageAndMetadata1 = Mockito.mock(MessageAndMetadata.class); + final MessageAndMetadata messageAndMetadata2 = Mockito.mock(MessageAndMetadata.class); + final MessageAndMetadata messageAndMetadata3 = Mockito.mock(MessageAndMetadata.class); - Mockito.when(iterator1.next()).thenReturn(messageAndMetadata1); - Mockito.when(iterator2.next()).thenReturn(messageAndMetadata2); - Mockito.when(iterator3.next()).thenReturn(messageAndMetadata3); + Mockito.when(iterator1.next()).thenReturn(messageAndMetadata1); + Mockito.when(iterator2.next()).thenReturn(messageAndMetadata2); + Mockito.when(iterator3.next()).thenReturn(messageAndMetadata3); - Mockito.when(messageAndMetadata1.message()).thenReturn("got message1"); - Mockito.when(messageAndMetadata1.topic()).thenReturn("topic1"); - Mockito.when(messageAndMetadata1.partition()).thenAnswer(getAnswer()); + Mockito.when(messageAndMetadata1.message()).thenReturn("got message1"); + Mockito.when(messageAndMetadata1.topic()).thenReturn("topic1"); + Mockito.when(messageAndMetadata1.partition()).thenAnswer(getAnswer()); - Mockito.when(messageAndMetadata2.message()).thenReturn("got message2"); - Mockito.when(messageAndMetadata2.topic()).thenReturn("topic2"); - Mockito.when(messageAndMetadata1.partition()).thenAnswer(getAnswer()); + Mockito.when(messageAndMetadata2.message()).thenReturn("got message2"); + Mockito.when(messageAndMetadata2.topic()).thenReturn("topic2"); + Mockito.when(messageAndMetadata1.partition()).thenAnswer(getAnswer()); - Mockito.when(messageAndMetadata3.message()).thenReturn("got message3"); - Mockito.when(messageAndMetadata3.topic()).thenReturn("topic3"); - Mockito.when(messageAndMetadata1.partition()).thenAnswer(getAnswer()); + Mockito.when(messageAndMetadata3.message()).thenReturn("got message3"); + Mockito.when(messageAndMetadata3.topic()).thenReturn("topic3"); + Mockito.when(messageAndMetadata1.partition()).thenAnswer(getAnswer()); - final Map>> messages = consumerConfiguration.receive(); - int sum = 0; + final Map>> messages = consumerConfiguration.receive(); + int sum = 0; - final Collection>> values = messages.values(); + final Collection>> values = messages.values(); - for (final Map> m : values) { - for (final List l : m.values()) { - sum += l.size(); - } - } + for (final Map> m : values) { + for (final List l : m.values()) { + sum += l.size(); + } + } - Assert.assertEquals(sum, 9); - } + Assert.assertEquals(sum, 9); + } - private Answer getAnswer() { - return new Answer() { - private int count = 0; + private Answer getAnswer() { + return new Answer() { + private int count = 0; - @Override - public Object answer(final InvocationOnMock invocation) throws Throwable { - if (count++ == 1) { - return 1; - } else if (count++ == 2) { - return 2; - } + @Override + public Object answer(final InvocationOnMock invocation) throws Throwable { + if (count++ == 1) { + return 1; + } else if (count++ == 2) { + return 2; + } - return 3; - } - }; - } + return 3; + } + }; + } - @Test - @SuppressWarnings("unchecked") - public void testReceiveMessageAndVerifyMessageLeftoverFromPreviousPollAreTakenFirst() { - final ConsumerMetadata consumerMetadata = Mockito.mock(ConsumerMetadata.class); - final ConsumerConnectionProvider consumerConnectionProvider = - Mockito.mock(ConsumerConnectionProvider.class); - final MessageLeftOverTracker messageLeftOverTracker = Mockito.mock(MessageLeftOverTracker.class); - final ConsumerConnector consumerConnector = Mockito.mock(ConsumerConnector.class); + @Test + @SuppressWarnings("unchecked") + public void testReceiveMessageAndVerifyMessageLeftoverFromPreviousPollAreTakenFirst() { + final ConsumerMetadata consumerMetadata = Mockito.mock(ConsumerMetadata.class); + final ConsumerConnectionProvider consumerConnectionProvider = + Mockito.mock(ConsumerConnectionProvider.class); + final MessageLeftOverTracker messageLeftOverTracker = Mockito.mock(MessageLeftOverTracker.class); + final ConsumerConnector consumerConnector = Mockito.mock(ConsumerConnector.class); - Mockito.when(messageLeftOverTracker.getCurrentCount()).thenReturn(3); - final MessageAndMetadata m1 = new MessageAndMetadata("key1", "value1", "topic1", 1, 1L); - final MessageAndMetadata m2 = new MessageAndMetadata("key2", "value2", "topic2", 1, 1L); - final MessageAndMetadata m3 = new MessageAndMetadata("key1", "value3", "topic3", 1, 1L); + Mockito.when(messageLeftOverTracker.getCurrentCount()).thenReturn(3); + final MessageAndMetadata m1 = new MessageAndMetadata("key1", "value1", "topic1", 1, 1L); + final MessageAndMetadata m2 = new MessageAndMetadata("key2", "value2", "topic2", 1, 1L); + final MessageAndMetadata m3 = new MessageAndMetadata("key1", "value3", "topic3", 1, 1L); - final List mList = new ArrayList(); - mList.add(m1); - mList.add(m2); - mList.add(m3); + final List mList = new ArrayList(); + mList.add(m1); + mList.add(m2); + mList.add(m3); - Mockito.when(messageLeftOverTracker.getMessageLeftOverFromPreviousPoll()).thenReturn(mList); + Mockito.when(messageLeftOverTracker.getMessageLeftOverFromPreviousPoll()).thenReturn(mList); - Mockito.when(consumerConnectionProvider.getConsumerConnector()).thenReturn(consumerConnector); + Mockito.when(consumerConnectionProvider.getConsumerConnector()).thenReturn(consumerConnector); - final ConsumerConfiguration consumerConfiguration = new ConsumerConfiguration(consumerMetadata, - consumerConnectionProvider, messageLeftOverTracker); - consumerConfiguration.setMaxMessages(5); + final ConsumerConfiguration consumerConfiguration = new ConsumerConfiguration(consumerMetadata, + consumerConnectionProvider, messageLeftOverTracker); + consumerConfiguration.setMaxMessages(5); - final KafkaStream stream = Mockito.mock(KafkaStream.class); - final List> streams = new ArrayList>(); - streams.add(stream); - final Map>> messageStreams = new HashMap>>(); - messageStreams.put("topic1", streams); + final KafkaStream stream = Mockito.mock(KafkaStream.class); + final List> streams = new ArrayList>(); + streams.add(stream); + final Map>> messageStreams = new HashMap>>(); + messageStreams.put("topic1", streams); - Mockito.when(consumerConfiguration.getConsumerMapWithMessageStreams()).thenReturn(messageStreams); - final ConsumerIterator iterator = Mockito.mock(ConsumerIterator.class); - Mockito.when(stream.iterator()).thenReturn(iterator); - final MessageAndMetadata messageAndMetadata = Mockito.mock(MessageAndMetadata.class); - Mockito.when(iterator.next()).thenReturn(messageAndMetadata); - Mockito.when(messageAndMetadata.message()).thenReturn("got message"); - Mockito.when(messageAndMetadata.topic()).thenReturn("topic1"); - Mockito.when(messageAndMetadata.partition()).thenReturn(1); + Mockito.when(consumerConfiguration.getConsumerMapWithMessageStreams()).thenReturn(messageStreams); + final ConsumerIterator iterator = Mockito.mock(ConsumerIterator.class); + Mockito.when(stream.iterator()).thenReturn(iterator); + final MessageAndMetadata messageAndMetadata = Mockito.mock(MessageAndMetadata.class); + Mockito.when(iterator.next()).thenReturn(messageAndMetadata); + Mockito.when(messageAndMetadata.message()).thenReturn("got message"); + Mockito.when(messageAndMetadata.topic()).thenReturn("topic1"); + Mockito.when(messageAndMetadata.partition()).thenReturn(1); - final Map>> messages = consumerConfiguration.receive(); - int sum = 0; + final Map>> messages = consumerConfiguration.receive(); + int sum = 0; - final Collection>> values = messages.values(); + final Collection>> values = messages.values(); - for (final Map> m : values) { - for (final List l : m.values()) { - sum += l.size(); - } + for (final Map> m : values) { + for (final List l : m.values()) { + sum += l.size(); + } - } - Assert.assertEquals(sum, 5); + } + Assert.assertEquals(sum, 5); - Assert.assertTrue(messages.containsKey("topic1")); - Assert.assertTrue(messages.containsKey("topic2")); - Assert.assertTrue(messages.containsKey("topic3")); + Assert.assertTrue(messages.containsKey("topic1")); + Assert.assertTrue(messages.containsKey("topic2")); + Assert.assertTrue(messages.containsKey("topic3")); - Assert.assertTrue(valueFound(messages.get("topic1").get(1), "value1")); - Assert.assertTrue(valueFound(messages.get("topic2").get(1), "value2")); - Assert.assertTrue(valueFound(messages.get("topic3").get(1), "value3")); - } + Assert.assertTrue(valueFound(messages.get("topic1").get(1), "value1")); + Assert.assertTrue(valueFound(messages.get("topic2").get(1), "value2")); + Assert.assertTrue(valueFound(messages.get("topic3").get(1), "value3")); + } - private boolean valueFound(final List l, final String value){ - for (final Object o : l){ - if (value.equals(o)){ - return true; - } - } + private boolean valueFound(final List l, final String value){ + for (final Object o : l){ + if (value.equals(o)){ + return true; + } + } - return false; - } + return false; + } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/KafkaConsumerContextTest.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/KafkaConsumerContextTest.java index 12bc189..456bca8 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/KafkaConsumerContextTest.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/KafkaConsumerContextTest.java @@ -28,53 +28,54 @@ import java.util.Map; /** * @author Soby Chacko + * @since 0.5 */ public class KafkaConsumerContextTest { - @Test - public void testMergeResultsFromMultipleConsumerConfiguration() { - final KafkaConsumerContext kafkaConsumerContext = new KafkaConsumerContext(); - final ListableBeanFactory beanFactory = Mockito.mock(ListableBeanFactory.class); - final ConsumerConfiguration consumerConfiguration1 = Mockito.mock(ConsumerConfiguration.class); - final ConsumerConfiguration consumerConfiguration2 = Mockito.mock(ConsumerConfiguration.class); + @Test + public void testMergeResultsFromMultipleConsumerConfiguration() { + final KafkaConsumerContext kafkaConsumerContext = new KafkaConsumerContext(); + final ListableBeanFactory beanFactory = Mockito.mock(ListableBeanFactory.class); + final ConsumerConfiguration consumerConfiguration1 = Mockito.mock(ConsumerConfiguration.class); + final ConsumerConfiguration consumerConfiguration2 = Mockito.mock(ConsumerConfiguration.class); - final Map map = new HashMap(); - map.put("config1", consumerConfiguration1); - map.put("config2", consumerConfiguration2); + final Map map = new HashMap(); + map.put("config1", consumerConfiguration1); + map.put("config2", consumerConfiguration2); - Mockito.when(beanFactory.getBeansOfType(ConsumerConfiguration.class)).thenReturn(map); - kafkaConsumerContext.setBeanFactory(beanFactory); + Mockito.when(beanFactory.getBeansOfType(ConsumerConfiguration.class)).thenReturn(map); + kafkaConsumerContext.setBeanFactory(beanFactory); - final Map>> result1 = new HashMap>>(); - final List l1 = new ArrayList(); - l1.add("got message1 - l1"); - l1.add("got message2 - l1"); - final Map> innerMap1 = new HashMap>(); - innerMap1.put(1, l1); - result1.put("topic1", innerMap1); + final Map>> result1 = new HashMap>>(); + final List l1 = new ArrayList(); + l1.add("got message1 - l1"); + l1.add("got message2 - l1"); + final Map> innerMap1 = new HashMap>(); + innerMap1.put(1, l1); + result1.put("topic1", innerMap1); - final Map>> result2 = new HashMap>>(); - final List l2 = new ArrayList(); - l2.add("got message1 - l2"); - l2.add("got message2 - l2"); - l2.add("got message3 - l2"); + final Map>> result2 = new HashMap>>(); + final List l2 = new ArrayList(); + l2.add("got message1 - l2"); + l2.add("got message2 - l2"); + l2.add("got message3 - l2"); - final Map> innerMap2 = new HashMap>(); - innerMap2.put(1, l2); - result1.put("topic2", innerMap2); + final Map> innerMap2 = new HashMap>(); + innerMap2.put(1, l2); + result1.put("topic2", innerMap2); - Mockito.when(consumerConfiguration1.receive()).thenReturn(result1); - Mockito.when(consumerConfiguration2.receive()).thenReturn(result2); + Mockito.when(consumerConfiguration1.receive()).thenReturn(result1); + Mockito.when(consumerConfiguration2.receive()).thenReturn(result2); - final Message>>> messages = kafkaConsumerContext.receive(); - Assert.assertEquals(messages.getPayload().size(), 2); - Assert.assertEquals(messages.getPayload().get("topic1").size(), 1); - Assert.assertEquals(messages.getPayload().get("topic1").get(1).get(0), "got message1 - l1"); - Assert.assertEquals(messages.getPayload().get("topic1").get(1).get(1), "got message2 - l1"); + final Message>>> messages = kafkaConsumerContext.receive(); + Assert.assertEquals(messages.getPayload().size(), 2); + Assert.assertEquals(messages.getPayload().get("topic1").size(), 1); + Assert.assertEquals(messages.getPayload().get("topic1").get(1).get(0), "got message1 - l1"); + Assert.assertEquals(messages.getPayload().get("topic1").get(1).get(1), "got message2 - l1"); - Assert.assertEquals(messages.getPayload().get("topic2").size(), 1); - Assert.assertEquals(messages.getPayload().get("topic2").get(1).get(0), "got message1 - l2"); - Assert.assertEquals(messages.getPayload().get("topic2").get(1).get(1), "got message2 - l2"); - Assert.assertEquals(messages.getPayload().get("topic2").get(1).get(2), "got message3 - l2"); - } + Assert.assertEquals(messages.getPayload().get("topic2").size(), 1); + Assert.assertEquals(messages.getPayload().get("topic2").get(1).get(0), "got message1 - l2"); + Assert.assertEquals(messages.getPayload().get("topic2").get(1).get(1), "got message2 - l2"); + Assert.assertEquals(messages.getPayload().get("topic2").get(1).get(2), "got message3 - l2"); + } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/ProducerConfigurationTests.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/ProducerConfigurationTests.java index 2fa2021..6feefe0 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/ProducerConfigurationTests.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/ProducerConfigurationTests.java @@ -37,267 +37,271 @@ import java.io.ObjectInputStream; /** * @author Soby Chacko + * @since 0.5 */ public class ProducerConfigurationTests { - @Test - @SuppressWarnings("unchecked") - public void testSendMessageWithNonDefaultKeyAndValueEncoders() throws Exception { - final ProducerMetadata producerMetadata = new ProducerMetadata("test"); - producerMetadata.setValueEncoder(new StringEncoder(null)); - producerMetadata.setKeyEncoder(new StringEncoder(null)); - producerMetadata.setKeyClassType(String.class); - producerMetadata.setValueClassType(String.class); - final Producer producer = Mockito.mock(Producer.class); + @Test + @SuppressWarnings("unchecked") + public void testSendMessageWithNonDefaultKeyAndValueEncoders() throws Exception { + final ProducerMetadata producerMetadata = new ProducerMetadata("test"); + producerMetadata.setValueEncoder(new StringEncoder(null)); + producerMetadata.setKeyEncoder(new StringEncoder(null)); + producerMetadata.setKeyClassType(String.class); + producerMetadata.setValueClassType(String.class); + final Producer producer = Mockito.mock(Producer.class); - final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); + final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); - final Message message = MessageBuilder.withPayload("test message"). - setHeader("messageKey", "key") - .setHeader("topic", "test").build(); + final Message message = MessageBuilder.withPayload("test message") + .setHeader("messageKey", "key") + .setHeader("topic", "test") + .build(); - configuration.send(message); + configuration.send(message); - Mockito.verify(producer, Mockito.times(1)).send(Mockito.any(KeyedMessage.class)); + Mockito.verify(producer, Mockito.times(1)).send(Mockito.any(KeyedMessage.class)); - final ArgumentCaptor argument = ArgumentCaptor.forClass(KeyedMessage.class); - Mockito.verify(producer).send(argument.capture()); + final ArgumentCaptor argument = ArgumentCaptor.forClass(KeyedMessage.class); + Mockito.verify(producer).send(argument.capture()); - final KeyedMessage capturedKeyMessage = argument.getValue(); + final KeyedMessage capturedKeyMessage = argument.getValue(); - Assert.assertEquals(capturedKeyMessage.key(), "key"); - Assert.assertEquals(capturedKeyMessage.message(), "test message"); - Assert.assertEquals(capturedKeyMessage.topic(), "test"); - } + Assert.assertEquals(capturedKeyMessage.key(), "key"); + Assert.assertEquals(capturedKeyMessage.message(), "test message"); + Assert.assertEquals(capturedKeyMessage.topic(), "test"); + } - /** - * User does not set an explicit key/value encoder, but send a serializable object for both key/value - */ - @Test - @SuppressWarnings("unchecked") - public void testSendMessageWithDefaultKeyAndValueEncodersAndCustomSerializableKeyAndPayloadObject() throws Exception { - final ProducerMetadata producerMetadata = new ProducerMetadata("test"); - producerMetadata.setValueEncoder(new DefaultEncoder(null)); - producerMetadata.setKeyEncoder(new DefaultEncoder(null)); - final Producer producer = Mockito.mock(Producer.class); + /** + * User does not set an explicit key/value encoder, but send a serializable object for both key/value + */ + @Test + @SuppressWarnings("unchecked") + public void testSendMessageWithDefaultKeyAndValueEncodersAndCustomSerializableKeyAndPayloadObject() throws Exception { + final ProducerMetadata producerMetadata = new ProducerMetadata("test"); + producerMetadata.setValueEncoder(new DefaultEncoder(null)); + producerMetadata.setKeyEncoder(new DefaultEncoder(null)); + final Producer producer = Mockito.mock(Producer.class); - final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); + final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); - final Message message = MessageBuilder.withPayload(new TestPayload("part1", "part2")). - setHeader("messageKey", new TestKey("compositePart1", "compositePart2")) - .setHeader("topic", "test").build(); + final Message message = MessageBuilder.withPayload(new TestPayload("part1", "part2")) + .setHeader("messageKey", new TestKey("compositePart1", "compositePart2")) + .setHeader("topic", "test") + .build(); - configuration.send(message); + configuration.send(message); - Mockito.verify(producer, Mockito.times(1)).send(Mockito.any(KeyedMessage.class)); + Mockito.verify(producer, Mockito.times(1)).send(Mockito.any(KeyedMessage.class)); - final ArgumentCaptor argument = ArgumentCaptor.forClass(KeyedMessage.class); - Mockito.verify(producer).send(argument.capture()); + final ArgumentCaptor argument = ArgumentCaptor.forClass(KeyedMessage.class); + Mockito.verify(producer).send(argument.capture()); - final KeyedMessage capturedKeyMessage = argument.getValue(); + final KeyedMessage capturedKeyMessage = argument.getValue(); - final byte[] keyBytes = (byte[])capturedKeyMessage.key(); + final byte[] keyBytes = (byte[])capturedKeyMessage.key(); - final ByteArrayInputStream keyInputStream = new ByteArrayInputStream (keyBytes); - final ObjectInputStream keyObjectInputStream = new ObjectInputStream (keyInputStream); - final Object keyObj = keyObjectInputStream.readObject(); + final ByteArrayInputStream keyInputStream = new ByteArrayInputStream (keyBytes); + final ObjectInputStream keyObjectInputStream = new ObjectInputStream (keyInputStream); + final Object keyObj = keyObjectInputStream.readObject(); - final TestKey tk = (TestKey)keyObj; + final TestKey tk = (TestKey)keyObj; - Assert.assertEquals(tk.getKeyPart1(), "compositePart1"); - Assert.assertEquals(tk.getKeyPart2(), "compositePart2"); + Assert.assertEquals(tk.getKeyPart1(), "compositePart1"); + Assert.assertEquals(tk.getKeyPart2(), "compositePart2"); - final byte[] messageBytes = (byte[])capturedKeyMessage.message(); + final byte[] messageBytes = (byte[])capturedKeyMessage.message(); - final ByteArrayInputStream messageInputStream = new ByteArrayInputStream (messageBytes); - final ObjectInputStream messageObjectInputStream = new ObjectInputStream (messageInputStream); - final Object messageObj = messageObjectInputStream.readObject(); + final ByteArrayInputStream messageInputStream = new ByteArrayInputStream (messageBytes); + final ObjectInputStream messageObjectInputStream = new ObjectInputStream (messageInputStream); + final Object messageObj = messageObjectInputStream.readObject(); - final TestPayload tp = (TestPayload)messageObj; + final TestPayload tp = (TestPayload)messageObj; - Assert.assertEquals(tp.getPart1(), "part1"); - Assert.assertEquals(tp.getPart2(), "part2"); + Assert.assertEquals(tp.getPart1(), "part1"); + Assert.assertEquals(tp.getPart2(), "part2"); - Assert.assertEquals(capturedKeyMessage.topic(), "test"); - } + Assert.assertEquals(capturedKeyMessage.topic(), "test"); + } - /** - * User does not set an explicit key encoder, but a value encoder, and sends the corresponding data - */ - @Test - @SuppressWarnings("unchecked") - public void testSendMessageWithDefaultKeyEncoderAndNonDefaultValueEncoderAndCorrespondingData() throws Exception { - final ProducerMetadata producerMetadata = new ProducerMetadata("test"); - final AvroBackedKafkaEncoder encoder = new AvroBackedKafkaEncoder(TestPayload.class); - producerMetadata.setValueEncoder(encoder); - producerMetadata.setKeyEncoder(new DefaultEncoder(null)); - producerMetadata.setValueClassType(TestPayload.class); - final Producer producer = Mockito.mock(Producer.class); + /** + * User does not set an explicit key encoder, but a value encoder, and sends the corresponding data + */ + @Test + @SuppressWarnings("unchecked") + public void testSendMessageWithDefaultKeyEncoderAndNonDefaultValueEncoderAndCorrespondingData() throws Exception { + final ProducerMetadata producerMetadata = new ProducerMetadata("test"); + final AvroBackedKafkaEncoder encoder = new AvroBackedKafkaEncoder(TestPayload.class); + producerMetadata.setValueEncoder(encoder); + producerMetadata.setKeyEncoder(new DefaultEncoder(null)); + producerMetadata.setValueClassType(TestPayload.class); + final Producer producer = Mockito.mock(Producer.class); - final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); - final TestPayload tp = new TestPayload("part1", "part2"); - final Message message = MessageBuilder.withPayload(tp). - setHeader("messageKey", "key") - .setHeader("topic", "test").build(); + final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); + final TestPayload tp = new TestPayload("part1", "part2"); + final Message message = MessageBuilder.withPayload(tp) + .setHeader("messageKey", "key") + .setHeader("topic", "test") + .build(); - configuration.send(message); + configuration.send(message); - Mockito.verify(producer, Mockito.times(1)).send(Mockito.any(KeyedMessage.class)); + Mockito.verify(producer, Mockito.times(1)).send(Mockito.any(KeyedMessage.class)); - final ArgumentCaptor argument = ArgumentCaptor.forClass(KeyedMessage.class); - Mockito.verify(producer).send(argument.capture()); + final ArgumentCaptor argument = ArgumentCaptor.forClass(KeyedMessage.class); + Mockito.verify(producer).send(argument.capture()); - final KeyedMessage capturedKeyMessage = argument.getValue(); + final KeyedMessage capturedKeyMessage = argument.getValue(); - final byte[] keyBytes = (byte[])capturedKeyMessage.key(); + final byte[] keyBytes = (byte[])capturedKeyMessage.key(); - final ByteArrayInputStream keyInputStream = new ByteArrayInputStream (keyBytes); - final ObjectInputStream keyObjectInputStream = new ObjectInputStream (keyInputStream); - final Object keyObj = keyObjectInputStream.readObject(); + final ByteArrayInputStream keyInputStream = new ByteArrayInputStream (keyBytes); + final ObjectInputStream keyObjectInputStream = new ObjectInputStream (keyInputStream); + final Object keyObj = keyObjectInputStream.readObject(); - Assert.assertEquals("key", keyObj); - Assert.assertEquals(capturedKeyMessage.message(), tp); + Assert.assertEquals("key", keyObj); + Assert.assertEquals(capturedKeyMessage.message(), tp); - Assert.assertEquals(capturedKeyMessage.topic(), "test"); - } + Assert.assertEquals(capturedKeyMessage.topic(), "test"); + } - /** - * User does set an explicit key encoder, but not a value encoder, and sends the corresponding data - */ - @Test - @SuppressWarnings("unchecked") - public void testSendMessageWithNonDefaultKeyEncoderAndDefaultValueEncoderAndCorrespondingData() throws Exception { - final ProducerMetadata producerMetadata = new ProducerMetadata("test"); - final AvroBackedKafkaEncoder encoder = new AvroBackedKafkaEncoder(TestKey.class); - producerMetadata.setKeyEncoder(encoder); - producerMetadata.setValueEncoder(new DefaultEncoder(null)); - producerMetadata.setKeyClassType(TestKey.class); - final Producer producer = Mockito.mock(Producer.class); + /** + * User does set an explicit key encoder, but not a value encoder, and sends the corresponding data + */ + @Test + @SuppressWarnings("unchecked") + public void testSendMessageWithNonDefaultKeyEncoderAndDefaultValueEncoderAndCorrespondingData() throws Exception { + final ProducerMetadata producerMetadata = new ProducerMetadata("test"); + final AvroBackedKafkaEncoder encoder = new AvroBackedKafkaEncoder(TestKey.class); + producerMetadata.setKeyEncoder(encoder); + producerMetadata.setValueEncoder(new DefaultEncoder(null)); + producerMetadata.setKeyClassType(TestKey.class); + final Producer producer = Mockito.mock(Producer.class); - final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); - final TestKey tk = new TestKey("part1", "part2"); - final Message message = MessageBuilder.withPayload("test message"). - setHeader("messageKey", tk) - .setHeader("topic", "test").build(); + final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); + final TestKey tk = new TestKey("part1", "part2"); + final Message message = MessageBuilder.withPayload("test message"). + setHeader("messageKey", tk) + .setHeader("topic", "test").build(); - configuration.send(message); + configuration.send(message); - Mockito.verify(producer, Mockito.times(1)).send(Mockito.any(KeyedMessage.class)); + Mockito.verify(producer, Mockito.times(1)).send(Mockito.any(KeyedMessage.class)); - final ArgumentCaptor argument = ArgumentCaptor.forClass(KeyedMessage.class); - Mockito.verify(producer).send(argument.capture()); + final ArgumentCaptor argument = ArgumentCaptor.forClass(KeyedMessage.class); + Mockito.verify(producer).send(argument.capture()); - final KeyedMessage capturedKeyMessage = argument.getValue(); + final KeyedMessage capturedKeyMessage = argument.getValue(); - Assert.assertEquals(capturedKeyMessage.key(), tk); + Assert.assertEquals(capturedKeyMessage.key(), tk); - final byte[] payloadBytes = (byte[])capturedKeyMessage.message(); + final byte[] payloadBytes = (byte[])capturedKeyMessage.message(); - final ByteArrayInputStream payloadBis = new ByteArrayInputStream (payloadBytes); - final ObjectInputStream payloadOis = new ObjectInputStream (payloadBis); - final Object payloadObj = payloadOis.readObject(); + final ByteArrayInputStream payloadBis = new ByteArrayInputStream (payloadBytes); + final ObjectInputStream payloadOis = new ObjectInputStream (payloadBis); + final Object payloadObj = payloadOis.readObject(); - Assert.assertEquals("test message", payloadObj); - - Assert.assertEquals(capturedKeyMessage.topic(), "test"); - } - - /** - * User does not set an explicit key/value encoder, but send a serializable String key/value pair - */ - @Test - @SuppressWarnings("unchecked") - public void testSendMessageWithDefaultKeyAndValueEncodersAndStringKeyAndValue() throws Exception { - final ProducerMetadata producerMetadata = new ProducerMetadata("test"); - producerMetadata.setValueEncoder(new DefaultEncoder(null)); - producerMetadata.setKeyEncoder(new DefaultEncoder(null)); - final Producer producer = Mockito.mock(Producer.class); - - final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); - - final Message message = MessageBuilder.withPayload("test message"). - setHeader("messageKey", "key") - .setHeader("topic", "test").build(); - - configuration.send(message); - - Mockito.verify(producer, Mockito.times(1)).send(Mockito.any(KeyedMessage.class)); - - final ArgumentCaptor argument = ArgumentCaptor.forClass(KeyedMessage.class); - Mockito.verify(producer).send(argument.capture()); - - final KeyedMessage capturedKeyMessage = argument.getValue(); - final byte[] keyBytes = (byte[])capturedKeyMessage.key(); - - final ByteArrayInputStream keyBis = new ByteArrayInputStream (keyBytes); - final ObjectInputStream keyOis = new ObjectInputStream (keyBis); - final Object keyObj = keyOis.readObject(); - - Assert.assertEquals("key", keyObj); - - final byte[] payloadBytes = (byte[])capturedKeyMessage.message(); - - final ByteArrayInputStream payloadBis = new ByteArrayInputStream (payloadBytes); - final ObjectInputStream payloadOis = new ObjectInputStream (payloadBis); - final Object payloadObj = payloadOis.readObject(); - - Assert.assertEquals("test message", payloadObj); - Assert.assertEquals(capturedKeyMessage.topic(), "test"); - } - - /** - * User does not set an explicit key/value encoder, but send non-serializable object for both key/value - */ - @Test(expected = NotSerializableException.class) - @SuppressWarnings("unchecked") - public void testSendMessageWithDefaultKeyAndValueEncodersButNonSerializableKeyAndValue() throws Exception { - final ProducerMetadata producerMetadata = new ProducerMetadata("test"); - producerMetadata.setValueEncoder(new DefaultEncoder(null)); - producerMetadata.setKeyEncoder(new DefaultEncoder(null)); - final Producer producer = Mockito.mock(Producer.class); - - final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); - - final Message message = MessageBuilder.withPayload(new NonSerializableTestPayload("part1", "part2")). - setHeader("messageKey", new NonSerializableTestKey("compositePart1", "compositePart2")) - .setHeader("topic", "test").build(); - configuration.send(message); - } - - /** - * User does not set an explicit key/value encoder, but send non-serializable key and serializable value - */ - @Test(expected = NotSerializableException.class) - @SuppressWarnings("unchecked") - public void testSendMessageWithDefaultKeyAndValueEncodersButNonSerializableKeyAndSerializableValue() throws Exception { - final ProducerMetadata producerMetadata = new ProducerMetadata("test"); - producerMetadata.setValueEncoder(new DefaultEncoder(null)); - producerMetadata.setKeyEncoder(new DefaultEncoder(null)); - final Producer producer = Mockito.mock(Producer.class); - - final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); - - final Message message = MessageBuilder.withPayload(new TestPayload("part1", "part2")). - setHeader("messageKey", new NonSerializableTestKey("compositePart1", "compositePart2")) - .setHeader("topic", "test").build(); - configuration.send(message); - } - - /** - * User does not set an explicit key/value encoder, but send serializable key and non-serializable value - */ - @Test(expected = NotSerializableException.class) - @SuppressWarnings("unchecked") - public void testSendMessageWithDefaultKeyAndValueEncodersButSerializableKeyAndNonSerializableValue() throws Exception { - final ProducerMetadata producerMetadata = new ProducerMetadata("test"); - producerMetadata.setValueEncoder(new DefaultEncoder(null)); - producerMetadata.setKeyEncoder(new DefaultEncoder(null)); - final Producer producer = Mockito.mock(Producer.class); - - final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); - - final Message message = MessageBuilder.withPayload(new NonSerializableTestPayload("part1", "part2")). - setHeader("messageKey", new TestKey("compositePart1", "compositePart2")) - .setHeader("topic", "test").build(); - configuration.send(message); - } + Assert.assertEquals("test message", payloadObj); + + Assert.assertEquals(capturedKeyMessage.topic(), "test"); + } + + /** + * User does not set an explicit key/value encoder, but send a serializable String key/value pair + */ + @Test + @SuppressWarnings("unchecked") + public void testSendMessageWithDefaultKeyAndValueEncodersAndStringKeyAndValue() throws Exception { + final ProducerMetadata producerMetadata = new ProducerMetadata("test"); + producerMetadata.setValueEncoder(new DefaultEncoder(null)); + producerMetadata.setKeyEncoder(new DefaultEncoder(null)); + final Producer producer = Mockito.mock(Producer.class); + + final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); + + final Message message = MessageBuilder.withPayload("test message"). + setHeader("messageKey", "key") + .setHeader("topic", "test").build(); + + configuration.send(message); + + Mockito.verify(producer, Mockito.times(1)).send(Mockito.any(KeyedMessage.class)); + + final ArgumentCaptor argument = ArgumentCaptor.forClass(KeyedMessage.class); + Mockito.verify(producer).send(argument.capture()); + + final KeyedMessage capturedKeyMessage = argument.getValue(); + final byte[] keyBytes = (byte[])capturedKeyMessage.key(); + + final ByteArrayInputStream keyBis = new ByteArrayInputStream (keyBytes); + final ObjectInputStream keyOis = new ObjectInputStream (keyBis); + final Object keyObj = keyOis.readObject(); + + Assert.assertEquals("key", keyObj); + + final byte[] payloadBytes = (byte[])capturedKeyMessage.message(); + + final ByteArrayInputStream payloadBis = new ByteArrayInputStream (payloadBytes); + final ObjectInputStream payloadOis = new ObjectInputStream (payloadBis); + final Object payloadObj = payloadOis.readObject(); + + Assert.assertEquals("test message", payloadObj); + Assert.assertEquals(capturedKeyMessage.topic(), "test"); + } + + /** + * User does not set an explicit key/value encoder, but send non-serializable object for both key/value + */ + @Test(expected = NotSerializableException.class) + @SuppressWarnings("unchecked") + public void testSendMessageWithDefaultKeyAndValueEncodersButNonSerializableKeyAndValue() throws Exception { + final ProducerMetadata producerMetadata = new ProducerMetadata("test"); + producerMetadata.setValueEncoder(new DefaultEncoder(null)); + producerMetadata.setKeyEncoder(new DefaultEncoder(null)); + final Producer producer = Mockito.mock(Producer.class); + + final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); + + final Message message = MessageBuilder.withPayload(new NonSerializableTestPayload("part1", "part2")). + setHeader("messageKey", new NonSerializableTestKey("compositePart1", "compositePart2")) + .setHeader("topic", "test").build(); + configuration.send(message); + } + + /** + * User does not set an explicit key/value encoder, but send non-serializable key and serializable value + */ + @Test(expected = NotSerializableException.class) + @SuppressWarnings("unchecked") + public void testSendMessageWithDefaultKeyAndValueEncodersButNonSerializableKeyAndSerializableValue() throws Exception { + final ProducerMetadata producerMetadata = new ProducerMetadata("test"); + producerMetadata.setValueEncoder(new DefaultEncoder(null)); + producerMetadata.setKeyEncoder(new DefaultEncoder(null)); + final Producer producer = Mockito.mock(Producer.class); + + final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); + + final Message message = MessageBuilder.withPayload(new TestPayload("part1", "part2")). + setHeader("messageKey", new NonSerializableTestKey("compositePart1", "compositePart2")) + .setHeader("topic", "test").build(); + configuration.send(message); + } + + /** + * User does not set an explicit key/value encoder, but send serializable key and non-serializable value + */ + @Test(expected = NotSerializableException.class) + @SuppressWarnings("unchecked") + public void testSendMessageWithDefaultKeyAndValueEncodersButSerializableKeyAndNonSerializableValue() throws Exception { + final ProducerMetadata producerMetadata = new ProducerMetadata("test"); + producerMetadata.setValueEncoder(new DefaultEncoder(null)); + producerMetadata.setKeyEncoder(new DefaultEncoder(null)); + final Producer producer = Mockito.mock(Producer.class); + + final ProducerConfiguration configuration = new ProducerConfiguration(producerMetadata, producer); + + final Message message = MessageBuilder.withPayload(new NonSerializableTestPayload("part1", "part2")). + setHeader("messageKey", new TestKey("compositePart1", "compositePart2")) + .setHeader("topic", "test").build(); + configuration.send(message); + } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/ProducerFactoryBeanTests.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/ProducerFactoryBeanTests.java index 0089e73..683a269 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/ProducerFactoryBeanTests.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/support/ProducerFactoryBeanTests.java @@ -15,49 +15,50 @@ */ package org.springframework.integration.kafka.support; -import junit.framework.Assert; +import org.junit.Assert; import kafka.javaapi.producer.Producer; import org.junit.Test; import org.mockito.Mockito; /** * @author Soby Chacko + * @since 0.5 */ public class ProducerFactoryBeanTests { - @Test - public void createProducerWithDefaultMetadata() throws Exception { - final ProducerMetadata producerMetadata = new ProducerMetadata("test"); - final ProducerMetadata tm = Mockito.spy(producerMetadata); - final ProducerFactoryBean producerFactoryBean = new ProducerFactoryBean(tm, "localhost:9092"); - final Producer producer = producerFactoryBean.getObject(); + @Test + public void createProducerWithDefaultMetadata() throws Exception { + final ProducerMetadata producerMetadata = new ProducerMetadata("test"); + final ProducerMetadata tm = Mockito.spy(producerMetadata); + final ProducerFactoryBean producerFactoryBean = new ProducerFactoryBean(tm, "localhost:9092"); + final Producer producer = producerFactoryBean.getObject(); - Assert.assertTrue(producer != null); + Assert.assertTrue(producer != null); - Mockito.verify(tm, Mockito.times(1)).getPartitioner(); - Mockito.verify(tm, Mockito.times(1)).getCompressionCodec(); - Mockito.verify(tm, Mockito.times(1)).getValueEncoder(); - Mockito.verify(tm, Mockito.times(1)).getKeyEncoder(); - Mockito.verify(tm, Mockito.times(1)).isAsync(); - Mockito.verify(tm, Mockito.times(0)).getBatchNumMessages(); - } + Mockito.verify(tm, Mockito.times(1)).getPartitioner(); + Mockito.verify(tm, Mockito.times(1)).getCompressionCodec(); + Mockito.verify(tm, Mockito.times(1)).getValueEncoder(); + Mockito.verify(tm, Mockito.times(1)).getKeyEncoder(); + Mockito.verify(tm, Mockito.times(1)).isAsync(); + Mockito.verify(tm, Mockito.times(0)).getBatchNumMessages(); + } - @Test - public void createProducerWithAsyncFeatures() throws Exception { - final ProducerMetadata producerMetadata = new ProducerMetadata("test"); - producerMetadata.setAsync(true); - producerMetadata.setBatchNumMessages("300"); - final ProducerMetadata tm = Mockito.spy(producerMetadata); - final ProducerFactoryBean producerFactoryBean = new ProducerFactoryBean(tm, "localhost:9092"); - final Producer producer = producerFactoryBean.getObject(); + @Test + public void createProducerWithAsyncFeatures() throws Exception { + final ProducerMetadata producerMetadata = new ProducerMetadata("test"); + producerMetadata.setAsync(true); + producerMetadata.setBatchNumMessages("300"); + final ProducerMetadata tm = Mockito.spy(producerMetadata); + final ProducerFactoryBean producerFactoryBean = new ProducerFactoryBean(tm, "localhost:9092"); + final Producer producer = producerFactoryBean.getObject(); - Assert.assertTrue(producer != null); + Assert.assertTrue(producer != null); - Mockito.verify(tm, Mockito.times(1)).getPartitioner(); - Mockito.verify(tm, Mockito.times(1)).getCompressionCodec(); - Mockito.verify(tm, Mockito.times(1)).getValueEncoder(); - Mockito.verify(tm, Mockito.times(1)).getKeyEncoder(); - Mockito.verify(tm, Mockito.times(1)).isAsync(); - Mockito.verify(tm, Mockito.times(2)).getBatchNumMessages(); - } + Mockito.verify(tm, Mockito.times(1)).getPartitioner(); + Mockito.verify(tm, Mockito.times(1)).getCompressionCodec(); + Mockito.verify(tm, Mockito.times(1)).getValueEncoder(); + Mockito.verify(tm, Mockito.times(1)).getKeyEncoder(); + Mockito.verify(tm, Mockito.times(1)).isAsync(); + Mockito.verify(tm, Mockito.times(2)).getBatchNumMessages(); + } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/NonSerializableTestKey.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/NonSerializableTestKey.java index eef22df..fab58fd 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/NonSerializableTestKey.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/NonSerializableTestKey.java @@ -15,21 +15,25 @@ */ package org.springframework.integration.kafka.test.utils; +/** + * @author Soby Chacko + * @since 0.5 + */ public class NonSerializableTestKey { - private final String keyPart1; - private final String keyPart2; + private final String keyPart1; + private final String keyPart2; - public NonSerializableTestKey(final String keyPart1, final String keyPart2) { - this.keyPart1 = keyPart1; - this.keyPart2 = keyPart2; - } + public NonSerializableTestKey(final String keyPart1, final String keyPart2) { + this.keyPart1 = keyPart1; + this.keyPart2 = keyPart2; + } - public String getKeyPart1() { - return keyPart1; - } + public String getKeyPart1() { + return keyPart1; + } - public String getKeyPart2() { - return keyPart2; - } + public String getKeyPart2() { + return keyPart2; + } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/NonSerializableTestPayload.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/NonSerializableTestPayload.java index 6b2bb2f..f18a10f 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/NonSerializableTestPayload.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/NonSerializableTestPayload.java @@ -15,20 +15,24 @@ */ package org.springframework.integration.kafka.test.utils; +/** + * @author Soby Chacko + * @since 0.5 + */ public class NonSerializableTestPayload { - private final String part1; - private final String part2; + private final String part1; + private final String part2; - public NonSerializableTestPayload(final String part1, final String part2) { - this.part1 = part1; - this.part2 = part2; - } + public NonSerializableTestPayload(final String part1, final String part2) { + this.part1 = part1; + this.part2 = part2; + } - public String getPart1() { - return part1; - } + public String getPart1() { + return part1; + } - public String getPart2() { - return part2; - } + public String getPart2() { + return part2; + } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/TestKey.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/TestKey.java index 10e0480..ee4314e 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/TestKey.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/TestKey.java @@ -17,22 +17,26 @@ package org.springframework.integration.kafka.test.utils; import java.io.Serializable; +/** + * @author Soby Chacko + * @since 0.5 + */ public class TestKey implements Serializable { - private static final long serialVersionUID = -6415387283545560656L; + private static final long serialVersionUID = -6415387283545560656L; - private final String keyPart1; - private final String keyPart2; + private final String keyPart1; + private final String keyPart2; - public TestKey(final String keyPart1, final String keyPart2) { - this.keyPart1 = keyPart1; - this.keyPart2 = keyPart2; - } + public TestKey(final String keyPart1, final String keyPart2) { + this.keyPart1 = keyPart1; + this.keyPart2 = keyPart2; + } - public String getKeyPart1() { - return keyPart1; - } + public String getKeyPart1() { + return keyPart1; + } - public String getKeyPart2() { - return keyPart2; - } + public String getKeyPart2() { + return keyPart2; + } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/TestObject.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/TestObject.java index 42c2ec1..4cb5302 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/TestObject.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/TestObject.java @@ -15,24 +15,28 @@ */ package org.springframework.integration.kafka.test.utils; +/** + * @author Soby Chacko + * @since 0.5 + */ public class TestObject { - public String testData1; - public int testData2; + public String testData1; + public int testData2; - public String getTestData1() { - return testData1; - } + public String getTestData1() { + return testData1; + } - public void setTestData1(final String testData1) { - this.testData1 = testData1; - } + public void setTestData1(final String testData1) { + this.testData1 = testData1; + } - public int getTestData2() { - return testData2; - } + public int getTestData2() { + return testData2; + } - public void setTestData2(final int testData2) { - this.testData2 = testData2; - } + public void setTestData2(final int testData2) { + this.testData2 = testData2; + } } diff --git a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/TestPayload.java b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/TestPayload.java index 3ac94f8..73e9bf4 100644 --- a/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/TestPayload.java +++ b/spring-integration-kafka/src/test/java/org/springframework/integration/kafka/test/utils/TestPayload.java @@ -17,22 +17,26 @@ package org.springframework.integration.kafka.test.utils; import java.io.Serializable; +/** + * @author Soby Chacko + * @since 0.5 + */ public class TestPayload implements Serializable { - private static final long serialVersionUID = -8560378224929007403L; + private static final long serialVersionUID = -8560378224929007403L; - private final String part1; - private final String part2; + private final String part1; + private final String part2; - public TestPayload(final String part1, final String part2){ - this.part1 = part1; - this.part2 = part2; - } + public TestPayload(final String part1, final String part2){ + this.part1 = part1; + this.part2 = part2; + } - public String getPart1() { - return part1; - } + public String getPart1() { + return part1; + } - public String getPart2() { - return part2; - } + public String getPart2() { + return part2; + } }