diff --git a/.gitignore b/.gitignore index 2872fc2069..66bb817bf3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,11 @@ +*.iml +*.ipr +*.sw? +*/src/main/java/META-INF +.classpath .gradle .idea +.project .settings .springBeans build @@ -7,10 +13,7 @@ derby.log integration-repo lib logs +pom.xml si.java.hsp -target spring-integration-jms/activemq-data/ -spring-integration-parent/.project spring-integration-samples/loanshark/application.log* -*.iml -*/src/main/java/META-INF diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..d5d63fe083 --- /dev/null +++ b/build.gradle @@ -0,0 +1,421 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ----------------------------------------------------------------------------- +// Main gradle build file for Spring Integration +// +// - run `./gradlew(.bat) build` to kick off a complete compile-test-package +// +// @author Chris Beams +// @author Mark Fisher +// ----------------------------------------------------------------------------- + + +// ----------------------------------------------------------------------------- +// Configuration for the root project +// ----------------------------------------------------------------------------- +apply from: "$rootDir/gradle/version.gradle" +apply plugin: 'idea' + +// used for artifact names, building doc upload urls, etc. +description = 'Spring Integration' +abbreviation = 'INT' + +// ----------------------------------------------------------------------------- +// Configuration for all projects including this one (the root project) +// +// @see settings.gradle for list of all subprojects +// ----------------------------------------------------------------------------- +allprojects { + // group will translate to groupId during pom generation and deployment + group = 'org.springframework.integration' + + // version will be used in maven pom generation as well as determining + // where artifacts should be deployed, based on release type of snapshot, + // milestone or release. + // @see org.springframework.build.Version under buildSrc/ for more info + // @see gradle.properties for the declaration of this property. + version = createVersion(springIntegrationVersion) + + // default set of maven repositories to be used when resolving dependencies + repositories { + mavenRepo urls: 'http://maven.springframework.org/snapshot' + mavenCentral() + mavenRepo urls: 'http://maven.springframework.org/release' + mavenRepo urls: 'http://maven.springframework.org/milestone' + mavenRepo urls: 'http://repository.springsource.com/maven/bundles/external' + mavenRepo urls: 'http://repository.springsource.com/maven/bundles/release' + mavenRepo urls: 'http://repository.springsource.com/maven/bundles/milestone' + } +} + + +// ----------------------------------------------------------------------------- +// Create collections of subprojects - each will receive their own configuration +// - all subprojects that start with spring-integration-* are 'java projects' +// - documentation-related subprojects are not collected here +// +// @see configure(*) sections below +// ----------------------------------------------------------------------------- + +javaprojects = subprojects.findAll { project -> + project.path.startsWith(':spring-integration-') +} + +// ----------------------------------------------------------------------------- +// Configuration for all java subprojects +// ----------------------------------------------------------------------------- +configure(javaprojects) { + + apply plugin: 'java' // tasks for conventional java lifecycle + apply plugin: 'maven' // `gradle install` to push jars to local .m2 cache + apply plugin: 'eclipse' // `gradle eclipse` to generate .classpath/.project + apply plugin: 'idea' // `gradle idea` to generate .ipr/.iml + + // set up dedicated directories for jars and source jars. + // this makes it easier when putting together the distribution + libsBinDir = new File(libsDir, 'bin') + libsSrcDir = new File(libsDir, 'src') + + // all core projects should be OSGi-compliant bundles + // add the bundlor task to ensure proper manifests + apply from: "$rootDir/gradle/bundlor.gradle" + apply from: "$rootDir/gradle/maven-deployment.gradle" + + aspectjVersion = '1.6.8' + cglibVersion = '2.2' + commonsIoVersion = '1.4' + commonsLangVersion = '2.5' + commonsNetVersion = '2.0' + easymockVersion = '2.3' + jacksonVersion = '1.4.3' + javaxActivationVersion = '1.1.1' + junitVersion = '4.7' + log4jVersion = '1.2.12' + mockitoVersion = '1.8.4' + springVersion = '3.0.5.RELEASE' + springSecurityVersion = '3.0.3.RELEASE' + springWsVersion = '1.5.9' + + sourceSets { + test { + resources { + srcDirs = ['src/test/resources', 'src/test/java'] + } + } + } + + // dependencies that are common across all java projects + dependencies { + testCompile "cglib:cglib-nodep:$cglibVersion" + testCompile "junit:junit:$junitVersion" + testCompile "log4j:log4j:$log4jVersion" + testCompile "org.easymock:easymock:$easymockVersion" + testCompile "org.easymock:easymockclassextension:$easymockVersion" + testCompile "org.hamcrest:hamcrest-all:1.1" + testCompile "org.mockito:mockito-all:$mockitoVersion" + testCompile "org.springframework:spring-test:$springVersion" + } + + // enable all compiler warnings (GRADLE-1077) + [compileJava, compileTestJava]*.options*.compilerArgs = ['-Xlint:all'] + + // generate .classpath files without GRADLE_CACHE variable (GRADLE-1079) + eclipseClasspath.variables = [:] +} + + +// ----------------------------------------------------------------------------- +// Configuration for each individual core java subproject +// +// @see configure(javaprojects) above for general config +// ----------------------------------------------------------------------------- +project('spring-integration-core') { + description = 'Spring Integration Core' + dependencies { + compile "org.springframework:spring-aop:$springVersion" + compile "org.springframework:spring-context:$springVersion" + compile("org.springframework:spring-tx:$springVersion") { optional = true } + compile("org.codehaus.jackson:jackson-mapper-asl:$jacksonVersion") { optional = true } + testCompile "org.aspectj:aspectjrt:$aspectjVersion" + testCompile "org.aspectj:aspectjweaver:$aspectjVersion" + } +} + +project('spring-integration-event') { + description = 'Spring Integration Event Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-context:$springVersion" + testCompile project(":spring-integration-test") + } +} + +project('spring-integration-feed') { + description = 'Spring Integration RSS Feed Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-context:$springVersion" + compile "commons-lang:commons-lang:$commonsLangVersion" + compile "net.java.dev.rome:rome-fetcher:1.0.0" + compile "net.java.dev.rome:rome:1.0.0" + testCompile project(":spring-integration-test") + } +} + +project('spring-integration-file') { + description = 'Spring Integration File Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-context:$springVersion" + testCompile project(":spring-integration-test") + } +} + +project('spring-integration-ftp') { + description = 'Spring Integration FTP Support' + dependencies { + compile project(":spring-integration-file") + compile "commons-io:commons-io:$commonsIoVersion" + compile "commons-lang:commons-lang:$commonsLangVersion" + compile "commons-net:commons-net:$commonsNetVersion" + compile "org.springframework:spring-context-support:$springVersion" + compile("javax.activation:activation:$javaxActivationVersion") { optional = true } + testCompile project(":spring-integration-test") + } +} + +project('spring-integration-groovy') { + description = 'Spring Integration Groovy Support' + dependencies { + compile project(":spring-integration-core") + compile "org.codehaus.groovy:groovy-all:1.7.5" + compile "org.springframework:spring-context-support:$springVersion" + } +} + +project('spring-integration-http') { + description = 'Spring Integration HTTP Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-webmvc:$springVersion" + compile("javax.servlet:servlet-api:2.4") { provided = true } + compile("commons-httpclient:commons-httpclient:3.1") { optional = true } + testCompile project(":spring-integration-test") + } +} + +project('spring-integration-httpinvoker') { + description = 'Spring Integration HttpInvoker Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-aop:$springVersion" + compile "org.springframework:spring-web:$springVersion" + compile("javax.servlet:servlet-api:2.4") { provided = true } + } +} + +project('spring-integration-ip') { + description = 'Spring Integration IP Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-context:$springVersion" + runtime project(":spring-integration-stream") + testCompile project(":spring-integration-test") + } +} + +project('spring-integration-jdbc') { + description = 'Spring Integration JDBC Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-aop:$springVersion" + compile "org.springframework:spring-context:$springVersion" + compile "org.springframework:spring-jdbc:$springVersion" + compile "org.springframework:spring-tx:$springVersion" + testCompile project(":spring-integration-test") + testCompile "com.h2database:h2:1.2.125" + testCompile "hsqldb:hsqldb:1.8.0.10" + testCompile "org.apache.derby:derby:10.5.3.0_1" + testCompile "org.aspectj:aspectjrt:$aspectjVersion" + testCompile "org.aspectj:aspectjweaver:$aspectjVersion" + } +} + +project('spring-integration-jms') { + description = 'Spring Integration JMS Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-jms:$springVersion" + compile "org.springframework:spring-tx:$springVersion" + compile ("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1") { provided = true } + testCompile project(":spring-integration-test") + testCompile "org.apache.activemq:activemq-core:5.3.0" + testCompile "org.springframework:spring-oxm:$springVersion" + } +} + +project('spring-integration-jmx') { + description = 'Spring Integration JMX Support' + dependencies { + compile project(":spring-integration-core") + compile "org.aspectj:aspectjrt:$aspectjVersion" + compile "org.aspectj:aspectjweaver:$aspectjVersion" + compile "org.springframework:spring-context:$springVersion" + } +} + +project('spring-integration-mail') { + description = 'Spring Integration Mail Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-context-support:$springVersion" + compile("javax.mail:mail:1.4.1") { provided = true } + compile("javax.activation:activation:$javaxActivationVersion") { optional = true } + testCompile project(":spring-integration-test") + } +} + +project('spring-integration-rmi') { + description = 'Spring Integration RMI Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-aop:$springVersion" + compile "org.springframework:spring-context:$springVersion" + } +} + +project('spring-integration-security') { + description = 'Spring Integration Security Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-aop:$springVersion" + compile "org.springframework:spring-tx:$springVersion" + compile("org.springframework.security:spring-security-core:$springSecurityVersion") { + exclude group: 'org.springframework', module: 'spring-support' + } + compile("org.springframework.security:spring-security-config:$springSecurityVersion") { + exclude group: 'org.springframework', module: 'spring-support' + } + } +} + +project('spring-integration-sftp') { + description = 'Spring Integration SFTP Support' + dependencies { + compile project(":spring-integration-core") + compile project(":spring-integration-file") + compile project(":spring-integration-stream") + compile "com.jcraft:jsch:0.1.42" + compile "commons-io:commons-io:$commonsIoVersion" + compile "commons-lang:commons-lang:$commonsLangVersion" + compile "org.springframework:spring-context-support:$springVersion" + compile("javax.activation:activation:$javaxActivationVersion") { optional = true } + } +} + +project('spring-integration-stream') { + description = 'Spring Integration Stream Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-context:$springVersion" + } +} + +project('spring-integration-test') { + description = 'Spring Integration Test Support' + dependencies { + compile project(":spring-integration-core") + compile "junit:junit:$junitVersion" + compile "org.mockito:mockito-all:$mockitoVersion" + compile "org.springframework:spring-context:$springVersion" + } +} + +project('spring-integration-twitter') { + description = 'Spring Integration Twitter Support' + dependencies { + compile project(":spring-integration-core") + compile "commons-io:commons-io:$commonsIoVersion" + compile "commons-lang:commons-lang:$commonsLangVersion" + compile "org.springframework:spring-context-support:$springVersion" + compile "org.twitter4j:twitter4j-core:2.1.3" + compile("javax.activation:activation:$javaxActivationVersion") { optional = true } + } +} + +project('spring-integration-ws') { + description = 'Spring Integration Web Services Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-expression:$springVersion" + compile "org.springframework:spring-oxm:$springVersion" + compile "org.springframework.ws:spring-ws-core:$springWsVersion" + compile("javax.xml.soap:saaj-api:1.3") { + optional = true + exclude group: 'javax.activation', module: 'activation' + } + compile("com.sun.xml.messaging.saaj:saaj-impl:1.3") { optional = true } + compile("javax.activation:activation:$javaxActivationVersion") { optional = true } + testCompile project(":spring-integration-test") + } +} + +project('spring-integration-xml') { + description = 'Spring Integration XML Support' + dependencies { + compile project(":spring-integration-core") + compile "org.springframework:spring-context:$springVersion" + compile "org.springframework:spring-oxm:$springVersion" + compile "org.springframework.ws:spring-xml:$springWsVersion" + compile("javax.activation:activation:$javaxActivationVersion") { optional = true } + testCompile project(":spring-integration-test") + testCompile "xmlunit:xmlunit:1.2" + } +} + +project('spring-integration-xmpp') { + description = 'Spring Integration XMPP Support' + dependencies { + compile project(":spring-integration-core") + compile "commons-io:commons-io:$commonsIoVersion" + compile "commons-lang:commons-lang:$commonsLangVersion" + compile("javax.activation:activation:$javaxActivationVersion") { optional = true } + compile "jivesoftware:smack:3.1.0" + compile "jivesoftware:smackx:3.1.0" + compile "org.springframework:spring-context-support:$springVersion" + } +} + +// add basic tasks like 'clean' and 'assemble' to the root project. e.g.: allows +// running `gradle clean` from the root project and deleting the build directory +apply plugin: 'base' + +// add tasks like 'distArchive' +apply from: "$rootDir/gradle/dist.gradle" + +// add tasks like 'snapshotDependencyCheck' +apply from: "${rootDir}/gradle/checks.gradle" + + +// ----------------------------------------------------------------------------- +// Import tasks related to releasing and managing the project +// depending on the role played by the current user. +// +// @see gradle.properties for more information on roles +// ----------------------------------------------------------------------------- +// add management tasks like `wrapper` for generating the gradlew* scripts +apply from: "$rootDir/gradle/wrapper.gradle" diff --git a/docs/build.gradle b/docs/build.gradle new file mode 100644 index 0000000000..7c35775829 --- /dev/null +++ b/docs/build.gradle @@ -0,0 +1,240 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'base' +apply from: "$rootDir/gradle/docbook.gradle" + +description = "Spring Integration Documentation" + +task build(dependsOn: assemble) { + group = 'Build' + description = 'Builds reference and API documentation and archives' +} + + +/** + * Build aggregated JavaDoc HTML for all core project classes. Result is + * suitable for packaging into a distribution zip or viewing directly with + * a browser. + * + * @author Chris Beams + * @author Luke Taylor + * @see http://gradle.org/0.9-rc-1/docs/javadoc/org/gradle/api/tasks/javadoc/Javadoc.html + */ + task api(type: Javadoc) { + group = 'Documentation' + description = "Builds aggregated JavaDoc HTML for all core project classes." + + // this task is a bit ugly to configure. it was a user contribution, and + // Hans tells me it's on the roadmap to redesign it. + srcDir = file("${projectDir}/src/api") + destinationDir = file("${buildDir}/api") + tmpDir = file("${buildDir}/api-work") + optionsFile = file("${tmpDir}/apidocs/javadoc.options") + options.stylesheetFile = file("${srcDir}/spring-javadoc.css") + options.links = ["http://static.springframework.org/spring/docs/3.0.x/javadoc-api"] + options.overview = "${srcDir}/overview.html" + options.docFilesSubDirs = true + title = "Spring Integration ${version} API" + + // collect all the sources that will be included in the javadoc output + source javaprojects.collect {project -> + project.sourceSets.main.allJava + } + + // collect all main classpaths to be able to resolve @see refs, etc. + // this collection also determines the set of projects that this + // task dependsOn, thus the runtimeClasspath is used to ensure all + // projects are included, not just *dependencies* of all classes. + // this is awkward and took me a while to figure out. + classpath = files(javaprojects.collect {project -> + project.sourceSets.main.runtimeClasspath + }) + + // copy the images from the doc-files dir over to the target + doLast { task -> + copy { + from file("${task.srcDir}/doc-files") + into file("${task.destinationDir}/doc-files") + } + } +} + +/** + * Expand ${...} variables within docbook sources. This is a workaround + * accomodating the fact that the current docbook plugin has no way of + * parameterizing and replacing normal XML entities. + * + * Note that this task represents an implementation detail and it is + * unfortunate that it pollutes the listing of available tasks, e.g. + * during `gradle -t`. It's a good example of the need for 'task visibility' - + * a feature not yet implemented, but on the Gradle roadmap. + * + * @author Chris Beams + * @see http://jira.codehaus.org/browse/GRADLE-1026 + */ +task preprocessDocbookSources { + description = 'Expands ${...} variables within docbook sources.' + + doLast { + docbookSrcDir = file('src/reference/docbook') + docbookResourceDir = file('src/reference/resources/') + docbookWorkDir = file('build/reference-work') + + // copy everything but index.xml + copy { + into(docbookWorkDir) + from(docbookSrcDir) { exclude '**/index.xml' } + } + copy { + into(docbookWorkDir) + from(docbookResourceDir) + } + // copy index.xml and expand ${...} variables along the way + // e.g.: ${version} needs to be replaced in the header + copy { + into(docbookWorkDir) + from(docbookSrcDir) { include '**/index.xml' } + expand(version: "$version") + } + } +} + +// ----------------------------------------------------------------------------- +// Configure the three docbook* tasks that are added to the project by the +// 'docbook' plugin. +// ----------------------------------------------------------------------------- +task reference(dependsOn: [docbookHtml, docbookHtmlSingle, docbookPdf]) { + group = 'Documentation' + description = 'Generates all HTML and PDF reference documentation.' + + doLast { + // copy images and css into respective html dirs + ['html', 'htmlsingle'].each { dir -> + copy { + into "${buildDir}/reference/${dir}/images" + from "src/reference/resources/images" + } + copy { + into "${buildDir}/reference/${dir}/css" + from "src/reference/resources/css" + } + } + } +} + +[docbookHtml, docbookPdf, docbookHtmlSingle]*.sourceFileName = 'index.xml'; +[docbookHtml, docbookHtmlSingle, docbookPdf]*.dependsOn preprocessDocbookSources + +docbookHtml.stylesheet = file('src/reference/resources/xsl/html-custom.xsl') +docbookHtmlSingle.stylesheet = file('src/reference/resources/xsl/html-single-custom.xsl') +docbookPdf.stylesheet = file('src/reference/resources/xsl/pdf-custom.xsl') +def imagesDir = file('src/reference/resources/images'); +docbookPdf.admonGraphicsPath = "${imagesDir}/" + + +/** + * + * @see http://www.gradle.org/0.9-preview-3/docs/userguide/userguide_single.html#sec:copying_files + * @see http://www.gradle.org/0.9-preview-3/docs/javadoc/org/gradle/api/file/CopySpec.html + */ +docsSpec = copySpec { + into("${version}") { + from('src/info/changelog.txt') + } + + into("${version}/api") { + from(api.destinationDir) + } + + into("${version}/reference") { + from("${buildDir}/reference") + } +} + +task archive(type: Zip, dependsOn: [api, reference]) { + group = "Documentation" + description = "Create a zip archive of reference and API documentation." + + baseName = rootProject.name + '-docs' + + // drop it right in the root of the build dir for simplicity + destinationDir = buildDir + + // use the copy spec above to specify the contents of the zip + with docsSpec +} + +configurations { archives } +artifacts { archives archive } + +configurations { scpAntTask } +dependencies { + scpAntTask("org.apache.ant:ant-jsch:1.8.1") +} + +checkForProps(taskPath: project.path + ':uploadArchives', requiredProps: ['sshHost', 'sshUsername']) + +uploadArchives { + def sshHost = project.properties.sshHost + def sshUsername = project.properties.sshUsername + def remoteSiteDir = '/var/www/domains/springframework.org/static/htdocs/' + rootProject.name + def docUrl = "http://${sshHost}/${rootProject.name}/docs/${version}" + def remoteDocsDir = "${remoteSiteDir}/docs/" + def fqRemoteDir = "${sshUsername}@${sshHost}:${remoteDocsDir}" + + group = 'Buildmaster' + description = "Uploads and unpacks documentation archive" + (sshHost ? " to ${docUrl}" : ": Host is not specified") + + uploadDescriptor = false + + repositories { + add(new org.apache.ivy.plugins.resolver.SshResolver()) { + name = 'sshHost: ' + sshHost // used for debugging + host = sshHost + user = sshUsername + if (project.hasProperty('remoteSiteDir')) { + keyFile = sshPrivateKey as File + } + addArtifactPattern "${remoteDocsDir}/${archive.archiveName}" + } + } + + configurations { scpAntTask } + dependencies { scpAntTask 'org.apache.ant:ant-jsch:1.8.1' } + + doFirst { + println "Uploading: ${archive.archivePath} to ${fqRemoteDir}" + } + + doLast { + project.ant { + taskdef(name: 'sshexec', + classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec', + classpath: configurations.scpAntTask.asPath) + + // copy the archive, unpack it, then delete it + def unpackCommand = "cd ${remoteDocsDir} && unzip ${archive.archiveName}" + def deleteCommand = "rm ${remoteDocsDir}/${archive.archiveName}" + + println "sshexec ${unpackCommand}" + sshexec(host: sshHost, username: sshUsername, keyfile: sshPrivateKey, command: unpackCommand) + println "sshexec ${deleteCommand}" + sshexec(host: sshHost, username: sshUsername, keyfile: sshPrivateKey, command: deleteCommand) + println "UPLOAD SUCCESSFUL - validate by visiting ${docUrl}" + } + } +} diff --git a/src/main/javadoc/doc-files/th-background.png b/docs/src/api/doc-files/th-background.png similarity index 100% rename from src/main/javadoc/doc-files/th-background.png rename to docs/src/api/doc-files/th-background.png diff --git a/src/main/javadoc/overview.html b/docs/src/api/overview.html similarity index 100% rename from src/main/javadoc/overview.html rename to docs/src/api/overview.html diff --git a/src/main/javadoc/spring-javadoc.css b/docs/src/api/spring-javadoc.css similarity index 100% rename from src/main/javadoc/spring-javadoc.css rename to docs/src/api/spring-javadoc.css diff --git a/src/main/resources/changelog.txt b/docs/src/info/changelog.txt similarity index 99% rename from src/main/resources/changelog.txt rename to docs/src/info/changelog.txt index f7a37eecdc..a44a235c12 100644 --- a/src/main/resources/changelog.txt +++ b/docs/src/info/changelog.txt @@ -5,6 +5,9 @@ For the full detailed changelog, see: https://fisheye.springsource.org/changelog/spring-integration +Changes in version 2.0.0 Release Candidate 1 (Oct 28, 2010) +http://jira.springsource.org/secure/IssueNavigator.jspa?reset=true&pid=10121&fixfor=11656 + Changes in version 2.0.0 Milestone 7 (Sept 03, 2010) http://jira.springsource.org/secure/IssueNavigator.jspa?reset=true&pid=10121&fixfor=11311 diff --git a/src/main/resources/license.txt b/docs/src/info/license.txt similarity index 100% rename from src/main/resources/license.txt rename to docs/src/info/license.txt diff --git a/src/main/resources/notice.txt b/docs/src/info/notice.txt similarity index 100% rename from src/main/resources/notice.txt rename to docs/src/info/notice.txt diff --git a/docs/src/info/readme.txt b/docs/src/info/readme.txt new file mode 100644 index 0000000000..49ab1033e0 --- /dev/null +++ b/docs/src/info/readme.txt @@ -0,0 +1,37 @@ +SPRING INTEGRATION 2.0.0 Release Candidate 1 (Oct 28, 2010) +----------------------------------------------------------- + +To find out what has changed since version 1.0.x or 2.0 M7, see 'changelog.txt' + +Please consult the documentation located within the 'docs/reference' directory +of this release and also visit the official Spring Integration home at +http://www.springsource.org/spring-integration + +There you will find links to the forum, issue tracker, and several other resources. + +To check out the project and build from source, do the following: + + git clone git://git.springsource.org/spring-integration/spring-integration.git + cd spring-integration + ./gradlew build + +To generate Eclipse metadata (.classpath and .project files), do the following: + + ./gradlew eclipse + +Once complete, you may then import projects into Eclipse as usual: + + File->Import->Existing projects into workspace + +and point to the 'spring-integration' root directory. All projects should import +free of errors. + +To generate IDEA metadata (.iml and .ipr files), do the following: + + ./gradlew idea + +To build the JavaDoc, do the following from within the root directory: + + ./gradlew :docs:api + +the result will be available in 'docs/build/api'. diff --git a/docs/src/reference/docbook/.index.xml.swo b/docs/src/reference/docbook/.index.xml.swo new file mode 100644 index 0000000000..782ad922c7 Binary files /dev/null and b/docs/src/reference/docbook/.index.xml.swo differ diff --git a/src/docbkx/aggregator.xml b/docs/src/reference/docbook/aggregator.xml similarity index 99% rename from src/docbkx/aggregator.xml rename to docs/src/reference/docbook/aggregator.xml index 5efa549a06..4503c52671 100644 --- a/src/docbkx/aggregator.xml +++ b/docs/src/reference/docbook/aggregator.xml @@ -1,7 +1,6 @@ - - + Aggregator
diff --git a/src/docbkx/bridge.xml b/docs/src/reference/docbook/bridge.xml similarity index 95% rename from src/docbkx/bridge.xml rename to docs/src/reference/docbook/bridge.xml index a8a2d5778c..105cfc76e6 100644 --- a/src/docbkx/bridge.xml +++ b/docs/src/reference/docbook/bridge.xml @@ -1,7 +1,6 @@ - - + Messaging Bridge
@@ -57,4 +56,4 @@
-
\ No newline at end of file +
diff --git a/src/docbkx/chain.xml b/docs/src/reference/docbook/chain.xml similarity index 53% rename from src/docbkx/chain.xml rename to docs/src/reference/docbook/chain.xml index 14beee7766..c82a01577a 100644 --- a/src/docbkx/chain.xml +++ b/docs/src/reference/docbook/chain.xml @@ -1,7 +1,6 @@ - - + Message Handler Chain
@@ -26,27 +25,27 @@ - The handler chain simplifies configuration while internally maintaining the same degree of loose coupling between - components, and it is trivial to modify the configuration if at some point a non-linear arrangement is required. + The handler chain simplifies configuration while internally maintaining the same degree of loose coupling between + components, and it is trivial to modify the configuration if at some point a non-linear arrangement is required. - Internally, the chain will be expanded into a linear setup of the listed endpoints, separated by direct channels. - The reply channel header will not be taken into account within the chain: only after the last handler is invoked - will the resulting message be forwarded on to the reply channel or the chain's output channel. Because of this - setup all handlers except the last require a setOutputChannel implementation. The last - handler only needs an output channel if the outputChannel on the MessageHandlerChain is set. - - - As with other endpoints, the output-channel is optional. If there is a reply Message at the end of the - chain, the output-channel takes precedence, but if not available, the chain handler will check for a - reply channel header on the inbound Message. - - + Internally, the chain will be expanded into a linear setup of the listed endpoints, separated by direct channels. + The reply channel header will not be taken into account within the chain: only after the last handler is invoked + will the resulting message be forwarded on to the reply channel or the chain's output channel. Because of this + setup all handlers except the last require a setOutputChannel implementation. The last + handler only needs an output channel if the outputChannel on the MessageHandlerChain is set. + + + As with other endpoints, the output-channel is optional. If there is a reply Message at the end of the + chain, the output-channel takes precedence, but if not available, the chain handler will check for a + reply channel header on the inbound Message. + + - In most cases there is no need to implement MessageHandlers yourself. The next section will focus on namespace - support for the chain element. Most Spring Integration endpoints, like Service Activators and Transformers, are - suitable for use within a MessageHandlerChain. + In most cases there is no need to implement MessageHandlers yourself. The next section will focus on namespace + support for the chain element. Most Spring Integration endpoints, like Service Activators and Transformers, are + suitable for use within a MessageHandlerChain.
@@ -64,52 +63,52 @@ ]]> - - The <header-enricher> element used in the above example will set a message header with name "foo" and - value "bar" on the message. A header enricher is a specialization of Transformer that touches only header - values. You could obtain the same result by implementing a MessageHandler that did the header modifications - and wiring that as a bean. - - - - Some time you need to make a nested call to another chain from within the chain and then come - back and continue execution within the original chain. + + The <header-enricher> element used in the above example will set a message header with name "foo" and + value "bar" on the message. A header enricher is a specialization of Transformer that touches only header + values. You could obtain the same result by implementing a MessageHandler that did the header modifications + and wiring that as a bean. + + + + Some time you need to make a nested call to another chain from within the chain and then come + back and continue execution within the original chain. To accomplish this you can utilize Messaging Gateway by including light-configuration via <gateway> element. For example: - - - - - - - -   - - - - - -   - - - - - - - - - - - - ]]> + + + + + + + +   + + + + + +   + + + + + + + + + + + + ]]> -In the above example the nested-chain-a will be called at the end of main-chain processing by the 'gateway' element -configured there. While in nested-chain-a a call to a nested-chain-b will be made after header enrichment and then it will +In the above example the nested-chain-a will be called at the end of main-chain processing by the 'gateway' element +configured there. While in nested-chain-a a call to a nested-chain-b will be made after header enrichment and then it will come back to finish execution in nested-chain-b finally getting back to the main-chain. When light version of <gateway> element is defined in the chain SI will construct an instance SimpleMessagingGateway - (no need to provide 'service-interface' configuration) which will take the message in its current state and will place it on the channel defined via 'request-channel' attribute. + (no need to provide 'service-interface' configuration) which will take the message in its current state and will place it on the channel defined via 'request-channel' attribute. Upon processing Message will be returned to the gateway and continue its journey within the current chain. - +
-
\ No newline at end of file +
diff --git a/src/docbkx/channel-adapter.xml b/docs/src/reference/docbook/channel-adapter.xml similarity index 100% rename from src/docbkx/channel-adapter.xml rename to docs/src/reference/docbook/channel-adapter.xml diff --git a/src/docbkx/channel.xml b/docs/src/reference/docbook/channel.xml similarity index 92% rename from src/docbkx/channel.xml rename to docs/src/reference/docbook/channel.xml index ea8f942c94..c4babca116 100644 --- a/src/docbkx/channel.xml +++ b/docs/src/reference/docbook/channel.xml @@ -1,6 +1,6 @@ - - + Message Channels While the Message plays the crucial role of encapsulating data, it is the @@ -226,8 +226,8 @@ thread. It therefore does not support transactions spanning the sender and receiving handler. - Note that there are occasions where the sender may block. For example, when using a - TaskExecutor with a rejection-policy that throttles back on the client (such as the + Note that there are occasions where the sender may block. For example, when using a + TaskExecutor with a rejection-policy that throttles back on the client (such as the ThreadPoolExecutor.CallerRunsPolicy), the sender's thread will execute the method directly anytime the thread pool is at its maximum capacity and the executor's work queue is full. Since that situation would only occur in a non-predictable @@ -373,7 +373,7 @@ public Message receive(final PollableChannel channel) { ... }]]>java.lang.Integer or java.lang.Double. Multiple types can be provided as a comma-delimited list: - ]]> + ]]> When using the "channel" element without any sub-elements, it will create a DirectChannel @@ -425,7 +425,7 @@ public Message receive(final PollableChannel channel) { ... }]]> To create a PublishSubscribeChannel, use the "publish-subscribe-channel" element. When using this element, you can also specify the "task-executor" used for publishing - Messages (if none is specified it simply publishes in the sender's thread): + Messages (if none is specified it simply publishes in the sender's thread): <publish-subscribe-channel id="pubsubChannel" task-executor="someExecutor"/> If you are providing a Resequencer or Aggregator downstream from a PublishSubscribeChannel, then you can set the 'apply-sequence' property @@ -439,7 +439,7 @@ public Message receive(final PollableChannel channel) { ... }]]>true. + true. @@ -474,7 +474,7 @@ public Message receive(final PollableChannel channel) { ... }]]> ]]> - By default, the channel will consult the MessagePriority header of the + By default, the channel will consult the MessagePriority header of the message. However, a custom Comparator reference may be provided instead. Also, note that the PriorityChannel (like the other types) does support the "datatype" attribute. As with the QueueChannel, it also supports a "capacity" attribute. @@ -508,7 +508,7 @@ public Message receive(final PollableChannel channel) { ... }]]>
- Channel Interceptor Configuration + Channel Interceptor Configuration Message channels may also have interceptors as described in . The <interceptors> sub-element can be added within <channel> (or the more specific element @@ -523,55 +523,55 @@ public Message receive(final PollableChannel channel) { ... }]]>
- +
- Global Channel Interceptor Configuration + Global Channel Interceptor Configuration - Channel Interceptors allow you for a clean and concise way of applying cross-cutting behavior per individual channel. - But what if the same behavior should be applied on multiple channels, configuring the same set of interceptors for - each channel would not be the most efficient way. The better way would be to configure interceptors globally and apply - them on multiple channels in one shot. Spring Integration provides capabilities to configure Global Interceptors + Channel Interceptors allow you for a clean and concise way of applying cross-cutting behavior per individual channel. + But what if the same behavior should be applied on multiple channels, configuring the same set of interceptors for + each channel would not be the most efficient way. The better way would be to configure interceptors globally and apply + them on multiple channels in one shot. Spring Integration provides capabilities to configure Global Interceptors and apply them on multiple channels. - Look at the example below: + Look at the example below: ]]> - or - - + or + + ]]> - <channel-interceptor> element allows you to define a global interceptor which will be applied on all - channels that match patterns defined via pattern attribute. In the above case the global interceptor will be applied on - 'foo' channel and all other channels that begin with 'bar' and 'input'. - The order attribute allows you to manage the place where this interceptor will be injected. + <channel-interceptor> element allows you to define a global interceptor which will be applied on all + channels that match patterns defined via pattern attribute. In the above case the global interceptor will be applied on + 'foo' channel and all other channels that begin with 'bar' and 'input'. + The order attribute allows you to manage the place where this interceptor will be injected. For example, channel 'inputChannel' could have individual interceptors configured locally (see below):   - -   - + +   + ]]> - The reasonable question would be how global interceptor will be injected in relation to other interceptors - configured locally or through other global interceptor definitions? Current implementation provides - a very simple and clever mechanism of handling this. Positive number in the order attribute will ensure interceptor injection - after existing interceptors and negative number will ensure that such interceptors injected before. - This means that in the above example global interceptor will be injected AFTER (since its order is greater then 0) - 'wire-tap' interceptor configured locally. If there was another global interceptor with matching pattern their - order would be determined based on who's got the higher or lower value in order attribute. - To inject global interceptor BEFORE the existing interceptors use negative value for the order attribute. + The reasonable question would be how global interceptor will be injected in relation to other interceptors + configured locally or through other global interceptor definitions? Current implementation provides + a very simple and clever mechanism of handling this. Positive number in the order attribute will ensure interceptor injection + after existing interceptors and negative number will ensure that such interceptors injected before. + This means that in the above example global interceptor will be injected AFTER (since its order is greater then 0) + 'wire-tap' interceptor configured locally. If there was another global interceptor with matching pattern their + order would be determined based on who's got the higher or lower value in order attribute. + To inject global interceptor BEFORE the existing interceptors use negative value for the order attribute. - Note that order and pattern attributes are optional. The default value for order + Note that order and pattern attributes are optional. The default value for order will be 0 and for pattern is '*'
- Wire Tap + Wire Tap - As mentioned above, Spring Integration provides a simple Wire Tap interceptor out of - the box. You can configure a Wire Tap on any channel within an 'interceptors' element. + As mentioned above, Spring Integration provides a simple Wire Tap interceptor out of + the box. You can configure a Wire Tap on any channel within an 'interceptors' element. This is especially useful for debugging, and can be used in conjunction with Spring Integration's logging - Channel Adapter as follows: + Channel Adapter as follows: @@ -579,12 +579,12 @@ public Message receive(final PollableChannel channel) { ... }]]>]]> - The 'logging-channel-adapter' also accepts a boolean attribute: 'log-full-message'. - That is false by default so that only the payload is logged. Setting that to - true enables logging of all headers in addition to the payload. - + The 'logging-channel-adapter' also accepts a boolean attribute: 'log-full-message'. + That is false by default so that only the payload is logged. Setting that to + true enables logging of all headers in addition to the payload. + -
+ @@ -599,4 +599,4 @@ public Message receive(final PollableChannel channel) { ... }]]> -
\ No newline at end of file +
diff --git a/src/docbkx/configuration.xml b/docs/src/reference/docbook/configuration.xml similarity index 64% rename from src/docbkx/configuration.xml rename to docs/src/reference/docbook/configuration.xml index 995f948b8e..54271bab9d 100644 --- a/src/docbkx/configuration.xml +++ b/docs/src/reference/docbook/configuration.xml @@ -1,6 +1,6 @@ - - + Configuration
Introduction @@ -35,7 +35,7 @@ http://www.springframework.org/schema/integration/spring-integration-2.0.xsd"> - You can choose any name after "xmlns:"; integration is used here for clarity, but you might + You can choose any name after "xmlns:"; integration is used here for clarity, but you might prefer a shorter abbreviation. Of course if you are using an XML-editor or IDE support, then the availability of auto-completion may convince you to keep the longer name for clarity. Alternatively, you can create configuration files that use the Spring Integration schema as the primary namespace: @@ -263,7 +263,7 @@ public class FooService { forwarded to the reply channel as specified in the original request message. In other words, the final component depends on the information provided by the original sender and can dynamically support any number of clients as a result. This is an example of Return Address. - + In addition to the examples shown here, these annotations also support inputChannel and outputChannel properties. public class FooService { @@ -284,7 +284,7 @@ public class FooService { must be a reference to a SubscribableChannel instance. Otherwise, it would be necessary to also provide the full poller configuration via annotations, and those settings (e.g. the trigger for scheduling the poller) should be externalized rather than hard-coded within - an annotation. If the input channel that you want to receive Messages from is indeed a + an annotation. If the input channel that you want to receive Messages from is indeed a PollableChannel instance, one option to consider is the Messaging Bridge. Spring Integration's "bridge" element can be used to connect a PollableChannel directly to a SubscribableChannel. Then, the polling metadata is externally configured, but the annotation option is @@ -292,172 +292,172 @@ public class FooService {
- +
- Message Mapping rules and conventions - Spring Integration implements a flexible facility to map Messages to Methods and their arguments without - providing extra configuration by relying on some default rules as well as defining certain conventions. - -
- Simple Scenarios - - - Single un-annotated parameter (object or primitive) which is not a Map/Properties with non-void return type; - - public String foo(Object o); - Details: - Input parameter is Message Payload. If parameter type is not compatible with Message Payload an - attempt will be made to convert it using Conversion Service provided by Spring 3.0. The return value - will be incorporated as a Payload of the returned Message - - - Single un-annotated parameter (object or primitive) which is not a Map/Properties with Message return type; - - public Message  foo(Object o); - Details: - Input parameter is Message Payload. If parameter type is not compatible with Message Payload an attempt - will be made to convert it using Conversion Service provided by Spring 3.0. The return value is a newly constructed - Message that will be sent to the next destination. - - - Single parameter which is a Message or its subclass with arbitrary object/primitive return type; - - public int foo(Message  msg); - Details: - Input parameter is Message itself. The return value will become a payload of the - Message that will be sent to the next destination. - - - Single parameter which is a Message or its subclass with Message or its subclass as a return type; - - public Message foo(Message msg); - Details: - Input parameter is Message itself. The return value is a newly constructed Message that will be sent to the next destination. - - - Single parameter which is of type Map or Properties with Message as a return type; - - public Message foo(Map m); - Details: - This one is a bit interesting. Although at first it might seem like an easy mapping straight to Message Headers, - the preference is always given to a Message Payload. This means that if Message Payload is of type Map, this input argument will - represent Message Payload. However if Message Payload is not of type Map, then no conversion via Conversion Service will be - attempted and the input argument will be mapped to Message Headers. - - - Two parameters where one of them is arbitrary non-Map/Properties type object/primitive and another is Map/Properties type object (regardless of the return) - - public Message foo(Map h, <T> t); - Details: - This combination contains two input parameters where one of them is of type Map. Naturally the non-Map parameters (regardless of the order) will - be mapped to a Message Payload and the Map/Properties (regardless of the order) will be mapped to  Message Headers giving you a nice POJO way - of interacting with Message structure. - - - No parameters (regardless of the return) - - public String foo(); - Details: - This Message Handler method will be invoked based on the Message sent to the input channel this handler is hooked up to, - however no Message data will be mapped, thus making Message act as event/trigger to invoke such handlerThe output will be - mapped according to the rules above - - - No parameters, void return - - public void foo(); - Details: - Same as above, but no output  - - - Annotation based mappings - - Annotation based mapping is the safest and least ambiguous approach to map Messages to Methods. There wil be many pointers to annotation - based mapping throughout this manual, however here are couple of examples: - - - public String foo(@Payload String s,  @Header("foo") String b)  - Very simple and explicite way of mapping Messages to method. As you'll see later on without annotation this signature - would result in the ambiguous condition, however by explicitly mapping first argument to a Message Payload and second argument to - a value of the 'foo' Message Header we have avoided ambiguity. - - public String foo(@Payload String s,  @RequestParam("foo") String b)  - Looks almost identical to the previous example, however @RequestMapping or any other non-SI mapping annotation - is irrelevant  and therefore will be ignored leaving the second parameter unmapped. And although the second parameters could - easily be mapped to a Payload, there can only be one Payload, therefore this method becomes ambiguous.  - - public String foo(String s,  @Header("foo") String b)  - The same as above. The only difference is that the first argument will be mapped to Message Payload implicitly. - - public String foo(@Headers Map m,  @Header("foo")Map f, @Header("bar") String bar) - Yet another signature that would definitely be treated as ambiguous because it has more then 2 arguments, - plus two of them are Maps, however with annotation-based mapping ambiguity is easily avoided. In this example - the first argument is mapped to all the Message Headers, while second and third argument map to the values of Message Headers 'foo' and 'bar'. -
- -
- Complex Scenarios - - Multiple parameters: - Multiple parameters could create a lot of ambiguity with regards to determining the appropriate mappings. The general advice is to annotate your method parameters with @Payload and/or @Header/@Headers -Below are some of the examples of ambiguous conditions which result in exception being raised. - - public String foo(String s, int i) - - the two parameters are equal in weight, therefore no way to determine which one is a payload and what to do with another. - - public String foo(String s, Map m, String b) - - almost the same as above. Although Map could be easily mapped to Message Headers, there is no way to determine what to do with two Strings. - - public String foo(Map m, Map f) - - although one might argue that one Map could be mapped to Message Payload and another one to Message Headers, it would be unreasonable to rely on the order (e.g., first is Payload, second Headers) - - - Basically any method signature with more then one method argument which is not (Map, <T>) and those parameters are not annotated will result in the ambiguous condition thus triggering an exception. - - - Multiple methods: - - Message Handlers with multiple methods are mapped based on the same rules that are described above, however some scenarios might still look confusing. - - Multiple methods (same or different name) with legal (mappable) signatures: - - public class Foo{ - public String foo(String str, Map m); + Message Mapping rules and conventions + Spring Integration implements a flexible facility to map Messages to Methods and their arguments without + providing extra configuration by relying on some default rules as well as defining certain conventions. + +
+ Simple Scenarios - public String foo(Map m) -} - As you can see, the Message could be mapped to either method. The first method would be invoked where Message Payload - could be mapped to 'str'  and Message Headers could be mapped to 'm'. The second method could easily also be a candidate where - only Message Headers are mapped to 'm'. To make meters worse both methods have the same name which at first might look very - ambiguous considering the following configuration: - - -]]> - At this point it would be important to understand Spring Integration mapping Conventions where at the very core, - mappings are based on Payload first and everything else next. In other words the method whose argument could be mapped - to a Payload will take precedence over all other methods. - - On the other hand let's look at slightly different example: - public class Foo{ - public String foo(String str, Map m); + + Single un-annotated parameter (object or primitive) which is not a Map/Properties with non-void return type; + + public String foo(Object o); + Details: + Input parameter is Message Payload. If parameter type is not compatible with Message Payload an + attempt will be made to convert it using Conversion Service provided by Spring 3.0. The return value + will be incorporated as a Payload of the returned Message - public String foo(String str) -} + + Single un-annotated parameter (object or primitive) which is not a Map/Properties with Message return type; + + public Message  foo(Object o); + Details: + Input parameter is Message Payload. If parameter type is not compatible with Message Payload an attempt + will be made to convert it using Conversion Service provided by Spring 3.0. The return value is a newly constructed + Message that will be sent to the next destination. - If you look at it you can probably see a truly an ambiguous condition. In this example since both methods have signatures that - could be mapped to a Message Payload. They also have the same name. Such handler will trigger an exception. -However if method names were different you could influence the mapping with 'method' attribute (see below): - public class Foo{ - public String foo(String str, Map m); + + Single parameter which is a Message or its subclass with arbitrary object/primitive return type; + + public int foo(Message  msg); + Details: + Input parameter is Message itself. The return value will become a payload of the + Message that will be sent to the next destination. - public String bar(String str) -} - - -]]> + + Single parameter which is a Message or its subclass with Message or its subclass as a return type; + + public Message foo(Message msg); + Details: + Input parameter is Message itself. The return value is a newly constructed Message that will be sent to the next destination. - Now there is no ambiguity since the configuration explicitly maps to 'bar' method which has no name conflicts. -
+ + Single parameter which is of type Map or Properties with Message as a return type; + + public Message foo(Map m); + Details: + This one is a bit interesting. Although at first it might seem like an easy mapping straight to Message Headers, + the preference is always given to a Message Payload. This means that if Message Payload is of type Map, this input argument will + represent Message Payload. However if Message Payload is not of type Map, then no conversion via Conversion Service will be + attempted and the input argument will be mapped to Message Headers. + + + Two parameters where one of them is arbitrary non-Map/Properties type object/primitive and another is Map/Properties type object (regardless of the return) + + public Message foo(Map h, <T> t); + Details: + This combination contains two input parameters where one of them is of type Map. Naturally the non-Map parameters (regardless of the order) will + be mapped to a Message Payload and the Map/Properties (regardless of the order) will be mapped to  Message Headers giving you a nice POJO way + of interacting with Message structure. + + + No parameters (regardless of the return) + + public String foo(); + Details: + This Message Handler method will be invoked based on the Message sent to the input channel this handler is hooked up to, + however no Message data will be mapped, thus making Message act as event/trigger to invoke such handlerThe output will be + mapped according to the rules above + + + No parameters, void return + + public void foo(); + Details: + Same as above, but no output  + + + Annotation based mappings + + Annotation based mapping is the safest and least ambiguous approach to map Messages to Methods. There wil be many pointers to annotation + based mapping throughout this manual, however here are couple of examples: + + + public String foo(@Payload String s,  @Header("foo") String b)  + Very simple and explicite way of mapping Messages to method. As you'll see later on without annotation this signature + would result in the ambiguous condition, however by explicitly mapping first argument to a Message Payload and second argument to + a value of the 'foo' Message Header we have avoided ambiguity. + + public String foo(@Payload String s,  @RequestParam("foo") String b)  + Looks almost identical to the previous example, however @RequestMapping or any other non-SI mapping annotation + is irrelevant  and therefore will be ignored leaving the second parameter unmapped. And although the second parameters could + easily be mapped to a Payload, there can only be one Payload, therefore this method becomes ambiguous.  + + public String foo(String s,  @Header("foo") String b)  + The same as above. The only difference is that the first argument will be mapped to Message Payload implicitly. + + public String foo(@Headers Map m,  @Header("foo")Map f, @Header("bar") String bar) + Yet another signature that would definitely be treated as ambiguous because it has more then 2 arguments, + plus two of them are Maps, however with annotation-based mapping ambiguity is easily avoided. In this example + the first argument is mapped to all the Message Headers, while second and third argument map to the values of Message Headers 'foo' and 'bar'.
- \ No newline at end of file +
+ Complex Scenarios + + Multiple parameters: + Multiple parameters could create a lot of ambiguity with regards to determining the appropriate mappings. The general advice is to annotate your method parameters with @Payload and/or @Header/@Headers +Below are some of the examples of ambiguous conditions which result in exception being raised. + + public String foo(String s, int i) + - the two parameters are equal in weight, therefore no way to determine which one is a payload and what to do with another. + + public String foo(String s, Map m, String b) + - almost the same as above. Although Map could be easily mapped to Message Headers, there is no way to determine what to do with two Strings. + + public String foo(Map m, Map f) + - although one might argue that one Map could be mapped to Message Payload and another one to Message Headers, it would be unreasonable to rely on the order (e.g., first is Payload, second Headers) + + + Basically any method signature with more then one method argument which is not (Map, <T>) and those parameters are not annotated will result in the ambiguous condition thus triggering an exception. + + + Multiple methods: + + Message Handlers with multiple methods are mapped based on the same rules that are described above, however some scenarios might still look confusing. + + Multiple methods (same or different name) with legal (mappable) signatures: + + public class Foo{ + public String foo(String str, Map m); + + public String foo(Map m) +} + As you can see, the Message could be mapped to either method. The first method would be invoked where Message Payload + could be mapped to 'str'  and Message Headers could be mapped to 'm'. The second method could easily also be a candidate where + only Message Headers are mapped to 'm'. To make meters worse both methods have the same name which at first might look very + ambiguous considering the following configuration: + + +]]> + At this point it would be important to understand Spring Integration mapping Conventions where at the very core, + mappings are based on Payload first and everything else next. In other words the method whose argument could be mapped + to a Payload will take precedence over all other methods. + + On the other hand let's look at slightly different example: + public class Foo{ + public String foo(String str, Map m); + + public String foo(String str) +} + + If you look at it you can probably see a truly an ambiguous condition. In this example since both methods have signatures that + could be mapped to a Message Payload. They also have the same name. Such handler will trigger an exception. +However if method names were different you could influence the mapping with 'method' attribute (see below): + public class Foo{ + public String foo(String str, Map m); + + public String bar(String str) +} + + +]]> + + Now there is no ambiguity since the configuration explicitly maps to 'bar' method which has no name conflicts. +
+
+ +
diff --git a/src/docbkx/delayer.xml b/docs/src/reference/docbook/delayer.xml similarity index 96% rename from src/docbkx/delayer.xml rename to docs/src/reference/docbook/delayer.xml index f1e1d0f91c..3a41f4d63a 100644 --- a/src/docbkx/delayer.xml +++ b/docs/src/reference/docbook/delayer.xml @@ -1,7 +1,6 @@ - - + Delayer
@@ -59,4 +58,4 @@
-
\ No newline at end of file +
diff --git a/src/docbkx/endpoint.xml b/docs/src/reference/docbook/endpoint.xml similarity index 99% rename from src/docbkx/endpoint.xml rename to docs/src/reference/docbook/endpoint.xml index 21b69c4abe..de74cbc352 100644 --- a/src/docbkx/endpoint.xml +++ b/docs/src/reference/docbook/endpoint.xml @@ -1,7 +1,6 @@ - - + Message Endpoints The first part of this chapter covers some background theory and reveals quite a bit about the underlying API @@ -347,4 +346,4 @@ any transaction configuration essentially allowing you to enhance the behavior o to - Section 25 - Task Execution and Scheduling of Spring reference manual. - \ No newline at end of file + diff --git a/docs/src/reference/docbook/event.xml b/docs/src/reference/docbook/event.xml new file mode 100644 index 0000000000..3a9546edbf --- /dev/null +++ b/docs/src/reference/docbook/event.xml @@ -0,0 +1,62 @@ + + + Spring ApplicationEvent Support + + + Spring Integration provides support for inbound and outbound ApplicationEvents + as defined by the underlying Spring Framework. For more information about the events and listeners, + refer to the Spring Reference Manual. + + +
+ Receiving Spring ApplicationEvents + + To receive events and send them to a channel, simply define an instance of Spring Integration's + ApplicationEventListeningChannelAdapter. This class is an implementation of + Spring's ApplicationListener interface. By default it will pass all + received events as Spring Integration Messages. To limit based on the type of event, configure the + list of event types that you want to receive with the 'eventTypes' property. + + + For convenience namespace support was provided to configure ApplicationEventListeningChannelAdapter via inbound-channel-adapter + + +]]> +In the above sample, all Application Context events that are of type specified by the 'event-types' (optional) attribute will be +delivered as Spring Integration Messages to 'sampleEventChannel'. + + + +
+ +
+ Sending Spring ApplicationEvents + + To send Spring ApplicationEvents, create an instance of the + ApplicationEventPublishingMessageHandler and register it within an endpoint. + This implementation of the MessageHandler interface also implements + Spring's ApplicationEventPublisherAware interface and thus acts as a + bridge between Spring Integration Messages and ApplicationEvents. + + + For convenience namespace support was provided to configure ApplicationEventPublishingMessageHandler via outbound-channel-adapter element + + +]]> +If you are using PollableChannel (e.g., Queue), you can also provide poller as sub-element of outbound-channel-adapter, optionally providing task-executor + + + + + + + + +]]> + +In the above sample, all messages sent to an 'input' channel will be published as ApplicationEvents to Spring Application sContext + +
+ +
diff --git a/docs/src/reference/docbook/file.xml b/docs/src/reference/docbook/file.xml new file mode 100644 index 0000000000..6c198c643c --- /dev/null +++ b/docs/src/reference/docbook/file.xml @@ -0,0 +1,228 @@ + + + File Support + +
+ Introduction + + Spring Integration's File support extends the Spring Integration Core with + a dedicated vocabulary to deal with reading, writing, and transforming files. + It provides a namespace that enables elements defining Channel Adapters dedicated + to files and support for Transformers that can read file contents into strings or + byte arrays. + + + This section will explain the workings of FileReadingMessageSource + and FileWritingMessageHandler and how to configure them as + beans. Also the support for dealing with files through file specific + implementations of Transformer will be discussed. Finally the + file specific namespace will be explained. + +
+ +
+ Reading Files + + A FileReadingMessageSource can be used to consume files from the filesystem. + This is an implementation of MessageSource that creates messages from + a file system directory. ]]> + + + To prevent creating messages for certain files, you may supply a + FileListFilter. By default, an + AcceptOnceFileListFilter is used. This filter + ensures files are picked up only once from the directory. + ]]> + + + A common problem with reading files is that a file may be detected before + it is ready. The default AcceptOnceFileListFilter + does not prevent this. In most cases, this can be prevented if the + file-writing process renames each file as soon as it is ready for + reading. A pattern-matching filter that accepts only files that are + ready (e.g. based on a known suffix), composed with the default + AcceptOnceFileListFilter allows for this. + The CompositeFileListFilter enables the + composition. + + + + + + + + + + +]]> + + + The configuration can be simplified using the file specific namespace. To do + this use the following template. + + +]]> + Within this namespace you can reduce the FileReadingMessageSource and wrap + it in an inbound Channel Adapter like this: + + + + + ]]> + The first channel adapter is relying on the default filter that just prevents + duplication, the second is using a custom filter, and the third is using the + filename-pattern attribute to add a AntPathMatcher + based filter to the FileReadingMessageSource. + The file-name-pattern and filter attributes are mutually exclusive, but + you can use a CompositeFileListFilter to use any combination of filters, including a + pattern based filter to fit your particular needs. + + + When multiple processes are reading from the same directory it can be desirable to lock files to prevent + them from being picked up concurrently. To do this you can use a FileLocker. + There is a java.nio based implementation available out of the box, but it is also possible to implement your + own locking scheme. The nio locker can be injected as follows + + + ]]> + + A custom locker you can configure like this: + + + ]]> + + + + When filtering and locking files is not enough it might be needed to control the way files are listed entirely. To + implement this type of requirement you can use an implementation of DirectoryScanner. + This scanner allows you to determine entirely what files are listed each poll. This is also the interface + that Spring Integration uses internally to wire FileListFilters FileLocker to the FileReadingMessageSource. + A custom DirectoryScanner can be injected into the <file:inbound-channel-adapter/> on the scanner + attribute. + ]]> + + This gives you full freedom to choose the ordering, listing and locking strategies. + +
+ +
+ Writing files + + To write messages to the file system you can use a + FileWritingMessageHandler. This class can deal with + File, String, or byte array payloads. In its simplest form the + FileWritingMessageHandler only requires a + destination directory for writing the files. The name of the file to be + written is determined by the handler's FileNameGenerator. + The default implementation looks for a Message header whose key matches + the constant defined as FileHeaders.FILENAME. + + + Additionally, you can configure the encoding and the charset that + will be used in case of a String payload. + + + To make things easier you can configure the FileWritingMessageHandler as + part of an outbound channel adapter using the namespace. + ]]> + + + The namespace based configuration also supports a delete-source-files attribute. + If set to true, it will trigger deletion of the original source files after writing + to a destination. The default value for that flag is false. + ]]> + + + The delete-source-files attribute will only have an effect if the inbound + Message has a File payload or if the FileHeaders.ORIGINAL_FILE header + value contains either the source File instance or a String representing the original file path. + + + + + In cases where you want to continue processing messages based on the written File you can use + the outbound-gateway instead. It plays a very similar role as the + outbound-channel-adapter. However after writing the File, it will also send it + to the reply channel as the payload of a Message. + ]]> + + + The 'outbound-gateway' works well in cases where you want to first move a File and then send it + through a processing pipeline. In such cases, you may connect the file namespace's + 'inbound-channel-adapter' element to the 'outbound-gateway' and then connect that gateway's + reply-channel to the beginning of the pipeline. + + + If you have more elaborate requirements or need to support additional payload types as input + to be converted to file content you could extend the FileWritingMessageHandler, but a much + better option is to rely on a Transformer. + +
+ +
+ File Transformers + + To transform data read from the file system to objects and the other way around you need + to do some work. Contrary to FileReadingMessageSource and to a + lesser extent FileWritingMessageHandler, it is very likely that you + will need your own mechanism to get the job done. For this you can implement the + Transformer interface. Or extend the + AbstractFilePayloadTransformer for inbound messages. Some obvious + implementations have been provided. + + + FileToByteArrayTransformer transforms Files into byte[]s using + Spring's FileCopyUtils. It is often better to use a sequence of + transformers than to put all transformations in a single class. In that case the File to + byte[] conversion might be a logical first step. + + + FileToStringTransformer will convert Files to Strings as the name + suggests. If nothing else, this can be useful for debugging (consider using with a Wire Tap). + + + To configure File specific transformers you can use the appropriate elements from the file namespace. + + + ]]> + The delete-files option signals to the transformer that it should delete + the inbound File after the transformation is complete. This is in no way a replacement for using the + AcceptOnceFileListFilter when the FileReadingMessageSource is being used in a + multi-threaded environment (e.g. Spring Integration in general). + +
+ +
diff --git a/src/docbkx/filter.xml b/docs/src/reference/docbook/filter.xml similarity index 95% rename from src/docbkx/filter.xml rename to docs/src/reference/docbook/filter.xml index d0da4b7915..c9bd8aeb1d 100644 --- a/src/docbkx/filter.xml +++ b/docs/src/reference/docbook/filter.xml @@ -1,7 +1,6 @@ - - + Filter
@@ -34,7 +33,7 @@
The <filter> Element - The <filter> element is used to create a Message-selecting endpoint. In addition to "input-channel" + The <filter> element is used to create a Message-selecting endpoint. In addition to "input-channel" and "output-channel" attributes, it requires a "ref". The "ref" may point to a MessageSelector implementation: @@ -57,7 +56,7 @@ 'throw-exception-on-rejection' flag to true: ]]> - If you want the rejected messages to go to a specific channel, provide that reference as the 'discard-channel': + If you want the rejected messages to go to a specific channel, provide that reference as the 'discard-channel': ]]> @@ -68,12 +67,12 @@ alternative to the more proactive approach of using a Message Router with a single Point-to-Point input channel and multiple output channels. - + Using a "ref" attribute is generally recommended if the custom filter implementation can be reused in other <filter> definitions. However if the custom filter implementation should be scoped to a single <filter> element, provide an inner bean definition: - + ]]> @@ -118,7 +117,7 @@ Then, the 'config/integration/expressions.properties' file (or any more specific version with a locale extension to be resolved in the typical way that resource-bundles are loaded) would contain a key/value pair: - + 100 ]]> @@ -129,4 +128,4 @@ to be treated as Message Channel names by a router component.
- \ No newline at end of file + diff --git a/docs/src/reference/docbook/gateway.xml b/docs/src/reference/docbook/gateway.xml new file mode 100644 index 0000000000..12a88b2f27 --- /dev/null +++ b/docs/src/reference/docbook/gateway.xml @@ -0,0 +1,254 @@ + + + Inbound Messaging Gateways + +
+ GatewayProxyFactoryBean + + Working with Objects instead of Messages is an improvement. However, it would be even better to have no + dependency on the Spring Integration API at all - including the gateway class. For that reason, Spring + Integration also provides a GatewayProxyFactoryBean that generates a proxy for + any interface and internally invokes the gateway methods shown above. Namespace support is also + provided as demonstrated by the following example. + ]]> + Then, the "fooService" can be injected into other beans, and the code that invokes the methods on that + proxied instance of the FooService interface has no awareness of the Spring Integration API. The general + approach is similar to that of Spring Remoting (RMI, HttpInvoker, etc.). See the "Samples" Appendix for + an example that uses this "gateway" element (in the Cafe demo). + + + The reason that the attributes on the 'gateway' element are named 'default-request-channel' and + 'default-reply-channel' is that you may also provide per-method channel references by using the + @Gateway annotation. + + ... as well as method sub element if yuo prefer XML configuration (see next paragraph) + + + It is also possible to pass values to be interpreted as Message headers on the Message + that is created and sent to the request channel by using the @Header annotation: + + + + + If you prefer XML way of configuring Gateway methods, you can provide method sub-elements + to the gateway configuration (see below) + + + + +]]> + + + You can also provide individual headers per method invocation via XML. + This could be very useful if the headers you want to set are static in nature and you don't want + to embed them in the gateway's method signature via @Header annotations. + For example, in the Loan Broker example we want to influence how aggregation of the Loan quotes + will be done based on what type of request was initiated (single quote or all quotes). Determining the + type of the request by evaluating what gateway method was invoked, although possible would + violate the separation of concerns paradigm (method is a java artifact),  but expressing your + intention (meta information) via Message headers is natural in a Messaging architecture. + + + + + + + + +]]> + In the above case you can clearly see how a different header value will be set for the 'RESPONSE_TYPE' + header based on the gateway's method. + + + As with anything else, Gateway invocation might result in errors. + By default any error that has occurred downstream will be re-thrown as a MessagingExeption (RuntimeException) + upon the Gateway's method invocation. However there are times when you may want to treat an Exception as a valid reply, + by mapping it to a Message. To accomplish this our Gateway provides support for Exception mappers via the + exception-mapper attribute. + + + + + + + ]]> + + foo.bar.SampleExceptionMapper is the implementation of + org.springframework.integration.message.InboundMessageMapper which only defines one method: toMessage(Object object). +{ + public Message toMessage(Throwable object) throws Exception { + MessageHandlingException ex = (MessageHandlingException) object; + return MessageBuilder.withPayload("Error happened in message: " + + ex.getFailedMessage().getPayload()).build(); + } + +} + ]]> + + + + + Exposing messaging system via POJO Gateway is obviously a great benefit, but it does come at the price so there + are certain things you must be aware of. + + We want our Java method to return as quick as possible and not hang for infinite amount of time until they can + return (void , exception or return value). When regular methods are used as a proxies in front of the Messaging + system we have to take into account the asynchronous nature of the Messaging Systems. This means that there might + be a chance that a Message hat was initiated by a Gateway could be dropped by a Filter, thus never reaching a + component that is responsible to produce a reply. Some Service Activator method might result in the Exception, + thus resulting in no-reply (as we don't generate Null messages).So as you can see there are multiple scenarios + where reply message might not be coming which is perfectly natural in messaging systems. However think about the + implication on the gateway method.  The Gateway's method input arguments  were incorporated into a Message and + sent downstream. The reply Message would be converted to a return value of the Gateway's method. So you can see + how ugly it could get if you can not guarantee that for each Gateway call there will alway be a reply Message. + Basically your Gateway method will never return and will hang infinitely. (work in progress!!!!) +One of the ways of handling this situation is via AsyncGateway (explained later in this section). Another way of handling it is to explicitly set the reply-timeout attribute. This way gateway will not hang for more then the time that was specified by the reply-timout and will return 'null'.  + + +
+
+ Asynchronous Gateway + + As a pattern the Messaging Gateway is a very nice way to hide messaging-specific code while still exposing the full capabilities of the + messaging system. And GatewayProxyFactoryBean provides a convenient way to expose a Proxy over a service-interface + thus giving you a POJO-based access to a messaging system (based on objects in your own domain, or primitives/Strings, etc).  But when a + gateway is exposed via simple POJO methods which return values it does imply that for each Request message (generated when the method is invoked) + there must be a Reply message (generated when the method has returned). Since Messaging systems naturally are asynchronous you may not always be + able to guarantee the contract where "for each request there will always be be a reply".  + With Spring Integration 2.0 we are introducing support for an Asynchronous Gateway which is a convenient way to initiate + flows where you may not know if a reply is expected or how long will it take for it to arrive. + + + A natural way to handle these types of scenarios in Java would be relying upon java.util.concurrent.Future instances, and + that is exactly what Spring Integration uses to support an Asynchronous Gateway. + + + From the XML configuration, there is nothing different and you still define Asynchronous Gateway the same way as a regular Gateway. + ]]> + However the Gateway Interface (service-interface) is a bit different. + + public interface MathServiceGateway { + Future<Integer> multiplyByTwo(int i); +} + + + As you can see from the example above the return type for the gateway method is Future. When + GatewayProxyFactoryBean sees that the + return type of the gateway method is Future, it immediately switches to the async mode by utilizing + an AsyncTaskExecutor. That is all. The call to a method always returns immediately with Future + encapsulating  the interaction with the framework. + Now you can interact with the Future at your own pace to get the result, timeout, get the exception etc... + MathServiceGateway mathService = ac.getBean("mathService", MathServiceGateway.class); +Future<Integer> result = mathService.multiplyByTwo(number); +// do something else here since the reply might take a moment +int finalResult =  result.get(1000, TimeUnit.SECONDS); +For a more detailed example, please refer to the async-gateway sample distributed within the Spring Integration samples. + + +
+
+ Gateway behavior when no response is coming + + As it was explained earlier, Gateway provides a convenient way of interacting with Messaging system via POJO method + invocations, but realizing that a typical method invocation, which is generally expected to always return (even with Exception), + might not always map one-to-one to message exchanges (e.g., reply message might not be coming which is equivalent to + method not returning), it is important to go over several scenarios especially in the Sync Gateway case and understand + what the default behavior of the Gateway and how to deal with these scenarios to make Sync Gateway behavior more + predictable regardless of the outcome of the message flow that was initialed from such Gateway. + + + There are certain attributes that could be configured to make Sync Gateway behavior more predictable, + but some of them might not always work as you might have expected. One of them is reply-timeout. + So, lets look at the reply-timeout attribute and see how it can/can't influence the behavior + of the Sync Gateway in various scenarios. We will look at single-theraded scenario + (all components downstream are connected via Direct Channel) and multi-theraded scenarios + (e.g., somewhere downstream you may have Pollable or Executor Channel which breaks single-thread boundary) + + + Long running process downstream + + + Sync Gateway - single-threaded. + If a component downstream is still running (e.g., infinite loop or a very slow service), then setting reply-timeout + has no effect and Gateway method call will not return until such downstream service exits (e.g., return or exception). + Sync Gateway - multi-threaded. + If a component downstream is still running (e.g., infinite loop or a very slow service), in a multi-threaded message + flow setting reply-timeout will have an effect by allowing gateway method invocation to + return once the timeout has been reached, since GatewayProxyFactoryBean  will simply + poll on the reply channel waiting for a message untill the timeout expires. However it could result in the 'null' return + from the Gateway method if the timeout has been reached before the actual reply was produced. It is also important to understand that + the reply message (if produced) will be sent to a reply channel after Gateway method invocation might have returned, so you must be aware of that + and design your flow with this in mind. + + + Downstream component returns 'null' + + + Sync Gateway - single-threaded. + If a component downstream returns 'null' and no reply-timeout has been configured, the Gateway + method call will hang indefinitely unless: a) reply-timeout has been configured or b) + requires-reply attribute has been set on the downstream component (e.g., service-activator) + that might return 'null'. In this case, the exception will be thrown and propagated to the Gateway. + Sync Gateway - multi-threaded. Behavior is the same as above. + + + Downstream component return signature is 'void' while Gateway method signature is non-void + + + Sync Gateway - single-threaded. + If a component downstream returns 'void' and no reply-timeout has been configured, + the Gateway method call will hang indefinitely unless reply-timeout has been configured  + Sync Gateway - multi-threaded Behavior is the same as above. + + + Downstream component results in Runtime Exception (regardless of the method signature) + + + Sync Gateway - single-threaded. + If a component downstream throws a Runtime Exception, such exception will be propagated via Error Message back to + the gateway and re-thrown. + Sync Gateway - multi-threaded Behavior is the same as above. + + + + It is also important to understand that by default reply-timout is unbounded which means that + if not explicitly set there are several scenarios (described above) where your Gateway method invocation might + hang indefinitely, so make sure you analyze your flow and if there is even a remote possibility of one of these + scenarios to occur, set the reply-timout attribute to a 'safe' value or better off + set the requires-reply attribute of the downstream component to 'true' to ensure a timely response. + But also, realize that there are some scenarios (see the very first one) + where reply-timout will not help which means it is also important to analyze your message + flow and decide when to use Sync Gateway vs Async Gateway where Gateway method invocation is always guaranteed + to return while giving you a more granular control over the results of the invocation via Java Futures. + + Also, when dealing with Router you should remember that seeting resolution-required attribute to 'true' + will result in the exception thrown by the router if it can not resolve a particular chanel. And when dealing with the filter + you can also set throw-exception-on-rejection attribute. Both of these will help to ensure a timely response + from the Gateway method invocation. + + + +
+ +
diff --git a/src/docbkx/groovy.xml b/docs/src/reference/docbook/groovy.xml similarity index 74% rename from src/docbkx/groovy.xml rename to docs/src/reference/docbook/groovy.xml index 1ee695ff97..d23bd712ba 100644 --- a/src/docbkx/groovy.xml +++ b/docs/src/reference/docbook/groovy.xml @@ -1,28 +1,27 @@ - - + Groovy support - - With Spring Integration 2.0 we've added Groovy support allowing you to use Groovy scripting language to provide - integration and business logic  for various integration components similar to the way Spring Expression Language (SpEL) - is use to implement routing, transformation and other integration concerns. - + + With Spring Integration 2.0 we've added Groovy support allowing you to use Groovy scripting language to provide + integration and business logic  for various integration components similar to the way Spring Expression Language (SpEL) + is use to implement routing, transformation and other integration concerns. + For more information about Groovy please refer to Groovy documentation which you can find here: http://groovy.codehaus.org/ - +
Groovy configuration - Depending on the complexity of your integration requirements Groovy scripts could be provided inline as CDATA in XML + Depending on the complexity of your integration requirements Groovy scripts could be provided inline as CDATA in XML configuration or as a reference to a file containing Groovy script. - - To enable Groovy support Spring Integration defines GroovyScriptExecutingMessageProcessor which will - create a groovy Binding object identifying Message Payload as payload variable and Message Headers as + + To enable Groovy support Spring Integration defines GroovyScriptExecutingMessageProcessor which will + create a groovy Binding object identifying Message Payload as payload variable and Message Headers as headers variable. All that is left for you to do is write script that uses these variables. Below are couple of sample configurations: - + Filter <filter input-channel="referencedScriptInput"> @@ -30,44 +29,44 @@ </filter> <filter input-channel="inlineScriptInput"> - <groovy:script><![CDATA[ + <groovy:script><![CDATA[ return payload == 'good' ]]></groovy:script> </filter> You see that script could be included inline or via location attribute using the groovy namespace sport.  - + Other supported elements are router, service-activator, transformer, splitter - + Another interesting aspect of using Groovy support is framework's ability to update (reload) scripts  without restarting the Application Context. To accomplish this all you need is specify refresh-check-delay attribute on script element. The reason for this attribute is to make reloading of the script more efficient.  - + ]]> - - In the above example for the next 5 seconds after you update the script you'll still be using the old script and - after 5 seconds the context will be updated with the new script. This is a good example where  'near real time' + + In the above example for the next 5 seconds after you update the script you'll still be using the old script and + after 5 seconds the context will be updated with the new script. This is a good example where  'near real time' is acceptable. - + ]]> - - In the above example the context will be updated with the new script every time the script is modified. Basically this is the example of the + + In the above example the context will be updated with the new script every time the script is modified. Basically this is the example of the 'real-time' and might not be the most efficient way. - + ]]> - - - Any negative number value means the script will never be refreshed after initial initialization of application context. + + + Any negative number value means the script will never be refreshed after initial initialization of application context. DEFAULT BEHAVIOR - + Inline defined script can not be reloaded. - + - +
-
\ No newline at end of file +
diff --git a/docs/src/reference/docbook/http.xml b/docs/src/reference/docbook/http.xml new file mode 100644 index 0000000000..e25a5671e3 --- /dev/null +++ b/docs/src/reference/docbook/http.xml @@ -0,0 +1,210 @@ + + + HTTP Support + +
+ Introduction + + The HTTP support allows for the execution of HTTP requests and the processing of inbound HTTP requests. Because interaction over HTTP is always synchronous, even if all that is returned is a 200 status code, the HTTP support consists of two gateway implementations: + HttpInboundEndpoint and HttpRequestExecutingMessageHandler. + +
+ +
+ Http Inbound Gateway + + To receive messages over HTTP you need to use an HTTP inbound Channel Adapter or Gateway. In common with the HttpInvoker + support the HTTP inbound adapters need to be deployed within a servlet container. The easiest way to do this is to provide a servlet + definition in web.xml, see + for further details. Below is an example bean definition for a simple HTTP inbound endpoint. + + + +]]> + The HttpRequestHandlingMessagingGateway accepts a list of HttpMessageConverter instances or else + relies on a default list. The converters allow + customization of the mapping from HttpServletRequest to Message. The default converters + encapsulate simple strategies, which for + example will create a String message for a POST request where the content type starts with "text", see the Javadoc for + full details. + + Starting with this release MultiPart File support was implemented. If the request has been wrapped as a + MultipartHttpServletRequest, when using the default converters, that request will be converted + to a Message payload that is a MultiValueMap containing values that may be byte arrays, Strings, or instances of + Spring's MultipartFile depending on the content type of the individual parts. + + The HTTP inbound Endpoint will locate a MultipartResolver in the context if one exists with the bean name + "multipartResolver" (the same name expected by Spring's DispatcherServlet). If it does in fact locate that + bean, then the support for MultipartFiles will be enabled on the inbound request mapper. Otherwise, it will + fail when trying to map a multipart-file request to a Spring Integration Message. For more on Spring's + support for MultipartResolvers, refer to the Spring Reference Manual. + + + + In sending a response to the client there are a number of ways to customize the behavior of the gateway. By default the gateway will + simply acknowledge that the request was received by sending a 200 status code back. It is possible to customize this response by providing a + 'viewName' to be resolved by the Spring MVC ViewResolver. + In the case that the gateway should expect a reply to the Message then setting the expectReply flag + (constructor argument) will cause + the gateway to wait for a reply Message before creating an HTTP response. Below is an example of a gateway + configured to serve as a Spring MVC Controller with a view name. Because of the constructor arg value of TRUE, it wait for a reply. This also shows + how to customize the HTTP methods accepted by the gateway, which + are POST and GET by default. + + + + + + + + GET + DELETE + + + +]]> + The reply message will be available in the Model map. The key that is used + for that map entry by default is 'reply', but this can be overridden by setting the + 'replyKey' property on the endpoint's configuration. + +
+ +
+ Http Outbound Gateway + + + To configure the HttpRequestExecutingMessageHandler write a bean definition like this: + + + +]]> + This bean definition will execute HTTP requests by delegating to a RestTemplate. That template in turn delegates + to a list of HttpMessageConverters to generate the HTTP request body from the Message payload. You can configure those converters as well + as the ClientHttpRequestFactory instance to use: + + + + + +]]> +By default the HTTP request will be generated using an instance of SimpleClientHttpRequestFactory which uses the JDK + HttpURLConnection. Use of the Apache Commons HTTP Client is also supported through the provided + CommonsClientHttpRequestFactory which can be injected as shown above. + +
+ +
+ HTTP Namespace Support + + Spring Integration provides an "http" namespace and schema definition. To include it in your + configuration, simply provide the following URI within a namespace declaration: + 'http://www.springframework.org/schema/integration/http'. The schema location should then map to + 'http://www.springframework.org/schema/integration/http/spring-integration-http.xsd'. + + + To configure an inbound http channel adapter which is an instance of HttpInboundEndpoint configured + not to expect a response. + ]]> + + + To configure an inbound http gateway which expects a response. + ]]> + + + To configure the outbound gateway you can use the namespace support as well. The following code snippet shows the different configuration options for an outbound Http gateway. Most importantly, notice that the 'http-method' and 'expected-response-type' are provided. Those are two of the most commonly configured values. The + default http-method is POST, and the default response type is null. With a null response type, the payload of the reply Message would only + contain the status code (e.g. 200) as long as it's a successful status (non-successful status codes will throw Exceptions). If you are expecting a different + type, such as a String, then provide that fully-qualified class name as shown below. + ]]> + + If your outbound adapter is to be used in a unidirectional way, then you can use an outbound-channel-adapter instead. This means that + a successful response will simply execute without sending any Messages to a reply channel. In the case of any non-successful response + status code, it will throw an exception. The configuration looks very similar to the gateway: + ]]> + +
+
+ HTTP Samples +
+ Multipart HTTP request - RestTemplate (client) and Http Inbound Gateway (server) + + This example demonstrates how simple it is to send a Multipart HTTP request via Spring's RestTemplate and receive it by Spring Integration HTTP Inbound Adapter. +All we are doing is creating MultiValueMap and populating it with multi-part data. RestTemplate will take care of the rest +by converting it to MultipartHttpServletRequest   +THis particular client will send a multipart Http Request which contains the name of the company as well as the image file with company logo. + httpResponse = template.exchange(uri, HttpMethod.POST, request, null);]]> + + +That is all for the client. + + +On the server side we have the following configuration: + + + + + + + + + +]]> + + +The 'httpInboundAdapter' will receive the request, convert it to a Message with a payload as LinkedMultiValueMap which +we are parsing in the 'multipartReceiver' service-activator; + multipartRequest){ + System.out.println("### Successfully recieved multipart request ###"); + for (String elementName : multipartRequest.keySet()) { + if (elementName.equals("company")){ + System.out.println("\t" + elementName + " - " + + ((String[]) multipartRequest.getFirst("company"))[0]); + } else if (elementName.equals("company-logo")){ + System.out.println("\t" + elementName + " - as UploadedMultipartFile: " + + ((UploadedMultipartFile) multipartRequest.getFirst("company-logo")).getOriginalFilename()); + } + } +} + +]]> +You should see the following output: + + +
+
+
diff --git a/src/docbkx/httpinvoker.xml b/docs/src/reference/docbook/httpinvoker.xml similarity index 54% rename from src/docbkx/httpinvoker.xml rename to docs/src/reference/docbook/httpinvoker.xml index 1686072eed..a28f86d6f8 100644 --- a/src/docbkx/httpinvoker.xml +++ b/docs/src/reference/docbook/httpinvoker.xml @@ -1,6 +1,6 @@ - - + HttpInvoker Support
@@ -28,69 +28,69 @@
HttpInvoker Inbound Gateway - To receive messages over http you can use an HttpInvokerInboundGateway. Here is an - example bean definition: - HttpInvokerInboundGateway. Here is an + example bean definition: + ]]> - Because the inbound gateway must be able to receive HTTP requests, it must be configured within a Servlet - container. The easiest way to do this is to provide a servlet definition in web.xml: - + Because the inbound gateway must be able to receive HTTP requests, it must be configured within a Servlet + container. The easiest way to do this is to provide a servlet definition in web.xml: + inboundGateway org.springframework.web.context.support.HttpRequestHandlerServlet ]]> - Notice that the servlet name matches the bean name. - - If you are running within a Spring MVC application and using the BeanNameHandlerMapping, then the servlet - definition is not necessary. In that case, the bean name for your gateway can be matched against the URL - path just like a Spring MVC Controller bean. - + Notice that the servlet name matches the bean name. + + If you are running within a Spring MVC application and using the BeanNameHandlerMapping, then the servlet + definition is not necessary. In that case, the bean name for your gateway can be matched against the URL + path just like a Spring MVC Controller bean. +
HttpInvoker Outbound Gateway - - - To configure the HttpInvokerOutboundGateway write a bean definition like this: - + + To configure the HttpInvokerOutboundGateway write a bean definition like this: + ]]> - The outbound gateway is a MessageHandler and can therefore be registered with - either a PollingConsumer or EventDrivenConsumer. - The URL must match that defined by an inbound HttpInvoker Gateway as described in the previous section. + The outbound gateway is a MessageHandler and can therefore be registered with + either a PollingConsumer or EventDrivenConsumer. + The URL must match that defined by an inbound HttpInvoker Gateway as described in the previous section.
HttpInvoker Namespace Support - - Spring Integration provides an "httpinvoker" namespace and schema definition. To include it in your - configuration, simply provide the following URI within a namespace declaration: - 'http://www.springframework.org/schema/integration/httpinvoker'. The schema location should then map to - 'http://www.springframework.org/schema/integration/httpinvoker/spring-integration-httpinvoker-2.0.xsd'. - + + Spring Integration provides an "httpinvoker" namespace and schema definition. To include it in your + configuration, simply provide the following URI within a namespace declaration: + 'http://www.springframework.org/schema/integration/httpinvoker'. The schema location should then map to + 'http://www.springframework.org/schema/integration/httpinvoker/spring-integration-httpinvoker-2.0.xsd'. + - To configure the inbound gateway you can choose to use the namespace support for it. The following code snippet shows the different configuration options that are supported. - ]]> - - A 'reply-channel' may also be provided, but it is recommended to rely on the temporary anonymous channel - that will be created automatically for handling replies. - + + A 'reply-channel' may also be provided, but it is recommended to rely on the temporary anonymous channel + that will be created automatically for handling replies. + - To configure the outbound gateway you can use the namespace support as well. The following code snippet shows the different configuration for an outbound HttpInvoker gateway. Only the 'url' and 'request-channel' are required. - ]]>
- \ No newline at end of file + diff --git a/src/docbkx/index.xml b/docs/src/reference/docbook/index.xml similarity index 86% rename from src/docbkx/index.xml rename to docs/src/reference/docbook/index.xml index ceab56dd45..5b6086cc61 100644 --- a/src/docbkx/index.xml +++ b/docs/src/reference/docbook/index.xml @@ -1,16 +1,17 @@ - - + Spring Integration Reference Manual - Spring Integration &version; + Spring Integration ${version} Spring Integration - &version; + ${version} - @@ -50,7 +51,7 @@ - © SpringSource Inc., 2010 + © SpringSource Inc., 2010 diff --git a/src/docbkx/ip.xml b/docs/src/reference/docbook/ip.xml similarity index 79% rename from src/docbkx/ip.xml rename to docs/src/reference/docbook/ip.xml index 552e6be8da..9f3dd98307 100644 --- a/src/docbkx/ip.xml +++ b/docs/src/reference/docbook/ip.xml @@ -1,20 +1,20 @@ - - + TCP and UDP Support - Spring Integration provides Channel Adapters for receiving and sending messages over internet protocols. Both UDP + Spring Integration provides Channel Adapters for receiving and sending messages over internet protocols. Both UDP (User Datagram Protocol) - and TCP (Transmission Control Protocol) adapters are provided. Each adapter provides for one-way communication + and TCP (Transmission Control Protocol) adapters are provided. Each adapter provides for one-way communication over the underlying protocol. In addition, simple inbound and outbound tcp gateways are provided. These are used when two-way communication is - needed. + needed.
Introduction Two flavors each of UDP inbound and outbound adapters are provided UnicastSendingMessageHandler - sends a datagram packet to a single destination. UnicastReceivingChannelAdapter receives + sends a datagram packet to a single destination. UnicastReceivingChannelAdapter receives incoming datagram packets. MulticastSendingMessageHandler sends (broadcasts) datagram packets to a multicast address. MulticastReceivingChannelAdapter receives incoming datagram packets by joining to a multicast address. @@ -30,104 +30,104 @@ is configured for single use connections, the connection is closed after the socket times out. - An outbound TCP gateway is provided; this allows for simple request/response processing. - If the associated connection factory is configured for single use connections, a new connection is + An outbound TCP gateway is provided; this allows for simple request/response processing. + If the associated connection factory is configured for single use connections, a new connection is immediately created for each new request. Otherwise, if the connection is in use, the calling thread blocks on the connection until either a response is received or a timeout - or I/O error occurs. + or I/O error occurs.
UDP Adapters ]]> - A simple UDP outbound channel adapter. - - When setting multicast to true, provide the multicast address in the host - attribute. - + host="somehost" + port="11111" + multicast="false" + channel="exampleChannel" />]]> + A simple UDP outbound channel adapter. + + When setting multicast to true, provide the multicast address in the host + attribute. + - UDP is an efficient, but unreliable protocol. Two attributes are added to improve reliability. When check-length is - set to true, the adapter precedes the message data with a length field (4 bytes in network byte order). This enables - the receiving side to verify the length of the packet received. If a receiving system uses a buffer that is too - short the contain the packet, the packet can be truncated. The length header provides a mechanism to detect this. + UDP is an efficient, but unreliable protocol. Two attributes are added to improve reliability. When check-length is + set to true, the adapter precedes the message data with a length field (4 bytes in network byte order). This enables + the receiving side to verify the length of the packet received. If a receiving system uses a buffer that is too + short the contain the packet, the packet can be truncated. The length header provides a mechanism to detect this. ]]> - An outbound channel adapter that adds length checking to the datagram packets. - - The recipient of the packet must also be configured to expect a length to precede the - actual data. For a Spring Integration UDP inbound channel adapter, set its - check-length attribute. - + host="somehost" + port="11111" + multicast="false" + check-length="true" + channel="exampleChannel" />]]> + An outbound channel adapter that adds length checking to the datagram packets. + + The recipient of the packet must also be configured to expect a length to precede the + actual data. For a Spring Integration UDP inbound channel adapter, set its + check-length attribute. + - The second reliability improvement allows an application-level acknowledgment protocol to be used. The receiver - must send an acknowledgment to the sender within a specified time. + The second reliability improvement allows an application-level acknowledgment protocol to be used. The receiver + must send an acknowledgment to the sender within a specified time. ]]> - An outbound channel adapter that adds length checking to the datagram packets and waits for an acknowledgment. - - Setting acknowledge to true implies the recipient of the packet can interpret the header added to the packet - containing acknowledgment data (host and port). Most likely, the recipient will be a Spring Integration inbound - channel adapter. - - - When multicast is true, an additional attribute min-acks-for-success specifies - how many acknowledgments must be received within the ack-timeout. - + host="somehost" + port="11111" + multicast="false" + check-length="true" + acknowledge="true" + ack-host="thishost" + ack-port="22222" + ack-timeout="10000" + channel="exampleChannel" />]]> + An outbound channel adapter that adds length checking to the datagram packets and waits for an acknowledgment. + + Setting acknowledge to true implies the recipient of the packet can interpret the header added to the packet + containing acknowledgment data (host and port). Most likely, the recipient will be a Spring Integration inbound + channel adapter. + + + When multicast is true, an additional attribute min-acks-for-success specifies + how many acknowledgments must be received within the ack-timeout. + - For even more reliable networking, TCP can be used. + For even more reliable networking, TCP can be used. - ]]> - A basic unicast inbound udp channel adapter. + ]]> + A basic unicast inbound udp channel adapter. - ]]> - A basic multicast inbound udp channel adapter. + ]]> + A basic multicast inbound udp channel adapter.
TCP Connection Factories For TCP, the configuration of the underlying connection is provided using a - Connection Factory. Two types of connection factory are provided; a + Connection Factory. Two types of connection factory are provided; a client connection factory and a server connection factory. Client connection factories are used to establish outgoing connections; Server connection factories - listen for incoming connections. + listen for incoming connections. A client connection factory is used @@ -141,10 +141,10 @@ connection factory can also be provided to an outbound adapter; that adapter can then be used to send replies to incoming messages to the same connection. Reply messages will only be routed to the connection if the reply contains - the header $ip_connection_id that was inserted into the original message by - the connection factory. + the header $ip_connection_id that was inserted into the original message by + the connection factory. This is the extent of message correlation performed when sharing connection - factories between inbound and outbound adapters. Such sharing allows for + factories between inbound and outbound adapters. Such sharing allows for asynchronous two-way communication over TCP. Only payload information is transferred using TCP; therefore any message correlation must be performed by downstream components such as aggregators or other endpoints. @@ -154,114 +154,114 @@ factory. - Connection factories using java.net.Socket and + Connection factories using java.net.Socket and java.nio.channel.SocketChannel are provided. ]]> + ]]> A simple server connection factory that uses java.net.Socket connections. ]]> + />]]> A simple server connection factory that uses java.nio.channel.SocketChannel connections. ]]> + ]]> A client connection factory that uses java.net.Socket - connections and creates a new connection for each message. + connections and creates a new connection for each message. ]]> + />]]> A client connection factory that uses java.nio.channel.Socket connections and creates a new connection for each message. - TCP is a streaming protocol; this means that some structure has to be provided to data + TCP is a streaming protocol; this means that some structure has to be provided to data transported over TCP, so the receiver can demarcate the data into discrete messages. - Connection factories are configured to use (de)serializers to convert between the message - payload and the bits that are sent over TCP. This is accomplished by providing a + Connection factories are configured to use (de)serializers to convert between the message + payload and the bits that are sent over TCP. This is accomplished by providing a deserializer and serializer for inbound and outbound messages respectively. Four standard (de)serializers are provided; the first is ByteArrayCrlfSerializer, - which can convert a byte array to a stream of bytes followed by carriage - return and linefeed characters (\r\n). This is the default (de)serializer and can be used with + which can convert a byte array to a stream of bytes followed by carriage + return and linefeed characters (\r\n). This is the default (de)serializer and can be used with telnet as a client, for example. The second is is ByteArrayStxEtxSerializer, which can convert a byte array to a stream of bytes preceded by an STX (0x02) and followed by an ETX (0x03). The third is ByteArrayLengthHeaderSerializer, which can convert a byte array to a stream of bytes preceded by a 4 byte binary - length in network byte order. Each of these is a subclass of + length in network byte order. Each of these is a subclass of AbstractByteArraySerializer which implements both - org.springframework.core.serializer.Serializer and + org.springframework.core.serializer.Serializer and org.springframework.core.serializer.Deserializer. For backwards compatibility, connections using any subclass of AbstractByteArraySerializer for serialization will also accept a String which will be converted to a byte array first. - Each of these (de)serializers converts an input stream containing the - corresponding format to a byte array payload. The fourth standard serializer is + Each of these (de)serializers converts an input stream containing the + corresponding format to a byte array payload. The fourth standard serializer is org.springframework.core.serializer.DefaultSerializer which can be - used to convert Serializable objects using java serialization. + used to convert Serializable objects using java serialization. org.springframework.core.serializer.DefaultDeserializer is provided for inbound deserialization of streams containing Serializable objects. - To implement a custom (de)serializer pair, implement the + To implement a custom (de)serializer pair, implement the org.springframework.core.serializer.Deserializer and org.springframework.core.serializer.Serializer interfaces. If you do not wish to use - the default (de)serializer (ByteArrayCrLfSerializer), you must supply - serializer and + the default (de)serializer (ByteArrayCrLfSerializer), you must supply + serializer and deserializer attributes on the connection factory (example below). - - ]]> + />]]> A server connection factory that uses java.net.Socket connections and uses Java serialization on the wire. - For full details of the attributes available on connection factories, see the + For full details of the attributes available on connection factories, see the reference at the end of this section.
Tcp Connection Interceptors - Connection factories can be configured with a reference to a + Connection factories can be configured with a reference to a TcpConnectionInterceptorFactoryChain. Interceptors can be used to add behavior to connections, such as negotiation, security, and other setup. - No interceptors are currently provided by the framework but, for an example, + No interceptors are currently provided by the framework but, for an example, see the InterceptedSharedConnectionTests in the source repository. @@ -272,8 +272,8 @@ When configured with a client connection factory, when the first message is sent over a connection that is intercepted, the interceptor sends 'Hello' over the connection, and expects to receive 'world!'. When that occurs, - the negotiation is complete and the original message is sent; further messages - that use the same connection are sent without any additional negotiation. + the negotiation is complete and the original message is sent; further messages + that use the same connection are sent without any additional negotiation. When configured with a server connection factory, the interceptor requires the first @@ -282,20 +282,20 @@ All TcpConnection methods are intercepted. - Interceptor instances are created for each connection by an interceptor factory. - If an interceptor is stateful, the factory should create a new instance for each connection. + Interceptor instances are created for each connection by an interceptor factory. + If an interceptor is stateful, the factory should create a new instance for each connection. Interceptor factories are added to the configuration of an interceptor factory chain, which is provided to a connection factory using the interceptor-factory attribute. Interceptors must implement the TcpConnectionInterceptor interface; factories - must implement the TcpConnectionInterceptorFactory interface. A + must implement the TcpConnectionInterceptorFactory interface. A convenience class AbstractTcpConnectionInterceptor is provided with passthrough methods; by extending this class, you only need to implement those methods you wish to intercept. - @@ -303,23 +303,23 @@ - + ]]> Configuring a connection interceptor factory chain. @@ -327,7 +327,7 @@
TCP Adapters - TCP inbound and outbound channel adapters that utilize the above connection + TCP inbound and outbound channel adapters that utilize the above connection factories are provided. These adapters have just 2 attributes connection-factory and channel. The channel attribute specifies the channel on which messages arrive at an @@ -341,58 +341,58 @@ - - + - - - - - - - + - - - - - - - + - ]]> + + + + + + + + + + + + + ]]> In this configuration, messages arriving in channel 'input' are serialized over connections created by 'client' received at the server and placed on channel 'loop'. Since 'loop' is the input channel for 'outboundServer' the message is simply - looped back over the same connection and received by + looped back over the same connection and received by 'inboundClient' and deposited in channel 'replies'. Java serialization is used on the wire. @@ -403,47 +403,47 @@ The inbound TCP gateway TcpInboundGateway and oubound TCP gateway TcpOutboundGateway use a server and client connection factory respectively. Each connection - can process a single request/response at a time. - - + can process a single request/response at a time. + + The intbound gateway, after constructing a message with the incoming payload and sending - it to the requestChannel, waits for a response and sends the payload - from the response message by writing it to the connection. - - + it to the requestChannel, waits for a response and sends the payload + from the response message by writing it to the connection. + + The outbound gateway, after sending a message over the connection, waits for a response and - constructs a response message and puts in on the reply channel. - Communications over the connections are single-threaded. Users should be aware that only one - message can be handled at a time and, if another thread attempts to send - a message before the current response has been received, it will block until - any previous requests are complete (or time out). - If, however, the client connection factory is configured for single-use connections + constructs a response message and puts in on the reply channel. + Communications over the connections are single-threaded. Users should be aware that only one + message can be handled at a time and, if another thread attempts to send + a message before the current response has been received, it will block until + any previous requests are complete (or time out). + If, however, the client connection factory is configured for single-use connections each new request gets its own connection and is processed immediately. - + - ]]> - A simple inbound TCP gateway; if a connection factory configured with the default + A simple inbound TCP gateway; if a connection factory configured with the default (de)serializer is used, messages will be \r\n delimited data and the gateway can be - used by a simple client such as telnet. - + used by a simple client such as telnet. + - ]]> - A simple oubound TCP gateway. - -
+ ]]> + A simple oubound TCP gateway. + +
IP Configuration Attributes @@ -517,7 +517,7 @@ N true, false When using NIO, whether or not the tcp adapter uses direct buffers. - Refer to java.nio.ByteBuffer documentation for + Refer to java.nio.ByteBuffer documentation for more information. Must be false if using-nio is false. @@ -556,7 +556,7 @@ Y Y - Sets linger to true with supplied value. + Sets linger to true with supplied value. See java.net.Socket. setSoLinger(). @@ -578,7 +578,7 @@ N Y - On a multi-homed system, specifies an IP address + On a multi-homed system, specifies an IP address for the interface to which the socket will be bound. @@ -590,7 +590,7 @@ Specifies a specific Executor to be used for socket handling. If not supplied, an internal pooled executor will be used. Needed on some platforms that require the use of specific - task executors such as a WorkManagerTaskExecutor. See pool-size for thread + task executors such as a WorkManagerTaskExecutor. See pool-size for thread requirements, depending on other options. @@ -606,12 +606,12 @@ Y Y - Specifies the concurrency. For tcp, not using nio, specifies the + Specifies the concurrency. For tcp, not using nio, specifies the number of concurrent connections supported by the adapter. For tcp, using nio, specifies the number of tcp fragments that are concurrently - reassembled into complete messages. - It only applies in this sense if task-executor is not configured. - However, pool-size is also used for the server socket backlog, + reassembled into complete messages. + It only applies in this sense if task-executor is not configured. + However, pool-size is also used for the server socket backlog, regardless of whether an external task executor is used. Defaults to 5. @@ -658,7 +658,7 @@ acknowledge true, false - Whether or not a udp adapter requires an acknowledgment from the destination. + Whether or not a udp adapter requires an acknowledgment from the destination. when enabled, requires setting the following 4 attributes. @@ -666,7 +666,7 @@ When acknowledge is true, indicates the host or ip address to which the acknowledgment should be sent. Usually the current host, but may be - different, for example when Network Address Transation (NAT) is + different, for example when Network Address Transation (NAT) is being used. @@ -692,14 +692,14 @@ check-length true, false - Whether or not a udp adapter includes a data length field in the + Whether or not a udp adapter includes a data length field in the packet sent to the destination. time-to-live For multicast adapters, specifies the time to live attribute for - the MulticastSocket; controls the scope + the MulticastSocket; controls the scope of the multicasts. Refer to the Java API documentation for more information. @@ -724,7 +724,7 @@ local-address - On a multi-homed system, for the UDP adapter, specifies an IP address + On a multi-homed system, for the UDP adapter, specifies an IP address for the interface to which the socket will be bound for reply messages. For a multicast adapter it is also used to determine which interface the multicast packets will be sent over. @@ -735,7 +735,7 @@ Specifies a specific Executor to be used for acknowledgment handling. If not supplied, an internal single threaded executor will be used. Needed on some platforms that require the use of specific - task executors such as a WorkManagerTaskExecutor. One thread will be dedicated to handling + task executors such as a WorkManagerTaskExecutor. One thread will be dedicated to handling acknowledgments (if the acknowledge option is true). @@ -775,9 +775,9 @@ pool-size - Specifies the concurrency. Specifies how many packets can - be handled concurrently. - It only applies if task-executor is not configured. + Specifies the concurrency. Specifies how many packets can + be handled concurrently. + It only applies if task-executor is not configured. Defaults to 5. @@ -786,21 +786,21 @@ Specifies a specific Executor to be used for socket handling. If not supplied, an internal pooled executor will be used. Needed on some platforms that require the use of specific - task executors such as a WorkManagerTaskExecutor. See pool-size for thread + task executors such as a WorkManagerTaskExecutor. See pool-size for thread requirements. receive-buffer-size - The size of the buffer used to receive DatagramPackets. - Usually set to the MTU size. If a smaller buffer is used than the + The size of the buffer used to receive DatagramPackets. + Usually set to the MTU size. If a smaller buffer is used than the size of the sent packet, truncation can occur. This can be detected by means of the check-length attribute.. check-length true, false - Whether or not a udp adapter expects a data length field in the + Whether or not a udp adapter expects a data length field in the packet received. Used to detect packet truncation. @@ -824,7 +824,7 @@ local-address - On a multi-homed system, specifies an IP address + On a multi-homed system, specifies an IP address for the interface to which the socket will be bound. diff --git a/src/docbkx/jdbc.xml b/docs/src/reference/docbook/jdbc.xml similarity index 95% rename from src/docbkx/jdbc.xml rename to docs/src/reference/docbook/jdbc.xml index a34d208830..1a1b498625 100644 --- a/src/docbkx/jdbc.xml +++ b/docs/src/reference/docbook/jdbc.xml @@ -1,7 +1,6 @@ - - + JDBC Support Spring Integration provides Channel Adapters for receiving and sending @@ -39,11 +38,11 @@ the parameter map for the update called "id"). The following example defines an inbound Channel Adapter with an update query and a DataSource reference. <jdbc:inbound-channel-adapter query="select * from item where status=2" - channel="target" data-source="dataSource" + language="xml"><jdbc:inbound-channel-adapter query="select * from item where status=2" + channel="target" data-source="dataSource" update="update item set status=10 where id in (:id)" /> - The parameters in the update query are specified with a colon (:) prefix to the name of a parameter (which in this case is an expression to be applied to each of the rows in the polled result set). This is a standard feature of the named parameter JDBC support in Spring JDBC combined with a convention (projection onto the polled result list) adopted in Spring Integration. The underlying Spring JDBC features limit the available expressions (e.g. most special characters other than period are disallowed), but since the target is usually a list of or an individual object addressable by simple bean paths this isn't unduly restrictive. + The parameters in the update query are specified with a colon (:) prefix to the name of a parameter (which in this case is an expression to be applied to each of the rows in the polled result set). This is a standard feature of the named parameter JDBC support in Spring JDBC combined with a convention (projection onto the polled result list) adopted in Spring Integration. The underlying Spring JDBC features limit the available expressions (e.g. most special characters other than period are disallowed), but since the target is usually a list of or an individual object addressable by simple bean paths this isn't unduly restrictive. To change the parameter generation strategy you can inject a SqlParameterSourceFactory into the adapter to override the default behaviour (the adapter has a @@ -57,8 +56,8 @@ controlled. A very important feature of the poller for JDBC usage is the option to wrap the poll operation in a transaction, for example: - <jdbc:inbound-channel-adapter query="..." - channel="target" data-source="dataSource" + <jdbc:inbound-channel-adapter query="..." + channel="target" data-source="dataSource" update="..."> <poller fixed-rate"1000"> <transactional/> @@ -66,7 +65,7 @@ </jdbc:inbound-channel-adapter> - If a poller is not explicitly specified a default value will be used (and as per normal with Spring Integration can be defined as a top level bean) + If a poller is not explicitly specified a default value will be used (and as per normal with Spring Integration can be defined as a top level bean) In this example the database is polled every 1000 milliseconds, and the update and select queries are both executed in the same transaction. The transaction manager configuration is not shown, @@ -85,21 +84,21 @@ The outbound Channel Adapter is the inverse of the inbound: its role is to handle a message and use it to execute a SQL query. The message payload and headers are available by default as input parameters to the - query, for instance: <jdbc:outbound-channel-adapter + query, for instance: <jdbc:outbound-channel-adapter query="insert into foos (id, status, name) values (:headers[$id], 0, :payload[foo])" channel="input" data-source="dataSource"/> In the example above, messages arriving on the channel "input" have a payload of a map with key "foo", so the [] operator dereferences that value from the map. The headers are also accessed as a map. - The parameters in the query above are bean property expressions on the incoming message (not Spring EL expressions). This behaviour is part of the + The parameters in the query above are bean property expressions on the incoming message (not Spring EL expressions). This behaviour is part of the SqlParameterSource - which is the default source created by the outbound adapter. Other behaviour is possible in the adapter, and requires the user to inject a different + which is the default source created by the outbound adapter. Other behaviour is possible in the adapter, and requires the user to inject a different SqlParameterSourceFactory - . + . The outbound adapter requires a reference to either a DataSource or @@ -119,7 +118,7 @@ inbound adapters: its role is to handle a message and use it to execute a SQL query and then respond with the result sending it to a reply channel. The message payload and headers are available by default as input - parameters to the query, for instance: <jdbc:outbound-gateway + parameters to the query, for instance: <jdbc:outbound-gateway update="insert into foos (id, status, name) values (:headers[$id], 0, :payload[foo])" request-channel="input" reply-channel="output" data-source="dataSource" /> @@ -133,16 +132,16 @@ the default because it is not supported by some database platforms). For example: - <jdbc:outbound-gateway + <jdbc:outbound-gateway update="insert into foos (status, name) values (0, :payload[foo])" - request-channel="input" reply-channel="output" data-source="dataSource" + request-channel="input" reply-channel="output" data-source="dataSource" keys-generated="true"/> Instead of the update count or the generated keys, you can also provide a select query to execute and generate a reply message that way (like the inbound adapter), e.g: - <jdbc:outbound-gateway + <jdbc:outbound-gateway update="insert into foos (id, status, name) values (:headers[$id], 0, :payload[foo])" query="select * from foos where id=:headers[$id]" request-channel="input" reply-channel="output" data-source="dataSource" /> diff --git a/src/docbkx/jms.xml b/docs/src/reference/docbook/jms.xml similarity index 99% rename from src/docbkx/jms.xml rename to docs/src/reference/docbook/jms.xml index 87af25608a..98f875935b 100644 --- a/src/docbkx/jms.xml +++ b/docs/src/reference/docbook/jms.xml @@ -1,7 +1,6 @@ - - + JMS Support Spring Integration provides Channel Adapters for receiving and sending JMS messages. There are actually two @@ -309,4 +308,4 @@
-
\ No newline at end of file +
diff --git a/src/docbkx/jmx.xml b/docs/src/reference/docbook/jmx.xml similarity index 97% rename from src/docbkx/jmx.xml rename to docs/src/reference/docbook/jmx.xml index e96cb57809..d9802cd296 100644 --- a/src/docbkx/jmx.xml +++ b/docs/src/reference/docbook/jmx.xml @@ -1,7 +1,6 @@ - - + JMX Support Spring Integration provides Channel Adapters for receiving and @@ -19,11 +18,11 @@ channel="channel" object-name="example.domain:name=publisher"/> - The + The notification-listening-channel-adapter - registers with an MBeanServer at startup, and the default bean name is "mbeanServer" which happens to be the same bean name generated when using Spring's <context:mbean-server/> element. If you need to use a different name be sure to include the "mbean-server" attribute. + registers with an MBeanServer at startup, and the default bean name is "mbeanServer" which happens to be the same bean name generated when using Spring's <context:mbean-server/> element. If you need to use a different name be sure to include the "mbean-server" attribute. The adapter can also accept a reference to a NotificationFilter and a "handback" Object to provide some context that is passed back with each Notification. Both of those attributes are optional. Extending the @@ -47,7 +46,7 @@ only requires a JMX ObjectName in its configuration as shown below. <context:mbean:export/> - <jmx:notification-publishing-channel-adapter id="adapter" + <jmx:notification-publishing-channel-adapter id="adapter" channel="channel" object-name="example.domain:name=publisher"/> It does also require that an MBeanExporter be present in the @@ -67,7 +66,7 @@ fallback "default-notification-type" attribute provided in the configuration. <context:mbean:export/> - <jmx:notification-publishing-channel-adapter id="adapter" + <jmx:notification-publishing-channel-adapter id="adapter" channel="channel" object-name="example.domain:name=publisher" default-notification-type="some.default.type"/> diff --git a/src/docbkx/mail.xml b/docs/src/reference/docbook/mail.xml similarity index 83% rename from src/docbkx/mail.xml rename to docs/src/reference/docbook/mail.xml index 070efcf4e8..842224a0eb 100644 --- a/src/docbkx/mail.xml +++ b/docs/src/reference/docbook/mail.xml @@ -1,6 +1,6 @@ - - + Mail Support
@@ -14,14 +14,14 @@ MailSendingMessageHandler mailSendingHandler = new MailSendingMessageHandler(mailSender); MailSendingMessageHandler has various mapping strategies that use Spring's MailMessage abstraction. If the received Message's payload is already - a MailMessage instance, it will be sent directly. + a MailMessage instance, it will be sent directly. Therefore, it is generally recommended to precede this consumer with a Transformer for non-trivial MailMessage construction requirements. However, a few simple Message mapping strategies are supported out-of-the-box. For example, if the message payload is a byte array, then that will be mapped to an attachment. For simple text-based emails, you can provide a String-based Message payload. In that case, a MailMessage will be created with that String as the text content. If you are working with a Message payload type whose toString() method returns appropriate mail text content, then - consider adding Spring Integration's ObjectToStringTransformer prior to the outbound + consider adding Spring Integration's ObjectToStringTransformer prior to the outbound Mail adapter (see the example within for more detail). @@ -37,9 +37,9 @@ MailHeaders.REPLY_TO - MailHeaders also allows you to override corresponding MailMessage values. - For example: If MailMessage.to is set to 'foo@bar.com' and MailHeaders.TO - Message header is provided it will take precedence and override the corresponding value in MailMessage + MailHeaders also allows you to override corresponding MailMessage values. + For example: If MailMessage.to is set to 'foo@bar.com' and MailHeaders.TO + Message header is provided it will take precedence and override the corresponding value in MailMessage
@@ -93,35 +93,35 @@ mail server supports IMAP IDLE - if not, then polling is the only option). A polling Channel Adapter simply requires the store URI and the channel to send inbound Messages to. The URI may begin with "pop3" or "imap": - + store-uri="imaps://[username]:[password]@imap.gmail.com/INBOX" + java-mail-properties="javaMailProperties" + channel="recieveChannel" + should-delete-messages="true" + should-mark-messages-as-read="true" + auto-startup="true"> + ]]> If you do have IMAP idle support, then you may want to configure the "imap-idle-channel-adapter" element instead. Since the "idle" command enables event-driven notifications, no poller is necessary for this adapter. It will send a Message to the specified channel as soon as it receives the notification that new mail is available: ]]> - ... where javaMailProperties could be provided by creating and populating - a regular java.utils.Properties object. For example via util namespace - provided by Spring. - - javax.net.ssl.SSLSocketFactory - false - imaps - false + store-uri="imaps://[username]:[password]@imap.gmail.com/INBOX" + channel="recieveChannel" + auto-startup="true" + should-delete-messages="false" + should-mark-messages-as-read="true" + java-mail-properties="javaMailProperties"/>]]> + ... where javaMailProperties could be provided by creating and populating + a regular java.utils.Properties object. For example via util namespace + provided by Spring. + + javax.net.ssl.SSLSocketFactory + false + imaps + false ]]>
- + In both configurations channel and should-delete-messages are the REQUIRED     attributes. The important thing to understand is why should-delete-messages is required? @@ -138,12 +138,12 @@     the right default value for should-delete-messages attribute we simply made it required to be set - leaving it up to you     while also not letting you to forget that you must set it. - + When configuring a polling adapter (e.g., inbound-channel-adapter) should-mark-messages-as-read - be aware of the protocol you are configuring to retrieve messages. For example POP3 does not support this flag + be aware of the protocol you are configuring to retrieve messages. For example POP3 does not support this flag which means setting it to either value will have no effect as messages will NOT be marked as read - - + + When using the namespace support, a header-enricher Message Transformer is also available. This simplifies the application of the headers mentioned above to any Message prior to sending to the @@ -158,4 +158,4 @@
-
\ No newline at end of file +
diff --git a/src/docbkx/message-history.xml b/docs/src/reference/docbook/message-history.xml similarity index 86% rename from src/docbkx/message-history.xml rename to docs/src/reference/docbook/message-history.xml index e364f0e3f5..63857a403f 100644 --- a/src/docbkx/message-history.xml +++ b/docs/src/reference/docbook/message-history.xml @@ -1,20 +1,20 @@ - - + Message History - - The key benefit of messaging architecture is loose coupling where participating components do not maintain any awareness about one another. This fact + + The key benefit of messaging architecture is loose coupling where participating components do not maintain any awareness about one another. This fact alone makes you architecture extremely flexible  allowing you to change components without affecting the rest of the flow, change messaging routs,   message consuming styles (polling vs event driven) etc... - However, this unassuming style of architecture could prove to be problematic when things go wrong. For example, if something happened + However, this unassuming style of architecture could prove to be problematic when things go wrong. For example, if something happened you would probably like to get as much information about the message as you can (its origin, where it was etc.) - Message History is one of those patterns that could help by giving you an option to maintain some level of awareness of a + Message History is one of those patterns that could help by giving you an option to maintain some level of awareness of a message path either for debugging purposes or to maintain an audit trail. - Spring integration provides a simple way to configure your message flows to maintain Message History by adding Message History header to a + Spring integration provides a simple way to configure your message flows to maintain Message History by adding Message History header to a Message every time a message goes through a tracked component. - +
Message History Configuration @@ -23,25 +23,25 @@ Now every named component (component that has an 'id' defined) will be tracked. - The framework will set the '$history' header in your Message who's value is  very simple - List<Properties>. - The need for this simple structure is mandated by the loosely coupled architecture of messaging systems where the framework + The framework will set the '$history' header in your Message who's value is  very simple - List<Properties>. + The need for this simple structure is mandated by the loosely coupled architecture of messaging systems where the framework must not require you to share any dependencies outside of Java itself.  - + - - - + + + ]]> The above configuration will produce a very simple Message History structure: - To get access to Message History all you need is access the MessageHistory header. For example: - historyIterator = + historyIterator = message.getHeaders().get(MessageHistory.HEADER_NAME, MessageHistory.class).iterator(); assertTrue(historyIterator.hasNext()); Properties gatewayHistory = historyIterator.next(); @@ -51,14 +51,14 @@ Properties chainHistory = historyIterator.next(); assertEquals("sampleChain", chainHistory.get("name"));]]> - Some times you might not want to track all of the components. To accomplish this all you need is provide tracked-components attribute where you can specify + Some times you might not want to track all of the components. To accomplish this all you need is provide tracked-components attribute where you can specify comma delimited list of component names and/or patterns you want to track. ]]> In the above example, Message History will only be maintained for all of the components that end with 'Gateway', all components that start with 'sample' and 'foo' component. - Remember, that by definition History is immutable (you can't re-write history,although some try), therefore Message History can not + Remember, that by definition History is immutable (you can't re-write history,although some try), therefore Message History can not be changed once written. Every attempt will end in exception.
-
\ No newline at end of file +
diff --git a/docs/src/reference/docbook/message-publishing.xml b/docs/src/reference/docbook/message-publishing.xml new file mode 100644 index 0000000000..f599808dfc --- /dev/null +++ b/docs/src/reference/docbook/message-publishing.xml @@ -0,0 +1,371 @@ + + + Message Publishing + + The AOP Message Publishing feature allows you to construct and send a message as a by-product of method invocation. For example, imagine you + have a component and every time the state of this component changes you would like to be notified via a Message. The easiest + way to send such notifications would be to send a message to a dedicated channel, but how would you connect the method invocation that + changes the state of the object to a message sending process, and how should the notification Message be structured? + The AOP Message Publishing feature handles these responsibilities with a configuration-driven approach. + +
+ Message Publishing Configuration + + Spring Integration provides two approaches: XML and Annotation-driven. + +
+ Annotation-driven approach via @Publisher annotation + + The annotation-driven approach allows you to annotate any method with the @Publisher annotation, specifying 'channel' attribute. + The Message will be constructed from the return value of method invocation and sent to a channel specified by 'channel' attribute. + To further manage message structure you can also use a combination of both @Payload and @Header annotations. + + + Internally message publishing feature of Spring Integration uses both Spring AOP by defining PublisherAnnotationAdvisor and + Spring 3.0 Expression Language (SpEL) support, giving you considerable flexibility and control over the structure of the Message it will build. + + + PublisherAnnotationAdvisor defines and binds the following variables: + + + #return - will bind to a return value allowing you to reference it or its + attributes (e.g., #return.foo where 'foo' is an attribute of the object bound to + #return) + + + #exception - will bind to an exception if one is thrown by the method invocation. + + + #args - will bind to method arguments, so individual arguments could be extracted by name + (e.g., #args.fname as in the above method) + + + + + + Let's look at couple of examples: + + +@Publisher +public String defaultPayload(String fname, String lname) { + return fname + " " + lname; +} + + + In the above example the Message will be constructed with the following structure: + + + Message payload - will be the return type and value of the method. This is the default. + + + A newly constructed message will be sent to a default publisher channel configured with annotation post processor (see the end of this section). + + + + +@Publisher(channel="testChannel") +public String defaultPayload(String fname, @Header("last") String lname) { + return fname + " " + lname; +} + + + In this example everything is the same as above, however we are not using default publishing channel. Instead we are specifying + the publishing channel via 'channel' attribute of @Publisher annotation. + We are also adding @Header annotation which results in the Message header with the name 'last' and the value of 'lname' input parameter + to be added to the newly constructed Message. + + + +@Publisher(channel="testChannel") +@Payload +public String defaultPayloadButExplicitAnnotation(String fname, @Header String lname) { + return fname + " " + lname; +} + + + The above example is almost identical to the previous one. The only difference here is that we are using @Payload annotation + on the method, thus explicitly specifying that the return value of the method should be used as a payload of the Message. + + + +@Publisher(channel="testChannel") +@Payload("#return + #args.lname") +public String setName(String fname, String lname, @Header("x") int num) { + return fname + " " + lname; +} + + + Here we are expending on the previous configuration by using Spring Expression language in the @Payload annotation further instructing + the framework on how the message should be constructed. In this particular case the message will be a concatenation of the return value of the method invocation and + 'lname' input argument. Message header 'x' with value of 'num' input argument will be added to the newly constructed Message. + + + +@Publisher(channel="testChannel") +public String argumentAsPayload(@Payload String fname, @Header String lname) { + return fname + " " + lname; +} + + + In the above example you see another usage of @Payload annotation. Here we are annotating method argument + which will become a payload of newly constructed message. + + + + + As with most other annotation-driven features in Spring, you will need to register a post-processor + (PublisherAnnotationBeanPostProcessor). + <bean class="org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor"/> + You can also use namespace support for added convenience: + +<si:annotation-config default-publisher-channel="defaultChannel"/> + + + + Similar to other Spring annotations (e.g., @Controller), @Publisher is a meta-annotation, which means you can define your own annotations + that will be treated as @Publisher + +Here we defined @Audit annotation which itself is a @Publisher. Also note that you can define channel +attribute on the meta-annotation thus encapsulating the behavior of where messages will be sent inside of this annotation. + +Now you can annotate any method: + + +In the above example every invocation of test() method will result in Message with payload which is the return value of the method +invocation to be sent to auditChannel + +You can also annotate the class which would mean that the properties of this annotation will be applied on every public method of this class + + + + +
+ +
+ XML-based approach via <publishing-interceptor> element + + The XML-based approach allows you to configure the same AOP-based Message Publishing functionality with + simple namespace-based configuration of a MessagePublishingInterceptor. + It certainly has some benefits over the annotation-driven approach since it + allows you to use AOP pointcut expressions, thus possibly intercepting multiple methods at once or + intercepting and publishing methods to which you don't have the source code. + + + To configure Message Publishing via XML, you only need to do the following two things: + + + Provide configuration for MessagePublishingInterceptor + via the <publishing-interceptor> XML element. + + + Provide AOP configuration to apply the MessagePublishingInterceptor to managed objects. + + + + + + + + + +
+ + +
+ + +]]> + + + As you can see the <publishing-interceptor> configuration look rather similar to Annotation-based approach + and it also utilizes the power of the Spring 3.0 Expression Language. + + + In the above example the execution of the echo method of a testBean will + render a Message with the following structure: + + + The Message payload will be of type String and value of "Echoing: [value]" where value is the value + returned by an executed method. + + + The Message will have header with the key "foo" value "bar". + + + The Message will be sent to echoChannel. + + + + + + The second method is very similar to the first. Here every method that begins with 'repl' will render a Message with the following structure: + + + The Message payload will be the same as in the above sample + + + The Message will have header with the key "foo" and value that is the result of the SpEL expression 'bar'.toUpperCase() . + + + The Message will be sent to echoChannel. + + + + + + The second method, mapping the execution of any method that begins with echoDef of testBean, will produce a + Message with the following structure. + + + The Message payload will be the value returned by an executed method. + + + Since the channel attribute is not provided explicitly, the Message will be sent to the + defaultChannel defined by the publisher. + + + + + + For simple mapping rules you can rely on the publisher defaults. For example: + +<publishing-interceptor id="anotherInterceptor"/> + + This will map the return value of every method that matches the pointcut expression to a payload and will be sent to a default-channel. + If the defaultChannelis not specified (as above) the messages will be sent to the global nullChannel. + + + Async Publishing + + + One important thing to understand is that publishing occurs in the same thread as your component's execution. So by default in is synchronous. + This means that the entire message flow would have to wait until he publisher flow completes.  + However, quite often you want the complete opposite and that is to use Message publishing feature to initiate asynchronous sub-flows. + For example, you might host a service (HTTP, WS etc.) which receives a remote request.You may want to send this request internally into a + process that might take a while. However you may also want to reply to the user right away. So, instead of sending inbound + request for processing via the output channel (the conventional way), you can simply use ''outout-channel or $replyChannel'' header + to send simple acknowledgment-like reply back to the caller while using Message publisher feature to initiate a complex flow. + + + EXAMPLE: + Here is the simple service that receives a complex payload, which needs to be sent further for processing, but it + also need to reply to the caller with a simple acknowledgment. + + So instead of hooking up the complex flow to the output channel we use Message publishing feature instead configuring it to create a + new Message using the input argument of the service method (above) and sending it to the 'localProcessChannel'. And to make sure this sub-flow + is asynchronous all we need to do is make sure that we send it to any type of async channel (ExecutorChannel in this example). + + + + + + + + + + + + + + + + + +]]> + + + Another way of handling thi type of scenario is through wire-tap + +
+ +
+ Producing and publishing messages based on a scheduled trigger + + In the above sections we looked at the Message publishing feature of Spring Integration which constructs and publishes messages as by-products of Method invocations. + However in that case, you are still responsible for invoking the method. + In Spring Integration 2.0 we've added another related useful feature: support for scheduled Message producers/publishers via the new "expression" attribute + on the 'inbound-channel-adapter' element. Scheduling could be based on several triggers, any one of which may be configured on the 'poller' sub-element. + Currently we support cron, fixed-rate, fixed-delay as well as any custom trigger implemented by you. + + + As mentioned above, support for scheduled producers/publishers is provided via the <inbound-channel-adapter> xml element. + Let's look at couple of examples: + + + + + +]]> + + In the above example an inbound Channel Adapter will be created which will construct a Message with its payload being the result of the expression  + defined in the expression attribute. Such message will be created and sent every time after the delay specified by the fixed-delay attribute. + + + +]]> + + This example is very similar to the previous one, except that we are using the fixed-rate attribute which will allow us to send messages at a fixed rate (measuring from the start time of each task). + + + +]]> + + This example demonstrates how you can apply a Cron trigger with a value specified in the cron attribute. + + + + +
+
+]]> + + Here you can see that in a way very similar to the Message publishing feature we are enriching a newly constructed Message with + extra Message headers which could take scalar values as well as the results of evaluating Spring expressions. + + + + If you need to implement your own custom trigger you can use the trigger attribute to provide a reference to any spring configured + bean which implements the org.springframework.scheduling.Trigger interface. + + + + + + + +]]> + + +
+
+
diff --git a/src/docbkx/message.xml b/docs/src/reference/docbook/message.xml similarity index 97% rename from src/docbkx/message.xml rename to docs/src/reference/docbook/message.xml index 4e25938595..7656b0b030 100644 --- a/src/docbkx/message.xml +++ b/docs/src/reference/docbook/message.xml @@ -1,6 +1,6 @@ - - + Message Construction The Spring Integration Message is a generic container for data. Any object can @@ -31,12 +31,12 @@
Message Headers - + Just as Spring Integration allows any Object to be used as the payload of a Message, it also supports any Object types as header values. In fact, the MessageHeaders class implements the java.util.Map interface: public final class MessageHeaders implements Map<String, Object>, Serializable { - ... + ... } Even though the MessageHeaders implements Map, it is effectively a read-only implementation. Any attempt to @@ -119,7 +119,7 @@
- Message Implementations + Message Implementations The base implementation of the Message interface is GenericMessage<T>, and it provides two constructors: @@ -130,7 +130,7 @@ new GenericMessage<T>(T payload, Map<String, Object> headers) - There are also two convenient subclasses available: StringMessage and + There are also two convenient subclasses available: StringMessage and ErrorMessage. The former accepts a String as its payload: StringMessage message = new StringMessage("hello world"); diff --git a/src/docbkx/overview.xml b/docs/src/reference/docbook/overview.xml similarity index 97% rename from src/docbkx/overview.xml rename to docs/src/reference/docbook/overview.xml index 487d92819a..6241073c9f 100644 --- a/src/docbkx/overview.xml +++ b/docs/src/reference/docbook/overview.xml @@ -1,6 +1,6 @@ - - + Spring Integration Overview
@@ -106,7 +106,7 @@ store any arbitrary key-value pairs in the headers. - @@ -124,7 +124,7 @@ messaging components, and also provides a convenient point for interception and monitoring of Messages. - @@ -225,7 +225,7 @@ proactive alternative to the reactive Message Filters used by multiple subscribers as described above. - @@ -277,7 +277,7 @@ Message's "return address" if available. - @@ -302,7 +302,7 @@ chapters. - @@ -312,7 +312,7 @@ - diff --git a/src/docbkx/resequencer.xml b/docs/src/reference/docbook/resequencer.xml similarity index 94% rename from src/docbkx/resequencer.xml rename to docs/src/reference/docbook/resequencer.xml index acbdedf8ef..7c58816c8c 100644 --- a/src/docbkx/resequencer.xml +++ b/docs/src/reference/docbook/resequencer.xml @@ -1,7 +1,6 @@ - - + Resequencer
@@ -71,33 +70,33 @@ - + Whether to send out ordered sequences as soon as they are available, or only after the whole message group arrives. Optional (false by default). - If this flag is not specified (so a complete sequence is defined by the sequence headers) then it can make sense to provide a custom + If this flag is not specified (so a complete sequence is defined by the sequence headers) then it can make sense to provide a custom Comparator - to be used to order the messages when sending (use the XML attribute + to be used to order the messages when sending (use the XML attribute comparator - to point to a bean definition). If + to point to a bean definition). If release-partial-sequences - is true then there is no way with a custom comparator to define a partial sequence. To do that you would have to provide a + is true then there is no way with a custom comparator to define a partial sequence. To do that you would have to provide a release-strategy - (also a reference to another bean definition, either a POJO or a + (also a reference to another bean definition, either a POJO or a ReleaseStrategy - ). + ). @@ -121,7 +120,7 @@ - Since there is no custom behavior to be implemented in Java classes for resequencers, there is no annotation support for it. + Since there is no custom behavior to be implemented in Java classes for resequencers, there is no annotation support for it.
diff --git a/src/docbkx/resources.xml b/docs/src/reference/docbook/resources.xml similarity index 80% rename from src/docbkx/resources.xml rename to docs/src/reference/docbook/resources.xml index 0f13c011dc..109faa9b53 100644 --- a/src/docbkx/resources.xml +++ b/docs/src/reference/docbook/resources.xml @@ -1,6 +1,6 @@ - - + Additional Resources
@@ -14,4 +14,4 @@
-
\ No newline at end of file +
diff --git a/docs/src/reference/docbook/rmi.xml b/docs/src/reference/docbook/rmi.xml new file mode 100644 index 0000000000..ec642fe05c --- /dev/null +++ b/docs/src/reference/docbook/rmi.xml @@ -0,0 +1,66 @@ + + + RMI Support + +
+ Introduction + + This Chapter explains how to use RMI specific channel adapters to distribute a system over multiple JVMs. The first section will deal with sending messages over RMI. The second section shows how to receive messages over RMI. The last section shows how to define rmi channel adapters through the namespace support. + +
+ +
+ Outbound RMI + + To send messages from a channel over RMI, simply define an RmiOutboundGateway. This gateway will use Spring's RmiProxyFactoryBean internally to create a proxy for a remote gateway. Note that to invoke a remote interface that doesn't use Spring Integration you should use a service activator in combination with Spring's RmiProxyFactoryBean. + + + To configure the outbound gateway write a bean definition like this: + + + + ]]> + + +
+ +
+ Inbound RMI + + To receive messages over RMI you need to use a RmiInboundGateway. This gateway can be configured like this + + + ]]> + + +
+ +
+ RMI namespace support + + To configure the inbound gateway you can choose to use the namespace support for it. The following code snippet shows the different configuration options that are supported. + + + + + + + + + ]]> + + + To configure the outbound gateway you can use the namespace support as well. The following code snippet shows the different configuration for an outbound rmi gateway. + ]]> + +
+ +
diff --git a/src/docbkx/router.xml b/docs/src/reference/docbook/router.xml similarity index 54% rename from src/docbkx/router.xml rename to docs/src/reference/docbook/router.xml index c089a3960b..1fcc281e77 100644 --- a/src/docbkx/router.xml +++ b/docs/src/reference/docbook/router.xml @@ -1,7 +1,6 @@ - - + Router
@@ -28,16 +27,16 @@ Configuration of PayloadTypeRouter is also supported via the namespace provided by Spring Integration (see ), - which essentially simplifies configuration by combining <router/> configuration and its corresponding implementation defined using <bean/> element + which essentially simplifies configuration by combining <router/> configuration and its corresponding implementation defined using <bean/> element into a single and more concise configuration element. The example below demonstrates PayloadTypeRouter configuration which is equivalent to the one above using Spring Integration's namespace support: - - + + ]]> - +
HeaderValueRouter @@ -53,10 +52,10 @@ If arbitrary value, then a channelResolver should be provided to map header values to channel names. - The example below uses MapBasedChannelResolver to set up a map of header values to channel names. + The example below uses MapBasedChannelResolver to set up a map of header values to channel names. - + class="org.springframework.integration.router.HeaderValueRouter"> + @@ -69,14 +68,14 @@ ]]> - If channelResolver is not specified, then the header value will be treated as a channel name + If channelResolver is not specified, then the header value will be treated as a channel name making configuration much simpler, where no channelResolver needs to be specified. - - + class="org.springframework.integration.router.HeaderValueRouter"> + -]]> +]]> Similar to the PayloadTypeRouter, configuration of HeaderValueRouter is also supported via namespace support provided by Spring Integration (see ). @@ -85,15 +84,15 @@ 1. Configuration where mapping of header values to channels is required - - + + ]]> - - 2. Configuration where mapping of header values is not required if header values themselves represent the channel names + + 2. Configuration where mapping of header values is not required if header values themselves represent the channel names ]]> - - + + The two router implementations shown above share some common properties, such as "defaultOutputChannel" and "resolutionRequired". If "resolutionRequired" is set to "true", and the router is unable to determine a target channel (e.g. there is no matching payload for a PayloadTypeRouter and no "defaultOutputChannel" has been specified), then an Exception @@ -122,24 +121,24 @@ - - + timeout="1234" + ignore-send-failures="true" + apply-sequence="true"> + + ]]> - + The 'apply-sequence' flag here has the same affect as it does for a publish-subscribe-channel, and like publish-subscribe-channel it is disabled by default on the recipient-list-router. Refer to for more information. - +
The <router> element - The "router" element provides a simple way to connect a router to an input channel, and also accepts the + The "router" element provides a simple way to connect a router to an input channel, and also accepts the optional default output channel. The "ref" may provide the bean name of a custom Router implementation (extending AbstractMessageRouter): @@ -158,7 +157,7 @@ <router> definitions. However if the custom router implementation should be scoped to a concrete definition of the <router>, you can provide an inner bean definition: - + ]]> @@ -201,206 +200,206 @@ public List<String> route(@Header("orderStatus") OrderStatus status) For routing of XML-based Messages, including XPath support, see . - +
- Dynamic Routers - - So as you can see, Spring Integration provides quite a few different router configurations for most common - content-based routing use cases as well as the option of implementing custom routers as POJOs. - For example; Payload Type Router provides a simple way to configure a router which computes channels - based on the payload type of the incoming Message while Header Value Router provides the - same convenience in configuring a router which computes channels based on evaluating the value - of a particular Message Header. There is also an expression-based (SpEL) routers where the channel - is determined based on evaluating an expression which gives these type of routers some dynamic characteristics. - - - However these routers share one common attribute - static configuration. Even in the case of - expression-based routers, the expression itself is defined as part of the router configuration which means that - the same expression operating on the same value will always result in the computation of the same channel. - This is good in most cases since such routes are well defined and therefore predictable. But there are times when we - need to change router configurations dynamically so message flows could be routed to a different channel. - - For example: - - You might want to bring down some part of your system for maintenance. So, temporarily you want to re-reroute - messages to a different message flow. Or you may want to introduce more granularity to your message flow by adding another - route to handle a more concrete type of java.lang.Number (in cases of Payload Type Router). - - - Unfortunately with static router configuration to accomplish this you'd have to bring down your entire application, - change the configuration of the router (change routes) and bring it back up. This is obviously not the solution. - - - - Dynamic Router + Dynamic Routers + + So as you can see, Spring Integration provides quite a few different router configurations for most common + content-based routing use cases as well as the option of implementing custom routers as POJOs. + For example; Payload Type Router provides a simple way to configure a router which computes channels + based on the payload type of the incoming Message while Header Value Router provides the + same convenience in configuring a router which computes channels based on evaluating the value + of a particular Message Header. There is also an expression-based (SpEL) routers where the channel + is determined based on evaluating an expression which gives these type of routers some dynamic characteristics. + + + However these routers share one common attribute - static configuration. Even in the case of + expression-based routers, the expression itself is defined as part of the router configuration which means that + the same expression operating on the same value will always result in the computation of the same channel. + This is good in most cases since such routes are well defined and therefore predictable. But there are times when we + need to change router configurations dynamically so message flows could be routed to a different channel. + + For example: + + You might want to bring down some part of your system for maintenance. So, temporarily you want to re-reroute + messages to a different message flow. Or you may want to introduce more granularity to your message flow by adding another + route to handle a more concrete type of java.lang.Number (in cases of Payload Type Router). + + + Unfortunately with static router configuration to accomplish this you'd have to bring down your entire application, + change the configuration of the router (change routes) and bring it back up. This is obviously not the solution. + + + + Dynamic Router - pattern describes the mechanisms by which one can change/configure routers dynamically without - bringing down your system or individual routers.  - - - Before we get into the specifics of how it is accomplished in Spring Integration lets quickly summarize the - typical flow of the router, which consists of 3 simple steps: - + pattern describes the mechanisms by which one can change/configure routers dynamically without + bringing down your system or individual routers.  + + + Before we get into the specifics of how it is accomplished in Spring Integration lets quickly summarize the + typical flow of the router, which consists of 3 simple steps: + - Step 1 - Compute channel identifier which is a value calculated by the - router once it receives the Message. Typically it is a String or and instance of the actual + Step 1 - Compute channel identifier which is a value calculated by the + router once it receives the Message. Typically it is a String or and instance of the actual MessageChannel. - Step 2 - Resolve channel identifier to channel name. We'll describe + Step 2 - Resolve channel identifier to channel name. We'll describe specifics of this process in a moment. Step 3 - Resolve channel name to the actual MessageChannel - + - - - - There is not much that could be done with regard to router dynamics if Step 1 results in the actual instance of the - MessageChannel simply because MessageChannel is the final product of any - router's job. However, if Step 1 results in channel identifier that is not and instance of MessageChannel, - then there are quite a few possibilities to influence the process of calculating what will be the final instance of the Message Channel. - Lets look at couple of the examples in the context of the 3 steps mentioned above:  - - - Payload Type Router - - - - - + + + + There is not much that could be done with regard to router dynamics if Step 1 results in the actual instance of the + MessageChannel simply because MessageChannel is the final product of any + router's job. However, if Step 1 results in channel identifier that is not and instance of MessageChannel, + then there are quite a few possibilities to influence the process of calculating what will be the final instance of the Message Channel. + Lets look at couple of the examples in the context of the 3 steps mentioned above:  + + + Payload Type Router + + + + + ]]> - - - Within the context of the Payload Type Router the 3 steps mentioned above would be realized as: - + + + Within the context of the Payload Type Router the 3 steps mentioned above would be realized as: + - Step 1 - Compute channel identifier which is the fully qualified name of the payload type + Step 1 - Compute channel identifier which is the fully qualified name of the payload type (e.g., java.lang.String). - Step 2 - Resolve channel identifier to channel name where - the result of the previous step is used to select the appropriate value from the payload type mapping + Step 2 - Resolve channel identifier to channel name where + the result of the previous step is used to select the appropriate value from the payload type mapping defined via mapping element. - Step 3 - Resolve channel name to the actual instance of the + Step 3 - Resolve channel name to the actual instance of the MessageChannel where using ChannelResolver router will obtain a - reference to a bean (which is hopefully a MessageChannel) identified by the result of the + reference to a bean (which is hopefully a MessageChannel) identified by the result of the previous step. - + In other words each step feeds the next step until thr process completes. - - - Header Value Router - - - - - + + + Header Value Router + + + + + ]]> - - - Similar to the PayloadTypeRouter: - + + + Similar to the PayloadTypeRouter: + - Step 1 - Compute channel identifier which is the value of the header identified by the + Step 1 - Compute channel identifier which is the value of the header identified by the header-name attribute. - Step 2 - Resolve channel identifier to channel name where - the result of the previous step is used to select the appropriate value from the general mapping + Step 2 - Resolve channel identifier to channel name where + the result of the previous step is used to select the appropriate value from the general mapping defined via mapping element. - Step 3 - Resolve channel name to the actual instance of the + Step 3 - Resolve channel name to the actual instance of the MessageChannel where using ChannelResolver router will obtain a - reference to a bean (which is hopefully a MessageChannel) identified by the result of the + reference to a bean (which is hopefully a MessageChannel) identified by the result of the previous step. - + - - - The above two configurations of two different router types look almost identical. - However if we look at the different configuration of the HeaderValueRouter we clearly see that - there is no mapping sub element: - ]]> - But configuration is still perfectly valid. So the natural question is what about the maping in the Step 2? - - - What this means is that Step 2 is now an optional step. If mapping is not defined then the channel identifier - value computed in Step 1 will automatically be treated as the channel name which will now be resolved to the - actual MessageChannel in the Step 3. What it also means is that Step 2 is one of the key steps to - provide dynamic characteristics to the routers, since it introduces a process which - allows you to change the way 'channel identifier' resolves to 'channel name', - thus influencing the process of determining the final instance of the MessageChannel from the initial - channel identifier.  - - For Example: - - In the above configuration lets assume that the testHeader value is 'kermit' which is now a channel identifier - (Step 1). Since there is no mapping in this router, resolving this channel identifier to a channel name - (Step 2) is impossible and this channel identifier is now treated as channel name. However what if - there was mapping but for a different value, the end result would still be the same and that is: - if new value can not be determined through the process of resolving 'channel identifier' to a 'channel name', - such 'channel identifier' becomes 'channel name' - - - So all that is left is for Step 3 to resolve channel name ('kermit') to an actual instance of the - MessageChannel identified by this name. That will be done via default - ChannelResolver implementation which is BeanFactoryChannelResolver which - basically does a bean lookup by the name provided. So now all messages which contain the header/value pair as testHeader=kermit - are going to be routed to a 'kermit' MessageChannel. - - - But what if you want to route these messages to 'simpson' channel? Obviously changing static configuration would work, - but would also require bringing your system down. However if you had access to channel identifier map, then you - could just introduce a new mapping where header/value pair is now kermit=simpson, thus allowing Step 2 to treat - 'kermit' as channel identifier while resolving it to 'simpson' as channel name . - - - The same obviously applies for PayloadTypeRouter where you can now remap or remove a particular payload type - mapping, and every other router including expression-based routers since their computed value - will now have a chance to go through Step 2 to be aditionally resolved to the actual channel name. - - - In Spring Integration 2.0 routers hierarchy underwent major refactoring and now any router that is a subclass of the - AbstractMessageRouter (all framework defined routers) is a Dynamic Router simply because - channelIdentiferMap is defined at the AbstractMessageRouter with convenient accessors - and modifiers exposed as public methods allowing you to change/add/remove router mapping at runtime via JMX (see section section 29) or - ControlBus (see section section 29.7) functionality.  - - - - Control Bus - - - One of the way to manage the router mappings is through the Control Bus - which exposes a Control Channel where you can send - control messages to manage and monitor Spring Integration components which includes routers. - For more information about the Control Bus see section 29.7. Typically you would send a control message asking to invoke a + + + The above two configurations of two different router types look almost identical. + However if we look at the different configuration of the HeaderValueRouter we clearly see that + there is no mapping sub element: + ]]> + But configuration is still perfectly valid. So the natural question is what about the maping in the Step 2? + + + What this means is that Step 2 is now an optional step. If mapping is not defined then the channel identifier + value computed in Step 1 will automatically be treated as the channel name which will now be resolved to the + actual MessageChannel in the Step 3. What it also means is that Step 2 is one of the key steps to + provide dynamic characteristics to the routers, since it introduces a process which + allows you to change the way 'channel identifier' resolves to 'channel name', + thus influencing the process of determining the final instance of the MessageChannel from the initial + channel identifier.  + + For Example: + + In the above configuration lets assume that the testHeader value is 'kermit' which is now a channel identifier + (Step 1). Since there is no mapping in this router, resolving this channel identifier to a channel name + (Step 2) is impossible and this channel identifier is now treated as channel name. However what if + there was mapping but for a different value, the end result would still be the same and that is: + if new value can not be determined through the process of resolving 'channel identifier' to a 'channel name', + such 'channel identifier' becomes 'channel name' + + + So all that is left is for Step 3 to resolve channel name ('kermit') to an actual instance of the + MessageChannel identified by this name. That will be done via default + ChannelResolver implementation which is BeanFactoryChannelResolver which + basically does a bean lookup by the name provided. So now all messages which contain the header/value pair as testHeader=kermit + are going to be routed to a 'kermit' MessageChannel. + + + But what if you want to route these messages to 'simpson' channel? Obviously changing static configuration would work, + but would also require bringing your system down. However if you had access to channel identifier map, then you + could just introduce a new mapping where header/value pair is now kermit=simpson, thus allowing Step 2 to treat + 'kermit' as channel identifier while resolving it to 'simpson' as channel name . + + + The same obviously applies for PayloadTypeRouter where you can now remap or remove a particular payload type + mapping, and every other router including expression-based routers since their computed value + will now have a chance to go through Step 2 to be aditionally resolved to the actual channel name. + + + In Spring Integration 2.0 routers hierarchy underwent major refactoring and now any router that is a subclass of the + AbstractMessageRouter (all framework defined routers) is a Dynamic Router simply because + channelIdentiferMap is defined at the AbstractMessageRouter with convenient accessors + and modifiers exposed as public methods allowing you to change/add/remove router mapping at runtime via JMX (see section section 29) or + ControlBus (see section section 29.7) functionality.  + + + + Control Bus + + + One of the way to manage the router mappings is through the Control Bus + which exposes a Control Channel where you can send + control messages to manage and monitor Spring Integration components which includes routers. + For more information about the Control Bus see section 29.7. Typically you would send a control message asking to invoke a particular JMX operation on a particular managed component (e.g., router). The two managed operations (methods) that are specific to changing router resolution process are: - public void setChannelMapping(String channelIdentifier, String channelName) - + public void setChannelMapping(String channelIdentifier, String channelName) - will allow you to add new or modify existing mapping of channel identifier to channel name - public void removeChannelMapping(String channelIdentifier) - - will allow you to remove a particular channel mapping, thus disconnecting the relationship between + public void removeChannelMapping(String channelIdentifier) - + will allow you to remove a particular channel mapping, thus disconnecting the relationship between channel identifier and channel name - + There are obviously other managed operations, so please refer to an AbstractMessageRouter for more detail - - - You can also use your favorite JMX client (e.g., JConsole) and use those operations (methods) to change - router configuration. For more information on Spring Integration management and monitoring please visit - section 29 of this manual. - + + + You can also use your favorite JMX client (e.g., JConsole) and use those operations (methods) to change + router configuration. For more information on Spring Integration management and monitoring please visit + section 29 of this manual. +
- \ No newline at end of file + diff --git a/docs/src/reference/docbook/samples.xml b/docs/src/reference/docbook/samples.xml new file mode 100644 index 0000000000..9ab5f6e2b6 --- /dev/null +++ b/docs/src/reference/docbook/samples.xml @@ -0,0 +1,660 @@ + + + Spring Integration Samples + +
+ Introduction + + Starting with the current release of Spring Integration the samples are no longer included with + Spring Integration distribution. Instead we've switched to a much simpler collaborative model that should promote + better community participation and community contributions. Samples now have a dedicated Git SCM repository and a + dedicated JIRA Issue Tracking system. Sample development will also have its own lifecycle which is not dependent on the + lifecycle of the framework releases although the repository will still be tagged with each major release for compatibility + reasons. + + + The great benefit to the community is that we can now add more samples and make them available to you right away + without waiting for the release to get them out to you. Having its own JIRA that is not tied up to the the actual + framework is also a great benefit. You now have a dedicated place to suggest samples as well as report issues with existing + samples. Or you may want to submit a sample to us as an attachment through the JIRA and if we believe your sample adds value we + would be more then glad to add it to a samples repository properly crediting the author. + +
+ +
+ Where to get Samples + + To monitor samples development and to get more information on the repository you can visit the following + URL: http://git.springsource.org/spring-integration/samples + Since we are using Git SCM we should use the proper terminology as well when it comes to the tasks you need to perform to make + samples available locally on your machine. For more information on Git SCM please visit their + website: http://git-scm.com/ + + + CLONE samples repository. (For those unfamiliar with Git, this is somewhat the equivalent of a checkout.) + + + This is the first step you should go through. You must have Git installed on your machine. There are many GUI-based products + available for many platforms. Simple Google search will let you find them. + To clone samples repository from command line: + mkdir spring-itegration-samples +> cd spring-itegration-samples +> git clone git://git.springsource.org/spring-integration/samples.git]]> + + + That is all you need to do. Now you have cloned the entire samples repository. Since samples repository is a live + repository, you might want to perform periodic updates to get new samples as well as updates to the existing samples. + To get the updates use git PULL command: + git pull]]> + + + Submit samples or sample requests + + + As mentioned earlier, Spring Integration samples have a dedicated JIRA Issue tracking system. + To submit new sample request or to submit the actual sample (as an attachment) please visit our JIRA Issue Tracking system: + https://jira.springframework.org/browse/INTSAMPLES  + +
+
+ Samples structure + + The structure of the samples changed as well. With plans for more samples we realized that some + samples have different goals then others. While they all share the common  goal of showing you how to apply and work with + Spring Integration framework, they also defer in areas where some samples were meant to concentrate on a technical + use case while others on the business use case and some samples are all about showcasing various techniques that + could be applied to address certain scenarios (both technical and business). Categorization of samples will allow us + better organize them based on the problem each sample addresses while giving you a simpler way of finding the right sample + + + Currently there are 4 categories. Within the samples repository each category has its own directory which is named after the + category name: + + + + BASIC (samples/basic) + + + This is a good place to get started. The samples here are technically motivated and demonstrate the bare + minimum with regard to configuration and code, to help you to get started quickly by introducing you to the basic concepts, + API and configuration of Spring Integration as well as Enterprise Integration Patterns (EIP). For example; If your are + looking for an answer on how to implement and wire Service Activator to a Channel + or how to use Messaging Gateway to your message exchange or how to get started with using MAIL or + TCP/UDP modules etc., this would be the right place to find a good sample. The bottom line is this is a good place + to get started. + + + + INTERMEDIATE (samples/intermediate) + + + This category targets developers who are already familiar with Spring Integration framework (past getting started), + but need some more guidance while resolving a more advanced technical problems one might deal with + once switch to a Messaging architecture. + For example; If you are looking for an answer on how to handle errors in various message exchange + scenarios or how to properly configure the Aggregator for the situations where some messages + might not ever arrive for aggregation etc,. and any other issue that goes beyond a basic implementation and configuration + of a particular component and addresses "what else you can do with it" type of problem this + would be the right place to find these type of samples. + + + + ADVANCED (samples/advanced) + + + This category targets develoopers who are very familiar with Spring Integration framework but looking to + extend it to address a specific custom need by using Spring Integration public API. + For example; if you are looking for samples showing you how to implement a custom Channel or + Consumer (event-based or polling-based), or you trying to figure out what is the most appropriate + way to implement custom Bean parser on top of Spring Integration Bean parsers hierarchy when implementing custom name space + for a custom component, this would be the right place to look. + Here you can also find samples that will help you with Adapter development. Spring Integration comes + with an extensive library of adapters to allow you to connect remote systems with Spring Integration messaging framework. + However you might have a need to integrate with system for which the core framework does not provide an adapter. + So you have to implement your own. This category would include samples showing you how to do it. + + + + + APPLICATIONS (samples/applications) + + + This category targets developers and architects who have a good understanding of the Messaging architecture, + EIP and above average understanding of Spring and Spring Integration frameworks and are looking for samples that + address a particular business problem. In other words the emphasis of samples in this category + is business use cases and how it could be solved via Messaging Architecture and Spring Integration + in particular. + For example; If you are interested to see how a Loan Broker or Travel Agent + process could be implemented and automated via Spring Integration this would be the right place to find these types of samples. + + + + + Remember! Spring Integration is a community driven framework, therefore community participation is IMPORTANT. +That includes Samples, so if you can't find what you are looking for let us know. + + +
+
+ Samples + + Currently Spring Integration comes with quite a few samples and you can only expect more. + To help you better navigate through them, each sample comes with its own readme.txt file which coveres + sevaral details about the sample (e.g., what EIP patterns it addresses, what problem it is trying to solve, how to run sample etc.). + However, certain samples require a more detailed and some times graphical explanation. In these section you'll + find details on samples that we believe require special attention. + + +
+ Loan Broker + + In this section, we will review a Loan Broker sample application that is included in the + Spring Integration samples. This sample is inspired by one of the samples featured in Gregor + Hohpe's Ramblings. + + The diagram below represents the entire process + + + + + + + + + + + Now lets look at this process in more details + + At the core of EIP architecture are the very simple yet powerful concepts of Pipes and Filters and Message. Endpoints (Filters) are + connected with one another via Channels (Pipes). The producing endpoint sends Message to the Channel and the Message is retrieved + by the Consuming endpoint. This architecture is meant to define various mechanisms that describe How information is exchanged between + the endpoints, without any awareness of What those endpoints are or What information they are exchanging, thus providing for a very loosely + coupled and flexible collaboration model while also, decoupling Integration concerns from Business concerns. EIP extends this architecture + by further defining: + + + The types of pipes (Point-to-Point Channel, Publish-Subscribe Channel, Channel Adapter, etc.) + + + + The core filters and patterns around how filters collaborate with pipes + (Message Router, Splitters and Aggregators, various Message Transformation patterns, etc.) + + + + + + The details and variations of this use case are very nicely described in Chapter 9 of the EIP Book, but here is the brief summary; + A Consumer while shopping for the best Loan Quote(s) subscribes to the services of a Loan Broker, which handles details such as: + + + Consumer pre-screening (e.g., obtain and review the consumer's Credit history) + + + + Determine the most appropriate Banks (e.g., based on consumer's credit history/score) + + + + Send a Loan quote request to each selected Bank + + + Collect responses from each Bank + + + Filter responses and determine the best quote(s), based on consumer's requirements. + + + Pass the Loan quote(s) back to the consumer. + + + + + Obviously the real process of obtaining a loan quote is a bit more complex, but since our goal here is to demonstrate how + Enterprise Integration Patterns are realized and implemented within SI, the use case has been simplified to concentrate only on + the Integration aspects of the process. It is not an attempt to give you an advice in consumer finances. + + + As you can see, by hiring a Loan Broker, the consumer is isolated from the details of the Loan Broker's operations, and each Loan Broker's + operations may defer from one another to maintain competitive advantage, so whatever we assemble/implement must be flexible so any changes + could be introduced quickly and painlessly. + Speaking of change, the Loan Broker sample does not actually talk to any 'imaginary' Banks or Credit bureaus. Those services are stubbed out. + Our goal here is to assemble, orchestrate and test the integration aspect of the process as a whole. Only then can we start thinking about + wiring such process to the real services. At that time the assembled process and its configuration will not change regardless of the number + of Banks a particular Loan Broker is dealing with, or the type of communication media (or protocols) used (JMS, WS, TCP, etc.) + to communicate with these Banks. + + DESIGN + + As you analyze the 6 requirements above you'll quickly see that they all fall into the category of Integration concerns. + For example, in the consumer pre-screening step we need to gather additional information about the consumer and the consumer's desires + and enrich the loan request with additional meta information. We then have to filter such information to select the most appropriate list of + Banks, and so on. Enrich, filter, select – these are all integration concerns for which EIP defines a solution in the form of patterns. + SI provides an implementation of these patterns. + + Messaging Gateway + + + + + + + + + + + The Messaging Gateway pattern provides a simple mechanism to access messaging systems, including our Loan Broker. + In SI you define the Gateway as a Plain Old Java Interface (no need to provide an implementation), configure it via the + XML <gateway> element or via annotation and use it as any other Spring bean. SI will take care of + delegating and mapping method invocations to the Messaging infrastructure by generating a Message (payload is mapped to an + input parameter of the method) and sending it to the designated channel. + + +
+ +]]> + + + Our current Gateway provides two methods that could be invoked. One that will return the best single quote and another one that + will return all quotes. Somehow downstream we need to know what type of reply the caller is looking for. The best way to achieve + this in Messaging architecture is to enrich the content of the message with some meta-data describing your intentions. + Content Enricher is one of the patterns that addresses this and although Spring Integration does provide a + separate configuration element to enrich Message Headers with arbitrary data (we'll see it later), as a convenience, since + Gateway element is responsible to construct the initial Message it provides embedded + capability to enrich the newly created Message with arbitrary Message Headers. In our + example we are adding header RESPONSE_TYPE with value 'BEST'' whenever the getBestQuote() method is invoked. For other method + we are not adding any header. Now we can check downstream for an existence of this header and based on its presence and its value + we can determine what type of reply the caller is looking for. + + + + Based on the use case we also know there are some pre-screening steps that needs to be performed such as getting and evaluating the consumer's + credit score, simply because some premiere Banks will only typically accept quote requests from consumers that meet a minimum credit + score requirement. So it would be nice if the Message would be enriched with such information before it is forwarded + to the Banks. It would also be nice if when several processes needs to be completed to provide such meta-information, those + processes could be grouped in a single unit. In our use case we need to determine credit score and based on the credit score and some + rule select a list of Message Channels (Bank Channels) we will sent quote request to. + + Composed Message Processor + + The Composed Message Processor pattern describes rules around building endpoints that maintain control over message flow which + consists of multiple message processors. In Sprig Integration Composed Message Processor pattern is implemented via + <chain> element. + + + + + + + + + + + As you can see from the above configuration we have a chain with inner header-enricher element which will further enrich the + content of the Message with the header CREDIT_SCORE and value that will be determined by the call to a + credit service (simple POJO spring bean identified by 'creditBureau' name) and then it will delegate to the Message Router + + Message Router + + + + + + + + + + + There are several implementation of Message Routing pattern available in Spring Integration. Here we are using + router that will determine a list of channels based on evaluating an expression (Spring Expression Language) which will look at + the credit score that was determined is the previous step and will select the list of channels from the Map bean with id 'banks' + whose values are 'premier' or 'secondary' based o the value of credit score. Once the list of Channels is selected, the + Message will be routed to those Channels. + + + Now, one last thing the Loan Broker needs to to is to receive the loan quotes form the banks, aggregate them by consumer + (we don't want to show quotes from one consumer to another), assemble the response based on the consumer's selection criteria + (single best quote or all quotes) and reply back to the consumer. + + Message Aggregator + + + + + + + + + + + + An Aggregator pattern describes an endpoint which groups related Messages into a single + Message. Criteria and rules can be provided to determine an aggregation and correlation strategy. + SI provides several implementations of the Aggregator pattern as well as a convenient name-space based configuration. + + +]]> + + + + Our Loan Broker defines a 'quotesAggregator' bean via the <aggregator> element which provides a default + aggregation and correlation strategy. The default correlation strategy correlates messages based on the $corelationId header + (see Correlation Identifier pattern). What's interesting is that we never provided the value for this header. + It was set earlier by the router automatically, when it generated a separate Message for each Bank channel. + + + Once the Messages are correlated they are released to the actual Aggregator implementation. + Although default Aggregator is provided by SI, its strategy (gather the list of payloads from all + Messages and construct a new Message with this List as payload) does not satisfy our + requirement. The reason is that our consumer might require a single best quote or all quotes. To communicate the consumer's + intention, earlier in the process we set the RESPONSE_TYPE header. Now we have to evaluate this header and return either + all the quotes (the default aggregation strategy would work) or the best quote (the default aggregation strategy will not work + because we have to determine which loan quote is the best). + + + + Obviously selecting the best quote could be based on complex criteria and would influence the complexity of the aggregator implementation and + configuration, but for now we are making it simple. If consumer wants the best quote we will select a quote with the lowest interest + rate. To accomplish that the LoanQuoteAggregator.java will sort all the quotes and return the first one. + The LoanQuote.java implements Comparable which compares quotes based on the rate attribute. + Once the response Message is created it is sent to the default-reply-channel of the Messaging Gateway + (thus the consumer) which started the process. Our consumer got the Loan Quote! + + Conclusion + + As you can see a rather complex process was assembled based on POJO (read existing, legacy), light weight, embeddable messaging + framework (Spring Integration) with a loosely coupled programming model intended to simplify integration of heterogeneous systems + without requiring a heavy-weight ESB-like engine or proprietary development and deployment environment, becouse as a developer you + should not be porting your Swing or console-based application to an ESB-like server or implementing proprietary interfaces just + because you have an integration concern. + + + This and other samples in this section are build on top of Enterprise Integration Patterns that meant to describe "building blocks" + for YOUR solution but not to be solutions in of themselves. Integration concerns exist in all types of applications (server based and not) + and should not require change in design, testing and deployment strategy if such applications need to integrate with one another. + +
+ + +
+ The Cafe Sample + + In this section, we will review a Cafe sample application that is included in the + Spring Integration samples. This sample is inspired by another sample featured in Gregor + Hohpe's Ramblings. + + + The domain is that of a Cafe, and the basic flow is depicted in the following diagram: + + + + + + + + + + + + + The Order object may contain multiple OrderItems. Once the order + is placed, a Splitter will break the composite order message into a single message per + drink. Each of these is then processed by a Router that determines whether the drink is hot + or cold (checking the OrderItem object's 'isIced' property). The + Barista prepares each drink, but hot and cold drink preparation are handled by two + distinct methods: 'prepareHotDrink' and 'prepareColdDrink'. The prepared drinks are then sent to the Waiter where + they are aggregated into a Delivery object. + + + Here is the XML configuration: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + As you can see, each Message Endpoint is connected to input and/or output channels. Each endpoint will manage + its own Lifecycle (by default endpoints start automatically upon initialization - to prevent that add the + "auto-startup" attribute with a value of "false"). Most importantly, notice that the objects are simple POJOs + with strongly typed method arguments. For example, here is the Splitter: + split(Order order) { + return order.getItems(); + } + }]]> + In the case of the Router, the return value does not have to be a MessageChannel + instance (although it can be). As you see in this example, a String-value representing the channel name is + returned instead. + + + + Now turning back to the XML, you see that there are two <service-activator> elements. Each of these + is delegating to the same Barista instance but different methods: 'prepareHotDrink' + or 'prepareColdDrink' corresponding to the two channels where order items have been routed. + + + + As you can see from the code excerpt above, the barista methods have different delays (the hot drinks take 5 + times as long to prepare). This simulates work being completed at different rates. When the + CafeDemo 'main' method runs, it will loop 100 times sending a single hot drink and a + single cold drink each time. It actually sends the messages by invoking the 'placeOrder' method on the Cafe + interface. Above, you will see that the <gateway> element is specified in the configuration file. This + triggers the creation of a proxy that implements the given 'service-interface' and connects it to a channel. + The channel name is provided on the @Gateway annotation of the Cafe interface. + public interface Cafe { + + @Gateway(requestChannel="orders") + void placeOrder(Order order); + + } + Finally, have a look at the main() method of the CafeDemo itself. + 0) { + context = new FileSystemXmlApplicationContext(args); + } + else { + context = new ClassPathXmlApplicationContext("cafeDemo.xml", CafeDemo.class); + } + Cafe cafe = (Cafe) context.getBean("cafe"); + for (int i = 1; i <= 100; i++) { + Order order = new Order(i); + order.addItem(DrinkType.LATTE, 2, false); + order.addItem(DrinkType.MOCHA, 3, true); + cafe.placeOrder(order); + } + }]]> + + + To run this sample as well as 8 others, refer to the README.txt within the "samples" directory + of the main distribution as described at the beginning of this chapter. + + + When you run cafeDemo, you will see that the cold drinks are initially prepared more quickly than the hot drinks. + Because there is an aggregator, the cold drinks are effectively limited by the rate of the hot drink preparation. + This is to be expected based on their respective delays of 1000 and 5000 milliseconds. However, by configuring a + poller with a concurrent task executor, you can dramatically change the results. For example, you could use a + thread pool executor with 5 workers for the hot drink barista while keeping the cold drink barista as it is: + + + + ]]> + ]]> + + ]]>]]> + + + Also, notice that the worker thread name is displayed with each invocation. You will see that the hot drinks are + prepared by the task-executor threads. If you provide a much shorter poller interval (such as 100 milliseconds), + then you will notice that occasionally it throttles the input by forcing the task-scheduler (the caller) to invoke + the operation. + + + In addition to experimenting with the poller's concurrency settings, you can also add the 'transactional' + sub-element and then refer to any PlatformTransactionManager instance within the context. + +
+ +
+ The XML Messaging Sample + + The xml messaging sample in the org.springframework.integration.samples.xml illustrates how to use + some of the provided components which deal with xml payloads. The sample uses the idea of processing an order for books + represented as xml. + + + First the order is split into a number of messages, each one representing a single order item using + the XPath splitter component. + + + + ]]> + + + A service activator is then used to pass the message into a stock checker POJO. The order item document is enriched with information + from the stock checker about order item stock level. This enriched order item message is then used to route the message. In the + case where the order item is in stock the message is routed to the warehouse. The XPath router makes use of a + MapBasedChannelResolver which maps the XPath evaluation result to a channel reference. + + + + + + + + + + + + + ]]> + + + Where the order item is not in stock the message is transformed using + xslt into a format suitable for sending to the supplier. + + ]]> + +
+
+ +
diff --git a/docs/src/reference/docbook/security.xml b/docs/src/reference/docbook/security.xml new file mode 100644 index 0000000000..1d17fb6ed6 --- /dev/null +++ b/docs/src/reference/docbook/security.xml @@ -0,0 +1,64 @@ + + + Security in Spring Integration + +
+ Introduction + + Spring Integration provides integration with the + Spring Security project + to allow role based security checks to be applied to channel send and receive invocations. + +
+ +
+ Securing channels + + Spring Integration provides the interceptor ChannelSecurityInterceptor, which extends + AbstractSecurityInterceptor and intercepts send and receive calls on the channel. Access decisions + are then made with reference to ChannelInvocationDefinitionSource which provides the definition of + the send and receive security constraints. The interceptor requires that a valid SecurityContext + has been established by authenticating with Spring Security, see the Spring Security reference documentation for details. + + + Namespace support is provided to allow easy configuration of security constraints. This consists of the secured channels tag which allows + definition of one or more channel name patterns in conjunction with a definition of the security configuration for send and receive. The pattern + is a java.util.regexp.Pattern. + + + + + + +]]> + + + By default the secured-channels namespace element expects a bean named authenticationManager which implements + AuthenticationManager and a bean named accessDecisionManager which implements + AccessDecisionManager. Where this is not the case references to the appropriate beans can be configured + as attributes of the secured-channels element as below. + + + +]]> + + + +
+ + +
diff --git a/src/docbkx/service-activator.xml b/docs/src/reference/docbook/service-activator.xml similarity index 93% rename from src/docbkx/service-activator.xml rename to docs/src/reference/docbook/service-activator.xml index 3aad8fc2e5..2325d17e54 100644 --- a/src/docbkx/service-activator.xml +++ b/docs/src/reference/docbook/service-activator.xml @@ -1,7 +1,6 @@ - - + Service Activator
@@ -56,9 +55,9 @@ Using a "ref" attribute is generally recommended if the custom Service Activator handler implementation can be reused in other <service-activator> definitions. However if the custom Service Activator handler implementation should be scoped to a single definition of the <service-activator>, you can use an inner bean definition: - - + + ]]> @@ -69,4 +68,4 @@
-
\ No newline at end of file +
diff --git a/src/docbkx/splitter.xml b/docs/src/reference/docbook/splitter.xml similarity index 95% rename from src/docbkx/splitter.xml rename to docs/src/reference/docbook/splitter.xml index db1dcf3032..b22ffe64b8 100644 --- a/src/docbkx/splitter.xml +++ b/docs/src/reference/docbook/splitter.xml @@ -1,7 +1,6 @@ - - + Splitter
@@ -98,8 +97,8 @@ A reference to a bean defined in the application context. The bean must implement the splitting logic as described in the section above. Optional. - If reference to a bean is not provided, then it is assumed that the payload of the Message that arrived on the input-channel is - an implementation of java.util.Collection and the default splitting logic will be applied on such Collection, + If reference to a bean is not provided, then it is assumed that the payload of the Message that arrived on the input-channel is + an implementation of java.util.Collection and the default splitting logic will be applied on such Collection, incorporating each individual element into a Message and depositing it on the output-channel. @@ -122,12 +121,12 @@ - Using a "ref" attribute is generally recommended if the custom splitter handler implementation can be reused in other + Using a "ref" attribute is generally recommended if the custom splitter handler implementation can be reused in other <splitter> definitions. However if the custom splitter handler implementation should be scoped to a single definition of the <splitter>, you can configure an inner bean definition: - + output-channel="outChannel"> + ]]> diff --git a/docs/src/reference/docbook/stream.xml b/docs/src/reference/docbook/stream.xml new file mode 100644 index 0000000000..f4b1c35d8e --- /dev/null +++ b/docs/src/reference/docbook/stream.xml @@ -0,0 +1,91 @@ + + + Stream Support + +
+ Introduction + + In many cases application data is obtained from a stream. It is not recommended to send a reference to a Stream as a message payload to a consumer. Instead messages are created from data that is read from an input stream and message payloads are written to an output stream one by one. + +
+ +
+ Reading from streams + + Spring Integration provides two adapters for streams. Both ByteStreamReadingMessageSource and + CharacterStreamReadingMessageSource implement MessageSource. + By configuring one of these within a channel-adapter element, the polling period can be configured, + and the Message Bus can automatically detect and schedule them. The byte stream version requires an + InputStream, and the character stream version requires a Reader as + the single constructor argument. The ByteStreamReadingMessageSource also accepts the 'bytesPerMessage' + property to determine how many bytes it will attempt to read into each Message. The + default value is 1024 + + + + + + + +]]> + + +
+ +
+ Writing to streams + + For target streams, there are also two implementations: ByteStreamWritingMessageHandler and + CharacterStreamWritingMessageHandler. Each requires a single constructor argument - + OutputStream for byte streams or Writer for character streams, + and each provides a second constructor that adds the optional 'bufferSize'. Since both of these + ultimately implement the MessageHandler interface, they can be referenced from a + channel-adapter configuration as described in more detail in + . + + + + + + + +]]> + + +
+ + + +
+ Stream namespace support + + To reduce the configuration needed for stream related channel adapters there is a namespace defined. The following schema locations are needed to use it. + +]]> + + + To configure the inbound channel adapter the following code snippet shows the different configuration options that are supported. + + +]]> + + + To configure the outbound channel adapter you can use the namespace support as well. The following code snippet shows the different configuration for an outbound channel adapters. + + + + + + + + ]]> + +
+
diff --git a/docs/src/reference/docbook/transactions.xml b/docs/src/reference/docbook/transactions.xml new file mode 100644 index 0000000000..99c173f65e --- /dev/null +++ b/docs/src/reference/docbook/transactions.xml @@ -0,0 +1,175 @@ + + + Transaction Support + +
+ Understanding Transactions in Message flows + + Spring Integration exposes several hooks to address transactional needs of you message flows. + But to better understand these hooks and how you can benefit from them we must first revisit the 6 mechanisms + that could be used to initiate Message flows and see how transactional needs of these flows + could be addressed within each of these mechanisms. + + + Here are the 6 mechanisms to initiate a Message flow and their short summary (details for each are provided throughout this manual): + + + Gateway Proxy - Your basic Messaging Gateway + + + MessageChannel - Direct interactions with MessageChannel methods (e.g., channel.send(message)) + + + Message Publisher - the way to initiate message flow as a bi-product of method invocations on Spring beans + + + Inbound Channel Adapters/Gateways - the way to initiate message flow based on connecting third-party + system with Spring Integration messaging system(e.g., [JmsMessage] -> Jms Inbound Adapter[SI Message] -> SI Channel) + + + Scheduler - the way to initiate message flow based on scheduling events distributed + by a pre-configured Scheduler + + + Poller - similar to the Scheduler and is the way to initiate message flow based on scheduling + or interval-based events distributed by a pre-configured Poller + + + + + These 6 cold be split in 2 general categories: + + + Message flows initiated by a USER process - Example scenarios in this category + would be invoking a Gateway method or explicitly sending a Message to a MessageChannel. In other words these message flows depend on third + party process (e.g., some code that we wrote) to be initiated + + + Message flows initiated by the DAEMON process - Example scenarios in this category would be a Poller + polling for a Message queue to initiate a new Message flow with the polled Message or a Scheduler scheduling the + process, by creating a new Message and initiating a message flow at a predefined time + + + + + Clearly the Gateway Proxy, MessageChannel.send(..) and MessagePublisher are + all belong to the 1st category and Inbound Adapters/Gateways, Scheduler and Poller belong to the 2nd. + + + So, how do we address transactional needs in various scenarios within each category and is there a need for Spring Integration + to provide something explicitly with regard to transaction for a particular scenario or Spring's Transaction Support could be leveraged instead?. + + + + First of all, the first and obvious goal is NOT to re-invent something that has already been invented unless you can provide a beter solution. + In our case Spring itself provides a first class support for transaction management. So our goal here is not to provide something new but rather + delegate/use Spring to benefit from the existing support for transactions. In other words as a framework we must expose hooks to the Transaction management functionality + provided by Spring. But since Spring Integration configuration is based on Spring Configuration it is not always neccessery to expose these hooks as they already + expposed via Spring natively. Remeber every Spring Integration component is a Spring Bean after all. + + + With this goal in mind let's look at the two scenarios.  + + + If you think about it, Message flows that are initiated by the USER process (Category 1) and obviously configured in Spring Application Context, + are subject to transactional configuration of such process and therefore don't need to be explicitly configured by Spring Integration to support transactions. + The transaction could and should be initiated by such process through standard Transaction support provided by Spring and Spring Integration message flow will honor + transactional semantics of the components naturally because it is Spring configured. For example; A Gateway or ServiceActivator methods could + be annotated with @Transactional or TransactionInterceptor could be configured in XML configuration + with point-cut expression pointing to specific methods that should be transactional. + The bottom line you have full control over transaction configuration and boundaries in these scenarios. + + + + However, things are a bit different when it comes to Message flows initiated by the DAEMON process (Category 2). + Although configured by the developer these flows do not directly involve human or some other process to be initiated. These are trigger-based flows + that are initiated by a trigger process (DAEMON process) based on the configuration of such process. For example, we could have a Scheduler + initiating a message flow every Friday night of every week. We can also configure a trigger that initiates a Message flow every second, etc. + So, we obviously need the same way to let these trigger-based processes know of our intention to make these Message flows transactional so + Transaction context could be created whenever a new Message flow is initiated. In other words we need to expose some Transaction configuration, but ONLY enough + to delegate to Transaction support already provided by Spring (as we do in other scenarios). + + + + Spring Integration provides transactional support for Pollers. Pollers are a special case comoponents becouse + we can call receive() within that poller task against a resource that is itself transactional thus including receive() + call in the the boundaries of the Transaction allowing it to be rolled back in case of a task failure. If we were to add the same support + for channels, the added transactions would affect all downstream components starting with that send() call. That is + providing a rather wide scope for transaction demarcation without any strong reason especially when Spring already provides several way to + address transactional needs of any component downstream. However the receive() method being included in a transaction + boundary is the "strong reason" for pollers.  + + + + +
+ Poller Transaction Support + + Any time you configure a Poller you can provide transactional configuration via transactional element and its attributes: + + +]]> + As you can see this configuration looks evry similar to native Spring transaction configuration. You must still provide reference to Transaction manager and specify + transaction attributes or rely on defauls (e.g., if 'transaction-manager'' attribute is not specified then it will default to the bean with the name 'transactionManager'). + Internally the process would be wrapped in the Spring's native Transaction where TransactionInterceptor is responsible to handle transactions. + For more information on how to configure Transaction Manager, the types of Transaction Managers (e.g., JTA, Datasource etc.) and other details related to + transaction configuration please refer to Spring's Reference manual (Chapter 10 - Transaction Management). + + + With the above configuration all Message flows initiated by this poller will be transactional. For more information and details on + Poller's transactional configuration please refer to section - 21.1.1. Polling and Transactions. + + + + There times when besides transaction several more cross cutting concerns needs to be addressed when running Poller. To help with that, + Poller element defines <advice-chain> sub-element which allows you to define a custom chain of Advices + to be applied on the Poller. (see section 4.4 for more details) + In Spring Integration 2.0 Poller went through the major  refactoring effort and is now using proxy mechanism to address transactional + concerns as well as other cross cutting concerns, one of the significant changes evolving from this effort is that we + made <transactional> and <advice-chain> elements mutually exclusive. + The rational behind this is; If you need more then one advice, and one of them is Transaction advice, then you can simply + include it in the <advice-chain> with the same convenience as before but with much more control + since you now have an option to position any advice in the desired order.  + + + + + + + + + + + + + + +]]> + +As yo can see from the example above, we have provided a very basic XML-based configuration of Spring Transaction advice  - "txAdvice" and +included it within the <advice-chain> defined by the Poller. + +And if you only need to address transactional concerns of the Poller, then you can still use <transactional> element +as a convinience. + +
+
+
+ Transaction Boundaries + + Another important factor that needs to be understood is the boundaries of the Transactions within the Message flow. + When transaction is started, transaction context is bound to the current thread. So regardless of how many endpoints and channels you have in your + Message flow you transaction context will be preserved as long as you are ensuring that the flow continues on the same thread. + As soon as you break it by introducing a Pollable Channel or Executor Channel or initiate a new thread manually in some + service, the Transactional boundary will be broken as well. Essentially the Transaction will END right there and if + successfull hand of happened between the threads, the flow would be considered a success and COMMIT signal would be sent + even though the flow might still result in the exception somewhere downstream. If such flow was synchronous the exception would be thrown back to the + initiator of the Message flow who is also the initiator of the transactional context and transaction would result in a ROLLBACK. + +
+
diff --git a/src/docbkx/transformer.xml b/docs/src/reference/docbook/transformer.xml similarity index 69% rename from src/docbkx/transformer.xml rename to docs/src/reference/docbook/transformer.xml index 58587deef3..42014c7e67 100644 --- a/src/docbkx/transformer.xml +++ b/docs/src/reference/docbook/transformer.xml @@ -1,7 +1,6 @@ - - + Transformer
@@ -31,12 +30,12 @@
The <transformer> Element - The <transformer> element is used to create a Message-transforming endpoint. In addition to "input-channel" + The <transformer> element is used to create a Message-transforming endpoint. In addition to "input-channel" and "output-channel" attributes, it requires a "ref". The "ref" may either point to an Object that contains the @Transformer annotation on a single method (see below) or it may be combined with an explicit method name value provided via the "method" attribute. - + ]]> @@ -44,8 +43,8 @@ other <transformer> definitions. However if the custom transformer handler implementation should be scoped to a single definition of the <transformer>, you can define an inner bean definition: - + output-channel="outChannel"> + ]]> @@ -65,43 +64,43 @@ be sent (effectively the same behavior as a Message Filter returning false). Otherwise, the return value will be sent as the payload of an outbound reply Message. - - There are a also a few Transformer implementations available out of the box. Because, it is fairly common - to use the toString() representation of an Object, Spring Integration provides an - ObjectToStringTransformer whose output is a Message with a String payload. That String - is the result of invoking the toString operation on the inbound Message's payload. - ]]> - A potential example for this would be sending some arbitrary object to the 'outbound-channel-adapter' in the - file namespace. Whereas that Channel Adapter only supports String, byte-array, or - java.io.File payloads by default, adding this transformer immediately before the - adapter will handle the necessary conversion. Of course, that works fine as long as the result of the - toString() call is what you want to be written to the File. Otherwise, you can - just provide a custom POJO-based Transformer via the generic 'transformer' element shown previously. - - When debugging, this transformer is not typically necessary since the 'logging-channel-adapter' is capable - of logging the Message payload. Refer to for more detail. - - - - If you need to serialize an Object to a byte array or deserialize a byte array back into an Object, - Spring Integration provides symmetrical serialization transformers. - + + There are a also a few Transformer implementations available out of the box. Because, it is fairly common + to use the toString() representation of an Object, Spring Integration provides an + ObjectToStringTransformer whose output is a Message with a String payload. That String + is the result of invoking the toString operation on the inbound Message's payload. + ]]> + A potential example for this would be sending some arbitrary object to the 'outbound-channel-adapter' in the + file namespace. Whereas that Channel Adapter only supports String, byte-array, or + java.io.File payloads by default, adding this transformer immediately before the + adapter will handle the necessary conversion. Of course, that works fine as long as the result of the + toString() call is what you want to be written to the File. Otherwise, you can + just provide a custom POJO-based Transformer via the generic 'transformer' element shown previously. + + When debugging, this transformer is not typically necessary since the 'logging-channel-adapter' is capable + of logging the Message payload. Refer to for more detail. + + + + If you need to serialize an Object to a byte array or deserialize a byte array back into an Object, + Spring Integration provides symmetrical serialization transformers. + ]]> - - - If you only need to add headers to a Message, and they are not dynamically determined by Message content, - then referencing a custom implementation may be overkill. For that reason, Spring Integration provides the - 'header-enricher' element. + + + If you only need to add headers to a Message, and they are not dynamically determined by Message content, + then referencing a custom implementation may be overkill. For that reason, Spring Integration provides the + 'header-enricher' element.
]]> - As added convenience, Spring Integration also provides Object-to-Map and Map-to-Object transformers which - utilize Spring Expression Language (SpEL) to serialize and de-serialize the object graphs. Object hierarchy is introspected - to the most primitive types (e.g., String, int etc.). The path to this type is described via SpEL, which becomes the keykey in the - transformed Map with primitive type being the value. + As added convenience, Spring Integration also provides Object-to-Map and Map-to-Object transformers which + utilize Spring Expression Language (SpEL) to serialize and de-serialize the object graphs. Object hierarchy is introspected + to the most primitive types (e.g., String, int etc.). The path to this type is described via SpEL, which becomes the keykey in the + transformed Map with primitive type being the value. For example: @@ -120,7 +119,7 @@ public class Child{ {person.name=George, person.child.name=Jenna, person.child.nickNames[0]=Bimbo . . . etc} - SpEL-based Map allows you to describe the object structure without sharing the actual types allowing + SpEL-based Map allows you to describe the object structure without sharing the actual types allowing you to restore/rebuild the object graph into a differently typed Object graph as long as you maintain the structure. @@ -144,19 +143,19 @@ public class Kid{ ]]> Map-to-Object ]]> - or +                        output-channel="output"  +                         type="org.foo.Person"/>]]> + or - -]]> +                               output-channel="outputA"  +                               ref="person"/> + +]]> - NOTE: 'ref' and 'type' attributes are mutually exclusive. You can only use either one. - Also, if using 'ref' attribute you must point to a 'prototype' scoped bean, otherwise + NOTE: 'ref' and 'type' attributes are mutually exclusive. You can only use either one. + Also, if using 'ref' attribute you must point to a 'prototype' scoped bean, otherwise BeanCreationException will be thrown. 
@@ -174,11 +173,11 @@ Order generateOrder(String productId) { Transformer methods may also accept the @Header and @Headers annotations that is documented in - @Transformer + @Transformer Order generateOrder(String productId, @Header("customerName") String customer) { return new Order(productId, customer); }
-
\ No newline at end of file +
diff --git a/src/docbkx/ws.xml b/docs/src/reference/docbook/ws.xml similarity index 68% rename from src/docbkx/ws.xml rename to docs/src/reference/docbook/ws.xml index 1a4a2a3a02..254bae2b17 100644 --- a/src/docbkx/ws.xml +++ b/docs/src/reference/docbook/ws.xml @@ -1,6 +1,6 @@ - - + Web Services Support
@@ -19,18 +19,18 @@ marshallingGateway = new MarshallingWebServiceOutboundGateway(destinationProvider, marshaller); - When using the namespace support described below, you will only need to set a URI. Internally, the parser - will configure a fixed URI DestinationProvider implementation. If you do need dynamic resolution of the - URI at runtime, however, then the DestinationProvider can provide such behavior as looking up the URI from - a registry. See the Spring Web Services - javadoc for - more information about the DestinationProvider strategy. - + When using the namespace support described below, you will only need to set a URI. Internally, the parser + will configure a fixed URI DestinationProvider implementation. If you do need dynamic resolution of the + URI at runtime, however, then the DestinationProvider can provide such behavior as looking up the URI from + a registry. See the Spring Web Services + javadoc for + more information about the DestinationProvider strategy. + - For more detail on the inner workings, see the Spring Web Services reference guide's chapter covering + For more detail on the inner workings, see the Spring Web Services reference guide's chapter covering client access - as well as the chapter covering + as well as the chapter covering Object/XML mapping.
@@ -39,13 +39,13 @@ Inbound Web Service Gateways To send a message to a channel upon receiving a Web Service invocation, there are two options again: SimpleWebServiceInboundGateway and - MarshallingWebServiceInboundGateway. The former will extract a javax.xml.transform.Source + MarshallingWebServiceInboundGateway. The former will extract a javax.xml.transform.Source from the WebServiceMessage and set it as the message payload. The latter provides support for implementation of the Marshaller - and Unmarshaller interfaces. - If the incoming web service message is a SOAP message the SOAP Action header will be added to the headers of the + and Unmarshaller interfaces. + If the incoming web service message is a SOAP message the SOAP Action header will be added to the headers of the Message that is forwarded onto the request channel. - + simpleGateway = new SimpleWebServiceInboundGateway(); simpleGateway.setRequestChannel(forwardOntoThisChannel); simpleGateway.setReplyChannel(listenForResponseHere); //Optional @@ -54,13 +54,13 @@ //set request and optionally reply channel Both gateways implement the Spring Web Services MessageEndpoint -interface, so they can be configured with a MessageDispatcherServlet +interface, so they can be configured with a MessageDispatcherServlet as per standard Spring Web Services configuration. - For more detail on how to use these components, see the Spring Web Services reference guide's chapter covering + For more detail on how to use these components, see the Spring Web Services reference guide's chapter covering creating a Web Service. - The chapter covering + The chapter covering Object/XML mapping is also applicable again.
@@ -72,28 +72,28 @@ as per standard Spring Web Services configuration. request-channel="inputChannel" uri="http://example.org"/>]]> - Notice that this example does not provide a 'reply-channel'. If the Web Service were to - return a non-empty response, the Message containing that response would be sent to the - reply channel provided in the request Message's REPLY_CHANNEL header, and if that were - not available a channel resolution Exception would be thrown. If you want to send the - reply to another channel instead, then provide a 'reply-channel' attribute on the - 'outbound-gateway' element. - - - When invoking a Web Service that returns an empty response after using a String payload - for the request Message, no reply Message will be sent by default. - Therefore you don't need to set a 'reply-channel' or have a REPLY_CHANNEL header in the - request Message. If for any reason you actually do want to receive - the empty response as a Message, then provide the 'ignore-empty-responses' attribute with - a value of false (this only applies for Strings, because using a - Source or Document object simply leads to a NULL response and will therefore - never generate a reply Message). - + Notice that this example does not provide a 'reply-channel'. If the Web Service were to + return a non-empty response, the Message containing that response would be sent to the + reply channel provided in the request Message's REPLY_CHANNEL header, and if that were + not available a channel resolution Exception would be thrown. If you want to send the + reply to another channel instead, then provide a 'reply-channel' attribute on the + 'outbound-gateway' element. + + + When invoking a Web Service that returns an empty response after using a String payload + for the request Message, no reply Message will be sent by default. + Therefore you don't need to set a 'reply-channel' or have a REPLY_CHANNEL header in the + request Message. If for any reason you actually do want to receive + the empty response as a Message, then provide the 'ignore-empty-responses' attribute with + a value of false (this only applies for Strings, because using a + Source or Document object simply leads to a NULL response and will therefore + never generate a reply Message). + To set up an inbound Web Service Gateway, use the "inbound-gateway": ]]> - + To use Spring OXM Marshallers and/or Unmarshallers, provide bean references. For outbound: Most Marshaller implementations also implement the - Unmarshaller interface. When using such a - Marshaller, only the "marshaller" - attribute is necessary. Even when using a Marshaller, + Unmarshaller interface. When using such a + Marshaller, only the "marshaller" + attribute is necessary. Even when using a Marshaller, you may also provide a reference for the "request-callback" on the outbound gateways. - - For either outbound gateway type, a "destination-provider" attribute can be specified instead of the "uri" - (exactly one of them is required). You can then reference any Spring Web Services DestinationProvider - implementation (e.g. to lookup the URI at runtime from a registry). - + + For either outbound gateway type, a "destination-provider" attribute can be specified instead of the "uri" + (exactly one of them is required). You can then reference any Spring Web Services DestinationProvider + implementation (e.g. to lookup the URI at runtime from a registry). + For either outbound gateway type, the "message-factory" attribute can also be configured with a reference to any Spring Web Services WebServiceMessageFactory implementation. For the simple inbound gateway type, the "extract-payload" attribute can be set to false to forward - the entire WebServiceMessage instead of just its payload as a + the entire WebServiceMessage instead of just its payload as a Message to the request channel. This might be useful, for example, when a custom Transformer works against the WebServiceMessage directly.
-
\ No newline at end of file +
diff --git a/docs/src/reference/docbook/xml.xml b/docs/src/reference/docbook/xml.xml new file mode 100644 index 0000000000..f466fc7014 --- /dev/null +++ b/docs/src/reference/docbook/xml.xml @@ -0,0 +1,505 @@ + + + XML Support - Dealing with XML Payloads + +
+ Introduction + + Spring Integration's XML support extends the Spring Integration Core with + implementations of splitter, transformer, selector and router designed + to make working with xml messages in Spring Integration simple. The provided messaging + components are designed to work with xml represented in a range of formats including + instances of + java.lang.String, org.w3c.dom.Document + and javax.xml.transform.Source. It should be noted however that + where a DOM representation is required, for example in order to evaluate an XPath expression, + the String payload will be converted into the required type and then + converted back again to String. Components that require an instance of + DocumentBuilder will create a namespace aware instance if one is + not provided. Where greater control of the document being created is required an appropriately + configured instance of DocumentBuilder should be provided. + +
+
+ Transforming xml payloads + + This section will explain the workings of + UnmarshallingTransformer, + MarshallingTransformer, + XsltPayloadTransformer + and how to configure them as + beans. All of the provided xml transformers extend + AbstractTransformer or AbstractPayloadTransformer + and therefore implement Transformer. When configuring xml + transformers as beans in Spring Integration you would normally configure the transformer + in conjunction with either a MessageTransformingChannelInterceptor or a + MessageTransformingHandler. This allows the transformer to be used as either an interceptor, + which transforms the message as it is sent or received to the channel, or as an endpoint. Finally the + namespace support will be discussed which allows for the simple configuration of the transformers as + elements in XML. + + + UnmarshallingTransformer allows an xml Source + to be unmarshalled using implementations of Spring OXM Unmarshaller. + Spring OXM provides several implementations supporting marshalling and unmarshalling using JAXB, + Castor and JiBX amongst others. Since the unmarshaller requires an instance of + Source where the message payload is not currently an instance of + Source, conversion will be attempted. Currently String + and org.w3c.dom.Document payloads are supported. Custom conversion to a + Source is also supported by injecting an implementation of + SourceFactory. + + + + + + +]]> + + + The MarshallingTransformer allows an object graph to be converted + into xml using a Spring OXM Marshaller. By default the + MarshallingTransformer will return a DomResult. + However the type of result can be controlled by configuring an alternative ResultFactory + such as StringResultFactory. In many cases it will be more convenient to transform + the payload into an alternative xml format. To achieve this configure a + ResultTransformer. Two implementations are provided, one which converts to + String and another which converts to Document. + + + + + + + + + +]]> + + + By default, the MarshallingTransformer will pass the payload Object + to the Marshaller, but if its boolean "extractPayload" property + is set to "false", the entire Message instance will be passed + to the Marshaller instead. That may be useful for certain custom + implementations of the Marshaller interface, but typically the + payload is the appropriate source Object for marshalling when delegating to any of the various + out-of-the-box Marshaller implementations. + + + XsltPayloadTransformer transforms xml payloads using xsl. + The transformer requires an instance of either Resource or + Templates. Passing in a Templates instance + allows for greater configuration of the TransformerFactory used to create + the template instance. As in the case of XmlPayloadMarshallingTransformer + by default XsltPayloadTransformer will create a message with a + Result payload. This can be customised by providing a + ResultFactory and/or a ResultTransformer. + + + + + +]]> + +
+
+ + Namespace support for xml transformers + + Namespace support for all xml transformers is provided in the Spring Integration xml namespace, + a template for which can be seen below. The namespace support for transformers creates an instance of either + EventDrivenConsumer or PollingConsumer + according to the type of the provided input channel. The namespace support is designed + to reduce the amount of xml configuration by allowing the creation of an endpoint and transformer + using one element. + + +]]> + The namespace support for UnmarshallingTransformer is shown below. + Since the namespace is now creating an endpoint instance rather than a transformer, + a poller can also be nested within the element to control the polling of the input channel. + + + + + + ]]> + + + + The namespace support for the marshalling transformer requires an input channel, output channel and a + reference to a marshaller. The optional result-type attribute can be used to control the type of result created, + valid values are StringResult or DomResult (the default). Where the provided result types are not sufficient a + reference to a custom implementation of ResultFactory can be provided as an alternative + to setting the result-type attribute using the result-factory attribute. An optional result-transformer can also be + specified in order to convert the created Result after marshalling. + + + + +]]> + + + + Namespace support for the XsltPayloadTransformer allows either a resource to be passed in in order to create the + Templates instance or alternatively a precreated Templates + instance can be passed in as a reference. In common with the marshalling transformer the type of the result output can + be controlled by specifying either the result-factory or result-type attribute. A result-transfomer attribute can also + be used to reference an implementation of ResultTransfomer where conversion of the result + is required before sending. + +]]> + + + Very often to assist with transformation you may need to have access to Message data (e.g., Message Headers). For example; you may need to get access to certain Message Headers + and pass them on as parameters to a transformer (e.g., transformer.setParameter(..)).  + Spring Integration provides two convenient ways to accomplish this. Just look at the following XML snippet. + + + + +]]> + If message header names match 1:1 to parameter names, you can simply use xslt-param-headers attribute. There you can also use wildcards for + simple pattern matching which supports the following simple pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy". + + + You can also configure individual xslt parameters via xslt-param sub element. There you can use expression or value attribute. + The expression attribute should be any valid SpEL expression with Message being the root object of the expression evaluation context. + The value attribute just like any value in Spring beans allows you to specify simple scalar vallue. YOu can also use property placeholders (e.g., ${some.value}) + So as you can see, with the expression and value attribute xslt parameters could now be mapped to any accessible part of the Message as well as any literal value. + +
+ +
+ Splitting xml messages + + XPathMessageSplitter supports messages with either + String or Document payloads. + The splitter uses the provided XPath expression to split the payload into a number of + nodes. By default this will result in each Node instance + becoming the payload of a new message. Where it is preferred that each message be a Document + the createDocuments flag can be set. Where a String payload is passed + in the payload will be converted then split before being converted back to a number of String + messages. The XPath splitter implements MessageHandler and should + therefore be configured in conjunction with an appropriate endpoint (see the namespace support below + for a simpler configuration alternative). + + + + + + + + + +]]> + + +
+ +
+ Routing xml messages using XPath + + Two Router implementations based on XPath are provided XPathSingleChannelRouter and + XPathMultiChannelRouter. The implementations differ in respect to how many channels + any given message may be routed to, exactly one in the case of the single channel version + or zero or more in the case of the multichannel router. Both evaluate an XPath + expression against the xml payload of the message, supported payload types by default + are Node, Document and + String. For other payload types a custom implementation + of XmlPayloadConverter can be provided. The router + implementations use ChannelResolver to convert the + result(s) of the XPath expression to a channel name. By default a + BeanFactoryChannelResolver strategy will be used, this means that the string returned by the XPath + evaluation should correspond directly to the name of a channel. Where this is not the case + an alternative implementation of ChannelResolver can + be used. Where there is a simple mapping from Xpath result to channel name + the provided MapBasedChannelResolver can be used. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + +
+ +
+ Selecting xml messages using XPath + + Two MessageSelector implementations are provided, + BooleanTestXPathMessageSelector and StringValueTestXPathMessageSelector. + BooleanTestXPathMessageSelector requires an XPathExpression which evaluates to a boolean, + for example boolean(/one/two) which will only select messages which have an element named + two which is a child of a root element named one. StringValueTestXPathMessageSelector + evaluates any XPath expression as a String and compares the result with the provided value. + + + + + + + + + + + + + + + + + + + + +]]> +
+ +
+ Transforming xml messages using XPath + + When it comes to message transformation XPath is a great way to transform Messages that have XML + payloads by defining XPath transformers via xpath-transformer element. + + + Simple XPath transformation + + + Let's look at the following transformer configuration: + ]]> + + . . . and Message + message = + MessageBuilder.withPayload("").build();]]> + After sending this message to the 'inputChannel' the XPath transformer configured above will transform + this XML Message to a simple Message with payload of 'John Doe' all based on + the simple XPath Expression specified in the xpath-expression attribute. + + + XPath also has capability to perform simple conversion of extracted elements + to a desired type. Valid return types are defined in XPathConstants and follows + the conversion rules specified by the XPath. + + + The following constants are defined by the XPathConstants: BOOLEAN, DOM_OBJECT_MODEL, NODE, NODESET, NUMBER, STRING + + + You can configure the desired type by simply using evaluation-type + attribute of the xpath-transformer element. + + + +]]> + + + Node Mappers + + + If you need to provide custom mapping for the node extracted by the XPath expression simply provide a reference to the + implementation of the org.springframework.xml.xpath.NodeMapper - an interface used by + XPathOperations implementations for mapping Node objects on a per-node basis. To provide a + reference to a NodeMapper simply use node-mapper attribute: + +]]> +. . . and Sample NodeMapper implementation: + + + + XML Payload Converter + + + You can also use implementation of the org.springframework.integration.xml.XmlPayloadConverter to + provide more granular transformation: + +]]> +. . . and Sample XmlPayloadConverter implementation: +"))); + } + catch (Exception e) { + throw new IllegalStateException(e); + } + } + // + public Document convertToDocument(Object object) { + throw new UnsupportedOperationException(); + } +}]]> + + + Combination of SpEL and XPath expressions + + + You can also combine Spring Expression Language (SpEL) expressions with XPath expression and configure + them using expression attribute: + ]]> + In the above case the overall result of the expression will be the result of the XPathe expression multiplied by 2. + +
+ + +
+ XPath components namespace support + All XPath based components have namespace support allowing them to be configured as + Message Endpoints with the exception of the XPath selectors which are not designed to act as + endpoints. Each component allows the XPath to either be referenced at the top level or configured via a nested + xpath-expression element. So the following configurations of an xpath-selector are all valid and represent the general + form of XPath namespace support. All forms of XPath expression result in the creation of an + XPathExpression using the Spring XPathExpressionFactory + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + XPath splitter namespace support allows the creation of a Message Endpoint with an input channel and output channel. + + + + + + + + + +]]> + + + XPath router namespace support allows for the creation of a Message Endpoint with an input channel but no output channel + since the output channel is determined dynamically. The multi-channel attribute causes the creation of a multi channel router capable of + routing a single message to many channels when true and a single channel router when false. + + + + + + + + + +]]> + +
+ +
diff --git a/src/docbkx/xmpp.xml b/docs/src/reference/docbook/xmpp.xml similarity index 98% rename from src/docbkx/xmpp.xml rename to docs/src/reference/docbook/xmpp.xml index 7ee1f384a0..9576a9fe9c 100644 --- a/src/docbkx/xmpp.xml +++ b/docs/src/reference/docbook/xmpp.xml @@ -1,7 +1,6 @@ - - + XMPP Support Spring Integration provides Channel Adapters for XMPP. @@ -21,7 +20,7 @@ XMPP provides the messaging fabric that underlies some of the biggest Instant Messaging networks in the world, including Google Talk (GTalk) @@ -241,7 +240,7 @@ public class XmppMessageConsumer { String text = input.getBody(); System.out.println( "Received message: " + text ) ; } - + } ]]> @@ -342,7 +341,7 @@ public class XmppMessageConsumer { let people who have you on their roster see your state changes. This happens all the time with your IM clients - you change your away status, and then set an away message, and everybody who has you on their roster sees your icon or username change to reflect this new state, and additionally might see your new "away" message. - + If you would like to receive notification, or notify others, of state changes, you can use Spring Integration's "presence" adapters. @@ -352,10 +351,7 @@ public class XmppMessageConsumer { The header keys specific to these "presence" adapters start with the token "PRESENCE_". - Not all headers are available for both inbound and outbound. - - - + Not all headers are available for both inbound and outbound. Header Values @@ -443,4 +439,4 @@ public class XmppMessageConsumer { --> - \ No newline at end of file + diff --git a/src/docbkx/resources/css/highlight.css b/docs/src/reference/resources/css/highlight.css similarity index 100% rename from src/docbkx/resources/css/highlight.css rename to docs/src/reference/resources/css/highlight.css diff --git a/src/docbkx/resources/css/html.css b/docs/src/reference/resources/css/html.css similarity index 100% rename from src/docbkx/resources/css/html.css rename to docs/src/reference/resources/css/html.css diff --git a/docs/src/reference/resources/css/manual.css b/docs/src/reference/resources/css/manual.css new file mode 100644 index 0000000000..524d462211 --- /dev/null +++ b/docs/src/reference/resources/css/manual.css @@ -0,0 +1,69 @@ +@IMPORT url("highlight.css"); + +html { + padding: 0pt; + margin: 0pt; +} + +body { + margin-left: 10%; + margin-right: 10%; + font-family: Arial, Sans-serif; +} + +div { + margin: 0pt; +} + +p { + text-align: justify; +} + +hr { + border: 1px solid gray; + background: gray; +} + +h1,h2,h3,h4 { + color: #234623; + font-family: Arial, Sans-serif; +} + +pre { + line-height: 1.0; + color: black; +} + +pre.programlisting { + font-size: 10pt; + padding: 7pt 3pt; + border: 1pt solid black; + background: #eeeeee; + clear: both; +} + +div.table { + margin: 1em; + padding: 0.5em; + text-align: center; +} + +div.table table { + display: table; + width: 100%; +} + +div.table td { + padding-left: 7px; + padding-right: 7px; +} + +.sidebar { + float: right; + margin: 10px 0 10px 30px; + padding: 10px 20px 20px 20px; + width: 33%; + border: 1px solid black; + background-color: #F4F4F4; + font-size: 14px; +} diff --git a/src/docbkx/resources/css/stylesheet.css b/docs/src/reference/resources/css/stylesheet.css similarity index 100% rename from src/docbkx/resources/css/stylesheet.css rename to docs/src/reference/resources/css/stylesheet.css diff --git a/src/docbkx/resources/images/bank-router.png b/docs/src/reference/resources/images/bank-router.png similarity index 100% rename from src/docbkx/resources/images/bank-router.png rename to docs/src/reference/resources/images/bank-router.png diff --git a/src/docbkx/resources/images/cafe-demo.png b/docs/src/reference/resources/images/cafe-demo.png similarity index 100% rename from src/docbkx/resources/images/cafe-demo.png rename to docs/src/reference/resources/images/cafe-demo.png diff --git a/src/docbkx/resources/images/cafe-eip.png b/docs/src/reference/resources/images/cafe-eip.png similarity index 100% rename from src/docbkx/resources/images/cafe-eip.png rename to docs/src/reference/resources/images/cafe-eip.png diff --git a/docs/src/reference/resources/images/callouts/1.gif b/docs/src/reference/resources/images/callouts/1.gif new file mode 100644 index 0000000000..9e7a87f754 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/1.gif differ diff --git a/docs/src/reference/resources/images/callouts/1.png b/docs/src/reference/resources/images/callouts/1.png new file mode 100644 index 0000000000..7d473430b7 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/1.png differ diff --git a/docs/src/reference/resources/images/callouts/1.svg b/docs/src/reference/resources/images/callouts/1.svg new file mode 100644 index 0000000000..e2e87dc526 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/1.svg @@ -0,0 +1,15 @@ + + + + +]> + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/10.gif b/docs/src/reference/resources/images/callouts/10.gif new file mode 100644 index 0000000000..e80f7f8e63 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/10.gif differ diff --git a/docs/src/reference/resources/images/callouts/10.png b/docs/src/reference/resources/images/callouts/10.png new file mode 100644 index 0000000000..997bbc8246 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/10.png differ diff --git a/docs/src/reference/resources/images/callouts/10.svg b/docs/src/reference/resources/images/callouts/10.svg new file mode 100644 index 0000000000..4740f587bd --- /dev/null +++ b/docs/src/reference/resources/images/callouts/10.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/11.gif b/docs/src/reference/resources/images/callouts/11.gif new file mode 100644 index 0000000000..67f91a239d Binary files /dev/null and b/docs/src/reference/resources/images/callouts/11.gif differ diff --git a/docs/src/reference/resources/images/callouts/11.png b/docs/src/reference/resources/images/callouts/11.png new file mode 100644 index 0000000000..ce47dac3f5 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/11.png differ diff --git a/docs/src/reference/resources/images/callouts/11.svg b/docs/src/reference/resources/images/callouts/11.svg new file mode 100644 index 0000000000..09a0b2cf71 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/11.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/12.gif b/docs/src/reference/resources/images/callouts/12.gif new file mode 100644 index 0000000000..54c4b42f19 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/12.gif differ diff --git a/docs/src/reference/resources/images/callouts/12.png b/docs/src/reference/resources/images/callouts/12.png new file mode 100644 index 0000000000..31daf4e2f2 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/12.png differ diff --git a/docs/src/reference/resources/images/callouts/12.svg b/docs/src/reference/resources/images/callouts/12.svg new file mode 100644 index 0000000000..9794044c71 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/12.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/13.gif b/docs/src/reference/resources/images/callouts/13.gif new file mode 100644 index 0000000000..dd5d7d9b64 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/13.gif differ diff --git a/docs/src/reference/resources/images/callouts/13.png b/docs/src/reference/resources/images/callouts/13.png new file mode 100644 index 0000000000..14021a89c2 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/13.png differ diff --git a/docs/src/reference/resources/images/callouts/13.svg b/docs/src/reference/resources/images/callouts/13.svg new file mode 100644 index 0000000000..64268bb4fa --- /dev/null +++ b/docs/src/reference/resources/images/callouts/13.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/14.gif b/docs/src/reference/resources/images/callouts/14.gif new file mode 100644 index 0000000000..3d7a952a31 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/14.gif differ diff --git a/docs/src/reference/resources/images/callouts/14.png b/docs/src/reference/resources/images/callouts/14.png new file mode 100644 index 0000000000..64014b75fe Binary files /dev/null and b/docs/src/reference/resources/images/callouts/14.png differ diff --git a/docs/src/reference/resources/images/callouts/14.svg b/docs/src/reference/resources/images/callouts/14.svg new file mode 100644 index 0000000000..469aa97487 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/14.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/15.gif b/docs/src/reference/resources/images/callouts/15.gif new file mode 100644 index 0000000000..1c9183d5bb Binary files /dev/null and b/docs/src/reference/resources/images/callouts/15.gif differ diff --git a/docs/src/reference/resources/images/callouts/15.png b/docs/src/reference/resources/images/callouts/15.png new file mode 100644 index 0000000000..0d65765fcf Binary files /dev/null and b/docs/src/reference/resources/images/callouts/15.png differ diff --git a/docs/src/reference/resources/images/callouts/15.svg b/docs/src/reference/resources/images/callouts/15.svg new file mode 100644 index 0000000000..8202233ef0 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/15.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/16.svg b/docs/src/reference/resources/images/callouts/16.svg new file mode 100644 index 0000000000..01d6bf8164 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/16.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/17.svg b/docs/src/reference/resources/images/callouts/17.svg new file mode 100644 index 0000000000..0a04c5560e --- /dev/null +++ b/docs/src/reference/resources/images/callouts/17.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/18.svg b/docs/src/reference/resources/images/callouts/18.svg new file mode 100644 index 0000000000..1cb891b34d --- /dev/null +++ b/docs/src/reference/resources/images/callouts/18.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/19.svg b/docs/src/reference/resources/images/callouts/19.svg new file mode 100644 index 0000000000..e6fbb179fc --- /dev/null +++ b/docs/src/reference/resources/images/callouts/19.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/2.gif b/docs/src/reference/resources/images/callouts/2.gif new file mode 100644 index 0000000000..94d42a30f9 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/2.gif differ diff --git a/docs/src/reference/resources/images/callouts/2.png b/docs/src/reference/resources/images/callouts/2.png new file mode 100644 index 0000000000..5d09341b2f Binary files /dev/null and b/docs/src/reference/resources/images/callouts/2.png differ diff --git a/docs/src/reference/resources/images/callouts/2.svg b/docs/src/reference/resources/images/callouts/2.svg new file mode 100644 index 0000000000..07d03395d0 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/2.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/20.svg b/docs/src/reference/resources/images/callouts/20.svg new file mode 100644 index 0000000000..ccbfd40319 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/20.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/21.svg b/docs/src/reference/resources/images/callouts/21.svg new file mode 100644 index 0000000000..93ec53fdd9 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/21.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/22.svg b/docs/src/reference/resources/images/callouts/22.svg new file mode 100644 index 0000000000..f48c5f3fd1 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/22.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/23.svg b/docs/src/reference/resources/images/callouts/23.svg new file mode 100644 index 0000000000..6624212957 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/23.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/24.svg b/docs/src/reference/resources/images/callouts/24.svg new file mode 100644 index 0000000000..a3d552535f --- /dev/null +++ b/docs/src/reference/resources/images/callouts/24.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/25.svg b/docs/src/reference/resources/images/callouts/25.svg new file mode 100644 index 0000000000..56614a979a --- /dev/null +++ b/docs/src/reference/resources/images/callouts/25.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/26.svg b/docs/src/reference/resources/images/callouts/26.svg new file mode 100644 index 0000000000..56faeaca30 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/26.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/27.svg b/docs/src/reference/resources/images/callouts/27.svg new file mode 100644 index 0000000000..a75c812159 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/27.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/28.svg b/docs/src/reference/resources/images/callouts/28.svg new file mode 100644 index 0000000000..7f8cf1a350 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/28.svg @@ -0,0 +1,23 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/29.svg b/docs/src/reference/resources/images/callouts/29.svg new file mode 100644 index 0000000000..cb63adf1fe --- /dev/null +++ b/docs/src/reference/resources/images/callouts/29.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/3.gif b/docs/src/reference/resources/images/callouts/3.gif new file mode 100644 index 0000000000..dd3541a1bc Binary files /dev/null and b/docs/src/reference/resources/images/callouts/3.gif differ diff --git a/docs/src/reference/resources/images/callouts/3.png b/docs/src/reference/resources/images/callouts/3.png new file mode 100644 index 0000000000..ef7b700471 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/3.png differ diff --git a/docs/src/reference/resources/images/callouts/3.svg b/docs/src/reference/resources/images/callouts/3.svg new file mode 100644 index 0000000000..918be806f4 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/3.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/30.svg b/docs/src/reference/resources/images/callouts/30.svg new file mode 100644 index 0000000000..dc43ba1e3c --- /dev/null +++ b/docs/src/reference/resources/images/callouts/30.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/4.gif b/docs/src/reference/resources/images/callouts/4.gif new file mode 100644 index 0000000000..4bcbf7e31a Binary files /dev/null and b/docs/src/reference/resources/images/callouts/4.gif differ diff --git a/docs/src/reference/resources/images/callouts/4.png b/docs/src/reference/resources/images/callouts/4.png new file mode 100644 index 0000000000..adb8364eb5 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/4.png differ diff --git a/docs/src/reference/resources/images/callouts/4.svg b/docs/src/reference/resources/images/callouts/4.svg new file mode 100644 index 0000000000..8eb6a53b3b --- /dev/null +++ b/docs/src/reference/resources/images/callouts/4.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/5.gif b/docs/src/reference/resources/images/callouts/5.gif new file mode 100644 index 0000000000..1c62b4f920 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/5.gif differ diff --git a/docs/src/reference/resources/images/callouts/5.png b/docs/src/reference/resources/images/callouts/5.png new file mode 100644 index 0000000000..4d7eb46002 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/5.png differ diff --git a/docs/src/reference/resources/images/callouts/5.svg b/docs/src/reference/resources/images/callouts/5.svg new file mode 100644 index 0000000000..ca7a9f22f6 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/5.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/6.gif b/docs/src/reference/resources/images/callouts/6.gif new file mode 100644 index 0000000000..23bc5555d2 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/6.gif differ diff --git a/docs/src/reference/resources/images/callouts/6.png b/docs/src/reference/resources/images/callouts/6.png new file mode 100644 index 0000000000..0ba694af6c Binary files /dev/null and b/docs/src/reference/resources/images/callouts/6.png differ diff --git a/docs/src/reference/resources/images/callouts/6.svg b/docs/src/reference/resources/images/callouts/6.svg new file mode 100644 index 0000000000..783a0b9d77 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/6.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/7.gif b/docs/src/reference/resources/images/callouts/7.gif new file mode 100644 index 0000000000..e55ce89585 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/7.gif differ diff --git a/docs/src/reference/resources/images/callouts/7.png b/docs/src/reference/resources/images/callouts/7.png new file mode 100644 index 0000000000..472e96f8ac Binary files /dev/null and b/docs/src/reference/resources/images/callouts/7.png differ diff --git a/docs/src/reference/resources/images/callouts/7.svg b/docs/src/reference/resources/images/callouts/7.svg new file mode 100644 index 0000000000..59b3714b56 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/7.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/8.gif b/docs/src/reference/resources/images/callouts/8.gif new file mode 100644 index 0000000000..49375e09f4 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/8.gif differ diff --git a/docs/src/reference/resources/images/callouts/8.png b/docs/src/reference/resources/images/callouts/8.png new file mode 100644 index 0000000000..5e60973c21 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/8.png differ diff --git a/docs/src/reference/resources/images/callouts/8.svg b/docs/src/reference/resources/images/callouts/8.svg new file mode 100644 index 0000000000..c1803a3c0d --- /dev/null +++ b/docs/src/reference/resources/images/callouts/8.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + diff --git a/docs/src/reference/resources/images/callouts/9.gif b/docs/src/reference/resources/images/callouts/9.gif new file mode 100644 index 0000000000..da12a4fe28 Binary files /dev/null and b/docs/src/reference/resources/images/callouts/9.gif differ diff --git a/docs/src/reference/resources/images/callouts/9.png b/docs/src/reference/resources/images/callouts/9.png new file mode 100644 index 0000000000..a0676d26cc Binary files /dev/null and b/docs/src/reference/resources/images/callouts/9.png differ diff --git a/docs/src/reference/resources/images/callouts/9.svg b/docs/src/reference/resources/images/callouts/9.svg new file mode 100644 index 0000000000..bc149d3cb2 --- /dev/null +++ b/docs/src/reference/resources/images/callouts/9.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/src/docbkx/resources/images/chain.png b/docs/src/reference/resources/images/chain.png similarity index 100% rename from src/docbkx/resources/images/chain.png rename to docs/src/reference/resources/images/chain.png diff --git a/src/docbkx/resources/images/channel.png b/docs/src/reference/resources/images/channel.png similarity index 100% rename from src/docbkx/resources/images/channel.png rename to docs/src/reference/resources/images/channel.png diff --git a/src/docbkx/resources/images/gateway.png b/docs/src/reference/resources/images/gateway.png similarity index 100% rename from src/docbkx/resources/images/gateway.png rename to docs/src/reference/resources/images/gateway.png diff --git a/src/docbkx/resources/images/handler-endpoint.png b/docs/src/reference/resources/images/handler-endpoint.png similarity index 100% rename from src/docbkx/resources/images/handler-endpoint.png rename to docs/src/reference/resources/images/handler-endpoint.png diff --git a/src/docbkx/resources/images/handler.png b/docs/src/reference/resources/images/handler.png similarity index 100% rename from src/docbkx/resources/images/handler.png rename to docs/src/reference/resources/images/handler.png diff --git a/docs/src/reference/resources/images/important.png b/docs/src/reference/resources/images/important.png new file mode 100644 index 0000000000..12c90f607a Binary files /dev/null and b/docs/src/reference/resources/images/important.png differ diff --git a/src/docbkx/resources/images/loan-broker-eip.png b/docs/src/reference/resources/images/loan-broker-eip.png similarity index 100% rename from src/docbkx/resources/images/loan-broker-eip.png rename to docs/src/reference/resources/images/loan-broker-eip.png diff --git a/src/docbkx/resources/images/logo.png b/docs/src/reference/resources/images/logo.png similarity index 100% rename from src/docbkx/resources/images/logo.png rename to docs/src/reference/resources/images/logo.png diff --git a/src/docbkx/resources/images/message-bus.png b/docs/src/reference/resources/images/message-bus.png similarity index 100% rename from src/docbkx/resources/images/message-bus.png rename to docs/src/reference/resources/images/message-bus.png diff --git a/src/docbkx/resources/images/message.png b/docs/src/reference/resources/images/message.png similarity index 100% rename from src/docbkx/resources/images/message.png rename to docs/src/reference/resources/images/message.png diff --git a/docs/src/reference/resources/images/note.png b/docs/src/reference/resources/images/note.png new file mode 100644 index 0000000000..ad57f6f72e Binary files /dev/null and b/docs/src/reference/resources/images/note.png differ diff --git a/src/docbkx/resources/images/quotes-aggregator.png b/docs/src/reference/resources/images/quotes-aggregator.png similarity index 100% rename from src/docbkx/resources/images/quotes-aggregator.png rename to docs/src/reference/resources/images/quotes-aggregator.png diff --git a/src/docbkx/resources/images/router.png b/docs/src/reference/resources/images/router.png similarity index 100% rename from src/docbkx/resources/images/router.png rename to docs/src/reference/resources/images/router.png diff --git a/src/docbkx/resources/images/source-endpoint.png b/docs/src/reference/resources/images/source-endpoint.png similarity index 100% rename from src/docbkx/resources/images/source-endpoint.png rename to docs/src/reference/resources/images/source-endpoint.png diff --git a/src/docbkx/resources/images/source.png b/docs/src/reference/resources/images/source.png similarity index 100% rename from src/docbkx/resources/images/source.png rename to docs/src/reference/resources/images/source.png diff --git a/src/docbkx/resources/images/target-endpoint.png b/docs/src/reference/resources/images/target-endpoint.png similarity index 100% rename from src/docbkx/resources/images/target-endpoint.png rename to docs/src/reference/resources/images/target-endpoint.png diff --git a/src/docbkx/resources/images/target.png b/docs/src/reference/resources/images/target.png similarity index 100% rename from src/docbkx/resources/images/target.png rename to docs/src/reference/resources/images/target.png diff --git a/docs/src/reference/resources/images/tip.png b/docs/src/reference/resources/images/tip.png new file mode 100644 index 0000000000..5c4aab3bb3 Binary files /dev/null and b/docs/src/reference/resources/images/tip.png differ diff --git a/src/docbkx/resources/images/xdev-spring_logo.jpg b/docs/src/reference/resources/images/xdev-spring_logo.jpg similarity index 100% rename from src/docbkx/resources/images/xdev-spring_logo.jpg rename to docs/src/reference/resources/images/xdev-spring_logo.jpg diff --git a/src/docbkx/resources/xsl/html/html_chunk.xsl b/docs/src/reference/resources/xsl/html-custom.xsl similarity index 67% rename from src/docbkx/resources/xsl/html/html_chunk.xsl rename to docs/src/reference/resources/xsl/html-custom.xsl index 81e6ab2358..76e6fb0bbe 100644 --- a/src/docbkx/resources/xsl/html/html_chunk.xsl +++ b/docs/src/reference/resources/xsl/html-custom.xsl @@ -24,8 +24,17 @@ exclude-result-prefixes="xslthl" version='1.0'> + + + '5' - + '1' + + + 1 + + + 1 1 @@ -35,23 +44,26 @@ images/ - .gif + .png 120 images/callouts/ - .gif + .png - css/stylesheet.css + css/manual.css text/css book toc,title text-align: left + + + - + @@ -70,39 +82,36 @@ - - - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/docs/src/reference/resources/xsl/html-single-custom.xsl b/docs/src/reference/resources/xsl/html-single-custom.xsl new file mode 100644 index 0000000000..63ccaaff6c --- /dev/null +++ b/docs/src/reference/resources/xsl/html-single-custom.xsl @@ -0,0 +1,142 @@ + + + + + + + + + + + 1 + + + 1 + + + 1 + 0 + 1 + + + + images/ + .png + + 120 + images/callouts/ + .png + + + css/manual.css + text/css + book toc,title + + text-align: left + + + + + + + + + + + + + + 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Begin Google Analytics code + + +End Google Analytics code + + + + +Begin LoopFuse code + + +End LoopFuse code + + + \ No newline at end of file diff --git a/docs/src/reference/resources/xsl/pdf-custom.xsl b/docs/src/reference/resources/xsl/pdf-custom.xsl new file mode 100644 index 0000000000..7de82b2546 --- /dev/null +++ b/docs/src/reference/resources/xsl/pdf-custom.xsl @@ -0,0 +1,502 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -5em + -5em + + + + + + book toc,title + + + + + + + + + + + + + + + + + please define productname in your docbook file! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 0 + 1 + 1 + + + + + 0 + 0 + 0 + + + + false + + + 11 + 8 + + + 1.4 + + + + left + bold + + + pt + + + + + + + + + + + + + + + + 0.8em + 0.8em + 0.8em + + + pt + + 0.1em + 0.1em + 0.1em + + + 0.6em + 0.6em + 0.6em + + + pt + + 0.1em + 0.1em + 0.1em + + + 0.4em + 0.4em + 0.4em + + + pt + + 0.1em + 0.1em + 0.1em + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4pt + 4pt + 4pt + 4pt + + + + 0.1pt + 0.1pt + + + + + + + + + + + + + + + + + + pt + + + + + 1em + 1em + 1em + 0.1em + 0.1em + 0.1em + + #444444 + solid + 0.1pt + 0.5em + 0.5em + 0.5em + 0.5em + 0.5em + 0.5em + + + + 1 + + #F0F0F0 + + + + 0.1em + 0.1em + 0.1em + 0.1em + 0.1em + 0.1em + + + + 0.5em + 0.5em + 0.5em + 0.1em + 0.1em + 0.1em + always + + + + + + normal + italic + + + pt + + false + 0.1em + 0.1em + 0.1em + + + + + + + + + + + figure after + example after + equation before + table before + procedure before + + + + 1 + + 0pt + + + 3 + + + + + + + + + + + + + + + + + + diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000000..bdd574521c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,42 @@ +# Copyright 2002-2010 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# ------------------------------------------------------------------------------ +# version to be applied to all projects in this multi-project build. this is +# the one and only location version changes need to be made. +# ------------------------------------------------------------------------------ +springIntegrationVersion=2.0.0.BUILD-SNAPSHOT + +# ------------------------------------------------------------------------------ +# build system user roles +# role may be either 'developer' or 'buildmaster' +# ------------------------------------------------------------------------------ +role=developer + +# ------------------------------------------------------------------------------ +# for buildmasters: create a $HOME/.gradle/gradle.properties with the following +# properties. They'll be necessary uploading artifacts to s3, maven repos, and +# static.springframework.org. By placing them in your home directory, there's +# no need to change/check in this file. Remember that properties can also be +# specified at the gradle command line with -P, e.g.: -Prole=buildmaster +# ------------------------------------------------------------------------------ +# role = buildmaster # overrides default 'role = developer' above +# s3AccessKey= +# s3SecretAccessKey= +# docsHost=static.springsource.org +# sshHost=static.springsource.org +# sshUsername= +# sshPrivateKey= diff --git a/gradle/bundlor.gradle b/gradle/bundlor.gradle new file mode 100644 index 0000000000..6672a01d1a --- /dev/null +++ b/gradle/bundlor.gradle @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ----------------------------------------------------------------------------- +// Task definitions and configuration relating to the SpringSource 'bundlor' +// OSGi manifest generation utility. +// +// @author Chris Beams +// see: http://www.springsource.org/bundlor +// ----------------------------------------------------------------------------- + +/** + * Generate an OSGi manifest using the ant bundlor task. + * + * @author Luke Taylor + * @author Chris Beams + * @see http://static.springsource.org/s2-bundlor/1.0.x/user-guide/html/ch04s02.html + */ +task bundlor(dependsOn: compileJava) { + description = 'Generates an OSGi-compatibile MANIFEST.MF file.' + + def template = new File(projectDir, 'template.mf') + def bundlorDir = new File("${project.buildDir}/bundlor") + def manifest = file("${bundlorDir}/META-INF/MANIFEST.MF") + + // inform gradle what directory this task writes so that + // it can be removed when issuing `gradle cleanBundlor` + outputs.dir bundlorDir + + // incremental build configuration + // if the $manifest output file already exists, the bundlor + // task will be skipped *unless* any of the following are true + // * template.mf has been changed + // * main classpath dependencies have been changed + // * main java sources for this project have been modified + outputs.files manifest + inputs.files template, project.sourceSets.main.runtimeClasspath + + // tell the jar task to use bundlor manifest instead of the default + jar.manifest.from manifest + + // the bundlor manifest should be evaluated as part of the jar task's + // incremental build + jar.inputs.files manifest + + // configuration that will be used when creating the ant taskdef classpath + configurations { bundlorconf } + dependencies { + bundlorconf 'com.springsource.bundlor:com.springsource.bundlor.ant:1.0.0.RELEASE', + 'com.springsource.bundlor:com.springsource.bundlor:1.0.0.RELEASE', + 'com.springsource.bundlor:com.springsource.bundlor.blint:1.0.0.RELEASE' + } + + doFirst { + ant.taskdef(resource: 'com/springsource/bundlor/ant/antlib.xml', + classpath: configurations.bundlorconf.asPath) + + // the bundlor ant task writes directly to standard out + // redirect it to INFO level logging, which gradle will + // deal with gracefully + logging.captureStandardOutput(LogLevel.INFO) + + // the ant task will throw unless this dir exists + if (!bundlorDir.isDirectory()) + bundlorDir.mkdir() + + // execute the ant task, and write out the $manifest file + ant.bundlor(inputPath: sourceSets.main.classesDir, + outputPath: bundlorDir, manifestTemplatePath: template) { + property(name: 'version', value: project.version) + property(name: 'spring.version', value: project.springVersion) + } + } +} + +// ensure that the bundlor task runs prior to the jar task +jar.dependsOn bundlor + diff --git a/gradle/checks.gradle b/gradle/checks.gradle new file mode 100644 index 0000000000..a06b4ec4a7 --- /dev/null +++ b/gradle/checks.gradle @@ -0,0 +1,90 @@ + +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Issue a snapshot dependency report across all Java projects. Detects not + * only direct snapshot dependencies, but transitive as well. + * + * @author Chris Beams + * @see snapshotDependencyCheck + */ +task snapshotDependencyReport { + description = 'Issues a snapshot dependency report across all Java projects' + + doFirst() { + def snapshotDependencies = new HashMap>() + + javaprojects.each { project -> + project.sourceSets.main.compileClasspath.allDependencies.each { dep -> + if (dep.version.endsWith('SNAPSHOT')) { + if (snapshotDependencies[project] == null) + snapshotDependencies[project] = new ArrayList() + snapshotDependencies[project].add(dep) + } + } + } + + project.hasSnapshotDependencies = snapshotDependencies.size() > 0 + + if (project.hasSnapshotDependencies) { + println "The following snapshot dependencies were found:" + snapshotDependencies.each { entry -> + println "${entry.key} depends on:" + entry.value.each { dep -> + println " ${dep}" + } + } + } + } +} + + +/** + * Abort the build if any Java projects have snapshot dependencies. It important + * that any non-snapshot release be checked for snapshot dependencies before + * final publication, as snapshot dependencies may change and thus make the + * release unstable and/or unreproducable. + * + * This task will be added to the build lifecycle automatically if the release + * is non-snapshot. + * + * -PignoreSnapshotDependencies will bypass aborting the build. A use case for + * this option would be if a transitive dependency out of your control is a + * snapshot release and you wish to proceed with releasing anyway. + * + * @author Chris Beams + * @see snapshotDependencyReport + */ +task snapshotDependencyCheck(dependsOn: snapshotDependencyReport) { + group = 'Verification' + description = 'Aborts the build if any Java project has snapshot dependencies.' + + // bind to build lifecycle if we're a non-snapshot release + if (version.releaseType != 'SNAPSHOT') { + check.dependsOn snapshotDependencyCheck + } + + onlyIf { + project.hasSnapshotDependencies && + !project.hasProperty('ignoreSnapshotDependencies') + } + doFirst { + throw new GradleException( + "aborting '${name}' task due to snapshot dependencies. " + + "supply -PignoreSnapshotDependencies to override") + } +} diff --git a/gradle/dist.gradle b/gradle/dist.gradle new file mode 100644 index 0000000000..abedc6e963 --- /dev/null +++ b/gradle/dist.gradle @@ -0,0 +1,138 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ----------------------------------------------------------------------------- +// Task definitions related to releasing the project +// +// @author Chris Beams +// ----------------------------------------------------------------------------- + +// ensure that every project has been evaluated before this script +// this allows us to look up tasks below and dereference dynamically +// assigned properties like 'docsSpec' below +project.subprojects.each { project -> + evaluationDependsOn project.path +} + +task check { + group = 'Verification' +} + +task build(dependsOn: [check, assemble]) { + group = 'Build' +} + +/** + * Build the distribution zip file. + * + * @author Chris Beams + */ +task distArchive(type: Zip) { + group = 'Build' + + destinationDir = buildDir + archiveName = "${project.name}-${project.version}.zip" + checksumPath = "${destinationDir}/${archiveName}.sha1" + def zipRootDir = "${project.name}-${project.version}" + + description = "Builds the distribution zip file at ${project.relativePath(destinationDir)}/${archiveName}" + + // depend on all projects with an assemble task + dependsOn subprojects*.tasks*.matching { task -> task.name == 'assemble' } + + // we need the docsSpec to be defined before evaluating this task + project.evaluationDependsOn(':docs') + + // set up outputs for use by incremental build and by tasks like 'cleanDist' + // the archive zip file will be added automatically to outputs.files + // but we must add the sha1 checksum ourselves + outputs.files file(checksumPath) + + // configure the contents of the zip file. remember that this is a + // configuration phase event. no zip is being created yet. the Zip + // task we extend will do that for us during the execution phase. + into(zipRootDir) { + // add all jars from java subprojects + into('bin') { + from javaprojects.collect { project -> project.libsBinDir } + } + + // add all source jars from java subprojects + into('src') { + from javaprojects.collect { project -> project.libsSrcDir } + } + + into('') { + from('docs/src/info') + } + + into("docs/api") { + from("docs/build/api") + } + + into("docs/reference") { + from("docs/build/reference") + } + } + + // once the zip has been written, create a sha1 hash for it + // this will write out the file at ${checksumPath} + doLast { + ant.checksum(file: archivePath, algorithm: 'SHA1', fileext: '.sha1') + assert file(checksumPath).isFile(): "${checksumPath} was not created" + } +} + +/** + * Upload the distribution zip file. + * + * @author Luke Taylor + * @author Chris Beams + */ +task uploadArchives(overwrite: true, dependsOn: distArchive) { // base plugin adds one we need to overwrite + group = 'Buildmaster' + description = 'Uploads the distribution zip file.' + + configurations { antlibs } + dependencies { + antlibs "org.springframework.build:org.springframework.build.aws.ant:3.0.3.RELEASE", + "net.java.dev.jets3t:jets3t:0.6.1" + } + + def releaseType = version.releaseType.toString().toLowerCase() + + doLast() { + println "Uploading: ${distArchive.archivePath} to s3" + project.ant { + taskdef(resource: 'org/springframework/build/aws/ant/antlib.xml', + classpath: configurations.antlibs.asPath) + s3(accessKey: s3AccessKey, secretKey: s3SecretAccessKey) { + upload(bucketName: 'dist.springframework.org', file: distArchive.archivePath, + toFile: releaseType + "/${rootProject.abbreviation}/${distArchive.archiveName}", publicRead: 'true') { + metadata(name: 'project.name', value: 'Spring Integration') + metadata(name: 'release.type', value: releaseType) + metadata(name: 'bundle.version', value: version) + metadata(name: 'package.file.name', value: distArchive.archiveName) + } + upload(bucketName: 'dist.springframework.org', file: "${distArchive.archivePath}.sha1", + toFile: releaseType + "/${rootProject.abbreviation}/${distArchive.archiveName}.sha1", publicRead: 'true') + } + } + } +} + + + diff --git a/gradle/docbook.gradle b/gradle/docbook.gradle new file mode 100644 index 0000000000..225e4033fe --- /dev/null +++ b/gradle/docbook.gradle @@ -0,0 +1,315 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import org.xml.sax.XMLReader; +import org.xml.sax.InputSource; +import org.apache.xml.resolver.CatalogManager; +import org.apache.xml.resolver.tools.CatalogResolver; + +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.*; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import java.util.zip.*; + +import org.apache.fop.apps.*; + +import org.gradle.api.logging.LogLevel; + +import com.icl.saxon.TransformerFactoryImpl; +import ch.qos.logback.classic.Level; +import org.slf4j.LoggerFactory; + +buildscript { + repositories { + mavenCentral() + mavenRepo name: 'Shibboleth Repo', urls: 'http://shibboleth.internet2.edu/downloads/maven2' + } + dependencies { + def fopDeps = ['org.apache.xmlgraphics:fop:0.95-1@jar', + 'org.apache.xmlgraphics:xmlgraphics-commons:1.3', + 'org.apache.xmlgraphics:batik-bridge:1.7@jar', + 'org.apache.xmlgraphics:batik-util:1.7@jar', + 'org.apache.xmlgraphics:batik-css:1.7@jar', + 'org.apache.xmlgraphics:batik-dom:1.7', + 'org.apache.xmlgraphics:batik-svg-dom:1.7@jar', + 'org.apache.avalon.framework:avalon-framework-api:4.3.1'] + + classpath 'org.apache.xerces:resolver:2.9.1', + 'saxon:saxon:6.5.3', + 'org.apache.xerces:xercesImpl:2.9.1', + fopDeps, + 'net.sf.xslthl:xslthl:2.0.1', + 'net.sf.docbook:docbook-xsl:1.75.2:resources@zip' + } + +} + +/** + * Gradle Docbook plugin implementation. + *

+ * Creates three tasks: docbookHtml, docbookHtmlSingle and docbookPdf. + * Each task takes a single File on which it operates. + * + * @author Luke Taylor + */ +// Add the plugin tasks to the project +task docbookHtml(type: DocbookHtml) { + setDescription('Generates chunked docbook html output.') + xdir = 'html' + classpath = buildscript.configurations.classpath +} + +task docbookHtmlSingle(type: Docbook) { + setDescription('Generates single page docbook html output.') + xdir = 'htmlsingle' + classpath = buildscript.configurations.classpath +} + +task docbookPdf(type: DocbookFoPdf) { + setDescription('Generates PDF docbook output.') + extension = 'fo' + xdir = 'pdf' + classpath = buildscript.configurations.classpath +} + +/** + */ +public class Docbook extends DefaultTask { + @Input + String extension = 'html'; + + @Input + boolean XIncludeAware = true; + + @Input + boolean highlightingEnabled = true; + + String admonGraphicsPath; + + @InputDirectory + File sourceDirectory = new File(project.getProjectDir(), "build/reference-work"); + + @Input + String sourceFileName; + + @InputFile + File stylesheet; + + @OutputDirectory + File docsDir = new File(project.getBuildDir(), "reference"); + + @InputFiles + Configuration classpath + + @TaskAction + public final void transform() { + // the docbook tasks issue spurious content to the console. redirect to INFO level + // so it doesn't show up in the default log level of LIFECYCLE unless the user has + // run gradle with '-d' or '-i' switches -- in that case show them everything + switch (project.gradle.startParameter.logLevel) { + case LogLevel.DEBUG: + case LogLevel.INFO: + break; + default: + logging.captureStandardOutput(LogLevel.INFO) + logging.captureStandardError(LogLevel.INFO) + } + + SAXParserFactory factory = new org.apache.xerces.jaxp.SAXParserFactoryImpl(); + factory.setXIncludeAware(XIncludeAware); + docsDir.mkdirs(); + + File srcFile = new File(sourceDirectory, sourceFileName); + String outputFilename = srcFile.getName().substring(0, srcFile.getName().length() - 4) + '.' + extension; + + File oDir = new File(getDocsDir(), xdir) + File outputFile = new File(oDir, outputFilename); + + Result result = new StreamResult(outputFile.getAbsolutePath()); + CatalogResolver resolver = new CatalogResolver(createCatalogManager()); + InputSource inputSource = new InputSource(srcFile.getAbsolutePath()); + + XMLReader reader = factory.newSAXParser().getXMLReader(); + reader.setEntityResolver(resolver); + TransformerFactory transformerFactory = new TransformerFactoryImpl(); + transformerFactory.setURIResolver(resolver); + URL url = stylesheet.toURL(); + Source source = new StreamSource(url.openStream(), url.toExternalForm()); + Transformer transformer = transformerFactory.newTransformer(source); + + if (highlightingEnabled) { + File highlightingDir = new File(getProject().getBuildDir(), "highlighting"); + if (!highlightingDir.exists()) { + highlightingDir.mkdirs(); + extractHighlightFiles(highlightingDir); + } + + transformer.setParameter("highlight.xslthl.config", new File(highlightingDir, "xslthl-config.xml").toURI().toURL()); + + if (admonGraphicsPath != null) { + transformer.setParameter("admon.graphics", "1"); + transformer.setParameter("admon.graphics.path", admonGraphicsPath); + } + } + + preTransform(transformer, srcFile, outputFile); + + transformer.transform(new SAXSource(reader, inputSource), result); + + postTransform(outputFile); + } + + private void extractHighlightFiles(File toDir) { + File docbookZip = classpath.files.find { file -> file.name.contains('docbook-xsl-')}; + + if (docbookZip == null) { + throw new GradleException("Docbook zip file not found"); + } + + ZipFile zipFile = new ZipFile(docbookZip); + + Enumeration e = zipFile.entries(); + while (e.hasMoreElements()) { + ZipEntry ze = (ZipEntry) e.nextElement(); + if (ze.getName().matches(".*/highlighting/.*\\.xml")) { + String filename = ze.getName().substring(ze.getName().lastIndexOf("/highlighting/") + 14); + copyFile(zipFile.getInputStream(ze), new File(toDir, filename)); + } + } + } + + private void copyFile(InputStream source, File destFile) { + destFile.createNewFile(); + FileOutputStream to = null; + try { + to = new FileOutputStream(destFile); + byte[] buffer = new byte[4096]; + int bytesRead; + + while ((bytesRead = source.read(buffer)) > 0) { + to.write(buffer, 0, bytesRead); + } + } finally { + if (source != null) { + source.close(); + } + if (to != null) { + to.close(); + } + } + } + + protected void preTransform(Transformer transformer, File sourceFile, File outputFile) { + } + + protected void postTransform(File outputFile) { + } + + private CatalogManager createCatalogManager() { + CatalogManager manager = new CatalogManager(); + manager.setIgnoreMissingProperties(true); + ClassLoader classLoader = this.getClass().getClassLoader(); + StringBuilder builder = new StringBuilder(); + String docbookCatalogName = "docbook/catalog.xml"; + URL docbookCatalog = classLoader.getResource(docbookCatalogName); + + if (docbookCatalog == null) { + throw new IllegalStateException("Docbook catalog " + docbookCatalogName + " could not be found in " + classLoader); + } + + builder.append(docbookCatalog.toExternalForm()); + + Enumeration enumeration = classLoader.getResources("/catalog.xml"); + while (enumeration.hasMoreElements()) { + builder.append(';'); + URL resource = (URL) enumeration.nextElement(); + builder.append(resource.toExternalForm()); + } + String catalogFiles = builder.toString(); + manager.setCatalogFiles(catalogFiles); + return manager; + } +} + +/** + */ +class DocbookHtml extends Docbook { + + @Override + protected void preTransform(Transformer transformer, File sourceFile, File outputFile) { + String rootFilename = outputFile.getName(); + rootFilename = rootFilename.substring(0, rootFilename.lastIndexOf('.')); + transformer.setParameter("root.filename", rootFilename); + transformer.setParameter("base.dir", outputFile.getParent() + File.separator); + } +} + +/** + */ +class DocbookFoPdf extends Docbook { + + /** + * From the FOP usage guide + */ + @Override + protected void postTransform(File foFile) { + FopFactory fopFactory = FopFactory.newInstance(); + + OutputStream out = null; + final File pdfFile = getPdfOutputFile(foFile); + logger.debug("Transforming 'fo' file " + foFile + " to PDF: " + pdfFile); + + try { + out = new BufferedOutputStream(new FileOutputStream(pdfFile)); + + Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out); + + TransformerFactory factory = TransformerFactory.newInstance(); + Transformer transformer = factory.newTransformer(); + + Source src = new StreamSource(foFile); + + Result res = new SAXResult(fop.getDefaultHandler()); + + switch (project.gradle.startParameter.logLevel) { + case LogLevel.DEBUG: + case LogLevel.INFO: + break; + default: + // only show verbose fop output if the user has specified 'gradle -d' or 'gradle -i' + LoggerFactory.getILoggerFactory().getLogger('org.apache.fop').level = Level.ERROR + } + + transformer.transform(src, res); + + } finally { + if (out != null) { + out.close(); + } + } + + if (!foFile.delete()) { + logger.warn("Failed to delete 'fo' file " + foFile); + } + } + + private File getPdfOutputFile(File foFile) { + String name = foFile.getAbsolutePath(); + return new File(name.substring(0, name.length() - 2) + "pdf"); + } +} diff --git a/gradle/maven-deployment.gradle b/gradle/maven-deployment.gradle new file mode 100644 index 0000000000..1da52540f6 --- /dev/null +++ b/gradle/maven-deployment.gradle @@ -0,0 +1,171 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ----------------------------------------------------------------------------- +// Tasks related to deploying Maven artifacts. +// +// @author Chris Beams +// ----------------------------------------------------------------------------- + +// check that upload-related properties are defined and fail early if not +// these properties ('s3AccessKey', etc) should be defined in +// 'gradle.properties' in $HOME/.gradle/gradle.properties +def requiredProps = version.releaseType == 'RELEASE' ? ['mavenSyncRepoDir'] : ['s3AccessKey', 's3SecretAccessKey'] +checkForProps(taskPath: project.path + ':uploadArchives', requiredProps: requiredProps) + +/** + * Builds a source jar artifact for all main java sources. + * + * @author Luke Taylor + */ +task sourceJar(type: Jar) { + description = 'Builds a source jar artifact suitable for maven deployment.' + classifier = 'sources' + from sourceSets.main.java +} +build.dependsOn sourceJar + +jar.destinationDir = project.libsBinDir +sourceJar.destinationDir = project.libsSrcDir + +// Add the source jar archive to the set of artifacts for this project. +// Note that the regular 'jar' archive is already added by default. +artifacts { + archives sourceJar +} + + +/** + * Deploy gradle-built artifacts to a remote maven repository. Overrides and + * further customizes the 'uploadArchives' task contributed by the 'maven' + * plugin. + * + * The repository that artifacts are deployed to is determined conditionally + * based on the release type of the project version. Snapshot builds will + * be deployed via s3 to the springframework maven snapshot repository; + * milestone builds will happen via s3 as well; release builds will be deployed + * to the local filesystem to be sync'd via sourceforge SVN and ultimately + * deployed to maven central. + * + * Gradle will generate Maven poms on-the-fly during the deployment process. + * This process is customized to add ASL license information, and for projects + * that have the erlangLicense property set to true, the Erlang License will be + * added to the pom as well. + * + * @author Chris Beams + * @see 'mavenSyncRepoDir' in gradle.properties + * @see `gradle install` for deploying artifacts to the local .m2 cache + * @see http://maven.apache.org/guides/mini/guide-central-repository-upload.html + */ +uploadArchives { + group = 'Buildmaster' + description = "Does a maven deploy of archives artifacts to " // url appended below + + def releaseRepositoryUrl = "file://${project.properties.mavenSyncRepoDir}" + def milestoneRepositoryUrl = 's3://maven.springframework.org/milestone' + def snapshotRepositoryUrl = 's3://maven.springframework.org/snapshot' + + // add a configuration with a classpath that includes our s3 maven deployer + configurations { deployerJars } + dependencies { + deployerJars "org.springframework.build.aws:org.springframework.build.aws.maven:3.0.0.RELEASE" + } + + def deployer = repositories.mavenDeployer { + switch (version.releaseType) { + case 'RELEASE': + repository(url: releaseRepositoryUrl) + description += releaseRepositoryUrl + break; + + case 'MILESTONE': + description += milestoneRepositoryUrl + s3credentials = [userName: project.properties.s3AccessKey, passphrase: project.properties.s3SecretAccessKey] + configuration = configurations.deployerJars + repository(url: milestoneRepositoryUrl) { + authentication(s3credentials) + } + snapshotRepository(url: snapshotRepositoryUrl) { + authentication(s3credentials) + } + break; + + case 'SNAPSHOT': + description += snapshotRepositoryUrl + s3credentials = [userName: project.properties.s3AccessKey, passphrase: project.properties.s3SecretAccessKey] + configuration = configurations.deployerJars + repository(url: milestoneRepositoryUrl) { + authentication(s3credentials) + } + snapshotRepository(url: snapshotRepositoryUrl) { + authentication(s3credentials) + } + break; + + default: + throw new GradleException("unknown ReleaseType") + } + } + + configurePom(deployer.pom) +} + +/** + * Install gradle-built artifacts to the local m2 maven cache. + * Further customizes the 'install' task contributed by the 'maven' plugin. + */ +install { + group = 'Build' + description = "Does a maven install of archives artifacts to local m2 cache" + + configurePom(repositories.mavenInstaller.pom) +} + +def configurePom(def pom) { + pom.whenConfigured { generatedPom -> + def optionalDeps = configurations.testRuntime.allDependencies.findAll { gradleDep -> + gradleDep.asDynamicObject.hasProperty('optional') && gradleDep.optional + } + def providedDeps = configurations.testRuntime.allDependencies.findAll { gradleDep -> + gradleDep.asDynamicObject.hasProperty('provided') && gradleDep.provided + } + generatedPom.dependencies.each { mavenDep -> + mavenDep.optional = optionalDeps.any { optionalDep -> + optionalDep.group == mavenDep.groupId && + optionalDep.name == mavenDep.artifactId && + optionalDep.version == mavenDep.version + } + boolean isProvided = providedDeps.any { providedDep -> + providedDep.group == mavenDep.groupId && + providedDep.name == mavenDep.artifactId && + providedDep.version == mavenDep.version + } + if (isProvided) { + mavenDep.scope = 'provided' + } + } + } + + pom.project { + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution 'repo' + } + } + } +} diff --git a/gradle/version.gradle b/gradle/version.gradle new file mode 100644 index 0000000000..310cf2752d --- /dev/null +++ b/gradle/version.gradle @@ -0,0 +1,83 @@ +class Version { + /** + * Indicates whether a version is a release, milestone, or snapshot + */ + static final String RELEASE = 'RELEASE' + static final String MILESTONE = 'MILESTONE' + static final String SNAPSHOT = 'SNAPSHOT' + + String value + String releaseType + int majorVersion + int minorVersion + + /** + * @param dotted -quad version spec, e.g.: 1.0.0.RELEASE + */ + public Version(String value) { + this.value = value; + this.releaseType = releaseTypeFor(value); + this.majorVersion = Integer.parseInt(this.value.substring(0, this.value.indexOf('.'))); + String afterMajor = this.value.substring(this.value.indexOf('.') + 1); + this.minorVersion = Integer.parseInt(afterMajor.substring(0, afterMajor.indexOf('.'))); + } + + public int getMajorVersion() { + return this.majorVersion; + } + + public int getMinorVersion() { + return this.minorVersion + } + + /** + * @return 1.0.x style + */ + public String getWildcardValue() { + return majorVersion + '.' + minorVersion + '.x'; + } + + /** + * @return the version string returned by {@link getValue ( )} + */ + public String toString() { + return this.getValue(); + } + + /** + * @param dotted -quad version spec, e.g.: 1.0.0.RELEASE + */ + public static String releaseTypeFor(String version) { + if (version.endsWith("RELEASE")) return RELEASE; + if (version.endsWith("SNAPSHOT")) return SNAPSHOT; + if (version.matches(".*\\.M[0-9]+\$")) return MILESTONE; + if (version.matches(".*\\.RC[0-9]+\$")) return MILESTONE; + + throw new InvalidUserDataException("unknown version scheme: " + + "versions must end in (SNAPSHOT|M[0-9]+|RC[0-9]+|RELEASE), " + + "but got (" + version + ")"); + } +} + +project.createVersion = { value -> + new Version(value) +} + +def requiredPropSets = [] + +gradle.taskGraph.whenReady { graph -> + requiredPropSets.each { args -> + if (graph.hasTask(args.taskPath)) { + def missingProps = args.requiredProps.findAll { prop -> + !project.hasProperty(prop) + } + if (missingProps) { + throw new GradleException("For executing the ${args.taskPath} task you need to set all ${missingProps} properties") + } + } + } +} +project.checkForProps = { Map args -> + requiredPropSets.add args +} + diff --git a/gradle/wrapper.gradle b/gradle/wrapper.gradle new file mode 100644 index 0000000000..36e7ac7d0f --- /dev/null +++ b/gradle/wrapper.gradle @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Generate gradlew and gradlew.bat scripts and associated files. These + * convenience scripts allow users to operate the build without being forced to + * download and install gradle. + * + * @author Chris Beams + * @see http://gradle.org/0.9-preview-3/docs/userguide/userguide_single.html#gradle_wrapper + */ +task wrapper(type: Wrapper) { + group = 'Buildmaster' + description = "Generates gradlew and gradlew.bat bootstrap scripts" + gradleVersion = '0.9-preview-3' + // place jar file and properties into a + // subdirectory to avoid root dir clutter + jarPath = 'gradle/wrapper' +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..4eb13be9e5 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..682c93283d --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,9 @@ +#Wed Oct 27 06:30:22 EDT 2010 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +distributionVersion=0.9-build-daemon-20101027111821+1100 +zipStorePath=wrapper/dists +urlRoot=http\://gradle.artifactoryonline.com/gradle/distributions/gradle-snapshots +distributionName=gradle +distributionClassifier=bin diff --git a/gradlew b/gradlew new file mode 100755 index 0000000000..062dcf316d --- /dev/null +++ b/gradlew @@ -0,0 +1,142 @@ +#!/bin/bash + +############################################################################## +## ## +## Gradle wrapper script for UN*X ## +## ## +############################################################################## + +# Uncomment those lines to set JVM options. GRADLE_OPTS and JAVA_OPTS can be used together. +# GRADLE_OPTS="$GRADLE_OPTS -Xmx512" +# JAVA_OPTS="$JAVA_OPTS -Xmx512" + +GRADLE_APP_NAME=Gradle + +warn ( ) { + echo "${PROGNAME}: $*" +} + +die ( ) { + warn "$*" + exit 1 +} + + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set JAVA_HOME if it's not already set. +if [ -z "$JAVA_HOME" ] ; then + if $darwin ; then + [ -z "$JAVA_HOME" -a -d "/Library/Java/Home" ] && export JAVA_HOME="/Library/Java/Home" + [ -z "$JAVA_HOME" -a -d "/System/Library/Frameworks/JavaVM.framework/Home" ] && export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Home" + else + javaExecutable="`which javac`" + [ -z "$javaExecutable" -o "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ] && die "JAVA_HOME not set and cannot find javac to deduce location, please set JAVA_HOME." + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + [ `expr "$readLink" : '\([^ ]*\)'` = "no" ] && die "JAVA_HOME not set and readlink not available, please set JAVA_HOME." + javaExecutable="`readlink -f \"$javaExecutable\"`" + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + export JAVA_HOME="$javaHome" + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVACMD" ] && JAVACMD=`cygpath --unix "$JAVACMD"` + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +STARTER_MAIN_CLASS=org.gradle.wrapper.GradleWrapperMain +CLASSPATH=`dirname "$0"`/gradle/wrapper/gradle-wrapper.jar +WRAPPER_PROPERTIES=`dirname "$0"`/gradle/wrapper/gradle-wrapper.properties +# Determine the Java command to use to start the JVM. +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="java" + fi +fi +if [ ! -x "$JAVACMD" ] ; then + die "JAVA_HOME is not defined correctly, can not execute: $JAVACMD" +fi +if [ -z "$JAVA_HOME" ] ; then + warn "JAVA_HOME environment variable is not set" +fi + +# For Darwin, add GRADLE_APP_NAME to the JAVA_OPTS as -Xdock:name +if $darwin; then + JAVA_OPTS="$JAVA_OPTS -Xdock:name=$GRADLE_APP_NAME" +# we may also want to set -Xdock:image +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + JAVA_HOME=`cygpath --path --mixed "$JAVA_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +"$JAVACMD" $JAVA_OPTS $GRADLE_OPTS \ + -classpath "$CLASSPATH" \ + -Dorg.gradle.wrapper.properties="$WRAPPER_PROPERTIES" \ + $STARTER_MAIN_CLASS \ + "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100755 index 0000000000..114aaa4c7d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,126 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem ## +@rem Gradle startup script for Windows ## +@rem ## +@rem ########################################################################## + +@rem +@rem $Revision: 10602 $ $Date: 2008-01-25 02:49:54 +0100 (ven., 25 janv. 2008) $ +@rem + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Uncomment those lines to set JVM options. GRADLE_OPTS and JAVA_OPTS can be used together. +@rem set GRADLE_OPTS=%GRADLE_OPTS% -Xmx512 +@rem set JAVA_OPTS=%JAVA_OPTS% -Xmx512 + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=.\ + +@rem Determine the command interpreter to execute the "CD" later +set COMMAND_COM="cmd.exe" +if exist "%SystemRoot%\system32\cmd.exe" set COMMAND_COM="%SystemRoot%\system32\cmd.exe" +if exist "%SystemRoot%\command.com" set COMMAND_COM="%SystemRoot%\command.com" + +@rem Use explicit find.exe to prevent cygwin and others find.exe from being used +set FIND_EXE="find.exe" +if exist "%SystemRoot%\system32\find.exe" set FIND_EXE="%SystemRoot%\system32\find.exe" +if exist "%SystemRoot%\command\find.exe" set FIND_EXE="%SystemRoot%\command\find.exe" + +:check_JAVA_HOME +@rem Make sure we have a valid JAVA_HOME +if not "%JAVA_HOME%" == "" goto have_JAVA_HOME + +echo. +echo ERROR: Environment variable JAVA_HOME has not been set. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. +echo. +goto end + +:have_JAVA_HOME +@rem Validate JAVA_HOME +%COMMAND_COM% /C DIR "%JAVA_HOME%" 2>&1 | %FIND_EXE% /I /C "%JAVA_HOME%" >nul +if not errorlevel 1 goto init + +echo. +echo ERROR: JAVA_HOME might be 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 if there are problems. +echo. + +:init +@rem get name of script to launch with full path +@rem Get command-line arguments, handling Windowz variants +SET _marker=%JAVA_HOME: =% +@rem IF NOT "%_marker%" == "%JAVA_HOME%" ECHO JAVA_HOME "%JAVA_HOME%" contains spaces. Please change to a location without spaces if this causes problems. + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%eval[2+2]" == "4" goto 4NT_args + +IF "%_marker%" == "%JAVA_HOME%" goto :win9xME_args + +set _FIXPATH= +call :fixpath "%JAVA_HOME%" +set JAVA_HOME=%_FIXPATH:~1% + +goto win9xME_args + +:fixpath +if not %1.==. ( +for /f "tokens=1* delims=;" %%a in (%1) do ( +call :shortfilename "%%a" & call :fixpath "%%b" +) +) +goto :EOF +:shortfilename +for %%i in (%1) do set _FIXPATH=%_FIXPATH%;%%~fsi +goto :EOF + + +: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 STARTER_MAIN_CLASS=org.gradle.wrapper.GradleWrapperMain +set CLASSPATH=%DIRNAME%\gradle\wrapper\gradle-wrapper.jar +set WRAPPER_PROPERTIES=%DIRNAME%\gradle\wrapper\gradle-wrapper.properties +set JAVA_EXE=%JAVA_HOME%\bin\java.exe + +set GRADLE_OPTS=%JAVA_OPTS% %GRADLE_OPTS% -Dorg.gradle.wrapper.properties="%WRAPPER_PROPERTIES%" + +"%JAVA_EXE%" %GRADLE_OPTS% -classpath "%CLASSPATH%" %STARTER_MAIN_CLASS% %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +if not "%OS%"=="Windows_NT" echo 1 > nul | choice /n /c:1 + +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 "%ERRORLEVEL%" +exit /b "%ERRORLEVEL%" + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000000..cbb72884fa --- /dev/null +++ b/settings.gradle @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +include 'docs' +include 'spring-integration-core' +include 'spring-integration-event' +include 'spring-integration-feed' +include 'spring-integration-file' +include 'spring-integration-ftp' +include 'spring-integration-groovy' +include 'spring-integration-http' +include 'spring-integration-httpinvoker' +include 'spring-integration-ip' +include 'spring-integration-jdbc' +include 'spring-integration-jms' +include 'spring-integration-jmx' +include 'spring-integration-mail' +include 'spring-integration-rmi' +include 'spring-integration-security' +include 'spring-integration-sftp' +include 'spring-integration-stream' +include 'spring-integration-test' +include 'spring-integration-twitter' +include 'spring-integration-ws' +include 'spring-integration-xml' +include 'spring-integration-xmpp' diff --git a/spring-integration-core/src/test/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessorTests.java b/spring-integration-core/src/test/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessorTests.java index 2cc5c5aa2b..b7ed92dacd 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessorTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessorTests.java @@ -106,7 +106,7 @@ public class ExpressionEvaluatingMessageProcessorTests { processor.setBeanFactory(new GenericApplicationContext().getBeanFactory()); EvaluationContext evaluationContext = TestUtils.getPropertyValue(processor, "evaluationContext", EvaluationContext.class); evaluationContext.setVariable("target", new TestTarget()); - String result = (String) processor.processMessage(new GenericMessage("classpath:*.properties")); + String result = (String) processor.processMessage(new GenericMessage("classpath*:*.properties")); assertTrue("Wrong result: "+result, result.contains("log4j.properties")); } diff --git a/spring-integration-jdbc/build.gradle b/spring-integration-jdbc/build.gradle new file mode 100644 index 0000000000..92540e21a2 --- /dev/null +++ b/spring-integration-jdbc/build.gradle @@ -0,0 +1,46 @@ +/** + * Generate schema creation and drop scripts for various databases + * supported by the Spring Integration JDBC adapter. + * + * @author David Syer (original Ant/Maven work) + * @author Chris Beams (port to Gradle) + */ +task generateSql { + group = "Build" + description = "Generates schema creation and drop scripts for supported databases." + + repositories { mavenRepo urls: 'http://objectstyle.org/maven2/' } + configurations { vpp } + dependencies { vpp 'foundrylogic.vpp:vpp:2.2.1' } + + def generatedResourcesDir = new File(buildDir, 'generated-resources') + + outputs.dir generatedResourcesDir + + ant.typedef(resource: 'foundrylogic/vpp/typedef.properties', + classpath: configurations.vpp.asPath) + ant.taskdef(resource: 'foundrylogic/vpp/taskdef.properties', + classpath: configurations.vpp.asPath) + + doLast { + ['hsqldb', 'h2', 'db2', 'derby', 'mysql', + 'oracle10g', 'postgresql', 'sqlserver', 'sybase'].each { dbType -> + ant.vppcopy(todir: generatedResourcesDir, overwrite: 'true') { + config { + context { + property key: 'includes', value: 'src/main/sql' + property file: "src/main/sql/${dbType}.properties" + } + engine { + property key: 'velocimacro.library', value: "src/main/sql/${dbType}.vpp" + } + } + fileset dir: 'src/main/sql', includes: 'schema*.sql.vpp' + mapper type: 'glob', from: '*.sql.vpp', to: "*-${dbType}.sql" + } + } + } +} + +// tie schema generation to the build lifecycle +compileJava.dependsOn generateSql diff --git a/src/docbkx/event.xml b/src/docbkx/event.xml deleted file mode 100644 index b4533387f3..0000000000 --- a/src/docbkx/event.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - Spring ApplicationEvent Support - - - Spring Integration provides support for inbound and outbound ApplicationEvents - as defined by the underlying Spring Framework. For more information about the events and listeners, - refer to the Spring Reference Manual. - - -

- Receiving Spring ApplicationEvents - - To receive events and send them to a channel, simply define an instance of Spring Integration's - ApplicationEventListeningChannelAdapter. This class is an implementation of - Spring's ApplicationListener interface. By default it will pass all - received events as Spring Integration Messages. To limit based on the type of event, configure the - list of event types that you want to receive with the 'eventTypes' property. - - - For convenience namespace support was provided to configure ApplicationEventListeningChannelAdapter via inbound-channel-adapter - - -]]> -In the above sample, all Application Context events that are of type specified by the 'event-types' (optional) attribute will be -delivered as Spring Integration Messages to 'sampleEventChannel'. - - - -
- -
- Sending Spring ApplicationEvents - - To send Spring ApplicationEvents, create an instance of the - ApplicationEventPublishingMessageHandler and register it within an endpoint. - This implementation of the MessageHandler interface also implements - Spring's ApplicationEventPublisherAware interface and thus acts as a - bridge between Spring Integration Messages and ApplicationEvents. - - - For convenience namespace support was provided to configure ApplicationEventPublishingMessageHandler via outbound-channel-adapter element - - -]]> -If you are using PollableChannel (e.g., Queue), you can also provide poller as sub-element of outbound-channel-adapter, optionally providing task-executor - - - - - - - - -]]> - -In the above sample, all messages sent to an 'input' channel will be published as ApplicationEvents to Spring Application sContext - -
- - \ No newline at end of file diff --git a/src/docbkx/file.xml b/src/docbkx/file.xml deleted file mode 100644 index 005c164808..0000000000 --- a/src/docbkx/file.xml +++ /dev/null @@ -1,228 +0,0 @@ - - - - File Support - -
- Introduction - - Spring Integration's File support extends the Spring Integration Core with - a dedicated vocabulary to deal with reading, writing, and transforming files. - It provides a namespace that enables elements defining Channel Adapters dedicated - to files and support for Transformers that can read file contents into strings or - byte arrays. - - - This section will explain the workings of FileReadingMessageSource - and FileWritingMessageHandler and how to configure them as - beans. Also the support for dealing with files through file specific - implementations of Transformer will be discussed. Finally the - file specific namespace will be explained. - -
- -
- Reading Files - - A FileReadingMessageSource can be used to consume files from the filesystem. - This is an implementation of MessageSource that creates messages from - a file system directory. ]]> - - - To prevent creating messages for certain files, you may supply a - FileListFilter. By default, an - AcceptOnceFileListFilter is used. This filter - ensures files are picked up only once from the directory. - ]]> - - - A common problem with reading files is that a file may be detected before - it is ready. The default AcceptOnceFileListFilter - does not prevent this. In most cases, this can be prevented if the - file-writing process renames each file as soon as it is ready for - reading. A pattern-matching filter that accepts only files that are - ready (e.g. based on a known suffix), composed with the default - AcceptOnceFileListFilter allows for this. - The CompositeFileListFilter enables the - composition. - - - - - - - - - - -]]> - - - The configuration can be simplified using the file specific namespace. To do - this use the following template. - - -]]> - Within this namespace you can reduce the FileReadingMessageSource and wrap - it in an inbound Channel Adapter like this: - - - - - ]]> - The first channel adapter is relying on the default filter that just prevents - duplication, the second is using a custom filter, and the third is using the - filename-pattern attribute to add a AntPathMatcher - based filter to the FileReadingMessageSource. - The file-name-pattern and filter attributes are mutually exclusive, but - you can use a CompositeFileListFilter to use any combination of filters, including a - pattern based filter to fit your particular needs. - - - When multiple processes are reading from the same directory it can be desirable to lock files to prevent - them from being picked up concurrently. To do this you can use a FileLocker. - There is a java.nio based implementation available out of the box, but it is also possible to implement your - own locking scheme. The nio locker can be injected as follows - - - ]]> - - A custom locker you can configure like this: - - - ]]> - - - - When filtering and locking files is not enough it might be needed to control the way files are listed entirely. To - implement this type of requirement you can use an implementation of DirectoryScanner. - This scanner allows you to determine entirely what files are listed each poll. This is also the interface - that Spring Integration uses internally to wire FileListFilters FileLocker to the FileReadingMessageSource. - A custom DirectoryScanner can be injected into the <file:inbound-channel-adapter/> on the scanner - attribute. - ]]> - - This gives you full freedom to choose the ordering, listing and locking strategies. - -
- -
- Writing files - - To write messages to the file system you can use a - FileWritingMessageHandler. This class can deal with - File, String, or byte array payloads. In its simplest form the - FileWritingMessageHandler only requires a - destination directory for writing the files. The name of the file to be - written is determined by the handler's FileNameGenerator. - The default implementation looks for a Message header whose key matches - the constant defined as FileHeaders.FILENAME. - - - Additionally, you can configure the encoding and the charset that - will be used in case of a String payload. - - - To make things easier you can configure the FileWritingMessageHandler as - part of an outbound channel adapter using the namespace. - ]]> - - - The namespace based configuration also supports a delete-source-files attribute. - If set to true, it will trigger deletion of the original source files after writing - to a destination. The default value for that flag is false. - ]]> - - - The delete-source-files attribute will only have an effect if the inbound - Message has a File payload or if the FileHeaders.ORIGINAL_FILE header - value contains either the source File instance or a String representing the original file path. - - - - - In cases where you want to continue processing messages based on the written File you can use - the outbound-gateway instead. It plays a very similar role as the - outbound-channel-adapter. However after writing the File, it will also send it - to the reply channel as the payload of a Message. - ]]> - - - The 'outbound-gateway' works well in cases where you want to first move a File and then send it - through a processing pipeline. In such cases, you may connect the file namespace's - 'inbound-channel-adapter' element to the 'outbound-gateway' and then connect that gateway's - reply-channel to the beginning of the pipeline. - - - If you have more elaborate requirements or need to support additional payload types as input - to be converted to file content you could extend the FileWritingMessageHandler, but a much - better option is to rely on a Transformer. - -
- -
- File Transformers - - To transform data read from the file system to objects and the other way around you need - to do some work. Contrary to FileReadingMessageSource and to a - lesser extent FileWritingMessageHandler, it is very likely that you - will need your own mechanism to get the job done. For this you can implement the - Transformer interface. Or extend the - AbstractFilePayloadTransformer for inbound messages. Some obvious - implementations have been provided. - - - FileToByteArrayTransformer transforms Files into byte[]s using - Spring's FileCopyUtils. It is often better to use a sequence of - transformers than to put all transformations in a single class. In that case the File to - byte[] conversion might be a logical first step. - - - FileToStringTransformer will convert Files to Strings as the name - suggests. If nothing else, this can be useful for debugging (consider using with a Wire Tap). - - - To configure File specific transformers you can use the appropriate elements from the file namespace. - - - ]]> - The delete-files option signals to the transformer that it should delete - the inbound File after the transformation is complete. This is in no way a replacement for using the - AcceptOnceFileListFilter when the FileReadingMessageSource is being used in a - multi-threaded environment (e.g. Spring Integration in general). - -
- -
diff --git a/src/docbkx/gateway.xml b/src/docbkx/gateway.xml deleted file mode 100644 index bae14f5092..0000000000 --- a/src/docbkx/gateway.xml +++ /dev/null @@ -1,255 +0,0 @@ - - - - Inbound Messaging Gateways - -
- GatewayProxyFactoryBean - - Working with Objects instead of Messages is an improvement. However, it would be even better to have no - dependency on the Spring Integration API at all - including the gateway class. For that reason, Spring - Integration also provides a GatewayProxyFactoryBean that generates a proxy for - any interface and internally invokes the gateway methods shown above. Namespace support is also - provided as demonstrated by the following example. - ]]> - Then, the "fooService" can be injected into other beans, and the code that invokes the methods on that - proxied instance of the FooService interface has no awareness of the Spring Integration API. The general - approach is similar to that of Spring Remoting (RMI, HttpInvoker, etc.). See the "Samples" Appendix for - an example that uses this "gateway" element (in the Cafe demo). - - - The reason that the attributes on the 'gateway' element are named 'default-request-channel' and - 'default-reply-channel' is that you may also provide per-method channel references by using the - @Gateway annotation. - - ... as well as method sub element if yuo prefer XML configuration (see next paragraph) - - - It is also possible to pass values to be interpreted as Message headers on the Message - that is created and sent to the request channel by using the @Header annotation: - - - - - If you prefer XML way of configuring Gateway methods, you can provide method sub-elements - to the gateway configuration (see below) - - - - -]]> - - - You can also provide individual headers per method invocation via XML. - This could be very useful if the headers you want to set are static in nature and you don't want - to embed them in the gateway's method signature via @Header annotations. - For example, in the Loan Broker example we want to influence how aggregation of the Loan quotes - will be done based on what type of request was initiated (single quote or all quotes). Determining the - type of the request by evaluating what gateway method was invoked, although possible would - violate the separation of concerns paradigm (method is a java artifact),  but expressing your - intention (meta information) via Message headers is natural in a Messaging architecture. - - - - - - - - -]]> - In the above case you can clearly see how a different header value will be set for the 'RESPONSE_TYPE' - header based on the gateway's method. - - - As with anything else, Gateway invocation might result in errors. - By default any error that has occurred downstream will be re-thrown as a MessagingExeption (RuntimeException) - upon the Gateway's method invocation. However there are times when you may want to treat an Exception as a valid reply, - by mapping it to a Message. To accomplish this our Gateway provides support for Exception mappers via the - exception-mapper attribute. - - - - - - - ]]> - - foo.bar.SampleExceptionMapper is the implementation of - org.springframework.integration.message.InboundMessageMapper which only defines one method: toMessage(Object object). -{ - public Message toMessage(Throwable object) throws Exception { - MessageHandlingException ex = (MessageHandlingException) object; - return MessageBuilder.withPayload("Error happened in message: " + - ex.getFailedMessage().getPayload()).build(); - } - -} - ]]> - - - - - Exposing messaging system via POJO Gateway is obviously a great benefit, but it does come at the price so there - are certain things you must be aware of. - - We want our Java method to return as quick as possible and not hang for infinite amount of time until they can - return (void , exception or return value). When regular methods are used as a proxies in front of the Messaging - system we have to take into account the asynchronous nature of the Messaging Systems. This means that there might - be a chance that a Message hat was initiated by a Gateway could be dropped by a Filter, thus never reaching a - component that is responsible to produce a reply. Some Service Activator method might result in the Exception, - thus resulting in no-reply (as we don't generate Null messages).So as you can see there are multiple scenarios - where reply message might not be coming which is perfectly natural in messaging systems. However think about the - implication on the gateway method.  The Gateway's method input arguments  were incorporated into a Message and - sent downstream. The reply Message would be converted to a return value of the Gateway's method. So you can see - how ugly it could get if you can not guarantee that for each Gateway call there will alway be a reply Message. - Basically your Gateway method will never return and will hang infinitely. (work in progress!!!!) -One of the ways of handling this situation is via AsyncGateway (explained later in this section). Another way of handling it is to explicitly set the reply-timeout attribute. This way gateway will not hang for more then the time that was specified by the reply-timout and will return 'null'.  - - -
-
- Asynchronous Gateway - - As a pattern the Messaging Gateway is a very nice way to hide messaging-specific code while still exposing the full capabilities of the - messaging system. And GatewayProxyFactoryBean provides a convenient way to expose a Proxy over a service-interface - thus giving you a POJO-based access to a messaging system (based on objects in your own domain, or primitives/Strings, etc).  But when a - gateway is exposed via simple POJO methods which return values it does imply that for each Request message (generated when the method is invoked) - there must be a Reply message (generated when the method has returned). Since Messaging systems naturally are asynchronous you may not always be - able to guarantee the contract where "for each request there will always be be a reply".  - With Spring Integration 2.0 we are introducing support for an Asynchronous Gateway which is a convenient way to initiate - flows where you may not know if a reply is expected or how long will it take for it to arrive. - - - A natural way to handle these types of scenarios in Java would be relying upon java.util.concurrent.Future instances, and - that is exactly what Spring Integration uses to support an Asynchronous Gateway. - - - From the XML configuration, there is nothing different and you still define Asynchronous Gateway the same way as a regular Gateway. - ]]> - However the Gateway Interface (service-interface) is a bit different. - - public interface MathServiceGateway { - Future<Integer> multiplyByTwo(int i); -} - - - As you can see from the example above the return type for the gateway method is Future. When - GatewayProxyFactoryBean sees that the - return type of the gateway method is Future, it immediately switches to the async mode by utilizing - an AsyncTaskExecutor. That is all. The call to a method always returns immediately with Future - encapsulating  the interaction with the framework. - Now you can interact with the Future at your own pace to get the result, timeout, get the exception etc... - MathServiceGateway mathService = ac.getBean("mathService", MathServiceGateway.class); -Future<Integer> result = mathService.multiplyByTwo(number); -// do something else here since the reply might take a moment -int finalResult =  result.get(1000, TimeUnit.SECONDS); -For a more detailed example, please refer to the async-gateway sample distributed within the Spring Integration samples. - - -
-
- Gateway behavior when no response is coming - - As it was explained earlier, Gateway provides a convenient way of interacting with Messaging system via POJO method - invocations, but realizing that a typical method invocation, which is generally expected to always return (even with Exception), - might not always map one-to-one to message exchanges (e.g., reply message might not be coming which is equivalent to - method not returning), it is important to go over several scenarios especially in the Sync Gateway case and understand - what the default behavior of the Gateway and how to deal with these scenarios to make Sync Gateway behavior more - predictable regardless of the outcome of the message flow that was initialed from such Gateway. - - - There are certain attributes that could be configured to make Sync Gateway behavior more predictable, - but some of them might not always work as you might have expected. One of them is reply-timeout. - So, lets look at the reply-timeout attribute and see how it can/can't influence the behavior - of the Sync Gateway in various scenarios. We will look at single-theraded scenario - (all components downstream are connected via Direct Channel) and multi-theraded scenarios - (e.g., somewhere downstream you may have Pollable or Executor Channel which breaks single-thread boundary) - - - Long running process downstream - - - Sync Gateway - single-threaded. - If a component downstream is still running (e.g., infinite loop or a very slow service), then setting reply-timeout - has no effect and Gateway method call will not return until such downstream service exits (e.g., return or exception). - Sync Gateway - multi-threaded. - If a component downstream is still running (e.g., infinite loop or a very slow service), in a multi-threaded message - flow setting reply-timeout will have an effect by allowing gateway method invocation to - return once the timeout has been reached, since GatewayProxyFactoryBean  will simply - poll on the reply channel waiting for a message untill the timeout expires. However it could result in the 'null' return - from the Gateway method if the timeout has been reached before the actual reply was produced. It is also important to understand that - the reply message (if produced) will be sent to a reply channel after Gateway method invocation might have returned, so you must be aware of that - and design your flow with this in mind. - - - Downstream component returns 'null' - - - Sync Gateway - single-threaded. - If a component downstream returns 'null' and no reply-timeout has been configured, the Gateway - method call will hang indefinitely unless: a) reply-timeout has been configured or b) - requires-reply attribute has been set on the downstream component (e.g., service-activator) - that might return 'null'. In this case, the exception will be thrown and propagated to the Gateway. - Sync Gateway - multi-threaded. Behavior is the same as above. - - - Downstream component return signature is 'void' while Gateway method signature is non-void - - - Sync Gateway - single-threaded. - If a component downstream returns 'void' and no reply-timeout has been configured, - the Gateway method call will hang indefinitely unless reply-timeout has been configured  - Sync Gateway - multi-threaded Behavior is the same as above. - - - Downstream component results in Runtime Exception (regardless of the method signature) - - - Sync Gateway - single-threaded. - If a component downstream throws a Runtime Exception, such exception will be propagated via Error Message back to - the gateway and re-thrown. - Sync Gateway - multi-threaded Behavior is the same as above. - - - - It is also important to understand that by default reply-timout is unbounded which means that - if not explicitly set there are several scenarios (described above) where your Gateway method invocation might - hang indefinitely, so make sure you analyze your flow and if there is even a remote possibility of one of these - scenarios to occur, set the reply-timout attribute to a 'safe' value or better off - set the requires-reply attribute of the downstream component to 'true' to ensure a timely response. - But also, realize that there are some scenarios (see the very first one) - where reply-timout will not help which means it is also important to analyze your message - flow and decide when to use Sync Gateway vs Async Gateway where Gateway method invocation is always guaranteed - to return while giving you a more granular control over the results of the invocation via Java Futures. - - Also, when dealing with Router you should remember that seeting resolution-required attribute to 'true' - will result in the exception thrown by the router if it can not resolve a particular chanel. And when dealing with the filter - you can also set throw-exception-on-rejection attribute. Both of these will help to ensure a timely response - from the Gateway method invocation. - - - -
- -
\ No newline at end of file diff --git a/src/docbkx/http.xml b/src/docbkx/http.xml deleted file mode 100644 index 562787ed6d..0000000000 --- a/src/docbkx/http.xml +++ /dev/null @@ -1,210 +0,0 @@ - - - - HTTP Support - -
- Introduction - - The HTTP support allows for the execution of HTTP requests and the processing of inbound HTTP requests. Because interaction over HTTP is always synchronous, even if all that is returned is a 200 status code, the HTTP support consists of two gateway implementations: - HttpInboundEndpoint and HttpRequestExecutingMessageHandler. - -
- -
- Http Inbound Gateway - - To receive messages over HTTP you need to use an HTTP inbound Channel Adapter or Gateway. In common with the HttpInvoker - support the HTTP inbound adapters need to be deployed within a servlet container. The easiest way to do this is to provide a servlet - definition in web.xml, see - for further details. Below is an example bean definition for a simple HTTP inbound endpoint. - - - -]]> - The HttpRequestHandlingMessagingGateway accepts a list of HttpMessageConverter instances or else - relies on a default list. The converters allow - customization of the mapping from HttpServletRequest to Message. The default converters - encapsulate simple strategies, which for - example will create a String message for a POST request where the content type starts with "text", see the Javadoc for - full details. - - Starting with this release MultiPart File support was implemented. If the request has been wrapped as a - MultipartHttpServletRequest, when using the default converters, that request will be converted - to a Message payload that is a MultiValueMap containing values that may be byte arrays, Strings, or instances of - Spring's MultipartFile depending on the content type of the individual parts. - - The HTTP inbound Endpoint will locate a MultipartResolver in the context if one exists with the bean name - "multipartResolver" (the same name expected by Spring's DispatcherServlet). If it does in fact locate that - bean, then the support for MultipartFiles will be enabled on the inbound request mapper. Otherwise, it will - fail when trying to map a multipart-file request to a Spring Integration Message. For more on Spring's - support for MultipartResolvers, refer to the Spring Reference Manual. - - - - In sending a response to the client there are a number of ways to customize the behavior of the gateway. By default the gateway will - simply acknowledge that the request was received by sending a 200 status code back. It is possible to customize this response by providing a - 'viewName' to be resolved by the Spring MVC ViewResolver. - In the case that the gateway should expect a reply to the Message then setting the expectReply flag - (constructor argument) will cause - the gateway to wait for a reply Message before creating an HTTP response. Below is an example of a gateway - configured to serve as a Spring MVC Controller with a view name. Because of the constructor arg value of TRUE, it wait for a reply. This also shows - how to customize the HTTP methods accepted by the gateway, which - are POST and GET by default. - - - - - - - - GET - DELETE - - - -]]> - The reply message will be available in the Model map. The key that is used - for that map entry by default is 'reply', but this can be overridden by setting the - 'replyKey' property on the endpoint's configuration. - -
- -
- Http Outbound Gateway - - - To configure the HttpRequestExecutingMessageHandler write a bean definition like this: - - - -]]> - This bean definition will execute HTTP requests by delegating to a RestTemplate. That template in turn delegates - to a list of HttpMessageConverters to generate the HTTP request body from the Message payload. You can configure those converters as well - as the ClientHttpRequestFactory instance to use: - - - - - -]]> -By default the HTTP request will be generated using an instance of SimpleClientHttpRequestFactory which uses the JDK - HttpURLConnection. Use of the Apache Commons HTTP Client is also supported through the provided - CommonsClientHttpRequestFactory which can be injected as shown above. - -
- -
- HTTP Namespace Support - - Spring Integration provides an "http" namespace and schema definition. To include it in your - configuration, simply provide the following URI within a namespace declaration: - 'http://www.springframework.org/schema/integration/http'. The schema location should then map to - 'http://www.springframework.org/schema/integration/http/spring-integration-http.xsd'. - - - To configure an inbound http channel adapter which is an instance of HttpInboundEndpoint configured - not to expect a response. - ]]> - - - To configure an inbound http gateway which expects a response. - ]]> - - - To configure the outbound gateway you can use the namespace support as well. The following code snippet shows the different configuration options for an outbound Http gateway. Most importantly, notice that the 'http-method' and 'expected-response-type' are provided. Those are two of the most commonly configured values. The - default http-method is POST, and the default response type is null. With a null response type, the payload of the reply Message would only - contain the status code (e.g. 200) as long as it's a successful status (non-successful status codes will throw Exceptions). If you are expecting a different - type, such as a String, then provide that fully-qualified class name as shown below. - ]]> - - If your outbound adapter is to be used in a unidirectional way, then you can use an outbound-channel-adapter instead. This means that - a successful response will simply execute without sending any Messages to a reply channel. In the case of any non-successful response - status code, it will throw an exception. The configuration looks very similar to the gateway: - ]]> - -
-
- HTTP Samples -
- Multipart HTTP request - RestTemplate (client) and Http Inbound Gateway (server) - - This example demonstrates how simple it is to send a Multipart HTTP request via Spring's RestTemplate and receive it by Spring Integration HTTP Inbound Adapter. -All we are doing is creating MultiValueMap and populating it with multi-part data. RestTemplate will take care of the rest -by converting it to MultipartHttpServletRequest   -THis particular client will send a multipart Http Request which contains the name of the company as well as the image file with company logo. - httpResponse = template.exchange(uri, HttpMethod.POST, request, null);]]> - - -That is all for the client. - - -On the server side we have the following configuration: - - - - - - - - - -]]> - - -The 'httpInboundAdapter' will receive the request, convert it to a Message with a payload as LinkedMultiValueMap which -we are parsing in the 'multipartReceiver' service-activator; - multipartRequest){ - System.out.println("### Successfully recieved multipart request ###"); - for (String elementName : multipartRequest.keySet()) { - if (elementName.equals("company")){ - System.out.println("\t" + elementName + " - " + - ((String[]) multipartRequest.getFirst("company"))[0]); - } else if (elementName.equals("company-logo")){ - System.out.println("\t" + elementName + " - as UploadedMultipartFile: " + - ((UploadedMultipartFile) multipartRequest.getFirst("company-logo")).getOriginalFilename()); - } - } -} - -]]> -You should see the following output: - - -
-
-
diff --git a/src/docbkx/message-publishing.xml b/src/docbkx/message-publishing.xml deleted file mode 100644 index 89993ac699..0000000000 --- a/src/docbkx/message-publishing.xml +++ /dev/null @@ -1,371 +0,0 @@ - - - - Message Publishing - - The AOP Message Publishing feature allows you to construct and send a message as a by-product of method invocation. For example, imagine you - have a component and every time the state of this component changes you would like to be notified via a Message. The easiest - way to send such notifications would be to send a message to a dedicated channel, but how would you connect the method invocation that - changes the state of the object to a message sending process, and how should the notification Message be structured? - The AOP Message Publishing feature handles these responsibilities with a configuration-driven approach. - -
- Message Publishing Configuration - - Spring Integration provides two approaches: XML and Annotation-driven. - -
- Annotation-driven approach via @Publisher annotation - - The annotation-driven approach allows you to annotate any method with the @Publisher annotation, specifying 'channel' attribute. - The Message will be constructed from the return value of method invocation and sent to a channel specified by 'channel' attribute. - To further manage message structure you can also use a combination of both @Payload and @Header annotations. - - - Internally message publishing feature of Spring Integration uses both Spring AOP by defining PublisherAnnotationAdvisor and - Spring 3.0 Expression Language (SpEL) support, giving you considerable flexibility and control over the structure of the Message it will build. - - - PublisherAnnotationAdvisor defines and binds the following variables: - - - #return - will bind to a return value allowing you to reference it or its - attributes (e.g., #return.foo where 'foo' is an attribute of the object bound to - #return) - - - #exception - will bind to an exception if one is thrown by the method invocation. - - - #args - will bind to method arguments, so individual arguments could be extracted by name - (e.g., #args.fname as in the above method) - - - - - - Let's look at couple of examples: - - -@Publisher -public String defaultPayload(String fname, String lname) { - return fname + " " + lname; -} - - - In the above example the Message will be constructed with the following structure: - - - Message payload - will be the return type and value of the method. This is the default. - - - A newly constructed message will be sent to a default publisher channel configured with annotation post processor (see the end of this section). - - - - -@Publisher(channel="testChannel") -public String defaultPayload(String fname, @Header("last") String lname) { - return fname + " " + lname; -} - - - In this example everything is the same as above, however we are not using default publishing channel. Instead we are specifying - the publishing channel via 'channel' attribute of @Publisher annotation. - We are also adding @Header annotation which results in the Message header with the name 'last' and the value of 'lname' input parameter - to be added to the newly constructed Message. - - - -@Publisher(channel="testChannel") -@Payload -public String defaultPayloadButExplicitAnnotation(String fname, @Header String lname) { - return fname + " " + lname; -} - - - The above example is almost identical to the previous one. The only difference here is that we are using @Payload annotation - on the method, thus explicitly specifying that the return value of the method should be used as a payload of the Message. - - - -@Publisher(channel="testChannel") -@Payload("#return + #args.lname") -public String setName(String fname, String lname, @Header("x") int num) { - return fname + " " + lname; -} - - - Here we are expending on the previous configuration by using Spring Expression language in the @Payload annotation further instructing - the framework on how the message should be constructed. In this particular case the message will be a concatenation of the return value of the method invocation and - 'lname' input argument. Message header 'x' with value of 'num' input argument will be added to the newly constructed Message. - - - -@Publisher(channel="testChannel") -public String argumentAsPayload(@Payload String fname, @Header String lname) { - return fname + " " + lname; -} - - - In the above example you see another usage of @Payload annotation. Here we are annotating method argument - which will become a payload of newly constructed message. - - - - - As with most other annotation-driven features in Spring, you will need to register a post-processor - (PublisherAnnotationBeanPostProcessor). - <bean class="org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor"/> - You can also use namespace support for added convenience: - -<si:annotation-config default-publisher-channel="defaultChannel"/> - - - - Similar to other Spring annotations (e.g., @Controller), @Publisher is a meta-annotation, which means you can define your own annotations - that will be treated as @Publisher - -Here we defined @Audit annotation which itself is a @Publisher. Also note that you can define channel -attribute on the meta-annotation thus encapsulating the behavior of where messages will be sent inside of this annotation. - -Now you can annotate any method: - - -In the above example every invocation of test() method will result in Message with payload which is the return value of the method -invocation to be sent to auditChannel - -You can also annotate the class which would mean that the properties of this annotation will be applied on every public method of this class - - - - -
- -
- XML-based approach via <publishing-interceptor> element - - The XML-based approach allows you to configure the same AOP-based Message Publishing functionality with - simple namespace-based configuration of a MessagePublishingInterceptor. - It certainly has some benefits over the annotation-driven approach since it - allows you to use AOP pointcut expressions, thus possibly intercepting multiple methods at once or - intercepting and publishing methods to which you don't have the source code. - - - To configure Message Publishing via XML, you only need to do the following two things: - - - Provide configuration for MessagePublishingInterceptor - via the <publishing-interceptor> XML element. - - - Provide AOP configuration to apply the MessagePublishingInterceptor to managed objects. - - - - - - - - - -
- - -
- - -]]> - - - As you can see the <publishing-interceptor> configuration look rather similar to Annotation-based approach - and it also utilizes the power of the Spring 3.0 Expression Language. - - - In the above example the execution of the echo method of a testBean will - render a Message with the following structure: - - - The Message payload will be of type String and value of "Echoing: [value]" where value is the value - returned by an executed method. - - - The Message will have header with the key "foo" value "bar". - - - The Message will be sent to echoChannel. - - - - - - The second method is very similar to the first. Here every method that begins with 'repl' will render a Message with the following structure: - - - The Message payload will be the same as in the above sample - - - The Message will have header with the key "foo" and value that is the result of the SpEL expression 'bar'.toUpperCase() . - - - The Message will be sent to echoChannel. - - - - - - The second method, mapping the execution of any method that begins with echoDef of testBean, will produce a - Message with the following structure. - - - The Message payload will be the value returned by an executed method. - - - Since the channel attribute is not provided explicitly, the Message will be sent to the - defaultChannel defined by the publisher. - - - - - - For simple mapping rules you can rely on the publisher defaults. For example: - -<publishing-interceptor id="anotherInterceptor"/> - - This will map the return value of every method that matches the pointcut expression to a payload and will be sent to a default-channel. - If the defaultChannelis not specified (as above) the messages will be sent to the global nullChannel. - - - Async Publishing - - - One important thing to understand is that publishing occurs in the same thread as your component's execution. So by default in is synchronous. - This means that the entire message flow would have to wait until he publisher flow completes.  - However, quite often you want the complete opposite and that is to use Message publishing feature to initiate asynchronous sub-flows. - For example, you might host a service (HTTP, WS etc.) which receives a remote request.You may want to send this request internally into a - process that might take a while. However you may also want to reply to the user right away. So, instead of sending inbound - request for processing via the output channel (the conventional way), you can simply use ''outout-channel or $replyChannel'' header - to send simple acknowledgment-like reply back to the caller while using Message publisher feature to initiate a complex flow. - - - EXAMPLE: - Here is the simple service that receives a complex payload, which needs to be sent further for processing, but it - also need to reply to the caller with a simple acknowledgment. - - So instead of hooking up the complex flow to the output channel we use Message publishing feature instead configuring it to create a - new Message using the input argument of the service method (above) and sending it to the 'localProcessChannel'. And to make sure this sub-flow - is asynchronous all we need to do is make sure that we send it to any type of async channel (ExecutorChannel in this example). - - - - - - - - - - - - - - - - - -]]> - - - Another way of handling thi type of scenario is through wire-tap - -
- -
- Producing and publishing messages based on a scheduled trigger - - In the above sections we looked at the Message publishing feature of Spring Integration which constructs and publishes messages as by-products of Method invocations. - However in that case, you are still responsible for invoking the method. - In Spring Integration 2.0 we've added another related useful feature: support for scheduled Message producers/publishers via the new "expression" attribute - on the 'inbound-channel-adapter' element. Scheduling could be based on several triggers, any one of which may be configured on the 'poller' sub-element. - Currently we support cron, fixed-rate, fixed-delay as well as any custom trigger implemented by you. - - - As mentioned above, support for scheduled producers/publishers is provided via the <inbound-channel-adapter> xml element. - Let's look at couple of examples: - - - - - -]]> - - In the above example an inbound Channel Adapter will be created which will construct a Message with its payload being the result of the expression  - defined in the expression attribute. Such message will be created and sent every time after the delay specified by the fixed-delay attribute. - - - -]]> - - This example is very similar to the previous one, except that we are using the fixed-rate attribute which will allow us to send messages at a fixed rate (measuring from the start time of each task). - - - -]]> - - This example demonstrates how you can apply a Cron trigger with a value specified in the cron attribute. - - - - -
-
-]]> - - Here you can see that in a way very similar to the Message publishing feature we are enriching a newly constructed Message with - extra Message headers which could take scalar values as well as the results of evaluating Spring expressions. - - - - If you need to implement your own custom trigger you can use the trigger attribute to provide a reference to any spring configured - bean which implements the org.springframework.scheduling.Trigger interface. - - - - - - - -]]> - - -
-
-
\ No newline at end of file diff --git a/src/docbkx/resources/xsl/fopdf.xsl b/src/docbkx/resources/xsl/fopdf.xsl deleted file mode 100644 index b1fbf5dcdb..0000000000 --- a/src/docbkx/resources/xsl/fopdf.xsl +++ /dev/null @@ -1,418 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copyright © 2005-2010 - - - , - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -5em - -5em - - - - - - - - - - - Spring-Integration ( - - ) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - 0 - 1 - - 1 - - - - - - book toc - - - - 2 - - - - - - - - - - 0 - 0 - 0 - - - 5mm - 10mm - 10mm - - 15mm - 10mm - 0mm - - 18mm - 18mm - - - 0pc - - - - - justify - false - - - 11 - 8 - - - 1.4 - - - - - - - 0.8em - - - - - - 17.4cm - - - - 4pt - 4pt - 4pt - 4pt - - - - 0.1pt - 0.1pt - - - - - 1 - - - - - - - - left - bold - - - pt - - - - - - - - - - - - - - - 0.8em - 0.8em - 0.8em - - - pt - - 0.1em - 0.1em - 0.1em - - - 0.6em - 0.6em - 0.6em - - - pt - - 0.1em - 0.1em - 0.1em - - - 0.4em - 0.4em - 0.4em - - - pt - - 0.1em - 0.1em - 0.1em - - - - - bold - - - pt - - false - 0.4em - 0.6em - 0.8em - - - - - - - - - pt - - - - - 1em - 1em - 1em - #444444 - solid - 0.1pt - 0.5em - 0.5em - 0.5em - 0.5em - 0.5em - 0.5em - - - - 1 - - #F0F0F0 - - - - - - 0 - 1 - - - 90 - - - - - '1' - - - - - - - figure after - example before - equation before - table before - procedure before - - - - 1 - - - - 0.8em - 0.8em - 0.8em - 0.1em - 0.1em - 0.1em - - - - - - - - - - - - - - - - - diff --git a/src/docbkx/resources/xsl/html.xsl b/src/docbkx/resources/xsl/html.xsl deleted file mode 100644 index aa7930bab8..0000000000 --- a/src/docbkx/resources/xsl/html.xsl +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - html.css - - - 1 - 0 - 1 - 0 - - - - - - book toc - - - - 3 - - - - - 1 - - - - - - - 0 - - - 90 - - - - - 0 - - - - - figure after - example before - equation before - table before - procedure before - - - - , - - - - - - - - -
-

Authors

-

- -

-
- -
diff --git a/src/docbkx/resources/xsl/html/titlepage.xml b/src/docbkx/resources/xsl/html/titlepage.xml deleted file mode 100644 index 09539c068c..0000000000 --- a/src/docbkx/resources/xsl/html/titlepage.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - <subtitle/> - <!-- <corpauthor/> - <authorgroup/> - <author/> - <mediaobject/> --> - <othercredit/> - <releaseinfo/> - <copyright/> - <legalnotice/> - <pubdate/> - <revision/> - <revhistory/> - <abstract/> - </t:titlepage-content> - - <t:titlepage-content t:side="verso"> - </t:titlepage-content> - - <t:titlepage-separator> - <hr/> - </t:titlepage-separator> - - <t:titlepage-before t:side="recto"> - </t:titlepage-before> - - <t:titlepage-before t:side="verso"> - </t:titlepage-before> -</t:titlepage> - -</t:templates> diff --git a/src/docbkx/resources/xsl/html_chunk.xsl b/src/docbkx/resources/xsl/html_chunk.xsl deleted file mode 100644 index 59016d819a..0000000000 --- a/src/docbkx/resources/xsl/html_chunk.xsl +++ /dev/null @@ -1,208 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - This is the XSL HTML configuration file for the Spring Reference Documentation. ---> -<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" - xmlns:fo="http://www.w3.org/1999/XSL/Format" - version="1.0"> - - <xsl:import href="urn:docbkx:stylesheet"/> - <!--################################################### - HTML Settings - ################################################### --> - <xsl:param name="chunk.section.depth">'5'</xsl:param> - <xsl:param name="use.id.as.filename">'1'</xsl:param> - <!-- These extensions are required for table printing and other stuff --> - <xsl:param name="use.extensions">1</xsl:param> - <xsl:param name="tablecolumns.extension">0</xsl:param> - <xsl:param name="callout.extensions">1</xsl:param> - <xsl:param name="graphicsize.extension">0</xsl:param> - <!--################################################### - Table Of Contents - ################################################### --> - <!-- Generate the TOCs for named components only --> - <xsl:param name="generate.toc"> - book toc - </xsl:param> - <!-- Show only Sections up to level 3 in the TOCs --> - <xsl:param name="toc.section.depth">3</xsl:param> - <!--################################################### - Labels - ################################################### --> - <!-- Label Chapters and Sections (numbering) --> - <xsl:param name="chapter.autolabel">1</xsl:param> - <xsl:param name="section.autolabel" select="1"/> - <xsl:param name="section.label.includes.component.label" select="1"/> - <!--################################################### - Callouts - ################################################### --> - <!-- Place callout marks at this column in annotated areas --> - <xsl:param name="callout.graphics">1</xsl:param> - <xsl:param name="callout.defaultcolumn">90</xsl:param> - <!--################################################### - Misc - ################################################### --> - <!-- Placement of titles --> - <xsl:param name="formal.title.placement"> - figure after - example before - equation before - table before - procedure before - </xsl:param> - <xsl:template match="author" mode="titlepage.mode"> - <xsl:if test="name(preceding-sibling::*[1]) = 'author'"> - <xsl:text>, </xsl:text> - </xsl:if> - <span class="{name(.)}"> - <xsl:call-template name="person.name"/> - <xsl:apply-templates mode="titlepage.mode" select="./contrib"/> - <xsl:apply-templates mode="titlepage.mode" select="./affiliation"/> - </span> - </xsl:template> - <xsl:template match="authorgroup" mode="titlepage.mode"> - <div class="{name(.)}"> - <h2>Authors</h2> - <p/> - <xsl:apply-templates mode="titlepage.mode"/> - </div> - </xsl:template> - <!--################################################### - Headers and Footers - ################################################### --> - <!-- let's have a Spring and SpringSource banner across the top of each page --> - <xsl:template name="user.header.navigation"> - <div style="background-color:white;border:none;height:73px;border:1px solid black;"> - <a style="border:none;" href="http://static.springframework.org/spring-ws/site/" - title="The Spring Framework - Spring Web Services"> - <img style="border:none;" src="images/xdev-spring_logo.jpg"/> - </a> - <a style="border:none;" href="http://www.springsource.com/" title="SpringSource"> - <img style="border:none;position:absolute;padding-top:5px;right:42px;" src="images/s2_box_logo.png"/> - </a> - </div> - </xsl:template> - <!-- no other header navigation (prev, next, etc.) --> - <xsl:template name="header.navigation"/> - <xsl:param name="navig.showtitles">1</xsl:param> - <!-- let's have a 'Sponsored by SpringSource' strapline (or somesuch) across the bottom of each page --> - <xsl:template name="footer.navigation"> - <xsl:param name="prev" select="/foo"/> - <xsl:param name="next" select="/foo"/> - <xsl:param name="nav.context"/> - <xsl:variable name="home" select="/*[1]"/> - <xsl:variable name="up" select="parent::*"/> - <xsl:variable name="row1" select="count($prev) > 0 - or count($up) > 0 - or count($next) > 0"/> - <xsl:variable name="row2" select="($prev and $navig.showtitles != 0) - or (generate-id($home) != generate-id(.) - or $nav.context = 'toc') - or ($chunk.tocs.and.lots != 0 - and $nav.context != 'toc') - or ($next and $navig.showtitles != 0)"/> - <xsl:if test="$suppress.navigation = '0' and $suppress.footer.navigation = '0'"> - <div class="navfooter"> - <xsl:if test="$footer.rule != 0"> - <hr/> - </xsl:if> - <xsl:if test="$row1 or $row2"> - <table width="100%" summary="Navigation footer"> - <xsl:if test="$row1"> - <tr> - <td width="40%" align="left"> - <xsl:if test="count($prev)>0"> - <a accesskey="p"> - <xsl:attribute name="href"> - <xsl:call-template name="href.target"> - <xsl:with-param name="object" select="$prev"/> - </xsl:call-template> - </xsl:attribute> - <xsl:call-template name="navig.content"> - <xsl:with-param name="direction" select="'prev'"/> - </xsl:call-template> - </a> - </xsl:if> - <xsl:text> </xsl:text> - </td> - - <td width="20%" align="center"> - <xsl:choose> - <xsl:when test="$home != . or $nav.context = 'toc'"> - <a accesskey="h"> - <xsl:attribute name="href"> - <xsl:call-template name="href.target"> - <xsl:with-param name="object" select="$home"/> - </xsl:call-template> - </xsl:attribute> - <xsl:call-template name="navig.content"> - <xsl:with-param name="direction" select="'home'"/> - </xsl:call-template> - </a> - <xsl:if test="$chunk.tocs.and.lots != 0 and $nav.context != 'toc'"> - <xsl:text> | </xsl:text> - </xsl:if> - </xsl:when> - <xsl:otherwise> </xsl:otherwise> - </xsl:choose> - <xsl:if test="$chunk.tocs.and.lots != 0 and $nav.context != 'toc'"> - <a accesskey="t"> - <xsl:attribute name="href"> - <xsl:apply-templates select="/*[1]" mode="recursive-chunk-filename"> - <xsl:with-param name="recursive" select="true()"/> - </xsl:apply-templates> - <xsl:text>-toc</xsl:text> - <xsl:value-of select="$html.ext"/> - </xsl:attribute> - <xsl:call-template name="gentext"> - <xsl:with-param name="key" select="'nav-toc'"/> - </xsl:call-template> - </a> - </xsl:if> - </td> - <td width="40%" align="right"> - <xsl:text> </xsl:text> - <xsl:if test="count($next)>0"> - <a accesskey="n"> - <xsl:attribute name="href"> - <xsl:call-template name="href.target"> - <xsl:with-param name="object" select="$next"/> - </xsl:call-template> - </xsl:attribute> - <xsl:call-template name="navig.content"> - <xsl:with-param name="direction" select="'next'"/> - </xsl:call-template> - </a> - </xsl:if> - </td> - </tr> - </xsl:if> - <xsl:if test="$row2"> - <tr> - <td width="40%" align="left" valign="top"> - <xsl:if test="$navig.showtitles != 0"> - <xsl:apply-templates select="$prev" mode="object.title.markup"/> - </xsl:if> - <xsl:text> </xsl:text> - </td> - <td width="20%" align="center"> - <span style="color:white;font-size:90%;"> - <a href="http://www.springsource.com/" - title="SpringSource">Sponsored by SpringSource - </a> - </span> - </td> - <td width="40%" align="right" valign="top"> - <xsl:text> </xsl:text> - <xsl:if test="$navig.showtitles != 0"> - <xsl:apply-templates select="$next" mode="object.title.markup"/> - </xsl:if> - </td> - </tr> - </xsl:if> - </table> - </xsl:if> - </div> - </xsl:if> - </xsl:template> -</xsl:stylesheet> diff --git a/src/docbkx/resources/xsl/pdf/fopdf.xsl b/src/docbkx/resources/xsl/pdf/fopdf.xsl deleted file mode 100644 index 2905ee3c21..0000000000 --- a/src/docbkx/resources/xsl/pdf/fopdf.xsl +++ /dev/null @@ -1,518 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. ---> - -<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" - xmlns:fo="http://www.w3.org/1999/XSL/Format" - xmlns:xslthl="http://xslthl.sf.net" - exclude-result-prefixes="xslthl" - version='1.0'> - -<!-- Use nice graphics for admonitions --> - <xsl:param name="admon.graphics">'1'</xsl:param> - <xsl:param name="admon.graphics.path">@file.prefix@@dbf.xsl@/images/</xsl:param> - <xsl:param name="draft.watermark.image" select="'@file.prefix@@dbf.xsl@/images/draft.png'"/> - <xsl:param name="paper.type" select="'@paper.type@'"/> - - <xsl:param name="page.margin.top" select="'1cm'"/> - <xsl:param name="region.before.extent" select="'1cm'"/> - <xsl:param name="body.margin.top" select="'1.5cm'"/> - - <xsl:param name="body.margin.bottom" select="'1.5cm'"/> - <xsl:param name="region.after.extent" select="'1cm'"/> - <xsl:param name="page.margin.bottom" select="'1cm'"/> - <xsl:param name="title.margin.left" select="'0cm'"/> - -<!--################################################### - Header - ################################################### --> - -<!-- More space in the center header for long text --> - <xsl:attribute-set name="header.content.properties"> - <xsl:attribute name="font-family"> - <xsl:value-of select="$body.font.family"/> - </xsl:attribute> - <xsl:attribute name="margin-left">-5em</xsl:attribute> - <xsl:attribute name="margin-right">-5em</xsl:attribute> - </xsl:attribute-set> - -<!--################################################### - Table of Contents - ################################################### --> - - <xsl:param name="generate.toc"> - book toc,title - </xsl:param> - -<!--################################################### - Custom Header - ################################################### --> - - <xsl:template name="header.content"> - <xsl:param name="pageclass" select="''"/> - <xsl:param name="sequence" select="''"/> - <xsl:param name="position" select="''"/> - <xsl:param name="gentext-key" select="''"/> - - <xsl:variable name="Version"> - <xsl:choose> - <xsl:when test="//productname"> - <xsl:value-of select="//productname"/><xsl:text> </xsl:text> - </xsl:when> - <xsl:otherwise> - <xsl:text>please define productname in your docbook file!</xsl:text> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - - <xsl:choose> - <xsl:when test="$sequence='blank'"> - <xsl:choose> - <xsl:when test="$position='center'"> - <xsl:value-of select="$Version"/> - </xsl:when> - - <xsl:otherwise> - <!-- nop --> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - - <xsl:when test="$pageclass='titlepage'"> - <!-- nop: other titlepage sequences have no header --> - </xsl:when> - - <xsl:when test="$position='center'"> - <xsl:value-of select="$Version"/> - </xsl:when> - - <xsl:otherwise> - <!-- nop --> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - -<!--################################################### - Custom Footer - ################################################### --> - - <xsl:template name="footer.content"> - <xsl:param name="pageclass" select="''"/> - <xsl:param name="sequence" select="''"/> - <xsl:param name="position" select="''"/> - <xsl:param name="gentext-key" select="''"/> - - <xsl:variable name="Version"> - <xsl:choose> - <xsl:when test="//releaseinfo"> - <xsl:value-of select="//releaseinfo"/> - </xsl:when> - <xsl:otherwise> - <!-- nop --> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - - <xsl:variable name="Title"> - <xsl:value-of select="//title"/> - </xsl:variable> - - <xsl:choose> - <xsl:when test="$sequence='blank'"> - <xsl:choose> - <xsl:when test="$double.sided != 0 and $position = 'left'"> - <xsl:value-of select="$Version"/> - </xsl:when> - - <xsl:when test="$double.sided = 0 and $position = 'center'"> - <!-- nop --> - </xsl:when> - - <xsl:otherwise> - <fo:page-number/> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - - <xsl:when test="$pageclass='titlepage'"> - <!-- nop: other titlepage sequences have no footer --> - </xsl:when> - - <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='left'"> - <fo:page-number/> - </xsl:when> - - <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='right'"> - <fo:page-number/> - </xsl:when> - - <xsl:when test="$double.sided = 0 and $position='right'"> - <fo:page-number/> - </xsl:when> - - <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='left'"> - <xsl:value-of select="$Version"/> - </xsl:when> - - <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='right'"> - <xsl:value-of select="$Version"/> - </xsl:when> - - <xsl:when test="$double.sided = 0 and $position='left'"> - <xsl:value-of select="$Version"/> - </xsl:when> - - <xsl:when test="$position='center'"> - <xsl:value-of select="$Title"/> - </xsl:when> - - <xsl:otherwise> - <!-- nop --> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <xsl:template match="processing-instruction('hard-pagebreak')"> - <fo:block break-before='page'/> - </xsl:template> - -<!--################################################### - Extensions - ################################################### --> - -<!-- These extensions are required for table printing and other stuff --> - <xsl:param name="use.extensions">1</xsl:param> - <xsl:param name="tablecolumns.extension">0</xsl:param> - <xsl:param name="callout.extensions">1</xsl:param> - <xsl:param name="fop.extensions">1</xsl:param> - -<!--################################################### - Paper & Page Size - ################################################### --> - -<!-- Paper type, no headers on blank pages, no double sided printing --> - <xsl:param name="double.sided">0</xsl:param> - <xsl:param name="headers.on.blank.pages">0</xsl:param> - <xsl:param name="footers.on.blank.pages">0</xsl:param> - -<!--################################################### - Fonts & Styles - ################################################### --> - - <xsl:param name="hyphenate">false</xsl:param> - -<!-- Default Font size --> - <xsl:param name="body.font.master">11</xsl:param> - <xsl:param name="body.font.small">8</xsl:param> - -<!-- Line height in body text --> - <xsl:param name="line-height">1.4</xsl:param> - -<!-- Chapter title size --> - <xsl:attribute-set name="chapter.titlepage.recto.style"> - <xsl:attribute name="text-align">left</xsl:attribute> - <xsl:attribute name="font-weight">bold</xsl:attribute> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.master * 1.8"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - </xsl:attribute-set> - -<!-- Why is the font-size for chapters hardcoded in the XSL FO templates? - Let's remove it, so this sucker can use our attribute-set only... --> - <xsl:template match="title" mode="chapter.titlepage.recto.auto.mode"> - <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" - xsl:use-attribute-sets="chapter.titlepage.recto.style"> - <xsl:call-template name="component.title"> - <xsl:with-param name="node" select="ancestor-or-self::chapter[1]"/> - </xsl:call-template> - </fo:block> - </xsl:template> - -<!-- Sections 1, 2 and 3 titles have a small bump factor and padding --> - <xsl:attribute-set name="section.title.level1.properties"> - <xsl:attribute name="space-before.optimum">0.8em</xsl:attribute> - <xsl:attribute name="space-before.minimum">0.8em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.8em</xsl:attribute> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.master * 1.5"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - </xsl:attribute-set> - <xsl:attribute-set name="section.title.level2.properties"> - <xsl:attribute name="space-before.optimum">0.6em</xsl:attribute> - <xsl:attribute name="space-before.minimum">0.6em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.6em</xsl:attribute> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.master * 1.25"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - </xsl:attribute-set> - <xsl:attribute-set name="section.title.level3.properties"> - <xsl:attribute name="space-before.optimum">0.4em</xsl:attribute> - <xsl:attribute name="space-before.minimum">0.4em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.4em</xsl:attribute> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.master * 1.0"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - </xsl:attribute-set> - <xsl:attribute-set name="section.title.level4.properties"> - <xsl:attribute name="space-before.optimum">0.3em</xsl:attribute> - <xsl:attribute name="space-before.minimum">0.3em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.3em</xsl:attribute> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.master * 0.9"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - </xsl:attribute-set> - -<!-- Use code syntax highlighting --> - <xsl:param name="highlight.source" select="1"/> - <xsl:param name="highlight.default.language" select="xml" /> - - <xsl:template match='xslthl:keyword'> - <fo:inline font-weight="bold" color="#7F0055"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:comment'> - <fo:inline font-style="italic" color="#3F5F5F"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:oneline-comment'> - <fo:inline font-style="italic" color="#3F5F5F"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:multiline-comment'> - <fo:inline font-style="italic" color="#3F5FBF"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:tag'> - <fo:inline color="#3F7F7F"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:attribute'> - <fo:inline color="#7F007F"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:value'> - <fo:inline color="#2A00FF"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:string'> - <fo:inline color="#2A00FF"><xsl:apply-templates/></fo:inline> - </xsl:template> - -<!--################################################### - Tables - ################################################### --> - - <!-- Some padding inside tables --> - <xsl:attribute-set name="table.cell.padding"> - <xsl:attribute name="padding-left">4pt</xsl:attribute> - <xsl:attribute name="padding-right">4pt</xsl:attribute> - <xsl:attribute name="padding-top">4pt</xsl:attribute> - <xsl:attribute name="padding-bottom">4pt</xsl:attribute> - </xsl:attribute-set> - -<!-- Only hairlines as frame and cell borders in tables --> - <xsl:param name="table.frame.border.thickness">0.1pt</xsl:param> - <xsl:param name="table.cell.border.thickness">0.1pt</xsl:param> - -<!--################################################### - Labels - ################################################### --> - -<!-- Label Chapters and Sections (numbering) --> - <xsl:param name="chapter.autolabel" select="1"/> - <xsl:param name="section.autolabel" select="1"/> - <xsl:param name="section.autolabel.max.depth" select="1"/> - - <xsl:param name="section.label.includes.component.label" select="1"/> - <xsl:param name="table.footnote.number.format" select="'1'"/> - -<!--################################################### - Programlistings - ################################################### --> - -<!-- Verbatim text formatting (programlistings) --> - <xsl:attribute-set name="monospace.verbatim.properties"> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.small * 1.0"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - </xsl:attribute-set> - - <xsl:attribute-set name="verbatim.properties"> - <xsl:attribute name="space-before.minimum">1em</xsl:attribute> - <xsl:attribute name="space-before.optimum">1em</xsl:attribute> - <xsl:attribute name="space-before.maximum">1em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - - <xsl:attribute name="border-color">#444444</xsl:attribute> - <xsl:attribute name="border-style">solid</xsl:attribute> - <xsl:attribute name="border-width">0.1pt</xsl:attribute> - <xsl:attribute name="padding-top">0.5em</xsl:attribute> - <xsl:attribute name="padding-left">0.5em</xsl:attribute> - <xsl:attribute name="padding-right">0.5em</xsl:attribute> - <xsl:attribute name="padding-bottom">0.5em</xsl:attribute> - <xsl:attribute name="margin-left">0.5em</xsl:attribute> - <xsl:attribute name="margin-right">0.5em</xsl:attribute> - </xsl:attribute-set> - - <!-- Shade (background) programlistings --> - <xsl:param name="shade.verbatim">1</xsl:param> - <xsl:attribute-set name="shade.verbatim.style"> - <xsl:attribute name="background-color">#F0F0F0</xsl:attribute> - </xsl:attribute-set> - - <xsl:attribute-set name="list.block.spacing"> - <xsl:attribute name="space-before.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-before.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - </xsl:attribute-set> - - <xsl:attribute-set name="example.properties"> - <xsl:attribute name="space-before.minimum">0.5em</xsl:attribute> - <xsl:attribute name="space-before.optimum">0.5em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.5em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - <xsl:attribute name="keep-together.within-column">always</xsl:attribute> - </xsl:attribute-set> - -<!--################################################### - Title information for Figures, Examples etc. - ################################################### --> - - <xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing"> - <xsl:attribute name="font-weight">normal</xsl:attribute> - <xsl:attribute name="font-style">italic</xsl:attribute> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.master"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - <xsl:attribute name="hyphenate">false</xsl:attribute> - <xsl:attribute name="space-before.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-before.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.1em</xsl:attribute> - </xsl:attribute-set> - -<!--################################################### - Callouts - ################################################### --> - -<!-- don't use images for callouts --> - <xsl:param name="callout.graphics">0</xsl:param> - <xsl:param name="callout.unicode">1</xsl:param> - -<!-- Place callout marks at this column in annotated areas --> - <xsl:param name="callout.defaultcolumn">90</xsl:param> - -<!--################################################### - Misc - ################################################### --> - -<!-- Placement of titles --> - <xsl:param name="formal.title.placement"> - figure after - example after - equation before - table before - procedure before - </xsl:param> - -<!-- Format Variable Lists as Blocks (prevents horizontal overflow) --> - <xsl:param name="variablelist.as.blocks">1</xsl:param> - - <xsl:param name="body.start.indent">0pt</xsl:param> - -<!-- Show only Sections up to level 3 in the TOCs --> - <xsl:param name="toc.section.depth">3</xsl:param> - -<!-- Remove "Chapter" from the Chapter titles... --> - <xsl:param name="local.l10n.xml" select="document('')"/> - <l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0"> - <l:l10n language="en"> - <l:context name="title-numbered"> - <l:template name="chapter" text="%n. %t"/> - <l:template name="section" text="%n %t"/> - </l:context> - <l:context name="title"> - <l:template name="example" text="Example %n %t"/> - </l:context> - </l:l10n> - </l:i18n> - -<!--################################################### - colored and hyphenated links - ################################################### --> - - <xsl:template match="ulink"> - <fo:basic-link external-destination="{@url}" - xsl:use-attribute-sets="xref.properties" - text-decoration="underline" - color="blue"> - <xsl:choose> - <xsl:when test="count(child::node())=0"> - <xsl:value-of select="@url"/> - </xsl:when> - <xsl:otherwise> - <xsl:apply-templates/> - </xsl:otherwise> - </xsl:choose> - </fo:basic-link> - </xsl:template> - - <xsl:template match="link"> - <fo:basic-link internal-destination="{@linkend}" - xsl:use-attribute-sets="xref.properties" - text-decoration="underline" - color="blue"> - <xsl:choose> - <xsl:when test="count(child::node())=0"> - <xsl:value-of select="@linkend"/> - </xsl:when> - <xsl:otherwise> - <xsl:apply-templates/> - </xsl:otherwise> - </xsl:choose> - </fo:basic-link> - </xsl:template> - -</xsl:stylesheet> \ No newline at end of file diff --git a/src/docbkx/resources/xsl/pdf/titlepage.xml b/src/docbkx/resources/xsl/pdf/titlepage.xml deleted file mode 100644 index dc18e1e0de..0000000000 --- a/src/docbkx/resources/xsl/pdf/titlepage.xml +++ /dev/null @@ -1,101 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. ---> - -<!DOCTYPE t:templates [ -<!ENTITY hsize0 "10pt"> -<!ENTITY hsize1 "12pt"> -<!ENTITY hsize2 "14.4pt"> -<!ENTITY hsize3 "17.28pt"> -<!ENTITY hsize4 "20.736pt"> -<!ENTITY hsize5 "24.8832pt"> -<!ENTITY hsize0space "7.5pt"> <!-- 0.75 * hsize0 --> -<!ENTITY hsize1space "9pt"> <!-- 0.75 * hsize1 --> -<!ENTITY hsize2space "10.8pt"> <!-- 0.75 * hsize2 --> -<!ENTITY hsize3space "12.96pt"> <!-- 0.75 * hsize3 --> -<!ENTITY hsize4space "15.552pt"> <!-- 0.75 * hsize4 --> -<!ENTITY hsize5space "18.6624pt"> <!-- 0.75 * hsize5 --> -]> -<t:templates xmlns:t="http://nwalsh.com/docbook/xsl/template/1.0" - xmlns:param="http://nwalsh.com/docbook/xsl/template/1.0/param" - xmlns:fo="http://www.w3.org/1999/XSL/Format" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - - <t:titlepage t:element="book" t:wrapper="fo:block"> - <t:titlepage-content t:side="recto"> - <title - t:named-template="division.title" - param:node="ancestor-or-self::book[1]" - text-align="center" - font-size="&hsize5;" - space-before="&hsize5space;" - font-weight="bold" - font-family="{$title.fontset}"/> - <subtitle - text-align="center" - font-size="&hsize4;" - space-before="&hsize4space;" - font-family="{$title.fontset}"/> - - <!-- <corpauthor space-before="0.5em" - font-size="&hsize2;"/> - <authorgroup space-before="0.5em" - font-size="&hsize2;"/> - <author space-before="0.5em" - font-size="&hsize2;"/> --> - - <mediaobject space-before="2em" space-after="2em"/> - <releaseinfo space-before="5em" font-size="&hsize2;"/> - <copyright space-before="1.5em" - font-weight="normal" - font-size="8"/> - <legalnotice space-before="5em" - font-weight="normal" - font-style="italic" - font-size="8"/> - <othercredit space-before="2em" - font-weight="normal" - font-size="8"/> - <pubdate space-before="0.5em"/> - <revision space-before="0.5em"/> - <revhistory space-before="0.5em"/> - <abstract space-before="0.5em" - text-align="start" - margin-left="0.5in" - margin-right="0.5in" - font-family="{$body.fontset}"/> - </t:titlepage-content> - - <t:titlepage-content t:side="verso"> - </t:titlepage-content> - - <t:titlepage-separator> - </t:titlepage-separator> - - <t:titlepage-before t:side="recto"> - </t:titlepage-before> - - <t:titlepage-before t:side="verso"> - </t:titlepage-before> -</t:titlepage> - -<!-- ==================================================================== --> - -</t:templates> diff --git a/src/docbkx/rmi.xml b/src/docbkx/rmi.xml deleted file mode 100644 index 877dcfac5e..0000000000 --- a/src/docbkx/rmi.xml +++ /dev/null @@ -1,66 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> -<chapter id="rmi"> - <title>RMI Support - -
- Introduction - - This Chapter explains how to use RMI specific channel adapters to distribute a system over multiple JVMs. The first section will deal with sending messages over RMI. The second section shows how to receive messages over RMI. The last section shows how to define rmi channel adapters through the namespace support. - -
- -
- Outbound RMI - - To send messages from a channel over RMI, simply define an RmiOutboundGateway. This gateway will use Spring's RmiProxyFactoryBean internally to create a proxy for a remote gateway. Note that to invoke a remote interface that doesn't use Spring Integration you should use a service activator in combination with Spring's RmiProxyFactoryBean. - - - To configure the outbound gateway write a bean definition like this: - - - - ]]> - - -
- -
- Inbound RMI - - To receive messages over RMI you need to use a RmiInboundGateway. This gateway can be configured like this - - - ]]> - - -
- -
- RMI namespace support - - To configure the inbound gateway you can choose to use the namespace support for it. The following code snippet shows the different configuration options that are supported. - - - - - - - - - ]]> - - - To configure the outbound gateway you can use the namespace support as well. The following code snippet shows the different configuration for an outbound rmi gateway. - ]]> - -
- - \ No newline at end of file diff --git a/src/docbkx/samples.xml b/src/docbkx/samples.xml deleted file mode 100644 index 1992780cf7..0000000000 --- a/src/docbkx/samples.xml +++ /dev/null @@ -1,663 +0,0 @@ - - - - - Spring Integration Samples - -
- Introduction - - Starting with the current release of Spring Integration the samples are no longer included with - Spring Integration distribution. Instead we've switched to a much simpler collaborative model that should promote - better community participation and community contributions. Samples now have a dedicated Git SCM repository and a - dedicated JIRA Issue Tracking system. Sample development will also have its own lifecycle which is not dependent on the - lifecycle of the framework releases although the repository will still be tagged with each major release for compatibility - reasons. - - - The great benefit to the community is that we can now add more samples and make them available to you right away - without waiting for the release to get them out to you. Having its own JIRA that is not tied up to the the actual - framework is also a great benefit. You now have a dedicated place to suggest samples as well as report issues with existing - samples. Or you may want to submit a sample to us as an attachment through the JIRA and if we believe your sample adds value we - would be more then glad to add it to a samples repository properly crediting the author. - -
- -
- Where to get Samples - - To monitor samples development and to get more information on the repository you can visit the following - URL: http://git.springsource.org/spring-integration/samples - Since we are using Git SCM we should use the proper terminology as well when it comes to the tasks you need to perform to make - samples available locally on your machine. For more information on Git SCM please visit their - website: http://git-scm.com/ - - - CLONE samples repository. (For those unfamiliar with Git, this is somewhat the equivalent of a checkout.) - - - This is the first step you should go through. You must have Git installed on your machine. There are many GUI-based products - available for many platforms. Simple Google search will let you find them. - To clone samples repository from command line: - mkdir spring-itegration-samples -> cd spring-itegration-samples -> git clone git://git.springsource.org/spring-integration/samples.git]]> - - - That is all you need to do. Now you have cloned the entire samples repository. Since samples repository is a live - repository, you might want to perform periodic updates to get new samples as well as updates to the existing samples. - To get the updates use git PULL command: - git pull]]> - - - Submit samples or sample requests - - - As mentioned earlier, Spring Integration samples have a dedicated JIRA Issue tracking system. - To submit new sample request or to submit the actual sample (as an attachment) please visit our JIRA Issue Tracking system: - https://jira.springframework.org/browse/INTSAMPLES  - -
-
- Samples structure - - The structure of the samples changed as well. With plans for more samples we realized that some - samples have different goals then others. While they all share the common  goal of showing you how to apply and work with - Spring Integration framework, they also defer in areas where some samples were meant to concentrate on a technical - use case while others on the business use case and some samples are all about showcasing various techniques that - could be applied to address certain scenarios (both technical and business). Categorization of samples will allow us - better organize them based on the problem each sample addresses while giving you a simpler way of finding the right sample - - - Currently there are 4 categories. Within the samples repository each category has its own directory which is named after the - category name: - - - - BASIC (samples/basic) - - - This is a good place to get started. The samples here are technically motivated and demonstrate the bare - minimum with regard to configuration and code, to help you to get started quickly by introducing you to the basic concepts, - API and configuration of Spring Integration as well as Enterprise Integration Patterns (EIP). For example; If your are - looking for an answer on how to implement and wire Service Activator to a Channel - or how to use Messaging Gateway to your message exchange or how to get started with using MAIL or - TCP/UDP modules etc., this would be the right place to find a good sample. The bottom line is this is a good place - to get started. - - - - INTERMEDIATE (samples/intermediate) - - - This category targets developers who are already familiar with Spring Integration framework (past getting started), - but need some more guidance while resolving a more advanced technical problems one might deal with - once switch to a Messaging architecture. - For example; If you are looking for an answer on how to handle errors in various message exchange - scenarios or how to properly configure the Aggregator for the situations where some messages - might not ever arrive for aggregation etc,. and any other issue that goes beyond a basic implementation and configuration - of a particular component and addresses "what else you can do with it" type of problem this - would be the right place to find these type of samples. - - - - ADVANCED (samples/advanced) - - - This category targets develoopers who are very familiar with Spring Integration framework but looking to - extend it to address a specific custom need by using Spring Integration public API. - For example; if you are looking for samples showing you how to implement a custom Channel or - Consumer (event-based or polling-based), or you trying to figure out what is the most appropriate - way to implement custom Bean parser on top of Spring Integration Bean parsers hierarchy when implementing custom name space - for a custom component, this would be the right place to look. - Here you can also find samples that will help you with Adapter development. Spring Integration comes - with an extensive library of adapters to allow you to connect remote systems with Spring Integration messaging framework. - However you might have a need to integrate with system for which the core framework does not provide an adapter. - So you have to implement your own. This category would include samples showing you how to do it. - - - - - APPLICATIONS (samples/applications) - - - This category targets developers and architects who have a good understanding of the Messaging architecture, - EIP and above average understanding of Spring and Spring Integration frameworks and are looking for samples that - address a particular business problem. In other words the emphasis of samples in this category - is business use cases and how it could be solved via Messaging Architecture and Spring Integration - in particular. - For example; If you are interested to see how a Loan Broker or Travel Agent - process could be implemented and automated via Spring Integration this would be the right place to find these types of samples. - - - - - Remember! Spring Integration is a community driven framework, therefore community participation is IMPORTANT. -That includes Samples, so if you can't find what you are looking for let us know. - - -
- -
- Samples - - Currently Spring Integration comes with quite a few samples and you can only expect more. - To help you better navigate through them, each sample comes with its own readme.txt file which coveres - sevaral details about the sample (e.g., what EIP patterns it addresses, what problem it is trying to solve, how to run sample etc.). - However, certain samples require a more detailed and some times graphical explanation. In these section you'll - find details on samples that we believe require special attention. - -
- Loan Broker - - In this section, we will review a Loan Broker sample application that is included in the - Spring Integration samples. This sample is inspired by one of the samples featured in Gregor - Hohpe's Ramblings. - - The diagram below represents the entire process - - - - - - - - - - - Now lets look at this process in more details - - At the core of EIP architecture are the very simple yet powerful concepts of Pipes and Filters and Message. Endpoints (Filters) are - connected with one another via Channels (Pipes). The producing endpoint sends Message to the Channel and the Message is retrieved - by the Consuming endpoint. This architecture is meant to define various mechanisms that describe How information is exchanged between - the endpoints, without any awareness of What those endpoints are or What information they are exchanging, thus providing for a very loosely - coupled and flexible collaboration model while also, decoupling Integration concerns from Business concerns. EIP extends this architecture - by further defining: - - - The types of pipes (Point-to-Point Channel, Publish-Subscribe Channel, Channel Adapter, etc.) - - - - The core filters and patterns around how filters collaborate with pipes - (Message Router, Splitters and Aggregators, various Message Transformation patterns, etc.) - - - - - The details and variations of this use case are very nicely described in Chapter 9 of the EIP Book, but here is the brief summary; - A Consumer while shopping for the best Loan Quote(s) subscribes to the services of a Loan Broker, which handles details such as: - - - Consumer pre-screening (e.g., obtain and review the consumer's Credit history) - - - - Determine the most appropriate Banks (e.g., based on consumer's credit history/score) - - - - Send a Loan quote request to each selected Bank - - - Collect responses from each Bank - - - Filter responses and determine the best quote(s), based on consumer's requirements. - - - Pass the Loan quote(s) back to the consumer. - - - - - Obviously the real process of obtaining a loan quote is a bit more complex, but since our goal here is to demonstrate how - Enterprise Integration Patterns are realized and implemented within SI, the use case has been simplified to concentrate only on - the Integration aspects of the process. It is not an attempt to give you an advice in consumer finances. - - - As you can see, by hiring a Loan Broker, the consumer is isolated from the details of the Loan Broker's operations, and each Loan Broker's - operations may defer from one another to maintain competitive advantage, so whatever we assemble/implement must be flexible so any changes - could be introduced quickly and painlessly. - Speaking of change, the Loan Broker sample does not actually talk to any 'imaginary' Banks or Credit bureaus. Those services are stubbed out. - Our goal here is to assemble, orchestrate and test the integration aspect of the process as a whole. Only then can we start thinking about - wiring such process to the real services. At that time the assembled process and its configuration will not change regardless of the number - of Banks a particular Loan Broker is dealing with, or the type of communication media (or protocols) used (JMS, WS, TCP, etc.) - to communicate with these Banks. - - DESIGN - - As you analyze the 6 requirements above you'll quickly see that they all fall into the category of Integration concerns. - For example, in the consumer pre-screening step we need to gather additional information about the consumer and the consumer's desires - and enrich the loan request with additional meta information. We then have to filter such information to select the most appropriate list of - Banks, and so on. Enrich, filter, select – these are all integration concerns for which EIP defines a solution in the form of patterns. - SI provides an implementation of these patterns. - - Messaging Gateway - - - - - - - - - - - The Messaging Gateway pattern provides a simple mechanism to access messaging systems, including our Loan Broker. - In SI you define the Gateway as a Plain Old Java Interface (no need to provide an implementation), configure it via the - XML <gateway&gr; element or via annotation and use it as any other Spring bean. SI will take care of - delegating and mapping method invocations to the Messaging infrastructure by generating a Message (payload is mapped to an - input parameter of the method) and sending it to the designated channel. - - -
- -]]> - - - Our current Gateway provides two methods that could be invoked. One that will return the best single quote and another one that - will return all quotes. Somehow downstream we need to know what type of reply the caller is looking for. The best way to achieve - this in Messaging architecture is to enrich the content of the message with some meta-data describing your intentions. - Content Enricher is one of the patterns that addresses this and although Spring Integration does provide a - separate configuration element to enrich Message Headers with arbitrary data (we'll see it later), as a convenience, since - Gateway element is responsible to construct the initial Message it provides embedded - capability to enrich the newly created Message with arbitrary Message Headers. In our - example we are adding header RESPONSE_TYPE with value 'BEST'' whenever the getBestQuote() method is invoked. For other method - we are not adding any header. Now we can check downstream for an existence of this header and based on its presence and its value - we can determine what type of reply the caller is looking for. - - - - Based on the use case we also know there are some pre-screening steps that needs to be performed such as getting and evaluating the consumer's - credit score, simply because some premiere Banks will only typically accept quote requests from consumers that meet a minimum credit - score requirement. So it would be nice if the Message would be enriched with such information before it is forwarded - to the Banks. It would also be nice if when several processes needs to be completed to provide such meta-information, those - processes could be grouped in a single unit. In our use case we need to determine credit score and based on the credit score and some - rule select a list of Message Channels (Bank Channels) we will sent quote request to. - - Composed Message Processor - - The Composed Message Processor pattern describes rules around building endpoints that maintain control over message flow which - consists of multiple message processors. In Sprig Integration Composed Message Processor pattern is implemented via - <chain> element. - - - - - - - - - - - As you can see from the above configuration we have a chain with inner header-enricher element which will further enrich the - content of the Message with the header CREDIT_SCORE and value that will be determined by the call to a - credit service (simple POJO spring bean identified by 'creditBureau' name) and then it will delegate to the Message Router - - Message Router - - - - - - - - - - - There are several implementation of Message Routing pattern available in Spring Integration. Here we are using - router that will determine a list of channels based on evaluating an expression (Spring Expression Language) which will look at - the credit score that was determined is the previous step and will select the list of channels from the Map bean with id 'banks' - whose values are 'premier' or 'secondary' based o the value of credit score. Once the list of Channels is selected, the - Message will be routed to those Channels. - - - Now, one last thing the Loan Broker needs to to is to receive the loan quotes form the banks, aggregate them by consumer - (we don't want to show quotes from one consumer to another), assemble the response based on the consumer's selection criteria - (single best quote or all quotes) and reply back to the consumer. - - Message Aggregator - - - - - - - - - - - - An Aggregator pattern describes an endpoint which groups related Messages into a single - Message. Criteria and rules can be provided to determine an aggregation and correlation strategy. - SI provides several implementations of the Aggregator pattern as well as a convenient name-space based configuration. - - -]]> - - - - Our Loan Broker defines a 'quotesAggregator' bean via the <aggregator> element which provides a default - aggregation and correlation strategy. The default correlation strategy correlates messages based on the $corelationId header - (see Correlation Identifier pattern). What's interesting is that we never provided the value for this header. - It was set earlier by the router automatically, when it generated a separate Message for each Bank channel. - - - Once the Messages are correlated they are released to the actual Aggregator implementation. - Although default Aggregator is provided by SI, its strategy (gather the list of payloads from all - Messages and construct a new Message with this List as payload) does not satisfy our - requirement. The reason is that our consumer might require a single best quote or all quotes. To communicate the consumer's - intention, earlier in the process we set the RESPONSE_TYPE header. Now we have to evaluate this header and return either - all the quotes (the default aggregation strategy would work) or the best quote (the default aggregation strategy will not work - because we have to determine which loan quote is the best). - - - - Obviously selecting the best quote could be based on complex criteria and would influence the complexity of the aggregator implementation and - configuration, but for now we are making it simple. If consumer wants the best quote we will select a quote with the lowest interest - rate. To accomplish that the LoanQuoteAggregator.java will sort all the quotes and return the first one. - The LoanQuote.java implements Comparable which compares quotes based on the rate attribute. - Once the response Message is created it is sent to the default-reply-channel of the Messaging Gateway - (thus the consumer) which started the process. Our consumer got the Loan Quote! - - Conclusion - - As you can see a rather complex process was assembled based on POJO (read existing, legacy), light weight, embeddable messaging - framework (Sprig Integration) with a loosely coupled programming model intended to simplify integration of heterogeneous systems - without requiring a heavy-weight ESB-like engine or proprietary development and deployment environment, becouse as a developer you - should not be porting your Swing or console-based application to an ESB-like server or implementing proprietary interfaces just - because you have an integration concern. - - - This and other samples in this section are build on top of Enterprise Integration Patterns that meant to describe "building blocks" - for YOUR solution but not to be solutions in of themselves. Integration concerns exist in all types of applications (server based and not) - and should not require change in design, testing and deployment strategy if such applications need to integrate with one another. - -
- - - - -
- The Cafe Sample - - In this section, we will review a Cafe sample application that is included in the - Spring Integration samples. This sample is inspired by another sample featured in Gregor - Hohpe's Ramblings. - - - The domain is that of a Cafe, and the basic flow is depicted in the following diagram: - - - - - - - - - - - - - The Order object may contain multiple OrderItems. Once the order - is placed, a Splitter will break the composite order message into a single message per - drink. Each of these is then processed by a Router that determines whether the drink is hot - or cold (checking the OrderItem object's 'isIced' property). The - Barista prepares each drink, but hot and cold drink preparation are handled by two - distinct methods: 'prepareHotDrink' and 'prepareColdDrink'. The prepared drinks are then sent to the Waiter where - they are aggregated into a Delivery object. - - - Here is the XML configuration: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]]> - As you can see, each Message Endpoint is connected to input and/or output channels. Each endpoint will manage - its own Lifecycle (by default endpoints start automatically upon initialization - to prevent that add the - "auto-startup" attribute with a value of "false"). Most importantly, notice that the objects are simple POJOs - with strongly typed method arguments. For example, here is the Splitter: - split(Order order) { - return order.getItems(); - } - }]]> - In the case of the Router, the return value does not have to be a MessageChannel - instance (although it can be). As you see in this example, a String-value representing the channel name is - returned instead. - - - - Now turning back to the XML, you see that there are two <service-activator> elements. Each of these - is delegating to the same Barista instance but different methods: 'prepareHotDrink' - or 'prepareColdDrink' corresponding to the two channels where order items have been routed. - - - - As you can see from the code excerpt above, the barista methods have different delays (the hot drinks take 5 - times as long to prepare). This simulates work being completed at different rates. When the - CafeDemo 'main' method runs, it will loop 100 times sending a single hot drink and a - single cold drink each time. It actually sends the messages by invoking the 'placeOrder' method on the Cafe - interface. Above, you will see that the <gateway> element is specified in the configuration file. This - triggers the creation of a proxy that implements the given 'service-interface' and connects it to a channel. - The channel name is provided on the @Gateway annotation of the Cafe interface. - public interface Cafe { - - @Gateway(requestChannel="orders") - void placeOrder(Order order); - - } - Finally, have a look at the main() method of the CafeDemo itself. - 0) { - context = new FileSystemXmlApplicationContext(args); - } - else { - context = new ClassPathXmlApplicationContext("cafeDemo.xml", CafeDemo.class); - } - Cafe cafe = (Cafe) context.getBean("cafe"); - for (int i = 1; i <= 100; i++) { - Order order = new Order(i); - order.addItem(DrinkType.LATTE, 2, false); - order.addItem(DrinkType.MOCHA, 3, true); - cafe.placeOrder(order); - } - }]]> - - - To run this sample as well as 8 others, refer to the README.txt within the "samples" directory - of the main distribution as described at the beginning of this chapter. - - - When you run cafeDemo, you will see that the cold drinks are initially prepared more quickly than the hot drinks. - Because there is an aggregator, the cold drinks are effectively limited by the rate of the hot drink preparation. - This is to be expected based on their respective delays of 1000 and 5000 milliseconds. However, by configuring a - poller with a concurrent task executor, you can dramatically change the results. For example, you could use a - thread pool executor with 5 workers for the hot drink barista while keeping the cold drink barista as it is: - - - - ]]> - ]]> - - ]]>]]> - - - Also, notice that the worker thread name is displayed with each invocation. You will see that the hot drinks are - prepared by the task-executor threads. If you provide a much shorter poller interval (such as 100 milliseconds), - then you will notice that occasionally it throttles the input by forcing the task-scheduler (the caller) to invoke - the operation. - - - In addition to experimenting with the poller's concurrency settings, you can also add the 'transactional' - sub-element and then refer to any PlatformTransactionManager instance within the context. - -
- -
- The XML Messaging Sample - - The xml messaging sample in the org.springframework.integration.samples.xml illustrates how to use - some of the provided components which deal with xml payloads. The sample uses the idea of processing an order for books - represented as xml. - - - First the order is split into a number of messages, each one representing a single order item using - the XPath splitter component. - - - - ]]> - - - A service activator is then used to pass the message into a stock checker POJO. The order item document is enriched with information - from the stock checker about order item stock level. This enriched order item message is then used to route the message. In the - case where the order item is in stock the message is routed to the warehouse. The XPath router makes use of a - MapBasedChannelResolver which maps the XPath evaluation result to a channel reference. - - - - - - - - - - - - - ]]> - - - Where the order item is not in stock the message is transformed using - xslt into a format suitable for sending to the supplier. - - ]]> - -
-
- - -
diff --git a/src/docbkx/security.xml b/src/docbkx/security.xml deleted file mode 100644 index a614ebbc7c..0000000000 --- a/src/docbkx/security.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - Security in Spring Integration - -
- Introduction - - Spring Integration provides integration with the - Spring Security project - to allow role based security checks to be applied to channel send and receive invocations. - -
- -
- Securing channels - - Spring Integration provides the interceptor ChannelSecurityInterceptor, which extends - AbstractSecurityInterceptor and intercepts send and receive calls on the channel. Access decisions - are then made with reference to ChannelInvocationDefinitionSource which provides the definition of - the send and receive security constraints. The interceptor requires that a valid SecurityContext - has been established by authenticating with Spring Security, see the Spring Security reference documentation for details. - - - Namespace support is provided to allow easy configuration of security constraints. This consists of the secured channels tag which allows - definition of one or more channel name patterns in conjunction with a definition of the security configuration for send and receive. The pattern - is a java.util.regexp.Pattern. - - - - - - -]]> - - - By default the secured-channels namespace element expects a bean named authenticationManager which implements - AuthenticationManager and a bean named accessDecisionManager which implements - AccessDecisionManager. Where this is not the case references to the appropriate beans can be configured - as attributes of the secured-channels element as below. - - - -]]> - - - -
- - -
\ No newline at end of file diff --git a/src/docbkx/stream.xml b/src/docbkx/stream.xml deleted file mode 100644 index 7d263f059e..0000000000 --- a/src/docbkx/stream.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - Stream Support - -
- Introduction - - In many cases application data is obtained from a stream. It is not recommended to send a reference to a Stream as a message payload to a consumer. Instead messages are created from data that is read from an input stream and message payloads are written to an output stream one by one. - -
- -
- Reading from streams - - Spring Integration provides two adapters for streams. Both ByteStreamReadingMessageSource and - CharacterStreamReadingMessageSource implement MessageSource. - By configuring one of these within a channel-adapter element, the polling period can be configured, - and the Message Bus can automatically detect and schedule them. The byte stream version requires an - InputStream, and the character stream version requires a Reader as - the single constructor argument. The ByteStreamReadingMessageSource also accepts the 'bytesPerMessage' - property to determine how many bytes it will attempt to read into each Message. The - default value is 1024 - - - - - - - -]]> - - -
- -
- Writing to streams - - For target streams, there are also two implementations: ByteStreamWritingMessageHandler and - CharacterStreamWritingMessageHandler. Each requires a single constructor argument - - OutputStream for byte streams or Writer for character streams, - and each provides a second constructor that adds the optional 'bufferSize'. Since both of these - ultimately implement the MessageHandler interface, they can be referenced from a - channel-adapter configuration as described in more detail in - . - - - - - - - -]]> - - -
- - - -
- Stream namespace support - - To reduce the configuration needed for stream related channel adapters there is a namespace defined. The following schema locations are needed to use it. - -]]> - - - To configure the inbound channel adapter the following code snippet shows the different configuration options that are supported. - - -]]> - - - To configure the outbound channel adapter you can use the namespace support as well. The following code snippet shows the different configuration for an outbound channel adapters. - - - - - - - - ]]> - -
-
\ No newline at end of file diff --git a/src/docbkx/transactions.xml b/src/docbkx/transactions.xml deleted file mode 100644 index b0f62405a4..0000000000 --- a/src/docbkx/transactions.xml +++ /dev/null @@ -1,175 +0,0 @@ - - - - Transaction Support - -
- Understanding Transactions in Message flows - - Spring Integration exposes several hooks to address transactional needs of you message flows. - But to better understand these hooks and how you can benefit from them we must first revisit the 6 mechanisms - that could be used to initiate Message flows and see how transactional needs of these flows - could be addressed within each of these mechanisms. - - - Here are the 6 mechanisms to initiate a Message flow and their short summary (details for each are provided throughout this manual): - - - Gateway Proxy - Your basic Messaging Gateway - - - MessageChannel - Direct interactions with MessageChannel methods (e.g., channel.send(message)) - - - Message Publisher - the way to initiate message flow as a bi-product of method invocations on Spring beans - - - Inbound Channel Adapters/Gateways - the way to initiate message flow based on connecting third-party - system with Spring Integration messaging system(e.g., [JmsMessage] -> Jms Inbound Adapter[SI Message] -> SI Channel) - - - Scheduler - the way to initiate message flow based on scheduling events distributed - by a pre-configured Scheduler - - - Poller - similar to the Scheduler and is the way to initiate message flow based on scheduling - or interval-based events distributed by a pre-configured Poller - - - - - These 6 cold be split in 2 general categories: - - - Message flows initiated by a USER process - Example scenarios in this category - would be invoking a Gateway method or explicitly sending a Message to a MessageChannel. In other words these message flows depend on third - party process (e.g., some code that we wrote) to be initiated - - - Message flows initiated by the DAEMON process - Example scenarios in this category would be a Poller - polling for a Message queue to initiate a new Message flow with the polled Message or a Scheduler scheduling the - process, by creating a new Message and initiating a message flow at a predefined time - - - - - Clearly the Gateway Proxy, MessageChannel.send(..) and MessagePublisher are - all belong to the 1st category and Inbound Adapters/Gateways, Scheduler and Poller belong to the 2nd. - - - So, how do we address transactional needs in various scenarios within each category and is there a need for Spring Integration - to provide something explicitly with regard to transaction for a particular scenario or Spring's Transaction Support could be leveraged instead?. - - - - First of all, the first and obvious goal is NOT to re-invent something that has already been invented unless you can provide a beter solution. - In our case Spring itself provides a first class support for transaction management. So our goal here is not to provide something new but rather - delegate/use Spring to benefit from the existing support for transactions. In other words as a framework we must expose hooks to the Transaction management functionality - provided by Spring. But since Spring Integration configuration is based on Spring Configuration it is not always neccessery to expose these hooks as they already - expposed via Spring natively. Remeber every Spring Integration component is a Spring Bean after all. - - - With this goal in mind let's look at the two scenarios.  - - - If you think about it, Message flows that are initiated by the USER process (Category 1) and obviously configured in Spring Application Context, - are subject to transactional configuration of such process and therefore don't need to be explicitly configured by Spring Integration to support transactions. - The transaction could and should be initiated by such process through standard Transaction support provided by Spring and Spring Integration message flow will honor - transactional semantics of the components naturally because it is Spring configured. For example; A Gateway or ServiceActivator methods could - be annotated with @Transactional or TransactionInterceptor could be configured in XML configuration - with point-cut expression pointing to specific methods that should be transactional. - The bottom line you have full control over transaction configuration and boundaries in these scenarios. - - - - However, things are a bit different when it comes to Message flows initiated by the DAEMON process (Category 2). - Although configured by the developer these flows do not directly involve human or some other process to be initiated. These are trigger-based flows - that are initiated by a trigger process (DAEMON process) based on the configuration of such process. For example, we could have a Scheduler - initiating a message flow every Friday night of every week. We can also configure a trigger that initiates a Message flow every second, etc. - So, we obviously need the same way to let these trigger-based processes know of our intention to make these Message flows transactional so - Transaction context could be created whenever a new Message flow is initiated. In other words we need to expose some Transaction configuration, but ONLY enough - to delegate to Transaction support already provided by Spring (as we do in other scenarios). - - - - Spring Integration provides transactional support for Pollers. Pollers are a special case comoponents becouse - we can call receive() within that poller task against a resource that is itself transactional thus including receive() - call in the the boundaries of the Transaction allowing it to be rolled back in case of a task failure. If we were to add the same support - for channels, the added transactions would affect all downstream components starting with that send() call. That is - providing a rather wide scope for transaction demarcation without any strong reason especially when Spring already provides several way to - address transactional needs of any component downstream. However the receive() method being included in a transaction - boundary is the "strong reason" for pollers.  - - - - -
- Poller Transaction Support - - Any time you configure a Poller you can provide transactional configuration via transactional element and its attributes: - - -]]> - As you can see this configuration looks evry similar to native Spring transaction configuration. You must still provide reference to Transaction manager and specify - transaction attributes or rely on defauls (e.g., if 'transaction-manager'' attribute is not specified then it will default to the bean with the name 'transactionManager'). - Internally the process would be wrapped in the Spring's native Transaction where TransactionInterceptor is responsible to handle transactions. - For more information on how to configure Transaction Manager, the types of Transaction Managers (e.g., JTA, Datasource etc.) and other details related to - transaction configuration please refer to Spring's Reference manual (Chapter 10 - Transaction Management). - - - With the above configuration all Message flows initiated by this poller will be transactional. For more information and details on - Poller's transactional configuration please refer to section - 21.1.1. Polling and Transactions. - - - - There times when besides transaction several more cross cutting concerns needs to be addressed when running Poller. To help with that, - Poller element defines <advice-chain> sub-element which allows you to define a custom chain of Advices - to be applied on the Poller. (see section 4.4 for more details) - In Spring Integration 2.0 Poller went through the major  refactoring effort and is now using proxy mechanism to address transactional - concerns as well as other cross cutting concerns, one of the significant changes evolving from this effort is that we - made <transactional> and <advice-chain> elements mutually exclusive. - The rational behind this is; If you need more then one advice, and one of them is Transaction advice, then you can simply - include it in the <advice-chain> with the same convenience as before but with much more control - since you now have an option to position any advice in the desired order.  - - - - - - - - - - - - - - -]]> - -As yo can see from the example above, we have provided a very basic XML-based configuration of Spring Transaction advice  - "txAdvice" and -included it within the <advice-chain> defined by the Poller. - -And if you only need to address transactional concerns of the Poller, then you can still use <transactional> element -as a convinience. - -
-
-
- Transaction Boundaries - - Another important factor that needs to be understood is the boundaries of the Transactions within the Message flow. - When transaction is started, transaction context is bound to the current thread. So regardless of how many endpoints and channels you have in your - Message flow you transaction context will be preserved as long as you are ensuring that the flow continues on the same thread. - As soon as you break it by introducing a Pollable Channel or Executor Channel or initiate a new thread manually in some - service, the Transactional boundary will be broken as well. Essentially the Transaction will END right there and if - successfull hand of happened between the threads, the flow would be considered a success and COMMIT signal would be sent - even though the flow might still result in the exception somewhere downstream. If such flow was synchronous the exception would be thrown back to the - initiator of the Message flow who is also the initiator of the transactional context and transaction would result in a ROLLBACK. - -
-
\ No newline at end of file diff --git a/src/docbkx/xml.xml b/src/docbkx/xml.xml deleted file mode 100644 index 8a70c44701..0000000000 --- a/src/docbkx/xml.xml +++ /dev/null @@ -1,505 +0,0 @@ - - - - XML Support - Dealing with XML Payloads - -
- Introduction - - Spring Integration's XML support extends the Spring Integration Core with - implementations of splitter, transformer, selector and router designed - to make working with xml messages in Spring Integration simple. The provided messaging - components are designed to work with xml represented in a range of formats including - instances of - java.lang.String, org.w3c.dom.Document - and javax.xml.transform.Source. It should be noted however that - where a DOM representation is required, for example in order to evaluate an XPath expression, - the String payload will be converted into the required type and then - converted back again to String. Components that require an instance of - DocumentBuilder will create a namespace aware instance if one is - not provided. Where greater control of the document being created is required an appropriately - configured instance of DocumentBuilder should be provided. - -
-
- Transforming xml payloads - - This section will explain the workings of - UnmarshallingTransformer, - MarshallingTransformer, - XsltPayloadTransformer - and how to configure them as - beans. All of the provided xml transformers extend - AbstractTransformer or AbstractPayloadTransformer - and therefore implement Transformer. When configuring xml - transformers as beans in Spring Integration you would normally configure the transformer - in conjunction with either a MessageTransformingChannelInterceptor or a - MessageTransformingHandler. This allows the transformer to be used as either an interceptor, - which transforms the message as it is sent or received to the channel, or as an endpoint. Finally the - namespace support will be discussed which allows for the simple configuration of the transformers as - elements in XML. - - - UnmarshallingTransformer allows an xml Source - to be unmarshalled using implementations of Spring OXM Unmarshaller. - Spring OXM provides several implementations supporting marshalling and unmarshalling using JAXB, - Castor and JiBX amongst others. Since the unmarshaller requires an instance of - Source where the message payload is not currently an instance of - Source, conversion will be attempted. Currently String - and org.w3c.dom.Document payloads are supported. Custom conversion to a - Source is also supported by injecting an implementation of - SourceFactory. - - - - - - -]]> - - - The MarshallingTransformer allows an object graph to be converted - into xml using a Spring OXM Marshaller. By default the - MarshallingTransformer will return a DomResult. - However the type of result can be controlled by configuring an alternative ResultFactory - such as StringResultFactory. In many cases it will be more convenient to transform - the payload into an alternative xml format. To achieve this configure a - ResultTransformer. Two implementations are provided, one which converts to - String and another which converts to Document. - - - - - - - - - -]]> - - - By default, the MarshallingTransformer will pass the payload Object - to the Marshaller, but if its boolean "extractPayload" property - is set to "false", the entire Message instance will be passed - to the Marshaller instead. That may be useful for certain custom - implementations of the Marshaller interface, but typically the - payload is the appropriate source Object for marshalling when delegating to any of the various - out-of-the-box Marshaller implementations. - - - XsltPayloadTransformer transforms xml payloads using xsl. - The transformer requires an instance of either Resource or - Templates. Passing in a Templates instance - allows for greater configuration of the TransformerFactory used to create - the template instance. As in the case of XmlPayloadMarshallingTransformer - by default XsltPayloadTransformer will create a message with a - Result payload. This can be customised by providing a - ResultFactory and/or a ResultTransformer. - - - - - -]]> - -
-
- - Namespace support for xml transformers - - Namespace support for all xml transformers is provided in the Spring Integration xml namespace, - a template for which can be seen below. The namespace support for transformers creates an instance of either - EventDrivenConsumer or PollingConsumer - according to the type of the provided input channel. The namespace support is designed - to reduce the amount of xml configuration by allowing the creation of an endpoint and transformer - using one element. - - -]]> - The namespace support for UnmarshallingTransformer is shown below. - Since the namespace is now creating an endpoint instance rather than a transformer, - a poller can also be nested within the element to control the polling of the input channel. - - - - - - ]]> - - - - The namespace support for the marshalling transformer requires an input channel, output channel and a - reference to a marshaller. The optional result-type attribute can be used to control the type of result created, - valid values are StringResult or DomResult (the default). Where the provided result types are not sufficient a - reference to a custom implementation of ResultFactory can be provided as an alternative - to setting the result-type attribute using the result-factory attribute. An optional result-transformer can also be - specified in order to convert the created Result after marshalling. - - - - -]]> - - - - Namespace support for the XsltPayloadTransformer allows either a resource to be passed in in order to create the - Templates instance or alternatively a precreated Templates - instance can be passed in as a reference. In common with the marshalling transformer the type of the result output can - be controlled by specifying either the result-factory or result-type attribute. A result-transfomer attribute can also - be used to reference an implementation of ResultTransfomer where conversion of the result - is required before sending. - -]]> - - - Very often to assist with transformation you may need to have access to Message data (e.g., Message Headers). For example; you may need to get access to certain Message Headers - and pass them on as parameters to a transformer (e.g., transformer.setParameter(..)).  - Spring Integration provides two convenient ways to accomplish this. Just look at the following XML snippet. - - - - -]]> - If message header names match 1:1 to parameter names, you can simply use xslt-param-headers attribute. There you can also use wildcards for - simple pattern matching which supports the following simple pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy". - - - You can also configure individual xslt parameters via xslt-param sub element. There you can use expression or value attribute. - The expression attribute should be any valid SpEL expression with Message being the root object of the expression evaluation context. - The value attribute just like any value in Spring beans allows you to specify simple scalar vallue. YOu can also use property placeholders (e.g., ${some.value}) - So as you can see, with the expression and value attribute xslt parameters could now be mapped to any accessible part of the Message as well as any literal value. - -
- -
- Splitting xml messages - - XPathMessageSplitter supports messages with either - String or Document payloads. - The splitter uses the provided XPath expression to split the payload into a number of - nodes. By default this will result in each Node instance - becoming the payload of a new message. Where it is preferred that each message be a Document - the createDocuments flag can be set. Where a String payload is passed - in the payload will be converted then split before being converted back to a number of String - messages. The XPath splitter implements MessageHandler and should - therefore be configured in conjunction with an appropriate endpoint (see the namespace support below - for a simpler configuration alternative). - - - - - - - - - -]]> - - -
- -
- Routing xml messages using XPath - - Two Router implementations based on XPath are provided XPathSingleChannelRouter and - XPathMultiChannelRouter. The implementations differ in respect to how many channels - any given message may be routed to, exactly one in the case of the single channel version - or zero or more in the case of the multichannel router. Both evaluate an XPath - expression against the xml payload of the message, supported payload types by default - are Node, Document and - String. For other payload types a custom implementation - of XmlPayloadConverter can be provided. The router - implementations use ChannelResolver to convert the - result(s) of the XPath expression to a channel name. By default a - BeanFactoryChannelResolver strategy will be used, this means that the string returned by the XPath - evaluation should correspond directly to the name of a channel. Where this is not the case - an alternative implementation of ChannelResolver can - be used. Where there is a simple mapping from Xpath result to channel name - the provided MapBasedChannelResolver can be used. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -]]> - -
- -
- Selecting xml messages using XPath - - Two MessageSelector implementations are provided, - BooleanTestXPathMessageSelector and StringValueTestXPathMessageSelector. - BooleanTestXPathMessageSelector requires an XPathExpression which evaluates to a boolean, - for example boolean(/one/two) which will only select messages which have an element named - two which is a child of a root element named one. StringValueTestXPathMessageSelector - evaluates any XPath expression as a String and compares the result with the provided value. - - - - - - - - - - - - - - - - - - - - -]]> -
- -
- Transforming xml messages using XPath - - When it comes to message transformation XPath is a great way to transform Messages that have XML - payloads by defining XPath transformers via xpath-transformer element. - - - Simple XPath transformation - - - Let's look at the following transformer configuration: - ]]> - - . . . and Message - message = - MessageBuilder.withPayload("").build();]]> - After sending this message to the 'inputChannel' the XPath transformer configured above will transform - this XML Message to a simple Message with payload of 'John Doe' all based on - the simple XPath Expression specified in the xpath-expression attribute. - - - XPath also has capability to perform simple conversion of extracted elements - to a desired type. Valid return types are defined in XPathConstants and follows - the conversion rules specified by the XPath. - - - The following constants are defined by the XPathConstants: BOOLEAN, DOM_OBJECT_MODEL, NODE, NODESET, NUMBER, STRING - - - You can configure the desired type by simply using evaluation-type - attribute of the xpath-transformer element. - - - -]]> - - - Node Mappers - - - If you need to provide custom mapping for the node extracted by the XPath expression simply provide a reference to the - implementation of the org.springframework.xml.xpath.NodeMapper - an interface used by - XPathOperations implementations for mapping Node objects on a per-node basis. To provide a - reference to a NodeMapper simply use node-mapper attribute: - -]]> -. . . and Sample NodeMapper implementation: - - - - XML Payload Converter - - - You can also use implementation of the org.springframework.integration.xml.XmlPayloadConverter to - provide more granular transformation: - -]]> -. . . and Sample XmlPayloadConverter implementation: -"))); - } - catch (Exception e) { - throw new IllegalStateException(e); - } - } - // - public Document convertToDocument(Object object) { - throw new UnsupportedOperationException(); - } -}]]> - - - Combination of SpEL and XPath expressions - - - You can also combine Spring Expression Language (SpEL) expressions with XPath expression and configure - them using expression attribute: - ]]> - In the above case the overall result of the expression will be the result of the XPathe expression multiplied by 2. - -
- - -
- XPath components namespace support - All XPath based components have namespace support allowing them to be configured as - Message Endpoints with the exception of the XPath selectors which are not designed to act as - endpoints. Each component allows the XPath to either be referenced at the top level or configured via a nested - xpath-expression element. So the following configurations of an xpath-selector are all valid and represent the general - form of XPath namespace support. All forms of XPath expression result in the creation of an - XPathExpression using the Spring XPathExpressionFactory - - - - - - - - - - - - - - - - - - - - - - - - - - -]]> - - - XPath splitter namespace support allows the creation of a Message Endpoint with an input channel and output channel. - - - - - - - - - -]]> - - - XPath router namespace support allows for the creation of a Message Endpoint with an input channel but no output channel - since the output channel is determined dynamically. The multi-channel attribute causes the creation of a multi channel router capable of - routing a single message to many channels when true and a single channel router when false. - - - - - - - - - -]]> - -
- -
\ No newline at end of file diff --git a/src/main/resources/readme.txt b/src/main/resources/readme.txt deleted file mode 100644 index 2b952f7e34..0000000000 --- a/src/main/resources/readme.txt +++ /dev/null @@ -1,27 +0,0 @@ -SPRING INTEGRATION 2.0.0 Milestone 7 (Sept 03, 2010) ----------------------------------------------------- - -To find out what has changed since version 1.0.x or 2.0 M6, see 'changelog.txt' - -Please consult the documentation located within the 'docs/reference' directory of this -release and also visit the official Spring Integration home at: -http://www.springsource.org/spring-integration - -There you will find links to the forum, issue tracker, and several other resources. - -To build and run the sample applications that are included with this distribution, -view the README.txt file in the 'samples' directory. - -To checkout the project from the SVN head and build from source, do the following -(NOTE: this requires Maven 2.2.x): - - svn co https://src.springsource.org/svn/spring-integration/trunk . - mvn clean install - -To build the JavaDoc, run `mvn javadoc:aggregate` from within the root directory. The -result will be available in 'target/site/apidocs'. - -The projects are Maven enabled, so you should be able to import them into any IDE that -has support for Maven (2.2 or greater). The SpringSource Tool Suite (STS) ships with -support for Maven projects, is free-of-charge and is the recommended IDE for use with -Spring Integration (http://springsource.com/products/sts).