diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 00000000..9cc84ea9 Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..c3150437 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip diff --git a/circle.yml b/circle.yml index 592654c3..b747fe92 100644 --- a/circle.yml +++ b/circle.yml @@ -1,14 +1,28 @@ version: 2 jobs: - build: - docker: - - image: circleci/openjdk:8u141 - steps: - - checkout - - run: ./gradlew clean build - - run: ./gradlew -Pprofile=spring4-next clean build + build: + docker: + - image: circleci/openjdk:8u141 + steps: + - checkout + - run: + name: Test current version + command: ./mvnw -Pdistribute,snapshot,docs clean test + - run: + name: Test Spring.NEXT + command: ./mvnw -Pspringnext clean test + - run: + name: Test Spring.NEXT snapshots + command: ./mvnw -Pspringnext-snapshot clean test + - run: + name: Deploy to Artifactory + command: ./deploy.bash general: branches: ignore: - gh-pages # list of branches to ignore + +dependencies: + cache_directories: + - "~/.m2" diff --git a/deploy.bash b/deploy.bash new file mode 100755 index 00000000..d4b669a9 --- /dev/null +++ b/deploy.bash @@ -0,0 +1,7 @@ +#!/bin/bash -x + +if [ "${CIRCLE_BRANCH}" == "master" ] || [ "${CIRCLE_BRANCH}" == "2.x" ]; then + ./mvnw -Pdistribute,snapshot,docs clean -Dmaven.test.skip=true deploy +else + echo "We only deploy 'master' and '2.x' branches" +fi \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e31e486d..00000000 Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index f1952802..00000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Thu Oct 05 08:58:22 CDT 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.2-bin.zip diff --git a/mvnw b/mvnw new file mode 100755 index 00000000..5bf251c0 --- /dev/null +++ b/mvnw @@ -0,0 +1,225 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +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="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +echo $MAVEN_PROJECTBASEDIR +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 00000000..019bd74d --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,143 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..6ae7a2cb --- /dev/null +++ b/pom.xml @@ -0,0 +1,634 @@ + + + 4.0.0 + + org.springframework.ws + spring-ws + 2.4.1.BUILD-SNAPSHOT + pom + + Spring Web Services + http://project.spring.io/spring-ws + + + + apoutsma + Arjen Poutsma + apoutsma@pivotal.io + Pivotal Software, Inc. + + Project Creator + + + + tareqa + Tareq Abed Rabbo + tareq.abedrabbo@gmail.com + Pivotal Software, Inc. + + Developer + + + + gturnquist + Greg Turnquist + gturnquist@pivotal.io + Pivotal Software, Inc. + + Project Lead + + + + + + Pivotal Software + http://spring.io + + + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0 + + Copyright 2011 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. + + + + + + spring-ws-core + spring-ws-security + spring-ws-support + spring-ws-test + spring-xml + + + + UTF-8 + UTF-8 + 1.7 + 1.7 + false + + 4.1.2 + 1.6.12 + 1.2.20 + 3.1 + 1.1.3 + 1.6.1 + 3.1 + 2.8.9 + 4.3.6 + 1.4.7 + 3.0.1 + 1.1.6 + 2.0.6 + 6.1.26 + 1.1-rev-1 + 4.12 + 1.2.17 + 1.6 + 1.3.28 + 4.1.9 + 4.2.9.RELEASE + 4.0.4.RELEASE + 1.5.4 + 4.2.0 + 1.6.3 + 1.6.19 + 2.2.0 + 2.1.0 + 1.5 + 3.0 + 1.2.5 + + + + + + commons-logging + commons-logging + ${commons-logging.version} + + + org.springframework + spring-core + ${spring.version} + + + + junit + junit + ${junit.version} + test + + + org.easymock + easymock + ${easymock.version} + test + + + xmlunit + xmlunit + ${xmlunit.version} + test + + + com.sun.mail + javax.mail + ${sun-mail.version} + test + + + org.codehaus.woodstox + woodstox-core-asl + ${woodstox.version} + test + + + + + + + + maven-compiler-plugin + 3.6.1 + + + + + + + springnext + + 4.3.12.RELEASE + 4.2.3.RELEASE + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + spring-release + Spring Releases + https://repo.spring.io/release + + false + + + + + + + springnext-snapshot + + 4.3.13.BUILD-SNAPSHOT + 4.2.4.BUILD-SNAPSHOT + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + spring-release + Spring Releases + https://repo.spring.io/release + + false + + + + + + + distribute + + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.0 + + + attach-sources + + jar-no-fork + + + + + + + maven-javadoc-plugin + + -Xdoclint:none + -quiet + + + + attach-javadocs + + jar + + + + + + + + + + gpg + + + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifact + verify + + sign + + + + + + + + + + snapshot + + + + + org.jfrog.buildinfo + artifactory-maven-plugin + 2.6.1 + false + + + build-info + + publish + + + + *:*:*:*@zip zip.name:spring-ws, zip.displayname:Spring Web Services, zip.deployed:false + + + http://repo.spring.io + {{USERNAME}} + {{PASSWORD}} + libs-snapshot-local + libs-snapshot-local + + + + + + + + + + + milestone + + + + + org.jfrog.buildinfo + artifactory-maven-plugin + 2.6.1 + false + + + build-info + + publish + + + + *:*:*:*@zip zip.name:spring-ws, zip.displayname:Spring Web Services, zip.deployed:false + + + http://repo.spring.io + {{USERNAME}} + {{PASSWORD}} + libs-milestone-local + libs-snapshot-local + + + + + + + + + + + release + + + + + org.jfrog.buildinfo + artifactory-maven-plugin + 2.6.1 + false + + + build-info + + publish + + + + *:*:*:*@zip zip.name:spring-ws, zip.displayname:Spring Web Services, zip.deployed:false + + + http://repo.spring.io + {{USERNAME}} + {{PASSWORD}} + libs-release-local + libs-snapshot-local + + + + + + + + + + + docs + + + + + org.asciidoctor + asciidoctor-maven-plugin + 1.5.6 + + + org.asciidoctor + asciidoctorj-pdf + 1.5.0-alpha.15 + + + + + html + generate-resources + + process-asciidoc + + + html5 + ${project.build.directory}/site/reference/html + prettify + + font + true + + + + + + pdf + generate-resources + + process-asciidoc + + + pdf + coderay + + + + + + src/main/asciidoctor + index.adoc + book + + ${project.version} + ${project.name} + ${project.version} + true + 3 + true + ${project.basedir} + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + -Xdoclint:none + + + + + aggregate + + aggregate-jar + + prepare-package + false + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + ant-contrib + ant-contrib + 1.0b3 + + + ant + ant + + + + + org.apache.ant + ant-nodeps + 1.8.1 + + + org.tigris.antelope + antelopetasks + 3.2.10 + + + + + package-and-attach-docs-zip + + run + + package + false + + + + + + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.10 + false + + + attach-zip + + attach-artifact + + + + + ${project.build.directory}/${project.artifactId}-${project.version}.zip + zip;zip.type=docs;zip.deployed=false + + + + + + + + + + + + central + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots/ + + + sonatype-nexus-staging + Nexus Release Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/libs-snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/libs-milestone + + + spring-releases + Spring Releases + https://repo.spring.io/libs-release + + + + + https://github.com/spring-projects/spring-ws + scm:git:git://github.com/spring-projects/spring-ws.git + scm:git:ssh://git@github.com:spring-projects/spring-ws.git + + + diff --git a/settings.xml b/settings.xml new file mode 100644 index 00000000..cf86357e --- /dev/null +++ b/settings.xml @@ -0,0 +1,19 @@ + + + + + sonatype-nexus-snapshots + ${env.USERNAME} + ${env.PASSWORD} + + + sonatype-nexus-staging + ${env.USERNAME} + ${env.PASSWORD} + + + + \ No newline at end of file diff --git a/spring-ws-core/pom.xml b/spring-ws-core/pom.xml new file mode 100644 index 00000000..c9df82aa --- /dev/null +++ b/spring-ws-core/pom.xml @@ -0,0 +1,180 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws + 2.4.1.BUILD-SNAPSHOT + + + org.springframework.ws + spring-ws-core + jar + + Spring WS Core + + + + + org.springframework.ws + spring-xml + ${project.parent.version} + + + + org.springframework + spring-aop + ${spring.version} + + + org.springframework + spring-beans + ${spring.version} + + + org.springframework + spring-oxm + ${spring.version} + + + org.springframework + spring-web + ${spring.version} + + + org.springframework + spring-webmvc + ${spring.version} + + + org.springframework + spring-test + ${spring.version} + test + + + + + org.jdom + jdom2 + ${jdom2.version} + true + + + dom4j + dom4j + ${dom4j.version} + true + + + xom + xom + ${xom.version} + true + + + xml-apis + xml-apis + + + xerces + xercesImpl + + + xalan + xalan + + + + + org.apache.ws.xmlschema + xmlschema-core + ${xml-schema-core.version} + true + + + + + org.apache.ws.commons.axiom + axiom-api + ${axiom.version} + true + + + org.apache.ws.commons.axiom + axiom-impl + ${axiom.version} + true + + + org.codehaus.woodstox + wstx-asl + + + + + + + wsdl4j + wsdl4j + ${wsdl4j.version} + true + + + + + javax.servlet + javax.servlet-api + ${javax-servlet.version} + provided + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + true + + + commons-httpclient + commons-httpclient + ${commons-httpclient.version} + true + + + org.mortbay.jetty + jetty + ${jetty.version} + test + + + org.mortbay.jetty + servlet-api + + + + + + log4j + log4j + ${log4j.version} + test + + + org.aspectj + aspectjrt + ${aspectj.version} + test + + + org.aspectj + aspectjweaver + ${aspectj.version} + test + + + + + \ No newline at end of file diff --git a/spring-ws-core/src/test/java/org/springframework/ws/client/support/interceptor/ClientInterceptorAdapterTest.java b/spring-ws-core/src/test/java/org/springframework/ws/client/support/interceptor/ClientInterceptorAdapterTest.java index fa602dd7..cedf26a1 100644 --- a/spring-ws-core/src/test/java/org/springframework/ws/client/support/interceptor/ClientInterceptorAdapterTest.java +++ b/spring-ws-core/src/test/java/org/springframework/ws/client/support/interceptor/ClientInterceptorAdapterTest.java @@ -42,7 +42,7 @@ public class ClientInterceptorAdapterTest { @Test public void handleTestAdapter() { - TestClientInterceptorAdapter interceptor = new TestClientInterceptorAdapter(new ArrayList<>()); + TestClientInterceptorAdapter interceptor = new TestClientInterceptorAdapter(new ArrayList()); Assert.assertFalse(interceptor.handleRequest(null)); Assert.assertFalse(interceptor.handleResponse(null)); diff --git a/spring-ws-core/src/test/java/org/springframework/ws/server/endpoint/mapping/PayloadRootAnnotationMethodEndpointMappingTest.java b/spring-ws-core/src/test/java/org/springframework/ws/server/endpoint/mapping/PayloadRootAnnotationMethodEndpointMappingTest.java index e11b0d57..3e78e85e 100644 --- a/spring-ws-core/src/test/java/org/springframework/ws/server/endpoint/mapping/PayloadRootAnnotationMethodEndpointMappingTest.java +++ b/spring-ws-core/src/test/java/org/springframework/ws/server/endpoint/mapping/PayloadRootAnnotationMethodEndpointMappingTest.java @@ -18,16 +18,15 @@ package org.springframework.ws.server.endpoint.mapping; import java.lang.reflect.Method; import java.util.Collections; + import javax.xml.namespace.QName; import javax.xml.soap.MessageFactory; import javax.xml.soap.SOAPMessage; import javax.xml.transform.Source; import org.apache.commons.logging.LogFactory; -import static org.junit.Assert.*; import org.junit.Test; import org.junit.runner.RunWith; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.test.context.ContextConfiguration; @@ -47,6 +46,8 @@ import org.springframework.ws.soap.saaj.SaajSoapMessage; import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; import org.springframework.ws.soap.server.SoapMessageDispatcher; +import static org.junit.Assert.*; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("payloadRootAnnotationMethodEndpointMapping.xml") public class PayloadRootAnnotationMethodEndpointMappingTest { @@ -80,20 +81,6 @@ public class PayloadRootAnnotationMethodEndpointMappingTest { assertEquals("Invalid endpoint registered", expected, endpoint); } - @Test - public void registrationRepeatable() throws NoSuchMethodException { - Method doItMultiple = MyEndpoint.class.getMethod("doItRepeatable"); - MethodEndpoint expected = new MethodEndpoint("endpoint", applicationContext, doItMultiple); - - MethodEndpoint endpoint = mapping.lookupEndpoint(new QName("http://springframework.org/spring-ws", "Request3")); - assertNotNull("MethodEndpoint not registered", endpoint); - assertEquals("Invalid endpoint registered", expected, endpoint); - - endpoint = mapping.lookupEndpoint(new QName("http://springframework.org/spring-ws", "Request4")); - assertNotNull("MethodEndpoint not registered", endpoint); - assertEquals("Invalid endpoint registered", expected, endpoint); - } - @Test public void registrationInvalid() { assertNull("Invalid endpoint registered", @@ -150,14 +137,6 @@ public class PayloadRootAnnotationMethodEndpointMappingTest { public void doItMultiple() { } - @PayloadRoot(localPart = "Request3", - namespace = "http://springframework.org/spring-ws") - @PayloadRoot(localPart = "Request4", - namespace = "http://springframework.org/spring-ws") - public void doItRepeatable() { - - } - } static class OtherBean { diff --git a/spring-ws-core/src/test/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionAnnotationMethodEndpointMappingTest.java b/spring-ws-core/src/test/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionAnnotationMethodEndpointMappingTest.java index b2af407d..dfc297c0 100644 --- a/spring-ws-core/src/test/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionAnnotationMethodEndpointMappingTest.java +++ b/spring-ws-core/src/test/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionAnnotationMethodEndpointMappingTest.java @@ -18,11 +18,9 @@ package org.springframework.ws.soap.server.endpoint.mapping; import java.lang.reflect.Method; -import static org.easymock.EasyMock.*; import org.junit.Assert; import org.junit.Before; import org.junit.Test; - import org.springframework.context.support.StaticApplicationContext; import org.springframework.ws.WebServiceMessageFactory; import org.springframework.ws.context.DefaultMessageContext; @@ -34,6 +32,8 @@ import org.springframework.ws.soap.SoapMessage; import org.springframework.ws.soap.server.endpoint.annotation.SoapAction; import org.springframework.ws.soap.server.endpoint.annotation.SoapActions; +import static org.easymock.EasyMock.*; + public class SoapActionAnnotationMethodEndpointMappingTest { private SoapActionAnnotationMethodEndpointMapping mapping; @@ -89,29 +89,6 @@ public class SoapActionAnnotationMethodEndpointMappingTest { verify(requestMock, factoryMock); } - @Test - public void registrationRepeatable() throws Exception { - SoapMessage requestMock = createMock(SoapMessage.class); - expect(requestMock.getSoapAction()).andReturn("http://springframework.org/spring-ws/SoapAction3"); - expect(requestMock.getSoapAction()).andReturn("http://springframework.org/spring-ws/SoapAction4"); - WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class); - replay(requestMock, factoryMock); - - Method doItRepeatable = MyEndpoint.class.getMethod("doItRepeatable"); - MethodEndpoint expected = new MethodEndpoint("endpoint", applicationContext, doItRepeatable); - - MessageContext context = new DefaultMessageContext(requestMock, factoryMock); - EndpointInvocationChain chain = mapping.getEndpoint(context); - Assert.assertNotNull("MethodEndpoint not registered", chain); - Assert.assertEquals("Invalid endpoint registered", expected, chain.getEndpoint()); - - chain = mapping.getEndpoint(context); - Assert.assertNotNull("MethodEndpoint not registered", chain); - Assert.assertEquals("Invalid endpoint registered", expected, chain.getEndpoint()); - - verify(requestMock, factoryMock); - } - @Endpoint private static class MyEndpoint { @@ -124,13 +101,6 @@ public class SoapActionAnnotationMethodEndpointMappingTest { @SoapAction("http://springframework.org/spring-ws/SoapAction2")}) public void doItMultiple() { } - - @SoapAction("http://springframework.org/spring-ws/SoapAction3") - @SoapAction("http://springframework.org/spring-ws/SoapAction4") - public void doItRepeatable() { - - } - - + } } \ No newline at end of file diff --git a/spring-ws-security/pom.xml b/spring-ws-security/pom.xml new file mode 100644 index 00000000..fb253ac7 --- /dev/null +++ b/spring-ws-security/pom.xml @@ -0,0 +1,123 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws + 2.4.1.BUILD-SNAPSHOT + + + org.springframework.ws + spring-ws-security + jar + + Spring WS Security + + + + + org.springframework.ws + spring-xml + ${project.parent.version} + + + org.springframework.ws + spring-ws-core + ${project.parent.version} + + + + + org.springframework + spring-beans + ${spring.version} + + + org.springframework + spring-tx + ${spring.version} + + + org.springframework + spring-test + ${spring.version} + test + + + + + org.springframework.security + spring-security-core + ${spring-security.version} + + + net.sf.ehcache + ehcache + ${ehcache.version} + + + + + com.sun.xml.wss + xws-security + ${xws-security.version} + true + + + javax.xml.crypto + xmldsig + + + + + + org.apache.ws.security + wss4j + ${wss4j.version} + + + org.apache.santuario + xmlsec + + + + + + org.apache.wss4j + wss4j-ws-security-dom + ${wss4j2.version} + + + + + com.sun.xml.messaging.saaj + saaj-impl + ${saaj-impl.version} + provided + + + org.apache.ws.commons.axiom + axiom-api + ${axiom.version} + true + + + org.apache.ws.commons.axiom + axiom-impl + ${axiom.version} + true + + + org.codehaus.woodstox + wstx-asl + + + + + + + + \ No newline at end of file diff --git a/spring-ws-support/pom.xml b/spring-ws-support/pom.xml new file mode 100644 index 00000000..00d233b8 --- /dev/null +++ b/spring-ws-support/pom.xml @@ -0,0 +1,120 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws + 2.4.1.BUILD-SNAPSHOT + + + org.springframework.ws + spring-ws-support + jar + + Spring WS Support + + + + + org.springframework.ws + spring-xml + ${project.parent.version} + + + org.springframework.ws + spring-ws-core + ${project.parent.version} + + + + org.springframework + spring-beans + ${spring.version} + + + org.springframework + spring-jms + ${spring.version} + + + org.springframework + spring-test + ${spring.version} + test + + + + javax.jms + jms-api + ${jms.version} + provided + + + javax.mail + javax.mail-api + ${javax-mail.version} + provided + + + com.sun.mail + javax.mail + ${sun-mail.version} + + + org.igniterealtime.smack + smack-tcp + ${smack.version} + true + + + org.igniterealtime.smack + smack-java7 + ${smack.version} + true + + + + org.igniterealtime.smack + smack-extensions + ${smack.version} + true + + + + commons-httpclient + commons-httpclient + ${commons-httpclient.version} + test + + + + org.apache.activemq + activemq-core + ${activemq.version} + test + + + org.apache.geronimo.specs + geronimo-jms_1.1_spec + + + + + org.jvnet.mock-javamail + mock-javamail + ${mock-javamail.version} + test + + + javax.mail + mail + + + + + + + \ No newline at end of file diff --git a/spring-ws-test/pom.xml b/spring-ws-test/pom.xml new file mode 100644 index 00000000..4f1042eb --- /dev/null +++ b/spring-ws-test/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws + 2.4.1.BUILD-SNAPSHOT + + + org.springframework.ws + spring-ws-test + jar + + Spring WS Test + + + + + org.springframework.ws + spring-xml + ${project.parent.version} + + + + org.springframework.ws + spring-ws-core + ${project.parent.version} + + + + org.springframework + spring-context + ${spring.version} + + + + xmlunit + xmlunit + ${xmlunit.version} + + + + org.springframework + spring-test + ${spring.version} + test + + + + + \ No newline at end of file diff --git a/spring-xml/pom.xml b/spring-xml/pom.xml new file mode 100644 index 00000000..02f7c31f --- /dev/null +++ b/spring-xml/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws + 2.4.1.BUILD-SNAPSHOT + + + org.springframework.ws + spring-xml + jar + + Spring XML + + + + + org.springframework + spring-beans + ${spring.version} + + + org.springframework + spring-context + ${spring.version} + + + + org.apache.ws.xmlschema + xmlschema-core + ${xml-schema-core.version} + true + + + jaxen + jaxen + ${jaxen.version} + true + + + + + \ No newline at end of file diff --git a/src/main/asciidoctor/bibliography.adoc b/src/main/asciidoctor/bibliography.adoc new file mode 100644 index 00000000..84bc3b57 --- /dev/null +++ b/src/main/asciidoctor/bibliography.adoc @@ -0,0 +1,7 @@ +[bibliography] += Bibliography + +- [[[waldo-94]]] Jim Waldo, Ann Wollrath, and Sam Kendall. _A Note on Distributed Computing_. Springer Verlag. 1994 +- [[[alpine]]] Steve Loughran & Edmund Smith. _Rethinking the Java SOAP Stack_. May 17, 2005. (C) 2005 IEEE Telephone Laboratories, Inc. +- [[[effective-enterprise-java]]] Ted Neward. Scott Meyers. _Effective Enterprise Java_. Addison-Wesley. 2004 +- [[[effective-xml]]] Elliotte Rusty Harold. Scott Meyers. _Effective XML_. Addison-Wesley. 2004 \ No newline at end of file diff --git a/src/main/asciidoctor/client.adoc b/src/main/asciidoctor/client.adoc new file mode 100644 index 00000000..4f49ce1c --- /dev/null +++ b/src/main/asciidoctor/client.adoc @@ -0,0 +1,499 @@ +[[client]] += Using Spring Web Services on the Client + +== Introduction + +Spring-WS provides a client-side Web service API that allows for consistent, XML-driven access to Web services. It also caters for the use of marshallers and unmarshallers so that your service tier code can deal exclusively with Java objects. + +The `org.springframework.ws.client.core` package provides the core functionality for using the client-side access API. It contains template classes that simplify the use of Web services, much like the core Spring `JdbcTemplate` does for JDBC. The design principle common to Spring template classes is to provide helper methods to perform common operations, and for more sophisticated usage, delegate to user implemented callback interfaces. The Web service template follows the same design. The classes offer various convenience methods for the sending and receiving of XML messages, marshalling objects to XML before sending, and allows for multiple transport options. + +== Using the client-side API + +[[client-web-service-template]] +=== `WebServiceTemplate` + +The `WebServiceTemplate` is the core class for client-side Web service access in Spring-WS. It contains methods for sending `Source` objects, and receiving response messages as either `Source` or `Result`. Additionally, it can marshal objects to XML before sending them across a transport, and unmarshal any response XML into an object again. + +[[client-transports]] +==== URIs and Transports + +The `WebServiceTemplate` class uses an URI as the message destination. You can either set a `defaultUri` property on the template itself, or supply an URI explicitly when calling a method on the template. The URI will be resolved into a `WebServiceMessageSender`, which is responsible for sending the XML message across a transport layer. You can set one or more message senders using the `messageSender` or `messageSenders` properties of the `WebServiceTemplate` class. + +===== HTTP transports + +There are two implementations of the `WebServiceMessageSender` interface for sending messages via HTTP. The default implementation is the `HttpUrlConnectionMessageSender`, which uses the facilities provided by Java itself. The alternative is the `HttpComponentsMessageSender`, which uses the https://hc.apache.org/httpcomponents-client-ga[Apache HttpComponents HttpClient]. Use the latter if you need more advanced and easy-to-use functionality (such as authentication, HTTP connection pooling, and so forth). + +To use the HTTP transport, either set the `defaultUri` to something like `http://example.com/services`, or supply the *uri* parameter for one of the methods. + +The following example shows how the default configuration can be used for HTTP transports: + +[source,xml] +---- + + + + + + + + + + +---- + +The following example shows how override the default configuration, and to use Apache HttpClient to authenticate using HTTP authentication: + +[source,xml] +---- + + + + + + + + + + + + + +---- + +===== JMS transport + +For sending messages over JMS, Spring Web Services provides the `JmsMessageSender`. This class uses the facilities of the Spring framework to transform the `WebServiceMessage` into a JMS `Message`, send it on its way on a `Queue` or `Topic`, and receive a response (if any). + +To use the `JmsMessageSender`, you need to set the `defaultUri` or *uri* parameter to a JMS URI, which - at a minimum - consists of the `jms:` prefix and a destination name. Some examples of JMS URIs are: `jms:SomeQueue`, `jms:SomeTopic?priority=3&deliveryMode=NON_PERSISTENT`, and `jms:RequestQueue?replyToName=ResponseName`. For more information on this URI syntax, refer to the class level Javadoc of the `JmsMessageSender`. + +By default, the `JmsMessageSender` send JMS `BytesMessage`, but this can be overriden to use `TextMessages` by using the `messageType` parameter on the JMS URI. For example: `jms:Queue?messageType=TEXT_MESSAGE`. Note that `BytesMessages` are the preferred type, because `TextMessages` do not support attachments and character encodings reliably. + +The following example shows how to use the JMS transport in combination with an ActiveMQ connection factory: + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + +---- + +===== Email transport + +Spring Web Services also provides an email transport, which can be used to send web service messages via SMTP, and retrieve them via either POP3 or IMAP. The client-side email functionality is contained in the `MailMessageSender` class. This class creates an email message from the request `WebServiceMessage`, and sends it via SMTP. It then waits for a response message to arrive in the incoming POP3 or IMAP server. + +To use the `MailMessageSender`, set the `defaultUri` or *uri* parameter to a `mailto` URI. Here are some URI examples: `mailto:john@example.com`, and `mailto:server@localhost?subject=SOAP%20Test`. Make sure that the message sender is properly configured with a `transportUri`, which indicates the server to use for sending requests (typically a SMTP server), and a `storeUri`, which indicates the server to poll for responses (typically a POP3 or IMAP server). + +The following example shows how to use the email transport: + +[source,xml] +---- + + + + + + + + + + + + + + + + + +---- + +===== XMPP transport + +Spring Web Services 2.0 introduced an XMPP (Jabber) transport, which can be used to send and receive web service messages via XMPP. The client-side XMPP functionality is contained in the `XmppMessageSender` class. This class creates an XMPP message from the request `WebServiceMessage`, and sends it via XMPP. It then listens for a response message to arrive. + +To use the `XmppMessageSender`, set the `defaultUri` or *uri* parameter to a `xmpp` URI, for example `xmpp:johndoe@jabber.org`. The sender also requires an `XMPPConnection` to work, which can be conveniently created using the `org.springframework.ws.transport.xmpp.support.XmppConnectionFactoryBean`. + +The following example shows how to use the xmpp transport: + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + + + +---- + +==== Message factories + +In addition to a message sender, the `WebServiceTemplate` requires a Web service message factory. There are two message factories for SOAP: `SaajSoapMessageFactory` and `AxiomSoapMessageFactory`. If no message factory is specified (via the `messageFactory` property), Spring-WS will use the `SaajSoapMessageFactory` by default. + +=== Sending and receiving a `WebServiceMessage` + +The `WebServiceTemplate` contains many convenience methods to send and receive web service messages. There are methods that accept and return a `Source` and those that return a `Result`. Additionally, there are methods which marshal and unmarshal objects to XML. Here is an example that sends a simple XML message to a Web service. + +[source,xml,subs="verbatim,quotes"] +---- +import java.io.StringReader; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.springframework.ws.WebServiceMessageFactory; +import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.transport.WebServiceMessageSender; + +public class WebServiceClient { + + private static final String MESSAGE = + "Hello Web Service World"; + + private final WebServiceTemplate webServiceTemplate = new WebServiceTemplate(); + + public void setDefaultUri(String defaultUri) { + webServiceTemplate.setDefaultUri(defaultUri); + } + + _// send to the configured default URI_ + public void simpleSendAndReceive() { + StreamSource source = new StreamSource(new StringReader(MESSAGE)); + StreamResult result = new StreamResult(System.out); + webServiceTemplate.sendSourceAndReceiveToResult(source, result); + } + + _// send to an explicit URI_ + public void customSendAndReceive() { + StreamSource source = new StreamSource(new StringReader(MESSAGE)); + StreamResult result = new StreamResult(System.out); + webServiceTemplate.sendSourceAndReceiveToResult("http://localhost:8080/AnotherWebService", + source, result); + } + +} +---- + +[source,xml] +---- + + + + + + + + +---- + +The above example uses the `WebServiceTemplate` to send a hello world message to the web service located at `http://localhost:8080/WebService` (in the case of the `simpleSendAndReceive()` method), and writes the result to the console. The `WebServiceTemplate` is injected with the default URI, which is used because no URI was supplied explicitly in the Java code. + +Please note that the `WebServiceTemplate` class is thread-safe once configured (assuming that all of it's dependencies are thread-safe too, which is the case for all of the dependencies that ship with Spring-WS), and so multiple objects can use the same shared `WebServiceTemplate` instance if so desired. The `WebServiceTemplate` exposes a zero argument constructor and `messageFactory`/`messageSender` bean properties which can be used for constructing the instance (using a Spring container or plain Java code). Alternatively, consider deriving from Spring-WS's `WebServiceGatewaySupport` convenience base class, which exposes convenient bean properties to enable easy configuration. (You do *not* have to extend this base class... it is provided as a convenience class only.) + +=== Sending and receiving POJOs - marshalling and unmarshalling + +In order to facilitate the sending of plain Java objects, the `WebServiceTemplate` has a number of `send(..)` methods that take an `Object` as an argument for a message's data content. The method `marshalSendAndReceive(..)` in the `WebServiceTemplate` class delegates the conversion of the request object to XML to a `Marshaller`, and the conversion of the response XML to an object to an `Unmarshaller`. (For more information about marshalling and unmarshaller, refer to http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/oxm.html[the Spring documentation].) By using the marshallers, your application code can focus on the business object that is being sent or received and not be concerned with the details of how it is represented as XML. In order to use the marshalling functionality, you have to set a marshaller and unmarshaller with the `marshaller`/`unmarshaller` properties of the `WebServiceTemplate` class. + +=== `WebServiceMessageCallback` + +To accommodate the setting of SOAP headers and other settings on the message, the `WebServiceMessageCallback` interface gives you access to the message *after* it has been created, but *before* it is sent. The example below demonstrates how to set the SOAP Action header on a message that is created by marshalling an object. + +[source,java] +---- + +public void marshalWithSoapActionHeader(MyObject o) { + + webServiceTemplate.marshalSendAndReceive(o, new WebServiceMessageCallback() { + + public void doWithMessage(WebServiceMessage message) { + ((SoapMessage)message).setSoapAction("http://tempuri.org/Action"); + } + }); +} +---- + +NOTE: Note that you can also use the `org.springframework.ws.soap.client.core.SoapActionCallback` to set the SOAP Action header. + +==== WS-Addressing + +In addition to the <> support, Spring Web Services also has support for this specification on the client-side. + +For setting WS-Addressing headers on the client, you can use the `org.springframework.ws.soap.addressing.client.ActionCallback`. This callback takes the desired Action header as a parameter. It also has constructors for specifying the WS-Addressing version, and a `To` header. If not specified, the `To` header will default to the URL of the connection being made. + +Here is an example of setting the `Action` header to `http://samples/RequestOrder`: + +[source,java] +---- +webServiceTemplate.marshalSendAndReceive(o, new ActionCallback("http://samples/RequestOrder")); +---- + +=== `WebServiceMessageExtractor` + +The `WebServiceMessageExtractor` interface is a low-level callback interface that allows you to have full control over the process to extract an `Object` from a received `WebServiceMessage`. The `WebServiceTemplate` will invoke the `extractData(..)` method on a supplied `WebServiceMessageExtractor` *while the underlying connection to the serving resource is still open*. The following example illustrates the `WebServiceMessageExtractor` in action: + +[source,java,subs="verbatim,quotes"] +---- +public void marshalWithSoapActionHeader(final Source s) { + final Transformer transformer = transformerFactory.newTransformer(); + webServiceTemplate.sendAndReceive(new WebServiceMessageCallback() { + public void doWithMessage(WebServiceMessage message) { + transformer.transform(s, message.getPayloadResult()); + }, + new WebServiceMessageExtractor() { + public Object extractData(WebServiceMessage message) throws IOException + _// do your own transforms with message.getPayloadResult() + // or message.getPayloadSource()_ + } + }); +} +---- + +== Client-side testing + +When it comes to testing your Web service clients (i.e. classes that uses the `WebServiceTemplate` to access a Web service), there are two possible approaches: + +* Write *Unit Tests*, which simply mock away the `WebServiceTemplate` class, `WebServiceOperations` interface, or the complete client class. ++ +The advantage of this approach is that it's quite easy to accomplish; the disadvantage is that you are not really testing the exact content of the XML messages that are sent over the wire, especially when mocking out the entire client class. ++ +* Write *Integrations Tests*, which do test the contents of the message. + +The first approach can easily be accomplished with mocking frameworks such as EasyMock, JMock, etc. The next section will focus on writing integration tests, using the test features introduced in Spring Web Services 2.0. + +=== Writing client-side integration tests + +Spring Web Services 2.0 introduced support for creating Web service client integration tests. In this context, a client is a class that uses the `WebServiceTemplate` to access a Web service. + +The integration test support lives in the `org.springframework.ws.test.client` package. The core class in that package is the `MockWebServiceServer`. The underlying idea is that the web service template connects to this mock server, sends it request message, which the mock server then verifies against the registered expectations. If the expectations are met, the mock server then prepares a response message, which is send back to the template. + +The typical usage of the `MockWebServiceServer` is: . + +. Create a `MockWebServiceServer` instance by calling `MockWebServiceServer.createServer(WebServiceTemplate)`, `MockWebServiceServer.createServer(WebServiceGatewaySupport)`, or `MockWebServiceServer.createServer(ApplicationContext)`. +. Set up request expectations by calling `expect(RequestMatcher)`, possibly by using the default `RequestMatcher` implementations provided in `RequestMatchers` (which can be statically imported). Multiple expectations can be set up by chaining `andExpect(RequestMatcher)` calls. +. Create an appropriate response message by calling `andRespond(ResponseCreator)`, possibly by using the default `ResponseCreator` implementations provided in `ResponseCreators` (which can be statically imported). +. Use the `WebServiceTemplate` as normal, either directly of through client code. +. Call `MockWebServiceServer.verify()` to make sure that all expectations have been met. + +NOTE: Note that the `MockWebServiceServer` (and related classes) offers a 'fluent' API, so you can typically use the Code Completion features (i.e. ctrl-space) in your IDE to guide you through the process of setting up the mock server. + +NOTE: Also note that you rely on the standard logging features available in Spring Web Services in your unit tests. Sometimes it might be useful to inspect the request or response message to find out why a particular tests failed. See <> for more information. + +Consider, for example, this Web service client class: + +[source,java] +---- +import org.springframework.ws.client.core.support.WebServiceGatewaySupport; + +public class CustomerClient extends WebServiceGatewaySupport { //<1> + + public int getCustomerCount() { + CustomerCountRequest request = new CustomerCountRequest(); //<2> + request.setCustomerName("John Doe"); + + CustomerCountResponse response = + (CustomerCountResponse) getWebServiceTemplate().marshalSendAndReceive(request); //<3> + + return response.getCustomerCount(); + } + +} +---- + +<1> The `CustomerClient` extends `WebServiceGatewaySupport`, which provides it with a webServiceTemplate property. +<2> `CustomerCountRequest` is an object supported by a marshaller. For instance, it can have a `@XmlRootElement` annotation to be supported by JAXB2. +<3> The `CustomerClient` uses the `WebServiceTemplate` offered by `WebServiceGatewaySupport` to marshal the request object into a SOAP message, and sends that to the web service. The response object is unmarshalled into a `CustomerCountResponse`. + +A typical test for `CustomerClient` would look like this: + +[source,java] +---- +import javax.xml.transform.Source; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.xml.transform.StringSource; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertEquals; + +import org.springframework.ws.test.client.MockWebServiceServer; //<1> +import static org.springframework.ws.test.client.RequestMatchers.*; //<1> +import static org.springframework.ws.test.client.ResponseCreators.*; //<1> + +@RunWith(SpringJUnit4ClassRunner.class) //<2> +@ContextConfiguration("integration-test.xml") //<2> +public class CustomerClientIntegrationTest { + + @Autowired + private CustomerClient client; //<3> + + private MockWebServiceServer mockServer; //<4> + + @Before + public void createServer() throws Exception { + mockServer = MockWebServiceServer.createServer(client); + } + + @Test + public void customerClient() throws Exception { + Source requestPayload = new StringSource( + "" + + "John Doe" + + ""); + Source responsePayload = new StringSource( + "" + + "10" + + ""); + + mockServer.expect(payload(requestPayload)).andRespond(withPayload(responsePayload));//<5> + + int result = client.getCustomerCount(); //<6> + assertEquals(10, result); //<6> + + mockServer.verify(); //<7> + } + +} +---- + +<1> The `CustomerClientIntegrationTest` imports the `MockWebServiceServer`, and statically imports `RequestMatchers` and `ResponseCreators`. +<2> This test uses the standard testing facilities provided in the Spring Framework. This is not required, but is generally the easiest way to set up the test. +<3> The `CustomerClient` is configured in `integration-test.xml`, and wired into this test using `@Autowired`. +<4> In a `@Before` method, we create a `MockWebServiceServer` by using the `createServer` factory method. +<5> We define expectations by calling `expect()` with a `payload()` `RequestMatcher` provided by the statically imported `RequestMatchers` (see <>). ++ +We also set up a response by calling `andRespond()` with a `withPayload()` `ResponseCreator` provided by the statically imported `ResponseCreators` (see <>). ++ +This part of the test might look a bit confusing, but the Code Completion features of your IDE are of great help. After typing `expect(`, simply type ctrl-space, and your IDE will provide you with a list of possible request matching strategies, provided you statically imported `RequestMatchers`. The same applies to `andRespond(`, provided you statically imported `ResponseCreators`. +<6> We call `getCustomerCount()` on the `CustomerClient`, thus using the `WebServiceTemplate`. The template has been set up for 'testing mode' by now, so no real (HTTP) connection is made by this method call. We also make some JUnit assertions based on the result of the method call. +<7> We call `verify()` on the `MockWebServiceServer`, thus verifying that the expected message was actually received. + + +[[client-test-request-matcher]] +=== `RequestMatcher` and `RequestMatchers` + +To verify whether the request message meets certain expectations, the `MockWebServiceServer` uses the `RequestMatcher` strategy interface. The contract defined by this interface is quite simple: + +[source,java] +---- +public interface RequestMatcher { + + void match(URI uri, + WebServiceMessage request) + throws IOException, + AssertionError; +} +---- + +You can write your own implementations of this interface, throwing `AssertionError`s when the message does not meet your expectations, but you certainly do not have to. The `RequestMatchers` class provides standard `RequestMatcher` implementations for you to use in your tests. You will typically statically import this class. + +The `RequestMatchers` class provides the following request matchers: + +[cols="2", options="header"] +|=== +| `RequestMatchers` method +| Description + +| `anything()` +| Expects any sort of request. + +| `payload()` +| Expects a given request payload. + +| `validPayload()` +| Expects the request payload to validate against given XSD schema(s). + +| `xpath()` +| Expects a given XPath expression to exist, not exist, or evaluate to a given value. + +| `soapHeader()` +| Expects a given SOAP header to exist in the request message. + +| `connectionTo()` +| Expects a connection to the given URL. +|=== + +You can set up multiple request expectations by chaining `andExpect()` calls, like so: + +[source,java] +---- +mockServer.expect(connectionTo("http://example.com")). + andExpect(payload(expectedRequestPayload)). + andExpect(validPayload(schemaResource)). + andRespond(...); +---- + +For more information on the request matchers provided by `RequestMatchers`, refer to the class level Javadoc. + +[[client-test-response-creator]] +=== `ResponseCreator` and `ResponseCreators` + +When the request message has been verified and meets the defined expectations, the `MockWebServiceServer` will create a response message for the `WebServiceTemplate` to consume. The server uses the `ResponseCreator` strategy interface for this purpose: + +[source,java] +---- +public interface ResponseCreator { + + WebServiceMessage createResponse(URI uri, + WebServiceMessage request, + WebServiceMessageFactory messageFactory) + throws IOException; + +} +---- + +Once again you can write your own implementations of this interface, creating a response message by using the message factory, but you certainly do not have to, as the `ResponseCreators` class provides standard `ResponseCreator` implementations for you to use in your tests. You will typically statically import this class. + +The `ResponseCreators` class provides the following responses: + +[cols="2", options="header"] +|=== +| `ResponseCreators` method +| Description + +| `withPayload()` +| Creates a response message with a given payload. + +| `withError()` +| Creates an error in the response connection. This method gives you the opportunity to test your error handling. + +| `withException()` +| Throws an exception when reading from the response connection. This method gives you the opportunity to test your exception handling. + +| `withMustUnderstandFault()`, `withClientOrSenderFault()`, `withServerOrReceiverFault()`, and `withVersionMismatchFault()` +| Creates a response message with a given SOAP fault. This method gives you the opportunity to test your Fault handling. +|=== + +For more information on the request matchers provided by `RequestMatchers`, refer to the class level Javadoc. + diff --git a/src/main/asciidoctor/common.adoc b/src/main/asciidoctor/common.adoc new file mode 100644 index 00000000..1e235b0c --- /dev/null +++ b/src/main/asciidoctor/common.adoc @@ -0,0 +1,301 @@ +:toclevels: 10 + +[[common]] += Shared components + +In this chapter, we will explore the components which are shared between client- and server-side Spring-WS development. These interfaces and classes represent the building blocks of Spring-WS, so it is important to understand what they do, even if you do not use them directly. + +[[web-service-messages]] +== Web service messages + +[[web-service-message]] +=== `WebServiceMessage` + +One of the core interfaces of Spring Web Services is the `WebServiceMessage`. This interface represents a protocol-agnostic XML message. The interface contains methods that provide access to the payload of the message, in the form of a `javax.xml.transform.Source` or a `javax.xml.transform.Result`. `Source` and `Result` are tagging interfaces that represent an abstraction over XML input and output. Concrete implementations wrap various XML representations, as indicated in the following table. + +[cols="2", options="header"] +|=== +| Source/Result implementation +| Wraps XML representation + +| `javax.xml.transform.dom.DOMSource` +| `org.w3c.dom.Node` + +| `javax.xml.transform.dom.DOMResult` +| `org.w3c.dom.Node` + +| `javax.xml.transform.sax.SAXSource` +| `org.xml.sax.InputSource` and `org.xml.sax.XMLReader` + +| `javax.xml.transform.sax.SAXResult` +| `org.xml.sax.ContentHandler` + +| `javax.xml.transform.stream.StreamSource` +| `java.io.File`, `java.io.InputStream`, or `java.io.Reader` + +| `javax.xml.transform.stream.StreamResult` +| `java.io.File`, `java.io.OutputStream`, or `java.io.Writer` +|=== + +In addition to reading from and writing to the payload, a Web service message can write itself to an output stream. + +[[soap-message]] +=== `SoapMessage` + +The `SoapMessage` is a subclass of `WebServiceMessage`. It contains SOAP-specific methods, such as getting SOAP Headers, SOAP Faults, etc. Generally, your code should not be dependent on `SoapMessage`, because the content of the SOAP Body (the payload of the message) can be obtained via `getPayloadSource()` and `getPayloadResult()` in the `WebServiceMessage`. Only when it is necessary to perform SOAP-specific actions, such as adding a header, getting an attachment, etc., should you need to cast `WebServiceMessage` to `SoapMessage`. + +[[message-factories]] +=== Message Factories + +Concrete message implementations are created by a `WebServiceMessageFactory`. This factory can create an empty message, or read a message based on an input stream. There are two concrete implementations of `WebServiceMessageFactory`; one is based on SAAJ, the SOAP with Attachments API for Java, the other based on Axis 2's AXIOM, the AXis Object Model. + +==== `SaajSoapMessageFactory` + +The `SaajSoapMessageFactory` uses the SOAP with Attachments API for Java to create `SoapMessage` implementations. *SAAJ* is part of *J2EE* 1.4, so it should be supported under most modern application servers. Here is an overview of the *SAAJ* versions supplied by common application servers: + +[cols="2", options="header"] +|=== +| Application Server +| *SAAJ* Version + +| BEA WebLogic 8 +| 1.1 + +| BEA WebLogic 9 +| 1.1/1.2^1^ + +| IBM WebSphere 6 +| 1.2 + +| SUN Glassfish 1 +| 1.3 + +2+|^1^Weblogic 9 has a known bug in the *SAAJ* 1.2 implementation: it implement all the 1.2 interfaces, but throws a `UnsupportedOperationException` when called. Spring Web Services has a workaround: it uses *SAAJ* 1.1 when operating on WebLogic 9. +|=== + +Additionally, Java SE 6 includes *SAAJ* 1.3. You wire up a `SaajSoapMessageFactory` like so: + +[source,xml] +---- + +---- + +NOTE: *SAAJ* is based on DOM, the Document Object Model. This means that all SOAP messages are stored *in memory*. For larger SOAP messages, this may not be very performant. In that case, the `AxiomSoapMessageFactory` might be more applicable. + +==== `AxiomSoapMessageFactory` + +The `AxiomSoapMessageFactory` uses the AXis 2 Object Model to create `SoapMessage` implementations. *AXIOM* is based on *StAX*, the Streaming API for XML. StAX provides a pull-based mechanism for reading XML messages, which can be more efficient for larger messages. + +To increase reading performance on the `AxiomSoapMessageFactory`, you can set the `payloadCaching` property to false (default is true). This will read the contents of the SOAP body directly from the socket stream. When this setting is enabled, the payload can only be read once. This means that you have to make sure that any pre-processing (logging etc.) of the message does not consume it. + +You use the `AxiomSoapMessageFactory` as follows: + +[source,xml] +---- + + + +---- + +In addition to payload caching, *AXIOM* also supports full streaming messages, as defined in the `StreamingWebServiceMessage`. This means that the payload can be directly set on the response message, rather than being written to a DOM tree or buffer. + +Full streaming for *AXIOM* is used when a handler method returns a *JAXB2*-supported object. It will automatically set this marshalled object into the response message, and write it out to the outgoing socket stream when the response is going out. + +For more information about full streaming, refer to the class-level Javadoc for `StreamingWebServiceMessage` and `StreamingPayload`. + +[[soap_11_or_12]] +==== *SOAP* 1.1 or 1.2 + +Both the `SaajSoapMessageFactory` and the `AxiomSoapMessageFactory` have a `soapVersion` property, where you can inject a `SoapVersion` constant. By default, the version is 1.1, but you can set it to 1.2 like so: + +[source,xml] +---- + + + + + + + + + +---- + +In the example above, we define a `SaajSoapMessageFactory` that only accepts *SOAP* 1.2 messages. + +[WARNING] +==== +Even though both versions of *SOAP* are quite similar in format, the 1.2 version is not backwards compatible with 1.1 because it uses a different XML namespace. Other major differences between *SOAP* 1.1 and 1.2 include the different structure of a Fault, and the fact that `SOAPAction` HTTP headers are effectively deprecated, thought they still work. + +One important thing to note with *SOAP* version numbers, or WS-* specification version numbers in general, is that the latest version of a specification is generally not the most popular version. For *SOAP*, this means that currently, the best version to use is 1.1. Version 1.2 might become more popular in the future, but currently 1.1 is the safest bet. +==== + +[[message-context]] +=== `MessageContext` + +Typically, messages come in pairs: a request and a response. A request is created on the client-side, which is sent over some transport to the server-side, where a response is generated. This response gets sent back to the client, where it is read. + +In Spring Web Services, such a conversation is contained in a `MessageContext`, which has properties to get request and response messages. On the client-side, the message context is created by the <>. On the server-side, the message context is read from the transport-specific input stream. For example, in HTTP, it is read from the `HttpServletRequest` and the response is written back to the `HttpServletResponse`. + +[[transport-context]] +== `TransportContext` + +One of the key properties of the SOAP protocol is that it tries to be transport-agnostic. This is why, for instance, Spring-WS does not support mapping messages to endpoints by HTTP request URL, but rather by mesage content. + +However, sometimes it is necessary to get access to the underlying transport, either on the client or server side. For this, Spring Web Services has the `TransportContext`. The transport context allows access to the underlying `WebServiceConnection`, which typically is a `HttpServletConnection` on the server side; or a `HttpUrlConnection` or `CommonsHttpConnection` on the client side. For example, you can obtain the IP address of the current request in a server-side endpoint or interceptor like so: + +[source,java] +---- +TransportContext context = TransportContextHolder.getTransportContext(); +HttpServletConnection connection = (HttpServletConnection )context.getConnection(); +HttpServletRequest request = connection.getHttpServletRequest(); +String ipAddress = request.getRemoteAddr(); +---- + +[[xpath]] +== Handling XML With XPath + +One of the best ways to handle XML is to use XPath. Quoting <>, item 35: + +[quote, Elliotte Rusty Harold] +XPath is a fourth generation declarative language that allows you to specify which nodes you want to process without specifying exactly how the processor is supposed to navigate to those nodes. XPath's data model is very well designed to support exactly what almost all developers want from XML. For instance, it merges all adjacent text including that in CDATA sections, allows values to be calculated that skip over comments and processing instructions` and include text from child and descendant elements, and requires all external entity references to be resolved. In practice, XPath expressions tend to be much more robust against unexpected but perhaps insignificant changes in the input document. + +Spring Web Services has two ways to use XPath within your application: the faster `XPathExpression` or the more flexible `XPathTemplate`. + +[[xpath-expression]] +=== `XPathExpression` + +The `XPathExpression` is an abstraction over a compiled XPath expression, such as the Java 5 `javax.xml.xpath.XPathExpression`, or the Jaxen `XPath` class. To construct an expression in an application context, there is the `XPathExpressionFactoryBean`. Here is an example which uses this factory bean: + +[source,xml] +---- + + + + + + + + + + + +---- + +The expression above does not use namespaces, but we could set those using the `namespaces` property of the factory bean. The expression can be used in the code as follows: + +[source,java] +---- +package sample; + +public class MyXPathClass { + + private final XPathExpression nameExpression; + + public MyXPathClass(XPathExpression nameExpression) { + this.nameExpression = nameExpression; + } + + public void doXPath(Document document) { + String name = nameExpression.evaluateAsString(document.getDocumentElement()); + System.out.println("Name: " + name); + } + +} +---- + +For a more flexible approach, you can use a `NodeMapper`, which is similar to the `RowMapper` in Spring's JDBC support. The following example shows how we can use it: + +[source,java] +---- +package sample; + +public class MyXPathClass { + + private final XPathExpression contactExpression; + + public MyXPathClass(XPathExpression contactExpression) { + this.contactExpression = contactExpression; + } + + public void doXPath(Document document) { + List contacts = contactExpression.evaluate(document, + new NodeMapper() { + public Object mapNode(Node node, int nodeNum) throws DOMException { + Element contactElement = (Element) node; + Element nameElement = (Element) contactElement.getElementsByTagName("Name").item(0); + Element phoneElement = (Element) contactElement.getElementsByTagName("Phone").item(0); + return new Contact(nameElement.getTextContent(), phoneElement.getTextContent()); + } + }); + PlainText Section qName:lineannotation level:5, chunks:[// do something with list of Contact objects] attrs:[:] + } +} +---- + +Similar to mapping rows in Spring JDBC's `RowMapper`, each result node is mapped using an anonymous inner class. In this case, we create a `Contact` object, which we use later on. + +[[xpath-template]] +=== `XPathTemplate` + +The `XPathExpression` only allows you to evaluate a single, pre-compiled expression. A more flexible, though slower, alternative is the `XpathTemplate`. This class follows the common template pattern used throughout Spring (JdbcTemplate, JmsTemplate, etc.). Here is an example: + +[source,java,subs="verbatim,quotes"] +---- +package sample; + +public class MyXPathClass { + + private XPathOperations template = new Jaxp13XPathTemplate(); + + public void doXPath(Source source) { + String name = template.evaluateAsString("/Contacts/Contact/Name", request); + _// do something with name_ + } + +} +---- + +[[logging]] +== Message Logging and Tracing + +When developing or debugging a Web service, it can be quite useful to look at the content of a (SOAP) message when it arrives, or just before it is sent. Spring Web Services offer this functionality, via the standard Commons Logging interface. + +WARNING: Make sure to use Commons Logging version 1.1 or higher. Earlier versions have class loading issues, and do not integrate with the Log4J TRACE level. + +To log all server-side messages, simply set the `org.springframework.ws.server.MessageTracing` logger to level DEBUG or TRACE. On the debug level, only the payload root element is logged; on the TRACE level, the entire message content. If you only want to log sent messages, use the `org.springframework.ws.server.MessageTracing.sent` logger; or `org.springframework.ws.server.MessageTracing.received` to log received messages. + +On the client-side, similar loggers exist: `org.springframework.ws.client.MessageTracing.sent` and `org.springframework.ws.client.MessageTracing.received`. + +Here is an example `log4j.properties` configuration, logging the full content of sent messages on the client side, and only the payload root element for client-side received messages. On the server-side, the payload root is logged for both sent and received messages: + +[source] +---- +log4j.rootCategory=INFO, stdout +log4j.logger.org.springframework.ws.client.MessageTracing.sent=TRACE +log4j.logger.org.springframework.ws.client.MessageTracing.received=DEBUG + +log4j.logger.org.springframework.ws.server.MessageTracing=DEBUG + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%p [%c{3}] %m%n +---- + +With this configuration, a typical output will be: + +---- +TRACE [client.MessageTracing.sent] Sent request [