From 27b18118c17498d248ebe77e772edaa4afb60a24 Mon Sep 17 00:00:00 2001 From: "Greg L. Turnquist" Date: Mon, 22 Jun 2020 09:44:38 -0500 Subject: [PATCH] Upgrade to Spring Boot + Spring Data. Update this repository to use modern Spring practices including: * Spring Boot * Spring Data JPA * Spring Framework's Java configuration --- .gitignore | 2 + .mvn/wrapper/maven-wrapper.jar | Bin 0 -> 48337 bytes .mvn/wrapper/maven-wrapper.properties | 1 + airline/build.gradle | 19 -- .../axis1/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 48337 bytes .../.mvn/wrapper/maven-wrapper.properties | 1 + airline/client/axis1/build.gradle | 62 ---- airline/client/axis1/mvnw | 286 ++++++++++++++++++ airline/client/axis1/mvnw.cmd | 161 ++++++++++ airline/client/axis1/pom.xml | 173 +++++++++++ .../airline/client/axis1/AxisMain.java | 99 ++++++ .../ws/samples/airline/client/axis1/Main.java | 94 ------ .../jax-ws/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 48337 bytes .../.mvn/wrapper/maven-wrapper.properties | 1 + airline/client/jax-ws/build.gradle | 38 --- airline/client/jax-ws/mvnw | 286 ++++++++++++++++++ airline/client/jax-ws/mvnw.cmd | 161 ++++++++++ airline/client/jax-ws/pom.xml | 120 ++++++++ .../airline/client/jaxws/JaxWsMain.java | 108 +++++++ .../ws/samples/airline/client/jaxws/Main.java | 104 ------- airline/client/jms/build.gradle | 14 - airline/client/jms/pom.xml | 62 ++++ .../samples/airline/client/jms/JmsClient.java | 26 +- .../airline/client/jms/JmsConfiguration.java | 52 ++++ .../samples/airline/client/jms/JmsMain.java | 34 +++ .../airline/client/jms/applicationContext.xml | 19 -- airline/client/saaj/build.gradle | 10 - airline/client/saaj/pom.xml | 86 ++++++ .../saaj/{Driver.java => SaajMain.java} | 33 +- .../src/main/resources/application.properties | 4 + .../airline/client/saaj/securityPolicy.xml | 2 +- airline/client/spring-ws/build.gradle | 46 --- airline/client/spring-ws/pom.xml | 135 +++++++++ .../ws/samples/airline/client/sws/Driver.java | 39 --- .../airline/client/sws/GetFlights.java | 138 ++++----- .../client/sws/GetFrequentFlyerMileage.java | 17 +- .../airline/client/sws/SpringWsMain.java | 36 +++ .../airline/client/sws/WsConfiguration.java | 56 ++++ .../airline/client/sws/applicationContext.xml | 30 -- .../airline/client/sws/GetFlightsTest.java | 103 +++---- airline/server/build.gradle | 147 --------- airline/server/pom.xml | 224 ++++++++++++++ .../airline/AirlineServerApplication.java | 13 + .../ws/samples/airline/dao/AirportDao.java | 8 + .../ws/samples/airline/dao/Databaseinit.java | 50 +++ .../ws/samples/airline/dao/FlightDao.java | 44 ++- .../samples/airline/dao/FrequentFlyerDao.java | 13 +- .../ws/samples/airline/dao/TicketDao.java | 6 +- .../airline/dao/jpa/DatabaseInitializer.java | 108 ------- .../samples/airline/dao/jpa/JpaFlightDao.java | 74 ----- .../airline/dao/jpa/JpaFrequentFlyerDao.java | 46 --- .../samples/airline/dao/jpa/JpaTicketDao.java | 36 --- .../ws/samples/airline/domain/Airport.java | 1 + .../ws/samples/airline/domain/Flight.java | 202 ++++++------- .../samples/airline/domain/FrequentFlyer.java | 104 ++++--- .../ws/samples/airline/domain/Passenger.java | 1 + .../ws/samples/airline/domain/Ticket.java | 89 +++--- .../domain/openjpa/DateTimeValueHandler.java | 57 ---- .../domain/openjpa/LocalDateValueHandler.java | 51 ---- .../samples/airline/jms/JmsConfiguration.java | 52 ++++ .../schema/support/SchemaConversionUtils.java | 208 +++++++------ .../security/FrequentFlyerDetails.java | 4 +- .../security/SecurityConfiguration.java | 37 +++ .../SpringFrequentFlyerSecurityService.java | 82 +++-- .../airline/service/AirlineService.java | 15 +- .../service/NoSuchFlightException.java | 9 +- .../service/impl/AirlineServiceImpl.java | 176 ++++++----- .../airline/web/FlightsController.java | 78 +++-- .../samples/airline/ws/AirlineEndpoint.java | 223 +++++++------- .../airline/ws/WebServicesConfiguration.java | 121 ++++++++ .../main/resources/META-INF/persistence.xml | 14 - .../src/main/resources/application.properties | 3 + .../src/main/resources/log4j.properties | 8 - .../main/{webapp => resources}/messages.xsd | 0 .../dao/jpa/applicationContext-jpa.xml | 42 --- .../airline/jms/applicationContext-jms.xml | 28 -- .../security/applicationContext-security.xml | 26 -- .../airline/security/securityPolicy.xml | 2 +- .../airline/service/applicationContext.xml | 16 - .../airline/ws/applicationContext-ws.xml | 47 --- .../src/main/resources/templates/flight.html | 41 +++ .../src/main/resources/templates/flights.html | 62 ++++ .../resources/templates/noSuchFlight.html | 12 + .../src/main/{webapp => resources}/types.xsd | 0 .../src/main/webapp/WEB-INF/jsp/error.jsp | 13 - .../src/main/webapp/WEB-INF/jsp/flight.jsp | 47 --- .../src/main/webapp/WEB-INF/jsp/flights.jsp | 73 ----- .../main/webapp/WEB-INF/jsp/noSuchFlight.jsp | 13 - .../src/main/webapp/WEB-INF/mvc-servlet.xml | 33 -- .../server/src/main/webapp/WEB-INF/web.xml | 48 --- .../src/main/webapp/WEB-INF/ws-servlet.xml | 20 -- airline/server/src/main/webapp/index.jsp | 3 - .../airline/dao/jpa/JpaFlightDaoTest.java | 124 -------- .../dao/jpa/JpaFrequentFlyerDaoTest.java | 73 ----- .../airline/dao/jpa/JpaTicketDaoTest.java | 83 ----- ...pringFrequentFlyerSecurityServiceTest.java | 63 ---- .../service/impl/AirlineServiceImplTest.java | 184 ----------- .../airline/web/FlightsControllerTest.java | 62 ---- .../airline/ws/AirlineEndpointTest.java | 207 ------------- airline/settings.gradle | 2 - echo/build.gradle | 17 -- echo/client/saaj/build.gradle | 4 - echo/client/saaj/pom.xml | 48 +++ .../samples/echo/client/saaj/EchoClient.java | 103 +++---- .../echo/client/saaj/SaajEchoClient.java | 24 ++ echo/client/spring-ws/build.gradle | 9 - echo/client/spring-ws/pom.xml | 49 +++ .../samples/echo/client/sws/EchoClient.java | 38 +-- .../echo/client/sws/SpringWsEchoClient.java | 41 +++ .../src/main/resources/application.yml | 6 + .../echo/client/sws => }/echoRequest.xml | 0 .../src/main/resources/log4j.properties | 7 - echo/server/build.gradle | 38 --- echo/server/pom.xml | 121 ++++++++ .../ws/samples/echo/EchoApplication.java | 12 + .../ws/samples/echo/config/EchoConfig.java | 15 +- .../echo/config/EchoServletInitializer.java | 43 --- .../ws/samples/echo/service/EchoService.java | 12 +- .../echo/service/impl/EchoServiceImpl.java | 6 +- .../ws/samples/echo/ws/EchoEndpoint.java | 100 +++--- .../server/src/main/resources/application.yml | 9 + .../src/main/resources/log4j.properties | 7 - .../ws/samples/echo/ws/EchoEndpointTest.java | 72 +++-- echo/settings.gradle | 2 - mtom/build.gradle | 23 -- mtom/client/jax-ws/build.gradle | 39 --- mtom/client/jax-ws/mtom.wsdl | 73 ----- .../ws/samples/mtom/client/jaxws/Main.java | 76 ----- mtom/client/spring-ws/build.gradle | 58 ---- mtom/client/spring-ws/pom.xml | 112 +++++++ .../mtom/client/sws/AxiomMtomClient.java | 150 --------- .../ws/samples/mtom/client/sws/Driver.java | 39 --- .../mtom/client/sws/MtomClientConfig.java | 23 +- .../mtom/client/sws/SaajMtomClient.java | 137 ++++++--- .../src/main/resources/application.yml | 3 + .../src/main/resources/log4j.properties | 6 - .../src/main/resources}/spring-ws-logo.png | Bin mtom/server/build.gradle | 78 ----- mtom/server/pom.xml | 119 ++++++++ .../ws/samples/mtom/MtomServer.java | 12 + .../mtom/config/MtomServerConfiguration.java | 77 ++--- ...Repository.java => ContentRepository.java} | 10 +- .../mtom/service/ContentRepositoryImpl.java | 63 ++++ .../mtom/service/StubImageRepository.java | 45 --- .../mtom/ws/ContentRepositoryEndpoint.java | 76 +++++ .../mtom/ws/ImageRepositoryEndpoint.java | 63 ---- .../server/src/main/resources/application.yml | 3 + .../src/main/resources/contentStore.wsdl | 101 +++++++ .../src/main/resources/log4j.properties | 8 - mtom/server/src/main/resources/schema.xsd | 19 -- mtom/server/src/main/webapp/WEB-INF/web.xml | 23 -- mtom/settings.gradle | 2 - mvnw | 286 ++++++++++++++++++ mvnw.cmd | 161 ++++++++++ pom.xml | 83 +++++ stockquote/README.md | 31 -- stockquote/build.gradle | 18 -- stockquote/client/jax-ws/build.gradle | 38 --- .../samples/stockquote/client/jaxws/Main.java | 57 ---- stockquote/client/spring-ws/build.gradle | 9 - .../stockquote/client/sws/StockClient.java | 62 ---- .../src/main/resources/log4j.properties | 7 - .../stockquote/client/sws/quotesRequest.xml | 5 - stockquote/server/build.gradle | 57 ---- .../ws/samples/stockquote/Driver.java | 48 --- .../samples/stockquote/ws/StockService.java | 70 ----- .../ws/StockServiceConfiguration.java | 81 ----- .../src/main/resources/log4j.properties | 7 - .../ws/samples/stockquote/ws/stockquote.wsdl | 73 ----- stockquote/settings.gradle | 2 - tutorial/build.gradle | 47 --- tutorial/gradle/wrapper/gradle-wrapper.jar | Bin 50514 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - tutorial/gradlew | 164 ---------- tutorial/gradlew.bat | 90 ------ tutorial/pom.xml | 143 +++++++++ .../java/com/mycompany/hr/HrApplication.java | 12 + .../mycompany/hr/config/HRConfiguration.java | 13 +- .../hr/config/HRServletInitializer.java | 30 -- .../com/mycompany/hr/ws/HolidayEndpoint.java | 81 ++--- .../mycompany/hr/ws/HolidayEndpointTest.java | 72 ++--- weather/build.gradle | 65 ---- weather/pom.xml | 86 ++++++ .../ws/samples/weather/WeatherClient.java | 24 +- .../samples/weather/WeatherConfiguration.java | 7 +- weather/src/main/resources/log4j.properties | 5 - 186 files changed, 5247 insertions(+), 5200 deletions(-) create mode 100644 .mvn/wrapper/maven-wrapper.jar create mode 100644 .mvn/wrapper/maven-wrapper.properties delete mode 100644 airline/build.gradle create mode 100644 airline/client/axis1/.mvn/wrapper/maven-wrapper.jar create mode 100644 airline/client/axis1/.mvn/wrapper/maven-wrapper.properties delete mode 100644 airline/client/axis1/build.gradle create mode 100755 airline/client/axis1/mvnw create mode 100644 airline/client/axis1/mvnw.cmd create mode 100644 airline/client/axis1/pom.xml create mode 100644 airline/client/axis1/src/main/java/org/springframework/ws/samples/airline/client/axis1/AxisMain.java delete mode 100644 airline/client/axis1/src/main/java/org/springframework/ws/samples/airline/client/axis1/Main.java create mode 100644 airline/client/jax-ws/.mvn/wrapper/maven-wrapper.jar create mode 100644 airline/client/jax-ws/.mvn/wrapper/maven-wrapper.properties delete mode 100644 airline/client/jax-ws/build.gradle create mode 100755 airline/client/jax-ws/mvnw create mode 100644 airline/client/jax-ws/mvnw.cmd create mode 100644 airline/client/jax-ws/pom.xml create mode 100644 airline/client/jax-ws/src/main/java/org/springframework/ws/samples/airline/client/jaxws/JaxWsMain.java delete mode 100644 airline/client/jax-ws/src/main/java/org/springframework/ws/samples/airline/client/jaxws/Main.java delete mode 100644 airline/client/jms/build.gradle create mode 100644 airline/client/jms/pom.xml create mode 100644 airline/client/jms/src/main/java/org/springframework/ws/samples/airline/client/jms/JmsConfiguration.java create mode 100644 airline/client/jms/src/main/java/org/springframework/ws/samples/airline/client/jms/JmsMain.java delete mode 100644 airline/client/jms/src/main/resources/org/springframework/ws/samples/airline/client/jms/applicationContext.xml delete mode 100644 airline/client/saaj/build.gradle create mode 100644 airline/client/saaj/pom.xml rename airline/client/saaj/src/main/java/org/springframework/ws/samples/airline/client/saaj/{Driver.java => SaajMain.java} (55%) create mode 100644 airline/client/saaj/src/main/resources/application.properties delete mode 100644 airline/client/spring-ws/build.gradle create mode 100644 airline/client/spring-ws/pom.xml delete mode 100644 airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/Driver.java create mode 100644 airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/SpringWsMain.java create mode 100644 airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/WsConfiguration.java delete mode 100644 airline/client/spring-ws/src/main/resources/org/springframework/ws/samples/airline/client/sws/applicationContext.xml delete mode 100644 airline/server/build.gradle create mode 100644 airline/server/pom.xml create mode 100644 airline/server/src/main/java/org/springframework/ws/samples/airline/AirlineServerApplication.java create mode 100644 airline/server/src/main/java/org/springframework/ws/samples/airline/dao/AirportDao.java create mode 100644 airline/server/src/main/java/org/springframework/ws/samples/airline/dao/Databaseinit.java delete mode 100644 airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/DatabaseInitializer.java delete mode 100644 airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDao.java delete mode 100644 airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDao.java delete mode 100644 airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaTicketDao.java delete mode 100644 airline/server/src/main/java/org/springframework/ws/samples/airline/domain/openjpa/DateTimeValueHandler.java delete mode 100644 airline/server/src/main/java/org/springframework/ws/samples/airline/domain/openjpa/LocalDateValueHandler.java create mode 100644 airline/server/src/main/java/org/springframework/ws/samples/airline/jms/JmsConfiguration.java create mode 100644 airline/server/src/main/java/org/springframework/ws/samples/airline/security/SecurityConfiguration.java create mode 100644 airline/server/src/main/java/org/springframework/ws/samples/airline/ws/WebServicesConfiguration.java delete mode 100644 airline/server/src/main/resources/META-INF/persistence.xml create mode 100644 airline/server/src/main/resources/application.properties delete mode 100644 airline/server/src/main/resources/log4j.properties rename airline/server/src/main/{webapp => resources}/messages.xsd (100%) delete mode 100644 airline/server/src/main/resources/org/springframework/ws/samples/airline/dao/jpa/applicationContext-jpa.xml delete mode 100644 airline/server/src/main/resources/org/springframework/ws/samples/airline/jms/applicationContext-jms.xml delete mode 100644 airline/server/src/main/resources/org/springframework/ws/samples/airline/security/applicationContext-security.xml delete mode 100644 airline/server/src/main/resources/org/springframework/ws/samples/airline/service/applicationContext.xml delete mode 100644 airline/server/src/main/resources/org/springframework/ws/samples/airline/ws/applicationContext-ws.xml create mode 100644 airline/server/src/main/resources/templates/flight.html create mode 100644 airline/server/src/main/resources/templates/flights.html create mode 100644 airline/server/src/main/resources/templates/noSuchFlight.html rename airline/server/src/main/{webapp => resources}/types.xsd (100%) delete mode 100644 airline/server/src/main/webapp/WEB-INF/jsp/error.jsp delete mode 100644 airline/server/src/main/webapp/WEB-INF/jsp/flight.jsp delete mode 100644 airline/server/src/main/webapp/WEB-INF/jsp/flights.jsp delete mode 100644 airline/server/src/main/webapp/WEB-INF/jsp/noSuchFlight.jsp delete mode 100644 airline/server/src/main/webapp/WEB-INF/mvc-servlet.xml delete mode 100644 airline/server/src/main/webapp/WEB-INF/web.xml delete mode 100644 airline/server/src/main/webapp/WEB-INF/ws-servlet.xml delete mode 100644 airline/server/src/main/webapp/index.jsp delete mode 100644 airline/server/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDaoTest.java delete mode 100644 airline/server/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDaoTest.java delete mode 100644 airline/server/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaTicketDaoTest.java delete mode 100644 airline/server/src/test/java/org/springframework/ws/samples/airline/security/SpringFrequentFlyerSecurityServiceTest.java delete mode 100644 airline/server/src/test/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImplTest.java delete mode 100644 airline/server/src/test/java/org/springframework/ws/samples/airline/web/FlightsControllerTest.java delete mode 100644 airline/server/src/test/java/org/springframework/ws/samples/airline/ws/AirlineEndpointTest.java delete mode 100644 airline/settings.gradle delete mode 100644 echo/build.gradle delete mode 100644 echo/client/saaj/build.gradle create mode 100644 echo/client/saaj/pom.xml create mode 100644 echo/client/saaj/src/main/java/org/springframework/ws/samples/echo/client/saaj/SaajEchoClient.java delete mode 100644 echo/client/spring-ws/build.gradle create mode 100644 echo/client/spring-ws/pom.xml create mode 100644 echo/client/spring-ws/src/main/java/org/springframework/ws/samples/echo/client/sws/SpringWsEchoClient.java create mode 100644 echo/client/spring-ws/src/main/resources/application.yml rename echo/client/spring-ws/src/main/resources/{org/springframework/ws/samples/echo/client/sws => }/echoRequest.xml (100%) delete mode 100644 echo/client/spring-ws/src/main/resources/log4j.properties delete mode 100644 echo/server/build.gradle create mode 100644 echo/server/pom.xml create mode 100644 echo/server/src/main/java/org/springframework/ws/samples/echo/EchoApplication.java delete mode 100644 echo/server/src/main/java/org/springframework/ws/samples/echo/config/EchoServletInitializer.java create mode 100644 echo/server/src/main/resources/application.yml delete mode 100644 echo/server/src/main/resources/log4j.properties delete mode 100644 echo/settings.gradle delete mode 100644 mtom/build.gradle delete mode 100644 mtom/client/jax-ws/build.gradle delete mode 100644 mtom/client/jax-ws/mtom.wsdl delete mode 100644 mtom/client/jax-ws/src/main/java/org/springframework/ws/samples/mtom/client/jaxws/Main.java delete mode 100644 mtom/client/spring-ws/build.gradle create mode 100644 mtom/client/spring-ws/pom.xml delete mode 100644 mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/AxiomMtomClient.java delete mode 100644 mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/Driver.java create mode 100644 mtom/client/spring-ws/src/main/resources/application.yml delete mode 100644 mtom/client/spring-ws/src/main/resources/log4j.properties rename mtom/client/{ => spring-ws/src/main/resources}/spring-ws-logo.png (100%) delete mode 100644 mtom/server/build.gradle create mode 100644 mtom/server/pom.xml create mode 100644 mtom/server/src/main/java/org/springframework/ws/samples/mtom/MtomServer.java rename mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/{ImageRepository.java => ContentRepository.java} (78%) create mode 100644 mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/ContentRepositoryImpl.java delete mode 100644 mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/StubImageRepository.java create mode 100644 mtom/server/src/main/java/org/springframework/ws/samples/mtom/ws/ContentRepositoryEndpoint.java delete mode 100644 mtom/server/src/main/java/org/springframework/ws/samples/mtom/ws/ImageRepositoryEndpoint.java create mode 100644 mtom/server/src/main/resources/application.yml create mode 100644 mtom/server/src/main/resources/contentStore.wsdl delete mode 100644 mtom/server/src/main/resources/log4j.properties delete mode 100644 mtom/server/src/main/resources/schema.xsd delete mode 100644 mtom/server/src/main/webapp/WEB-INF/web.xml delete mode 100644 mtom/settings.gradle create mode 100755 mvnw create mode 100644 mvnw.cmd create mode 100644 pom.xml delete mode 100644 stockquote/README.md delete mode 100644 stockquote/build.gradle delete mode 100644 stockquote/client/jax-ws/build.gradle delete mode 100644 stockquote/client/jax-ws/src/main/java/org/springframework/ws/samples/stockquote/client/jaxws/Main.java delete mode 100644 stockquote/client/spring-ws/build.gradle delete mode 100644 stockquote/client/spring-ws/src/main/java/org/springframework/ws/samples/stockquote/client/sws/StockClient.java delete mode 100644 stockquote/client/spring-ws/src/main/resources/log4j.properties delete mode 100644 stockquote/client/spring-ws/src/main/resources/org/springframework/ws/samples/stockquote/client/sws/quotesRequest.xml delete mode 100644 stockquote/server/build.gradle delete mode 100644 stockquote/server/src/main/java/org/springframework/ws/samples/stockquote/Driver.java delete mode 100644 stockquote/server/src/main/java/org/springframework/ws/samples/stockquote/ws/StockService.java delete mode 100644 stockquote/server/src/main/java/org/springframework/ws/samples/stockquote/ws/StockServiceConfiguration.java delete mode 100644 stockquote/server/src/main/resources/log4j.properties delete mode 100644 stockquote/server/src/main/resources/org/springframework/ws/samples/stockquote/ws/stockquote.wsdl delete mode 100644 stockquote/settings.gradle delete mode 100644 tutorial/build.gradle delete mode 100644 tutorial/gradle/wrapper/gradle-wrapper.jar delete mode 100644 tutorial/gradle/wrapper/gradle-wrapper.properties delete mode 100755 tutorial/gradlew delete mode 100644 tutorial/gradlew.bat create mode 100644 tutorial/pom.xml create mode 100644 tutorial/src/main/java/com/mycompany/hr/HrApplication.java delete mode 100644 tutorial/src/main/java/com/mycompany/hr/config/HRServletInitializer.java delete mode 100644 weather/build.gradle create mode 100644 weather/pom.xml delete mode 100644 weather/src/main/resources/log4j.properties diff --git a/.gitignore b/.gitignore index c2b1080..35cfb44 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ atlassian-ide-plugin*.xml /*/*/build /*/*/*/build .gradle + +target \ No newline at end of file diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..01e67997377a393fd672c7dcde9dccbedf0cb1e9 GIT binary patch literal 48337 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 \(.*\)$'` + 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 Mingw, 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 + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + wget "$jarUrl" -O "$wrapperJarPath" + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + curl -o "$wrapperJarPath" "$jarUrl" + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +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/airline/client/axis1/mvnw.cmd b/airline/client/axis1/mvnw.cmd new file mode 100644 index 0000000..e5cfb0a --- /dev/null +++ b/airline/client/axis1/mvnw.cmd @@ -0,0 +1,161 @@ +@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 set title of command window +title %0 +@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 + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" +FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%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/airline/client/axis1/pom.xml b/airline/client/axis1/pom.xml new file mode 100644 index 0000000..9a4df3f --- /dev/null +++ b/airline/client/axis1/pom.xml @@ -0,0 +1,173 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws-samples + 1.0.0.BUILD-SNAPSHOT + ../../../ + + + org.springframework.ws + airline-client-axis1 + 0.0.1-SNAPSHOT + Spring Web Services Samples - Airline - Client - Axis1 + Demo project for Spring Web Services + + + 1.8 + 1.4 + 1.2.16 + ${project.basedir}/target/generated-sources/axis + ${project.basedir}/target/classes + ${project.basedir}/../airline.wsdl + + + + + + axis + axis + ${axis.version} + + + + axis + axis-jaxrpc + ${axis.version} + + + + log4j + log4j + ${log4j.version} + runtime + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + axis + axis + ${axis.version} + + + axis + axis-ant + ${axis.version} + + + + + generate-sources + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + run + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.1 + + + add-source + process-sources + + add-source + + + + ${sourcesDir} + + + + + + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + + diff --git a/airline/client/axis1/src/main/java/org/springframework/ws/samples/airline/client/axis1/AxisMain.java b/airline/client/axis1/src/main/java/org/springframework/ws/samples/airline/client/axis1/AxisMain.java new file mode 100644 index 0000000..6c191ea --- /dev/null +++ b/airline/client/axis1/src/main/java/org/springframework/ws/samples/airline/client/axis1/AxisMain.java @@ -0,0 +1,99 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.samples.airline.client.axis1; + +import java.rmi.RemoteException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +import javax.xml.rpc.ServiceException; + +/** + * Simple client that calls the GetFlights and BookFlight operations using JAX-RPC (Axis 1). + * + * @author Arjen Poutsma + */ +public class AxisMain { + + public static void main(String[] args) throws ServiceException, RemoteException { + + AirlineServiceLocator service = new AirlineServiceLocator(); + if (args.length > 0) { + service.setAirlineSoap11EndpointAddress(args[0]); + } + Airline airline = service.getAirlineSoap11(); + GetFlightsRequest request = new GetFlightsRequest(); + request.setFrom("AMS"); + request.setTo("VCE"); + Calendar departureCalendar = Calendar.getInstance(); + departureCalendar.set(Calendar.YEAR, 2006); + departureCalendar.set(Calendar.MONTH, Calendar.JANUARY); + departureCalendar.set(Calendar.DATE, 31); + Date departureDate = departureCalendar.getTime(); + request.setDepartureDate(departureDate); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + System.out.println("Requesting flights on " + dateFormat.format(departureDate)); + Flight[] flights = airline.getFlights(request); + System.out.println("Got " + flights.length + " results"); + if (flights.length > 0) { + // Book the first flight using John Doe as a frequent flyer + BookFlightRequest bookFlightRequest = new BookFlightRequest(); + bookFlightRequest.setFlightNumber(flights[0].getNumber()); + bookFlightRequest.setDepartureTime(flights[0].getDepartureTime()); + BookFlightRequestPassengers passengers = new BookFlightRequestPassengers(); + passengers.setUsername("john"); + bookFlightRequest.setPassengers(passengers); + Ticket ticket = airline.bookFlight(bookFlightRequest); + writeTicket(ticket); + } + } + + private static void writeTicket(Ticket ticket) { + + System.out.println("Ticket " + ticket.getId()); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + System.out.println("Ticket issue date:\t" + dateFormat.format(ticket.getIssueDate())); + for (int i = 0; i < ticket.getPassengers().length; i++) { + writeName(ticket.getPassengers()[i]); + + } + writeFlight(ticket.getFlight()); + } + + private static void writeName(Name name) { + + System.out.println("Passenger Name:"); + System.out.println(name.getFirst() + " " + name.getLast()); + System.out.println("------------"); + } + + private static void writeFlight(Flight flight) { + + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + System.out.println(dateFormat.format(flight.getDepartureTime().getTime())); + System.out.println(flight.getNumber() + "\t" + flight.getServiceClass()); + System.out.println("------------"); + System.out.println("Depart:\t" + flight.getFrom().getCode() + "-" + flight.getFrom().getName() + "\t" + + dateFormat.format(flight.getDepartureTime().getTime())); + System.out.println("\t" + flight.getFrom().getCity()); + System.out.println("Arrive:\t" + flight.getTo().getCode() + "-" + flight.getTo().getName() + "\t" + + dateFormat.format(flight.getArrivalTime().getTime())); + System.out.println("\t" + flight.getTo().getCity()); + } + +} diff --git a/airline/client/axis1/src/main/java/org/springframework/ws/samples/airline/client/axis1/Main.java b/airline/client/axis1/src/main/java/org/springframework/ws/samples/airline/client/axis1/Main.java deleted file mode 100644 index 18c25b4..0000000 --- a/airline/client/axis1/src/main/java/org/springframework/ws/samples/airline/client/axis1/Main.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2006 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.airline.client.axis1; - -import java.rmi.RemoteException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Calendar; -import javax.xml.rpc.ServiceException; - -/** - * Simple client that calls the GetFlights and BookFlight operations using JAX-RPC (Axis 1). - * - * @author Arjen Poutsma - */ -public class Main { - - public static void main(String[] args) throws ServiceException, RemoteException { - AirlineServiceLocator service = new AirlineServiceLocator(); - if (args.length > 0) { - service.setAirlineSoap11EndpointAddress(args[0]); - } - Airline airline = service.getAirlineSoap11(); - GetFlightsRequest request = new GetFlightsRequest(); - request.setFrom("AMS"); - request.setTo("VCE"); - Calendar departureCalendar = Calendar.getInstance(); - departureCalendar.set(Calendar.YEAR, 2006); - departureCalendar.set(Calendar.MONTH, Calendar.JANUARY); - departureCalendar.set(Calendar.DATE, 31); - Date departureDate = departureCalendar.getTime(); - request.setDepartureDate(departureDate); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - System.out.println("Requesting flights on " + dateFormat.format(departureDate)); - Flight[] flights = airline.getFlights(request); - System.out.println("Got " + flights.length + " results"); - if (flights.length > 0) - { - // Book the first flight using John Doe as a frequent flyer - BookFlightRequest bookFlightRequest = new BookFlightRequest(); - bookFlightRequest.setFlightNumber(flights[0].getNumber()); - bookFlightRequest.setDepartureTime(flights[0].getDepartureTime()); - BookFlightRequestPassengers passengers = new BookFlightRequestPassengers(); - passengers.setUsername("john"); - bookFlightRequest.setPassengers(passengers); - Ticket ticket = airline.bookFlight(bookFlightRequest); - writeTicket(ticket); - } - } - - private static void writeTicket(Ticket ticket) { - System.out.println("Ticket " + ticket.getId()); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - System.out.println("Ticket issue date:\t" + dateFormat.format(ticket.getIssueDate())); - for (int i = 0; i < ticket.getPassengers().length; i++) { - writeName(ticket.getPassengers()[i]); - - } - writeFlight(ticket.getFlight()); - } - - private static void writeName(Name name) { - System.out.println("Passenger Name:"); - System.out.println(name.getFirst() + " " + name.getLast()); - System.out.println("------------"); - } - - private static void writeFlight(Flight flight) { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - System.out.println(dateFormat.format(flight.getDepartureTime().getTime())); - System.out.println(flight.getNumber() + "\t" + flight.getServiceClass()); - System.out.println("------------"); - System.out.println("Depart:\t" + flight.getFrom().getCode() + "-" + flight.getFrom().getName() + "\t" + dateFormat.format(flight.getDepartureTime().getTime())); - System.out.println("\t" + flight.getFrom().getCity()); - System.out.println("Arrive:\t" + flight.getTo().getCode() + "-" + flight.getTo().getName() + "\t" + dateFormat.format(flight.getArrivalTime().getTime())); - System.out.println("\t" + flight.getTo().getCity()); - } - - -} diff --git a/airline/client/jax-ws/.mvn/wrapper/maven-wrapper.jar b/airline/client/jax-ws/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..01e67997377a393fd672c7dcde9dccbedf0cb1e9 GIT binary patch literal 48337 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 \(.*\)$'` + 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 Mingw, 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 + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + wget "$jarUrl" -O "$wrapperJarPath" + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + curl -o "$wrapperJarPath" "$jarUrl" + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +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/airline/client/jax-ws/mvnw.cmd b/airline/client/jax-ws/mvnw.cmd new file mode 100644 index 0000000..e5cfb0a --- /dev/null +++ b/airline/client/jax-ws/mvnw.cmd @@ -0,0 +1,161 @@ +@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 set title of command window +title %0 +@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 + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" +FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%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/airline/client/jax-ws/pom.xml b/airline/client/jax-ws/pom.xml new file mode 100644 index 0000000..23ee83a --- /dev/null +++ b/airline/client/jax-ws/pom.xml @@ -0,0 +1,120 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws-samples + 1.0.0.BUILD-SNAPSHOT + ../../../ + + + org.springframework.ws + airline-client-jax-ws + 0.0.1-SNAPSHOT + Spring Web Services Samples - Airline - Client - JAX-WS + Demo project for Spring Web Services + + + 1.8 + 2.1.7 + 1.2.16 + 2.1.4.RELEASE + ${project.basedir}/target/generated-sources/jaxws + ${project.basedir}/target/classes + ${project.basedir}/../airline.wsdl + + + + + + org.springframework.ws + spring-ws-core + ${spring-ws.version} + + + + log4j + log4j + ${log4j.version} + runtime + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + com.sun.xml.ws + jaxws-tools + ${jax-ws.version} + + + com.sun + tools + 1.5.0 + system + ${env.JAVA_HOME}/lib/tools.jar + + + + + generate-sources + + + + + + + + + + + + + + + + run + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.1 + + + add-source + process-sources + + add-source + + + + ${sourcesDir} + + + + + + + + + + diff --git a/airline/client/jax-ws/src/main/java/org/springframework/ws/samples/airline/client/jaxws/JaxWsMain.java b/airline/client/jax-ws/src/main/java/org/springframework/ws/samples/airline/client/jaxws/JaxWsMain.java new file mode 100644 index 0000000..a2b31fe --- /dev/null +++ b/airline/client/jax-ws/src/main/java/org/springframework/ws/samples/airline/client/jaxws/JaxWsMain.java @@ -0,0 +1,108 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.samples.airline.client.jaxws; + +import java.net.MalformedURLException; +import java.net.URL; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; +import javax.xml.namespace.QName; +import javax.xml.ws.soap.SOAPFaultException; + +/** + * Simple client that calls the GetFlights and BookFlight operations using JAX-WS. + * + * @author Arjen Poutsma + */ +public class JaxWsMain { + + public static void main(String[] args) throws MalformedURLException, DatatypeConfigurationException { + + try { + AirlineService service; + if (args.length == 0) { + service = new AirlineService(); + } else { + QName serviceName = new QName("http://www.springframework.org/spring-ws/samples/airline/definitions", + "AirlineService"); + service = new AirlineService(new URL(args[0]), serviceName); + } + Airline airline = service.getAirlineSoap11(); + GetFlightsRequest request = new GetFlightsRequest(); + request.setFrom("AMS"); + request.setTo("VCE"); + XMLGregorianCalendar departureDate = DatatypeFactory.newInstance().newXMLGregorianCalendarDate(2006, 1, 31, + DatatypeConstants.FIELD_UNDEFINED); + request.setDepartureDate(departureDate); + System.out.format("Requesting flights on %1tD%n", departureDate.toGregorianCalendar()); + GetFlightsResponse response = airline.getFlights(request); + System.out.format("Got %1d results%n", response.getFlight().size()); + if (!response.getFlight().isEmpty()) + // Book the first flight using John Doe as a frequent flyer + { + Flight flight = response.getFlight().get(0); + BookFlightRequest bookFlightRequest = new BookFlightRequest(); + bookFlightRequest.setFlightNumber(flight.getNumber()); + bookFlightRequest.setDepartureTime(flight.getDepartureTime()); + BookFlightRequest.Passengers passengers = new BookFlightRequest.Passengers(); + passengers.getPassengerOrUsername().add("john"); + bookFlightRequest.setPassengers(passengers); + Ticket ticket = airline.bookFlight(bookFlightRequest); + writeTicket(ticket); + } + } catch (SOAPFaultException ex) { + System.out.format("SOAP Fault Code %1s%n", ex.getFault().getFaultCodeAsQName()); + System.out.format("SOAP Fault String: %1s%n", ex.getFault().getFaultString()); + + } + } + + private static void writeTicket(Ticket ticket) { + + System.out.format("Ticket %1d%n", ticket.getId()); + System.out.format("Ticket issue date:\t%1tD%n", ticket.getIssueDate().toGregorianCalendar()); + for (Name passenger : ticket.getPassengers().getPassenger()) { + writeName(passenger); + + } + writeFlight(ticket.flight); + } + + private static void writeName(Name name) { + + System.out.format("Passenger Name:%n"); + System.out.format("%1s %2s%n", name.getFirst(), name.getLast()); + System.out.format("------------%n"); + } + + private static void writeFlight(Flight flight) { + + System.out.format("%1tD%n", flight.getDepartureTime().toGregorianCalendar()); + System.out.format("%1s\t%2s%n", flight.getNumber(), flight.getServiceClass()); + System.out.format("------------%n"); + System.out.format("Depart:\t%1s-%2s\t%tR%n", flight.getFrom().getCode(), flight.getFrom().getName(), + flight.getDepartureTime().toGregorianCalendar()); + System.out.format("\t%1s%n", flight.getFrom().getCity()); + System.out.format("Arrive:\t%1s-%2s\t%tR%n", flight.getTo().getCode(), flight.getTo().getName(), + flight.getArrivalTime().toGregorianCalendar()); + System.out.format("\t%1s%n", flight.getTo().getCity()); + } + +} diff --git a/airline/client/jax-ws/src/main/java/org/springframework/ws/samples/airline/client/jaxws/Main.java b/airline/client/jax-ws/src/main/java/org/springframework/ws/samples/airline/client/jaxws/Main.java deleted file mode 100644 index 12e2d2b..0000000 --- a/airline/client/jax-ws/src/main/java/org/springframework/ws/samples/airline/client/jaxws/Main.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2006 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.airline.client.jaxws; - -import java.net.MalformedURLException; -import java.net.URL; -import javax.xml.datatype.DatatypeConfigurationException; -import javax.xml.datatype.DatatypeConstants; -import javax.xml.datatype.DatatypeFactory; -import javax.xml.datatype.XMLGregorianCalendar; -import javax.xml.namespace.QName; -import javax.xml.ws.soap.SOAPFaultException; - -/** - * Simple client that calls the GetFlights and BookFlight operations using JAX-WS. - * - * @author Arjen Poutsma - */ -public class Main { - - public static void main(String[] args) throws MalformedURLException, DatatypeConfigurationException { - try { - AirlineService service; - if (args.length == 0) { - service = new AirlineService(); - } - else { - QName serviceName = new QName("http://www.springframework.org/spring-ws/samples/airline/definitions", - "AirlineService"); - service = new AirlineService(new URL(args[0]), serviceName); - } - Airline airline = service.getAirlineSoap11(); - GetFlightsRequest request = new GetFlightsRequest(); - request.setFrom("AMS"); - request.setTo("VCE"); - XMLGregorianCalendar departureDate = - DatatypeFactory.newInstance().newXMLGregorianCalendarDate(2006, 1, 31, - DatatypeConstants.FIELD_UNDEFINED); - request.setDepartureDate(departureDate); - System.out.format("Requesting flights on %1tD%n", departureDate.toGregorianCalendar()); - GetFlightsResponse response = airline.getFlights(request); - System.out.format("Got %1d results%n", response.getFlight().size()); - if (!response.getFlight().isEmpty()) - // Book the first flight using John Doe as a frequent flyer - { - Flight flight = response.getFlight().get(0); - BookFlightRequest bookFlightRequest = new BookFlightRequest(); - bookFlightRequest.setFlightNumber(flight.getNumber()); - bookFlightRequest.setDepartureTime(flight.getDepartureTime()); - BookFlightRequest.Passengers passengers = new BookFlightRequest.Passengers(); - passengers.getPassengerOrUsername().add("john"); - bookFlightRequest.setPassengers(passengers); - Ticket ticket = airline.bookFlight(bookFlightRequest); - writeTicket(ticket); - } - } - catch (SOAPFaultException ex) { - System.out.format("SOAP Fault Code %1s%n", ex.getFault().getFaultCodeAsQName()); - System.out.format("SOAP Fault String: %1s%n", ex.getFault().getFaultString()); - - } - } - - private static void writeTicket(Ticket ticket) { - System.out.format("Ticket %1d%n", ticket.getId()); - System.out.format("Ticket issue date:\t%1tD%n", ticket.getIssueDate().toGregorianCalendar()); - for (Name passenger : ticket.getPassengers().getPassenger()) { - writeName(passenger); - - } - writeFlight(ticket.flight); - } - - private static void writeName(Name name) { - System.out.format("Passenger Name:%n"); - System.out.format("%1s %2s%n", name.getFirst(), name.getLast()); - System.out.format("------------%n"); - } - - private static void writeFlight(Flight flight) { - System.out.format("%1tD%n", flight.getDepartureTime().toGregorianCalendar()); - System.out.format("%1s\t%2s%n", flight.getNumber(), flight.getServiceClass()); - System.out.format("------------%n"); - System.out.format("Depart:\t%1s-%2s\t%tR%n", flight.getFrom().getCode(), flight.getFrom().getName(), flight.getDepartureTime().toGregorianCalendar()); - System.out.format("\t%1s%n", flight.getFrom().getCity()); - System.out.format("Arrive:\t%1s-%2s\t%tR%n", flight.getTo().getCode(), flight.getTo().getName(), flight.getArrivalTime().toGregorianCalendar()); - System.out.format("\t%1s%n", flight.getTo().getCity()); - } - -} diff --git a/airline/client/jms/build.gradle b/airline/client/jms/build.gradle deleted file mode 100644 index e2cf3a8..0000000 --- a/airline/client/jms/build.gradle +++ /dev/null @@ -1,14 +0,0 @@ -ext.springWsVersion = '2.1.4.RELEASE' - -dependencies { - compile("org.springframework.ws:spring-ws-core:$springWsVersion") - compile("org.springframework.ws:spring-ws-support:$springWsVersion") - compile("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1") - runtime("log4j:log4j:1.2.16") - runtime("org.apache.activemq:activemq-core:4.1.2") -} - -task runClient(dependsOn: 'classes', type:JavaExec) { - main = "org.springframework.ws.samples.airline.client.jms.JmsClient" - classpath = sourceSets.main.runtimeClasspath -} \ No newline at end of file diff --git a/airline/client/jms/pom.xml b/airline/client/jms/pom.xml new file mode 100644 index 0000000..985c24e --- /dev/null +++ b/airline/client/jms/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws-samples + 1.0.0.BUILD-SNAPSHOT + ../../../ + + + org.springframework.ws + airline-client-jms + 0.0.1-SNAPSHOT + Spring Web Services Samples - Airline - Client - JMS + Demo project for Spring Web Services + + + 4.1.2 + 1.8 + 1.1 + 1.2.16 + ${project.basedir}/target/generated-sources/jaxws + ${project.basedir}/target/classes + ${project.basedir}/../airline.wsdl + + + + + + org.springframework.ws + spring-ws-core + + + + org.springframework.ws + spring-ws-support + + + + org.apache.geronimo.specs + geronimo-jms_1.1_spec + ${jms.version} + + + + log4j + log4j + ${log4j.version} + runtime + + + + org.apache.activemq + activemq-core + ${activemq.version} + + + + + diff --git a/airline/client/jms/src/main/java/org/springframework/ws/samples/airline/client/jms/JmsClient.java b/airline/client/jms/src/main/java/org/springframework/ws/samples/airline/client/jms/JmsClient.java index 34c5f68..9a3570e 100644 --- a/airline/client/jms/src/main/java/org/springframework/ws/samples/airline/client/jms/JmsClient.java +++ b/airline/client/jms/src/main/java/org/springframework/ws/samples/airline/client/jms/JmsClient.java @@ -16,10 +16,6 @@ package org.springframework.ws.samples.airline.client.jms; -import java.io.IOException; -import javax.jms.JMSException; -import javax.xml.soap.SOAPException; -import javax.xml.transform.TransformerException; import javax.xml.transform.stream.StreamResult; import org.springframework.context.ApplicationContext; @@ -30,19 +26,11 @@ import org.springframework.xml.transform.StringSource; /** @author Arjen Poutsma */ public class JmsClient extends WebServiceGatewaySupport { - private static final String PAYLOAD = - "" + - "AMS" + "VCE" + - "2006-01-31" + ""; + private static final String PAYLOAD = "" + + "AMS" + "VCE" + + "2006-01-31" + ""; - public void getFlights() throws SOAPException, IOException, TransformerException, JMSException { - getWebServiceTemplate().sendSourceAndReceiveToResult(new StringSource(PAYLOAD), new StreamResult(System.out)); - } - - public static void main(String[] args) throws Exception { - ApplicationContext applicationContext = - new ClassPathXmlApplicationContext("applicationContext.xml", JmsClient.class); - JmsClient jmsClient = (JmsClient) applicationContext.getBean("jmsClient", JmsClient.class); - jmsClient.getFlights(); - } -} \ No newline at end of file + public void getFlights() { + getWebServiceTemplate().sendSourceAndReceiveToResult(new StringSource(PAYLOAD), new StreamResult(System.out)); + } +} diff --git a/airline/client/jms/src/main/java/org/springframework/ws/samples/airline/client/jms/JmsConfiguration.java b/airline/client/jms/src/main/java/org/springframework/ws/samples/airline/client/jms/JmsConfiguration.java new file mode 100644 index 0000000..7ef3376 --- /dev/null +++ b/airline/client/jms/src/main/java/org/springframework/ws/samples/airline/client/jms/JmsConfiguration.java @@ -0,0 +1,52 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.samples.airline.client.jms; + +import javax.jms.ConnectionFactory; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.ws.transport.jms.JmsMessageSender; + +/** + * Java configuration for setting up a JMS-based client. + * + * @author Greg Turnquist + */ +@Configuration(proxyBeanMethods = false) +public class JmsConfiguration { + + @Bean + ConnectionFactory connectionFactory() { + return new ActiveMQConnectionFactory("tcp://localhost:61616"); + } + + @Bean + JmsMessageSender jmsMessageSender(ConnectionFactory connectionFactory) { + return new JmsMessageSender(connectionFactory); + } + + @Bean + JmsClient jmsClient(JmsMessageSender messageSender) { + + JmsClient jmsClient = new JmsClient(); + jmsClient.setDefaultUri("jms:RequestQueue"); + jmsClient.setMessageSender(messageSender); + return jmsClient; + } +} diff --git a/airline/client/jms/src/main/java/org/springframework/ws/samples/airline/client/jms/JmsMain.java b/airline/client/jms/src/main/java/org/springframework/ws/samples/airline/client/jms/JmsMain.java new file mode 100644 index 0000000..2257462 --- /dev/null +++ b/airline/client/jms/src/main/java/org/springframework/ws/samples/airline/client/jms/JmsMain.java @@ -0,0 +1,34 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.samples.airline.client.jms; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * "Main" that creates a {@link JmsClient} and uses it to talk to the SOAP-based server. + * + * @author Greg Turnquist + */ +public class JmsMain { + + public static void main(String[] args) { + + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JmsConfiguration.class); + + ctx.getBean(JmsClient.class).getFlights(); + } +} diff --git a/airline/client/jms/src/main/resources/org/springframework/ws/samples/airline/client/jms/applicationContext.xml b/airline/client/jms/src/main/resources/org/springframework/ws/samples/airline/client/jms/applicationContext.xml deleted file mode 100644 index 11067d7..0000000 --- a/airline/client/jms/src/main/resources/org/springframework/ws/samples/airline/client/jms/applicationContext.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/airline/client/saaj/build.gradle b/airline/client/saaj/build.gradle deleted file mode 100644 index ef6d75d..0000000 --- a/airline/client/saaj/build.gradle +++ /dev/null @@ -1,10 +0,0 @@ -dependencies { - compile("com.sun.xml.wss:xws-security:3.0") { - exclude group: 'javax.xml.crypto', module: 'xmldsig' - } -} - -task runClient(dependsOn: 'classes', type:JavaExec) { - main = "org.springframework.ws.samples.airline.client.saaj.Driver" - classpath = sourceSets.main.runtimeClasspath -} \ No newline at end of file diff --git a/airline/client/saaj/pom.xml b/airline/client/saaj/pom.xml new file mode 100644 index 0000000..eb56b3a --- /dev/null +++ b/airline/client/saaj/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws-samples + 1.0.0.BUILD-SNAPSHOT + ../../../ + + + org.springframework.ws + airline-client-saaj + 0.0.1-SNAPSHOT + Spring Web Services Samples - Airline - Client - SAAJ + Demo project for Spring Web Services + + + 1.8 + 3.0 + + + + + + org.slf4j + slf4j-api + + + + com.sun.xml.wss + xws-security + ${xws.version} + + + javax.xml.crypto + xmldsig + + + javax.activation + activation + + + + + + + + + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + + diff --git a/airline/client/saaj/src/main/java/org/springframework/ws/samples/airline/client/saaj/Driver.java b/airline/client/saaj/src/main/java/org/springframework/ws/samples/airline/client/saaj/SaajMain.java similarity index 55% rename from airline/client/saaj/src/main/java/org/springframework/ws/samples/airline/client/saaj/Driver.java rename to airline/client/saaj/src/main/java/org/springframework/ws/samples/airline/client/saaj/SaajMain.java index dc5459b..074d48f 100644 --- a/airline/client/saaj/src/main/java/org/springframework/ws/samples/airline/client/saaj/Driver.java +++ b/airline/client/saaj/src/main/java/org/springframework/ws/samples/airline/client/saaj/SaajMain.java @@ -16,23 +16,32 @@ package org.springframework.ws.samples.airline.client.saaj; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * @author Arjen Poutsma */ -public class Driver { +public class SaajMain { + + private static final Logger logger = LoggerFactory.getLogger(SaajMain.class); + + public static void main(String[] args) throws Exception { + + String url = "http://localhost:8080/airline-server/services"; + if (args.length > 0) { + url = args[0]; + } + + logger.info("Connecting to " + url + " for flight details..."); - public static void main(String[] args) throws Exception { - String url = "http://localhost:8080/airline-server/services"; - if (args.length > 0) { - url = args[0]; - } GetFlights getFlights = new GetFlights(url); - getFlights.getFlights(); + getFlights.getFlights(); - String username = "john"; - String password = "changeme"; - GetFrequentFlyerMileage getMileage = new GetFrequentFlyerMileage(url); - getMileage.getMileage(username, password); - } + String username = "john"; + String password = "changeme"; + GetFrequentFlyerMileage getMileage = new GetFrequentFlyerMileage(url); + getMileage.getMileage(username, password); + } } diff --git a/airline/client/saaj/src/main/resources/application.properties b/airline/client/saaj/src/main/resources/application.properties new file mode 100644 index 0000000..21c84be --- /dev/null +++ b/airline/client/saaj/src/main/resources/application.properties @@ -0,0 +1,4 @@ +logging.level.org.springframework.ws=TRACE +logging.level.javax.xml.soap=TRACE +logging.level.com.sun.xml=TRACE +logging.level.javax.security.auth=TRACE diff --git a/airline/client/saaj/src/main/resources/org/springframework/ws/samples/airline/client/saaj/securityPolicy.xml b/airline/client/saaj/src/main/resources/org/springframework/ws/samples/airline/client/saaj/securityPolicy.xml index 195eb98..8509073 100644 --- a/airline/client/saaj/src/main/resources/org/springframework/ws/samples/airline/client/saaj/securityPolicy.xml +++ b/airline/client/saaj/src/main/resources/org/springframework/ws/samples/airline/client/saaj/securityPolicy.xml @@ -1,3 +1,3 @@ - + diff --git a/airline/client/spring-ws/build.gradle b/airline/client/spring-ws/build.gradle deleted file mode 100644 index 8f86aa7..0000000 --- a/airline/client/spring-ws/build.gradle +++ /dev/null @@ -1,46 +0,0 @@ -configurations { - xmlbeans -} - -ext.springWsVersion = '2.1.4.RELEASE' - -task xmlbeans { - ext.schema = "${projectDir}/../../server/src/main/webapp/messages.xsd" - ext.classesDir = "${buildDir}/classes/xmlbeans" - - inputs.files schema - outputs.dir classesDir - - doLast() { - project.ant { - taskdef name: "xmlbeans", - classname: "org.apache.xmlbeans.impl.tool.XMLBean", - classpath: configurations.xmlbeans.asPath - - xmlbeans(classgendir: classesDir, schema: schema, - compiler: "modern", verbose: "false", - classpath: configurations.xmlbeans.asPath) - } - } -} - -dependencies { - compile(files(xmlbeans.classesDir).builtBy(xmlbeans)) - compile("org.apache.xmlbeans:xmlbeans:2.4.0") - compile("org.springframework.ws:spring-ws-core:$springWsVersion") - runtime("org.springframework.ws:spring-ws-security:$springWsVersion") { - exclude group: 'com.sun.xml.wsit', module: 'wsit-rt' - exclude group: 'com.sun.xml.wsit', module: 'xws-security' - } - runtime("com.sun.xml.wss:xws-security:3.0") { - exclude group: 'javax.xml.crypto', module: 'xmldsig' - } - runtime("log4j:log4j:1.2.16") - testCompile("org.springframework.ws:spring-ws-test:$springWsVersion") - xmlbeans("org.apache.xmlbeans:xmlbeans:2.4.0") -} - -task runClient(dependsOn: 'classes', type:JavaExec) { - main = "org.springframework.ws.samples.airline.client.sws.Driver" - classpath = sourceSets.main.runtimeClasspath -} \ No newline at end of file diff --git a/airline/client/spring-ws/pom.xml b/airline/client/spring-ws/pom.xml new file mode 100644 index 0000000..eaeef37 --- /dev/null +++ b/airline/client/spring-ws/pom.xml @@ -0,0 +1,135 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws-samples + 1.0.0.BUILD-SNAPSHOT + ../../../ + + + org.springframework.ws + airline-client-spring-ws + 0.0.1-SNAPSHOT + Spring Web Services Samples - Airline - Client - Spring WS + Demo project for Spring Web Services + + + 1.8 + 2.1.7 + 1.2.16 + 2.4.0 + 3.0 + ${project.basedir}/target/generated-sources/xjc + ${project.basedir}/target/classes + ${project.basedir}/../../server/src/main/resources + ${project.basedir}/../airline.wsdl + + + + + + org.springframework.ws + spring-ws-core + + + + org.springframework.ws + spring-ws-security + + + com.sun.xml.wsit + wsit-rt + + + com.sun.xml.wsit + xws-security + + + + + + com.sun.xml.wss + xws-security + ${xws.version} + runtime + + + javax.xml.crypto + xmldsig + + + javax.activation + activation + + + + + + log4j + log4j + ${log4j.version} + runtime + + + + org.springframework.ws + spring-ws-test + test + + + + + + + + + + org.jvnet.jaxb2.maven2 + maven-jaxb2-plugin + 0.14.0 + + + + generate + + + + + WSDL + org.springframework.springWs.samples.airline.schemas + + + ${wsdl} + + + true + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.1 + + + add-source + process-sources + + add-source + + + + ${sourcesDir} + + + + + + + + + + diff --git a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/Driver.java b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/Driver.java deleted file mode 100644 index dc2d350..0000000 --- a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/Driver.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2005-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. - */ - -package org.springframework.ws.samples.airline.client.sws; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -/** - * @author Arjen Poutsma - */ -public class Driver { - - public static void main(String[] args) { - ApplicationContext applicationContext = new ClassPathXmlApplicationContext( - "org/springframework/ws/samples/airline/client/sws/applicationContext.xml"); - GetFlights getFlights = applicationContext.getBean("getFlights", GetFlights.class); - getFlights.getFlights(); - - GetFrequentFlyerMileage getFrequentFlyerMileage = applicationContext - .getBean("getFrequentFlyerMileage", GetFrequentFlyerMileage.class); - getFrequentFlyerMileage.getFrequentFlyerMileage(); - - } - -} diff --git a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFlights.java b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFlights.java index a2d3ef5..e542e28 100644 --- a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFlights.java +++ b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFlights.java @@ -16,87 +16,87 @@ package org.springframework.ws.samples.airline.client.sws; -import java.text.SimpleDateFormat; -import java.util.Calendar; +import javax.xml.bind.JAXBElement; +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; -import org.springframework.springWs.samples.airline.schemas.messages.BookFlightRequestDocument; -import org.springframework.springWs.samples.airline.schemas.messages.BookFlightResponseDocument; -import org.springframework.springWs.samples.airline.schemas.messages.GetFlightsRequestDocument; -import org.springframework.springWs.samples.airline.schemas.messages.GetFlightsResponseDocument; -import org.springframework.springWs.samples.airline.schemas.types.Flight; -import org.springframework.springWs.samples.airline.schemas.types.Name; -import org.springframework.springWs.samples.airline.schemas.types.Ticket; +import org.springframework.springWs.samples.airline.schemas.BookFlightRequest; +import org.springframework.springWs.samples.airline.schemas.Flight; +import org.springframework.springWs.samples.airline.schemas.GetFlightsRequest; +import org.springframework.springWs.samples.airline.schemas.GetFlightsResponse; +import org.springframework.springWs.samples.airline.schemas.Name; +import org.springframework.springWs.samples.airline.schemas.Ticket; +import org.springframework.stereotype.Service; import org.springframework.ws.WebServiceMessageFactory; import org.springframework.ws.client.core.support.WebServiceGatewaySupport; public class GetFlights extends WebServiceGatewaySupport { - public GetFlights(WebServiceMessageFactory messageFactory) { - super(messageFactory); - } + public GetFlights(WebServiceMessageFactory messageFactory) { + super(messageFactory); + } - public void getFlights() { - GetFlightsRequestDocument getFlightsRequestDocument = GetFlightsRequestDocument.Factory.newInstance(); - GetFlightsRequestDocument.GetFlightsRequest getFlightsRequest = - getFlightsRequestDocument.addNewGetFlightsRequest(); - getFlightsRequest.setFrom("AMS"); - getFlightsRequest.setTo("VCE"); - Calendar departureDate = Calendar.getInstance(); - departureDate.clear(); - departureDate.set(2006, Calendar.JANUARY, 31); - getFlightsRequest.setDepartureDate(departureDate); + public void getFlights() { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - System.out.println("Requesting flights on " + dateFormat.format(departureDate.getTime())); - GetFlightsResponseDocument getFlightsResponseDocument = - (GetFlightsResponseDocument) getWebServiceTemplate().marshalSendAndReceive(getFlightsRequestDocument); - GetFlightsResponseDocument.GetFlightsResponse response = getFlightsResponseDocument.getGetFlightsResponse(); - System.out.println("Got " + response.sizeOfFlightArray() + " results"); - if (response.sizeOfFlightArray() > 0) { - // Book the first flight using John Doe as a frequent flyer - BookFlightRequestDocument bookFlightRequestDocument = BookFlightRequestDocument.Factory.newInstance(); - BookFlightRequestDocument.BookFlightRequest bookFlightRequest = - bookFlightRequestDocument.addNewBookFlightRequest(); - bookFlightRequest.setFlightNumber(response.getFlightArray(0).getNumber()); - bookFlightRequest.setDepartureTime(response.getFlightArray(0).getDepartureTime()); - BookFlightRequestDocument.BookFlightRequest.Passengers passengers = bookFlightRequest.addNewPassengers(); - passengers.addUsername("john"); + GetFlightsRequest getFlightsRequest = new GetFlightsRequest(); + getFlightsRequest.setFrom("AMS"); + getFlightsRequest.setTo("VCE"); + XMLGregorianCalendar departureDate = null; + try { + departureDate = DatatypeFactory.newInstance().newXMLGregorianCalendarDate(2006, 1, 31, + DatatypeConstants.FIELD_UNDEFINED); + } catch (DatatypeConfigurationException e) { + throw new RuntimeException(e); + } - BookFlightResponseDocument bookFlightResponseDocument = (BookFlightResponseDocument) getWebServiceTemplate() - .marshalSendAndReceive(bookFlightRequestDocument); - Ticket ticket = bookFlightResponseDocument.getBookFlightResponse(); - writeTicket(ticket); - } - } + getFlightsRequest.setDepartureDate(departureDate); - private void writeTicket(Ticket ticket) { - System.out.println("Ticket " + ticket.getId()); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - System.out.println("Ticket issue date:\t" + dateFormat.format(ticket.getIssueDate().getTime())); - for (int i = 0; i < ticket.getPassengers().sizeOfPassengerArray(); i++) { - writeName(ticket.getPassengers().getPassengerArray(i)); + System.out.println("Requesting flights on " + departureDate); + GetFlightsResponse response = (GetFlightsResponse) getWebServiceTemplate().marshalSendAndReceive(getFlightsRequest); + System.out.println("Got " + response.getFlight().size() + " results"); + if (response.getFlight().size() > 0) { + // Book the first flight using John Doe as a frequent flyer + BookFlightRequest bookFlightRequest = new BookFlightRequest(); + bookFlightRequest.setFlightNumber(response.getFlight().get(0).getNumber()); + bookFlightRequest.setDepartureTime(response.getFlight().get(0).getDepartureTime()); + BookFlightRequest.Passengers passengers = new BookFlightRequest.Passengers(); + passengers.getPassengerOrUsername().add("john"); + bookFlightRequest.setPassengers(passengers); - } - writeFlight(ticket.getFlight()); - } + JAXBElement ticket = (JAXBElement) getWebServiceTemplate() + .marshalSendAndReceive(bookFlightRequest); - private void writeName(Name name) { - System.out.println("Passenger Name:"); - System.out.println(name.getFirst() + " " + name.getLast()); - System.out.println("------------"); - } + writeTicket(ticket.getValue()); + } + } - private void writeFlight(Flight flight) { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - System.out.println(dateFormat.format(flight.getDepartureTime().getTime())); - System.out.println(flight.getNumber() + "\t" + flight.getServiceClass()); - System.out.println("------------"); - System.out.println("Depart:\t" + flight.getFrom().getCode() + "-" + flight.getFrom().getName() + "\t" + - dateFormat.format(flight.getDepartureTime().getTime())); - System.out.println("\t" + flight.getFrom().getCity()); - System.out.println("Arrive:\t" + flight.getTo().getCode() + "-" + flight.getTo().getName() + "\t" + - dateFormat.format(flight.getArrivalTime().getTime())); - System.out.println("\t" + flight.getTo().getCity()); - } + private void writeTicket(Ticket ticket) { + System.out.println("Ticket " + ticket.getId()); + System.out.println("Ticket issue date:\t" + ticket.getIssueDate()); + ticket.getPassengers().getPassenger().forEach(this::writeName); + writeFlight(ticket.getFlight()); + } + + private void writeName(Name name) { + + System.out.println("Passenger Name:"); + System.out.println(name.getFirst() + " " + name.getLast()); + System.out.println("------------"); + } + + private void writeFlight(Flight flight) { + + System.out.println(flight.getDepartureTime()); + System.out.println(flight.getNumber() + "\t" + flight.getServiceClass()); + System.out.println("------------"); + System.out.println( + "Depart:\t" + flight.getFrom().getCode() + "-" + flight.getFrom().getName() + "\t" + flight.getDepartureTime()); + System.out.println("\t" + flight.getFrom().getCity()); + System.out.println( + "Arrive:\t" + flight.getTo().getCode() + "-" + flight.getTo().getName() + "\t" + flight.getArrivalTime()); + System.out.println("\t" + flight.getTo().getCity()); + } } diff --git a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFrequentFlyerMileage.java b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFrequentFlyerMileage.java index 99021bc..be0aafe 100644 --- a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFrequentFlyerMileage.java +++ b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFrequentFlyerMileage.java @@ -25,16 +25,17 @@ import org.springframework.xml.transform.StringSource; public class GetFrequentFlyerMileage extends WebServiceGatewaySupport { - public GetFrequentFlyerMileage(WebServiceMessageFactory messageFactory) { - super(messageFactory); - } + public GetFrequentFlyerMileage(WebServiceMessageFactory messageFactory) { + super(messageFactory); + } - public void getFrequentFlyerMileage() { - Source source = new StringSource( - ""); + public void getFrequentFlyerMileage() { - getWebServiceTemplate().sendSourceAndReceiveToResult(source, new StreamResult(System.out)); + Source source = new StringSource( + ""); - } + getWebServiceTemplate().sendSourceAndReceiveToResult(source, new StreamResult(System.out)); + + } } diff --git a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/SpringWsMain.java b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/SpringWsMain.java new file mode 100644 index 0000000..6e91a54 --- /dev/null +++ b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/SpringWsMain.java @@ -0,0 +1,36 @@ +/* + * Copyright 2005-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. + */ + +package org.springframework.ws.samples.airline.client.sws; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * @author Arjen Poutsma + */ +public class SpringWsMain { + + public static void main(String[] args) { + + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(WsConfiguration.class); + + GetFlights getFlights = ctx.getBean(GetFlights.class); + getFlights.getFlights(); + + GetFrequentFlyerMileage getFrequentFlyerMileage = ctx.getBean(GetFrequentFlyerMileage.class); + getFrequentFlyerMileage.getFrequentFlyerMileage(); + } +} diff --git a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/WsConfiguration.java b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/WsConfiguration.java new file mode 100644 index 0000000..de35db2 --- /dev/null +++ b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/WsConfiguration.java @@ -0,0 +1,56 @@ +package org.springframework.ws.samples.airline.client.sws; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.oxm.jaxb.Jaxb2Marshaller; +import org.springframework.ws.soap.SoapMessageFactory; +import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; +import org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor; + +@Configuration(proxyBeanMethods = false) +public class WsConfiguration { + + @Bean + SoapMessageFactory messageFactory() { + return new SaajSoapMessageFactory(); + } + + @Bean + Jaxb2Marshaller marshaller() { + + Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); + marshaller.setPackagesToScan("org.springframework.springWs.samples.airline.schemas"); + return marshaller; + } + + @Bean + GetFlights getFlights(SoapMessageFactory messageFactory, Jaxb2Marshaller marshaller) { + + GetFlights getFlights = new GetFlights(messageFactory); + getFlights.setDefaultUri("http://localhost:8080/airline-server/services"); + getFlights.setMarshaller(marshaller); + getFlights.setUnmarshaller(marshaller); + return getFlights; + } + + @Bean + GetFrequentFlyerMileage getFrequentFlyerMileage(SoapMessageFactory messageFactory, + Wss4jSecurityInterceptor securityInterceptor) { + + GetFrequentFlyerMileage getFrequentFlyerMileage = new GetFrequentFlyerMileage(messageFactory); + getFrequentFlyerMileage.setDefaultUri("http://localhost:8080/airline-server/services"); + getFrequentFlyerMileage.setInterceptors(new Wss4jSecurityInterceptor[] { securityInterceptor }); + return getFrequentFlyerMileage; + } + + @Bean + Wss4jSecurityInterceptor securityInterceptor() { + + Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor(); + interceptor.setSecurementActions("UsernameToken"); + interceptor.setSecurementUsername("john"); + interceptor.setSecurementPassword("changeme"); + return interceptor; + } + +} diff --git a/airline/client/spring-ws/src/main/resources/org/springframework/ws/samples/airline/client/sws/applicationContext.xml b/airline/client/spring-ws/src/main/resources/org/springframework/ws/samples/airline/client/sws/applicationContext.xml deleted file mode 100644 index 21a31df..0000000 --- a/airline/client/spring-ws/src/main/resources/org/springframework/ws/samples/airline/client/sws/applicationContext.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/airline/client/spring-ws/src/test/java/org/springframework/ws/samples/airline/client/sws/GetFlightsTest.java b/airline/client/spring-ws/src/test/java/org/springframework/ws/samples/airline/client/sws/GetFlightsTest.java index 39eff19..d0cce92 100644 --- a/airline/client/spring-ws/src/test/java/org/springframework/ws/samples/airline/client/sws/GetFlightsTest.java +++ b/airline/client/spring-ws/src/test/java/org/springframework/ws/samples/airline/client/sws/GetFlightsTest.java @@ -16,85 +16,78 @@ package org.springframework.ws.samples.airline.client.sws; -import java.util.Collections; -import java.util.Map; -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 org.springframework.ws.test.client.MockWebServiceServer; import static org.springframework.ws.test.client.RequestMatchers.*; import static org.springframework.ws.test.client.ResponseCreators.*; +import java.util.Collections; +import java.util.Map; + +import javax.xml.transform.Source; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.ws.test.client.MockWebServiceServer; +import org.springframework.xml.transform.StringSource; /** * This test illustrates the use of the client-side testing API, introduced in Spring-WS 2.0. * * @author Arjen Poutsma */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration("applicationContext.xml") +@ExtendWith(SpringExtension.class) +@Import(WsConfiguration.class) public class GetFlightsTest { - @Autowired - GetFlights getFlights; - - private MockWebServiceServer mockServer; + @Autowired GetFlights getFlights; - private static final String MESSAGES_NS = - "http://www.springframework.org/spring-ws/samples/airline/schemas/messages"; + private MockWebServiceServer mockServer; - private static final String TYPES_NS = "http://www.springframework.org/spring-ws/samples/airline/schemas/types"; + private static final String MESSAGES_NS = "http://www.springframework.org/spring-ws/samples/airline/schemas/messages"; - @Before - public void setUpMocks() throws Exception { - mockServer = MockWebServiceServer.createServer(getFlights); - } + private static final String TYPES_NS = "http://www.springframework.org/spring-ws/samples/airline/schemas/types"; - @Test - public void getFlights() throws Exception { - Source getFlightsRequest = new StringSource( - "" + "AMS" + "VCE" + - "2006-01-31" + ""); + @BeforeEach + public void setUpMocks() { + mockServer = MockWebServiceServer.createServer(getFlights); + } - String flightInfo = - "KL1653" + "2006-01-31T10:05:00.000+01:00" + - "AMSSchiphol AirportAmsterdam" + - "2006-01-31T12:25:00.000+01:00" + - "VCEMarco Polo AirportVenice" + - "economy"; + @Test + public void getFlights() { - Source getFlightsResponse = new StringSource( - "" + "" + - flightInfo + "" + ""); + Source getFlightsRequest = new StringSource("" + "AMS" + + "VCE" + "2006-01-31" + ""); - mockServer.expect(payload(getFlightsRequest)).andRespond(withPayload(getFlightsResponse)); + String flightInfo = "KL1653" + + "2006-01-31T10:05:00.000+01:00" + + "AMSSchiphol AirportAmsterdam" + + "2006-01-31T12:25:00.000+01:00" + + "VCEMarco Polo AirportVenice" + + "economy"; - Source bookFlightResponse = new StringSource( - "" + "4" + - "2010-07-28" + - "JohnDoe" + - "" + flightInfo + "" + ""); + Source getFlightsResponse = new StringSource("" + "" + flightInfo + "" + ""); - Map namespaces = Collections.singletonMap("m", MESSAGES_NS); + mockServer.expect(payload(getFlightsRequest)).andRespond(withPayload(getFlightsResponse)); - mockServer.expect(xpath("/m:BookFlightRequest/m:flightNumber", namespaces).exists()) - .andExpect(xpath("/m:BookFlightRequest/m:departureTime", namespaces).exists()) - .andExpect(xpath("/m:BookFlightRequest/m:passengers", namespaces).exists()) - .andRespond(withPayload(bookFlightResponse)); + Source bookFlightResponse = new StringSource("" + "4" + "2010-07-28" + + "JohnDoe" + + "" + flightInfo + "" + ""); - getFlights.getFlights(); + Map namespaces = Collections.singletonMap("m", MESSAGES_NS); - mockServer.verify(); + mockServer.expect(xpath("/m:BookFlightRequest/m:flightNumber", namespaces).exists()) + .andExpect(xpath("/m:BookFlightRequest/m:departureTime", namespaces).exists()) + .andExpect(xpath("/m:BookFlightRequest/m:passengers", namespaces).exists()) + .andRespond(withPayload(bookFlightResponse)); - } + getFlights.getFlights(); + mockServer.verify(); + } } diff --git a/airline/server/build.gradle b/airline/server/build.gradle deleted file mode 100644 index 7e6e0e0..0000000 --- a/airline/server/build.gradle +++ /dev/null @@ -1,147 +0,0 @@ -configurations { - jaxb - openjpa -} - -buildscript { - repositories { - mavenCentral() - } - - dependencies { - classpath 'org.gradle.api.plugins:gradle-tomcat-plugin:0.9.9' - } -} - -ext.springVersion = '3.2.4.RELEASE' -ext.springWsVersion = '2.1.4.RELEASE' -ext.springSecVersion = '3.1.0.RELEASE' -ext.tomcatVersion = '7.0.42' - -apply plugin: 'war' -apply plugin: 'tomcat' - - -task genJaxb { - ext.sourcesDir = "${buildDir}/generated-sources/jaxb" - ext.classesDir = "${buildDir}/classes/jaxb" - ext.schema = "${projectDir}/src/main/webapp/messages.xsd" - - inputs.files schema - outputs.dir classesDir - - doLast() { - project.ant { - taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask", - classpath: configurations.jaxb.asPath - mkdir(dir: sourcesDir) - mkdir(dir: classesDir) - - xjc(destdir: sourcesDir, schema: schema, - package: "org.springframework.ws.samples.airline.schema") { - produces(dir: sourcesDir, includes: "**/*.java") - } - - javac(destdir: classesDir, source: 1.6, target: 1.6, debug: true, - debugLevel: "lines,vars,source", - classpath: configurations.jaxb.asPath) { - src(path: sourcesDir) - include(name: "**/*.java") - include(name: "*.java") - } - - copy(todir: classesDir) { - fileset(dir: sourcesDir, erroronmissingdir: false) { - exclude(name: "**/*.java") - } - } - } - } -} - -task enhance { - doLast { - ant.taskdef( name : 'openjpaenhancer', - classpath : project.runtimeClasspath.asPath, - classname : 'org.apache.openjpa.ant.PCEnhancerTask' - ) - - ant.openjpaenhancer( - classpath : project.runtimeClasspath.asPath) - ant.fileset(dir: "${projectDir}/src/main/java/") { - include(name: '**/domain/*.java') - exclude(name: 'ServiceClass.java') - } - } -} - -war { - it.dependsOn enhance -} - -test { - it.dependsOn enhance -} - -tomcatRun { - it.dependsOn enhance - contextPath = 'airline-server' -} - - - - -dependencies { - compile(files(genJaxb.classesDir).builtBy(genJaxb)) - - // Spring-WS - compile("org.springframework.ws:spring-ws-core:$springWsVersion") - compile("org.springframework.ws:spring-ws-security:$springWsVersion") { - exclude group: 'com.sun.xml.wsit', module: 'wsit-rt' - exclude group: 'com.sun.xml.wsit', module: 'xws-security' - } - - runtime("org.springframework.ws:spring-ws-support:$springWsVersion") - - // Spring - runtime("org.springframework:spring-orm:$springVersion") - testCompile("org.springframework:spring-jdbc:$springVersion") - testCompile("org.springframework:spring-test:$springVersion") - - // Spring Security - runtime("org.springframework.security:spring-security-core:$springSecVersion") - runtime("org.springframework.security:spring-security-config:$springSecVersion") - runtime("org.springframework.security:spring-security-web:$springSecVersion") - - // JEE - runtime("javax.servlet:jstl:1.2") - - // ORM - compile("org.apache.openjpa:openjpa:1.2.3") - runtime("commons-dbcp:commons-dbcp:1.2.1") { - exclude group: 'xml-apis', module: 'xml-apis' - exclude group: 'xerces', module: 'xerces' - } - runtime("hsqldb:hsqldb:1.8.0.7") - - // Various - runtime("org.apache.activemq:activemq-core:4.1.2") - runtime("org.apache.derby:derby:10.3.1.4") - runtime("org.apache.ws.xmlschema:xmlschema-core:2.0.2") - runtime("com.sun.xml.wss:xws-security:3.0") { - exclude group: 'javax.xml.crypto', module: 'xmldsig' - } - runtime("joda-time:joda-time-jsptags:1.1.1") - - runtime("log4j:log4j:1.2.16") - - - jaxb "com.sun.xml.bind:jaxb-xjc:2.1.7" - openjpa "org.apache.openjpa:openjpa:1.2.3" - - tomcat("org.apache.tomcat.embed:tomcat-embed-core:$tomcatVersion", - "org.apache.tomcat.embed:tomcat-embed-logging-juli:$tomcatVersion") - tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:$tomcatVersion") { - exclude group: 'org.eclipse.jdt.core.compiler', module: 'ecj' - } -} \ No newline at end of file diff --git a/airline/server/pom.xml b/airline/server/pom.xml new file mode 100644 index 0000000..3e85dc1 --- /dev/null +++ b/airline/server/pom.xml @@ -0,0 +1,224 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.3.1.RELEASE + + + + org.springframework.ws + airline-server + 0.0.1-SNAPSHOT + Spring Web Services Samples - Airline - Server + Demo project for Spring Web Services + + + 1.8 + 2.10.6 + 1.2.16 + ${project.basedir}/target/generated-sources/axis + ${project.basedir}/target/classes + ${project.basedir}/../airline.wsdl + 2.0.2 + 3.0 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-web-services + + + + org.springframework.ws + spring-ws-security + + + com.sun.xml.wsit + wsit-rt + + + com.sun.xml.wsit + xws-security + + + + + + com.sun.xml.wss + xws-security + ${xws-security.version} + + + javax.activation + activation + + + javax.xml.crypto + xmldsig + + + javax.xml.bind + jaxb-api + + + javax.xml.stream + stax-api + + + javax.xml.ws + jaxws-api + + + javax.mail + mail + + + + + + org.springframework.ws + spring-ws-support + + + + wsdl4j + wsdl4j + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.h2database + h2 + runtime + + + + org.apache.ws.xmlschema + xmlschema-core + ${xmlschema.version} + runtime + + + + org.springframework.boot + spring-boot-starter-activemq + + + + org.apache.activemq + activemq-kahadb-store + runtime + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + joda-time + joda-time + ${joda-time.version} + + + + + + + + + + + org.springframework + spring-test + test + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.codehaus.mojo + jaxb2-maven-plugin + 2.5.0 + + + xjc + + xjc + + + + + ${project.basedir}/src/main/resources/messages.xsd + org.springframework.ws.samples.airline.schema + 2.1 + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.1 + + + add-source + process-sources + + add-source + + + + target/generated-sources/xjc + + + + + + + + + + + + diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/AirlineServerApplication.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/AirlineServerApplication.java new file mode 100644 index 0000000..1d52b3e --- /dev/null +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/AirlineServerApplication.java @@ -0,0 +1,13 @@ +package org.springframework.ws.samples.airline; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; + +@SpringBootApplication(exclude = SecurityAutoConfiguration.class) +public class AirlineServerApplication { + + public static void main(String[] args) { + SpringApplication.run(AirlineServerApplication.class, args); + } +} diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/AirportDao.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/AirportDao.java new file mode 100644 index 0000000..5730213 --- /dev/null +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/AirportDao.java @@ -0,0 +1,8 @@ +package org.springframework.ws.samples.airline.dao; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.ws.samples.airline.domain.Airport; + +public interface AirportDao extends CrudRepository { + +} diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/Databaseinit.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/Databaseinit.java new file mode 100644 index 0000000..b31db40 --- /dev/null +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/Databaseinit.java @@ -0,0 +1,50 @@ +package org.springframework.ws.samples.airline.dao; + +import org.joda.time.DateTime; +import org.springframework.boot.CommandLineRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.ws.samples.airline.domain.Airport; +import org.springframework.ws.samples.airline.domain.Flight; +import org.springframework.ws.samples.airline.domain.FrequentFlyer; +import org.springframework.ws.samples.airline.domain.ServiceClass; + +@Configuration +public class Databaseinit { + + @Bean + CommandLineRunner initializeDatabase(AirportDao airportDao, FlightDao flightDao, FrequentFlyerDao frequentFlyerDao) { + return args -> { + Airport amsterdam = airportDao.save(new Airport("AMS", "Schiphol Airport", "Amsterdam")); + Airport venice = airportDao.save(new Airport("VCE", "Marco Polo Airport", "Venice")); + Airport rotterdam = airportDao.save(new Airport("RTM", "Rotterdam Airport", "Rotterdam")); + Airport gardermoen = airportDao.save(new Airport("OSL", "Gardermoen", "Oslo")); + + Flight flight = new Flight(); + flight.setNumber("KL1653"); + flight.setDepartureTime(new DateTime(2006, 1, 31, 10, 5, 0, 0).toGregorianCalendar().toZonedDateTime()); + flight.setFrom(amsterdam); + flight.setArrivalTime(new DateTime(2006, 1, 31, 12, 25, 0, 0).toGregorianCalendar().toZonedDateTime()); + flight.setTo(venice); + flight.setServiceClass(ServiceClass.ECONOMY); + flight.setSeatsAvailable(5); + flight.setMiles(200); + + flightDao.save(flight); + + flight = new Flight(); + flight.setNumber("KL1654"); + flight.setDepartureTime(new DateTime(2006, 2, 5, 12, 40, 0, 0).toGregorianCalendar().toZonedDateTime()); + flight.setFrom(venice); + flight.setArrivalTime(new DateTime(2006, 2, 5, 14, 15, 0, 0).toGregorianCalendar().toZonedDateTime()); + flight.setTo(amsterdam); + flight.setServiceClass(ServiceClass.ECONOMY); + flight.setSeatsAvailable(5); + flight.setMiles(200); + + flightDao.save(flight); + + frequentFlyerDao.save(new FrequentFlyer("John", "Doe", "john", "changeme")); + }; + } +} diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FlightDao.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FlightDao.java index dc8c18c..0edecba 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FlightDao.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FlightDao.java @@ -15,22 +15,50 @@ */ package org.springframework.ws.samples.airline.dao; +import java.time.ZonedDateTime; import java.util.List; -import org.joda.time.DateTime; import org.joda.time.Interval; -import org.springframework.dao.DataAccessException; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; import org.springframework.ws.samples.airline.domain.Flight; import org.springframework.ws.samples.airline.domain.ServiceClass; -public interface FlightDao { +public interface FlightDao extends CrudRepository { - List findFlights(String fromAirportCode, String toAirportCode, Interval interval, ServiceClass serviceClass) - throws DataAccessException; + @Query("SELECT f FROM Flight f WHERE f.from.code = :fromAirportCode " + + "AND f.to.code = :toAirportCode AND f.departureTime >= :#{#interval.start.toGregorianCalendar().toZonedDateTime()} AND f.departureTime <= :#{#interval.end.toGregorianCalendar().toZonedDateTime()} AND " + + "f.serviceClass = :class") + List findFlights(@Param("fromAirportCode") String fromAirportCode, // + @Param("toAirportCode") String toAirportCode, // + @Param("interval") Interval interval, // + @Param("class") ServiceClass serviceClass); - Flight getFlight(Long id); + /** + * @deprecated Migrate to {@link #findById(Object)}. + */ + default Flight getFlight(Long id) { + return findById(id).get(); + } - Flight getFlight(String flightNumber, DateTime departureTime); + ; - Flight update(Flight flight); + /** + * @deprecated Migrate to {@link #findFlightByNumberAndDepartureTime(String, ZonedDateTime)}. + */ + @Deprecated + default Flight getFlight(String flightNumber, ZonedDateTime departureTime) { + return findFlightByNumberAndDepartureTime(flightNumber, departureTime); + } + + Flight findFlightByNumberAndDepartureTime(String flightNumber, ZonedDateTime departureTime); + + /** + * @deprecated Migrate to {@link #save(Object)}. + */ + @Deprecated + default Flight update(Flight flight) { + return save(flight); + } } diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FrequentFlyerDao.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FrequentFlyerDao.java index e889cc9..a2e9c7e 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FrequentFlyerDao.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FrequentFlyerDao.java @@ -17,10 +17,19 @@ package org.springframework.ws.samples.airline.dao; import org.springframework.dao.DataAccessException; +import org.springframework.data.repository.CrudRepository; import org.springframework.ws.samples.airline.domain.FrequentFlyer; -public interface FrequentFlyerDao { +public interface FrequentFlyerDao extends CrudRepository { - FrequentFlyer get(String username) throws DataAccessException; + /** + * @deprecated Migrate to {@link #findByUsername(String)}. + */ + @Deprecated + default FrequentFlyer get(String username) throws DataAccessException { + return findByUsername(username); + } + + FrequentFlyer findByUsername(String username); } diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/TicketDao.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/TicketDao.java index e3be0ac..afe0b21 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/TicketDao.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/TicketDao.java @@ -16,11 +16,9 @@ package org.springframework.ws.samples.airline.dao; -import org.springframework.dao.DataAccessException; +import org.springframework.data.repository.CrudRepository; import org.springframework.ws.samples.airline.domain.Ticket; -public interface TicketDao { - - void save(Ticket ticket) throws DataAccessException; +public interface TicketDao extends CrudRepository { } diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/DatabaseInitializer.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/DatabaseInitializer.java deleted file mode 100644 index a4a506a..0000000 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/DatabaseInitializer.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2005-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. - */ - -package org.springframework.ws.samples.airline.dao.jpa; - -import javax.annotation.PostConstruct; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.TransactionStatus; -import org.springframework.transaction.support.TransactionCallbackWithoutResult; -import org.springframework.transaction.support.TransactionTemplate; -import org.springframework.ws.samples.airline.domain.Airport; -import org.springframework.ws.samples.airline.domain.Flight; -import org.springframework.ws.samples.airline.domain.FrequentFlyer; -import org.springframework.ws.samples.airline.domain.ServiceClass; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.joda.time.DateTime; - -/** - * A simple class that uses JPA to initialize the database. - * - * @author Arjen Poutsma - * @since 1.5.0 - */ -@Component -public class DatabaseInitializer { - - private static final Log logger = LogFactory.getLog(DatabaseInitializer.class); - - private final TransactionTemplate transactionTemplate; - - @PersistenceContext - private EntityManager entityManager; - - private Airport amsterdam; - - private Airport venice; - - @Autowired - public DatabaseInitializer(PlatformTransactionManager transactionManager) { - this.transactionTemplate = new TransactionTemplate(transactionManager); - } - - @PostConstruct - public void initDatabase() { - transactionTemplate.execute(new TransactionCallbackWithoutResult() { - protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { - logger.info("Initializing Database"); - createAirports(); - createFlights(); - createFrequentFlyers(); - } - }); - } - - private void createAirports() { - amsterdam = new Airport("AMS", "Schiphol Airport", "Amsterdam"); - entityManager.persist(amsterdam); - venice = new Airport("VCE", "Marco Polo Airport", "Venice"); - entityManager.persist(venice); - } - - private void createFlights() { - Flight flight = new Flight(); - flight.setNumber("KL1653"); - flight.setDepartureTime(new DateTime(2006, 1, 31, 10, 5, 0, 0)); - flight.setFrom(amsterdam); - flight.setArrivalTime(new DateTime(2006, 1, 31, 12, 25, 0, 0)); - flight.setTo(venice); - flight.setServiceClass(ServiceClass.ECONOMY); - flight.setSeatsAvailable(5); - flight.setMiles(200); - entityManager.persist(flight); - flight = new Flight(); - flight.setNumber("KL1654"); - flight.setDepartureTime(new DateTime(2006, 2, 5, 12, 40, 0, 0)); - flight.setFrom(venice); - flight.setArrivalTime(new DateTime(2006, 2, 5, 14, 15, 0, 0)); - flight.setTo(amsterdam); - flight.setServiceClass(ServiceClass.ECONOMY); - flight.setSeatsAvailable(5); - flight.setMiles(200); - entityManager.persist(flight); - } - - private void createFrequentFlyers() { - entityManager.persist(new FrequentFlyer("John", "Doe", "john", "changeme")); - } -} diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDao.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDao.java deleted file mode 100644 index 72ca105..0000000 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDao.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.airline.dao.jpa; - -import java.util.List; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; - -import org.joda.time.DateTime; -import org.joda.time.Interval; -import org.springframework.dao.DataAccessException; -import org.springframework.stereotype.Repository; -import org.springframework.ws.samples.airline.dao.FlightDao; -import org.springframework.ws.samples.airline.domain.Flight; -import org.springframework.ws.samples.airline.domain.ServiceClass; - -@Repository -public class JpaFlightDao implements FlightDao { - - @PersistenceContext - private EntityManager entityManager; - - public List findFlights(String fromAirportCode, - String toAirportCode, - Interval interval, - ServiceClass serviceClass) throws DataAccessException { - Query query = entityManager.createQuery("SELECT f FROM Flight f WHERE f.from.code = :fromParam " + - "AND f.to.code = :toParam AND f.departureTime >= :start AND f.departureTime <= :end AND " + - "f.serviceClass = :class"); - query.setParameter("fromParam", fromAirportCode); - query.setParameter("toParam", toAirportCode); - query.setParameter("start", interval.getStart()); - query.setParameter("end", interval.getEnd()); - query.setParameter("class", serviceClass); - return query.getResultList(); - } - - public Flight getFlight(Long id) { - return entityManager.find(Flight.class, id); - } - - public Flight getFlight(String flightNumber, DateTime departureTime) { - Query query = entityManager - .createQuery("SELECT f FROM Flight f WHERE f.number = :number AND f.departureTime = :departureTime"); - query.setParameter("number", flightNumber); - query.setParameter("departureTime", departureTime); - try { - return (Flight) query.getSingleResult(); - } - catch (NoResultException e) { - return null; - } - } - - public Flight update(Flight flight) { - return entityManager.merge(flight); - } -} diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDao.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDao.java deleted file mode 100644 index b7cb58d..0000000 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDao.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.airline.dao.jpa; - -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; - -import org.springframework.dao.DataAccessException; -import org.springframework.stereotype.Repository; -import org.springframework.ws.samples.airline.dao.FrequentFlyerDao; -import org.springframework.ws.samples.airline.domain.FrequentFlyer; - -@Repository -public class JpaFrequentFlyerDao implements FrequentFlyerDao { - - @PersistenceContext - private EntityManager entityManager; - - public FrequentFlyer get(String username) throws DataAccessException { - Query query = entityManager.createQuery("SELECT f FROM FrequentFlyer f WHERE f.username = :username"); - query.setParameter("username", username); - try { - return (FrequentFlyer) query.getSingleResult(); - } - catch (NoResultException e) { - return null; - } - } - -} diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaTicketDao.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaTicketDao.java deleted file mode 100644 index ba11a44..0000000 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaTicketDao.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.airline.dao.jpa; - -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; - -import org.springframework.dao.DataAccessException; -import org.springframework.stereotype.Repository; -import org.springframework.ws.samples.airline.dao.TicketDao; -import org.springframework.ws.samples.airline.domain.Ticket; - -@Repository -public class JpaTicketDao implements TicketDao { - - @PersistenceContext - private EntityManager entityManager; - - public void save(Ticket ticket) throws DataAccessException { - entityManager.persist(ticket); - } -} diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Airport.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Airport.java index d9951a0..ce55810 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Airport.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Airport.java @@ -17,6 +17,7 @@ package org.springframework.ws.samples.airline.domain; import java.io.Serializable; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Flight.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Flight.java index 102859f..32d7d17 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Flight.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Flight.java @@ -16,6 +16,8 @@ package org.springframework.ws.samples.airline.domain; import java.io.Serializable; +import java.time.ZonedDateTime; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; @@ -27,153 +29,131 @@ import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; -import org.apache.openjpa.persistence.Persistent; -import org.joda.time.DateTime; +import org.springframework.data.annotation.Persistent; @Entity @Table(name = "FLIGHT") public class Flight implements Serializable { - @Id - @Column(name = "ID") - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Id @Column(name = "ID") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(name = "NUMBER") - private String number; + @Column(name = "NUMBER") private String number; - @Column(name = "DEPARTURE_TIME") - @Persistent - private DateTime departureTime; + @Column(name = "DEPARTURE_TIME") @Persistent private ZonedDateTime departureTime; - @ManyToOne - @JoinColumn(name = "FROM_AIRPORT_CODE", nullable = false) - private Airport from; + @ManyToOne @JoinColumn(name = "FROM_AIRPORT_CODE", nullable = false) private Airport from; - @Column(name = "ARRIVAL_TIME") - @Persistent - private DateTime arrivalTime; + @Column(name = "ARRIVAL_TIME") @Persistent private ZonedDateTime arrivalTime; - @ManyToOne - @JoinColumn(name = "TO_AIRPORT_CODE", nullable = false) - private Airport to; + @ManyToOne @JoinColumn(name = "TO_AIRPORT_CODE", nullable = false) private Airport to; - @Column(name = "SERVICE_CLASS") - @Enumerated(EnumType.STRING) - private ServiceClass serviceClass; + @Column(name = "SERVICE_CLASS") @Enumerated(EnumType.STRING) private ServiceClass serviceClass; - @Column(name = "SEATS_AVAILABLE") - private int seatsAvailable; + @Column(name = "SEATS_AVAILABLE") private int seatsAvailable; - @Column(name = "MILES") - private int miles; + @Column(name = "MILES") private int miles; - public Flight() { - } + public Flight() {} - public Flight(Long id) { - this.id = id; - } + public Flight(Long id) { + this.id = id; + } - public Long getId() { - return id; - } + public Long getId() { + return id; + } - public DateTime getArrivalTime() { - return arrivalTime; - } + public ZonedDateTime getArrivalTime() { + return arrivalTime; + } - public void setArrivalTime(DateTime arrivalTime) { - this.arrivalTime = arrivalTime; - } + public void setArrivalTime(ZonedDateTime arrivalTime) { + this.arrivalTime = arrivalTime; + } - public DateTime getDepartureTime() { - return departureTime; - } + public ZonedDateTime getDepartureTime() { + return departureTime; + } - public void setDepartureTime(DateTime departureTime) { - this.departureTime = departureTime; - } + public void setDepartureTime(ZonedDateTime departureTime) { + this.departureTime = departureTime; + } - public Airport getFrom() { - return from; - } + public Airport getFrom() { + return from; + } - public void setFrom(Airport from) { - this.from = from; - } + public void setFrom(Airport from) { + this.from = from; + } - public int getMiles() { - return miles; - } + public int getMiles() { + return miles; + } - public void setMiles(int miles) { - this.miles = miles; - } + public void setMiles(int miles) { + this.miles = miles; + } - public String getNumber() { - return number; - } + public String getNumber() { + return number; + } - public void setNumber(String number) { - this.number = number; - } + public void setNumber(String number) { + this.number = number; + } - public int getSeatsAvailable() { - return seatsAvailable; - } + public int getSeatsAvailable() { + return seatsAvailable; + } - public void setSeatsAvailable(int seatsAvailable) { - this.seatsAvailable = seatsAvailable; - } + public void setSeatsAvailable(int seatsAvailable) { + this.seatsAvailable = seatsAvailable; + } - public ServiceClass getServiceClass() { - return serviceClass; - } + public ServiceClass getServiceClass() { + return serviceClass; + } - public void setServiceClass(ServiceClass serviceClass) { - this.serviceClass = serviceClass; - } + public void setServiceClass(ServiceClass serviceClass) { + this.serviceClass = serviceClass; + } - public Airport getTo() { - return to; - } + public Airport getTo() { + return to; + } - public void setTo(Airport to) { - this.to = to; - } + public void setTo(Airport to) { + this.to = to; + } - public void substractSeats(int count) { - seatsAvailable -= count; - } + public void substractSeats(int count) { + seatsAvailable -= count; + } - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } - final Flight flight = (Flight) o; + final Flight flight = (Flight) o; - if (!departureTime.equals(flight.departureTime)) { - return false; - } - return number.equals(flight.number); - } + if (!departureTime.equals(flight.departureTime)) { + return false; + } + return number.equals(flight.number); + } - public int hashCode() { - int result = number.hashCode(); - result = 29 * result + departureTime.hashCode(); - return result; - } + public int hashCode() { + int result = number.hashCode(); + result = 29 * result + departureTime.hashCode(); + return result; + } - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append(getNumber()); - buffer.append(' '); - buffer.append(getDepartureTime().toString()); - return buffer.toString(); - } + public String toString() { + return getNumber() + " " + getDepartureTime(); + } } diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/FrequentFlyer.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/FrequentFlyer.java index 7e428ea..a1ea89e 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/FrequentFlyer.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/FrequentFlyer.java @@ -26,72 +26,70 @@ import javax.persistence.Table; @PrimaryKeyJoinColumn(name = "PASSENGER_ID") public class FrequentFlyer extends Passenger { - @Column(name = "USERNAME") - private String username; + @Column(name = "USERNAME") private String username; - @Column(name = "PASSWORD") - private String password; + @Column(name = "PASSWORD") private String password; - @Column(name = "MILES") - private int miles; + @Column(name = "MILES") private int miles; - public FrequentFlyer() { - } + public FrequentFlyer() {} - public FrequentFlyer(String username) { - this.username = username; - } + public FrequentFlyer(String username) { + this.username = username; + } - public FrequentFlyer(String firstName, String lastName, String username, String password) { - super(firstName, lastName); - this.username = username; - this.password = password; - } + public FrequentFlyer(String firstName, String lastName, String username, String password) { - public int getMiles() { - return miles; - } + super(firstName, lastName); + this.username = username; + this.password = password; + } - public void setMiles(int miles) { - this.miles = miles; - } + public int getMiles() { + return miles; + } - public String getPassword() { - return password; - } + public void setMiles(int miles) { + this.miles = miles; + } - public void setPassword(String password) { - this.password = password; - } + public String getPassword() { + return password; + } - public String getUsername() { - return username; - } + public void setPassword(String password) { + this.password = password; + } - public void setUsername(String username) { - this.username = username; - } + public String getUsername() { + return username; + } - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (!(other instanceof FrequentFlyer)) { - return false; - } - final FrequentFlyer that = (FrequentFlyer) other; - return username.equals(that.username); - } + public void setUsername(String username) { + this.username = username; + } - public int hashCode() { - return username.hashCode(); - } + public boolean equals(Object other) { - public String toString() { - return username; - } + if (this == other) { + return true; + } + if (!(other instanceof FrequentFlyer)) { + return false; + } + final FrequentFlyer that = (FrequentFlyer) other; + return username.equals(that.username); + } - public void addMiles(int miles) { - this.miles += miles; - } + public int hashCode() { + return username.hashCode(); + } + + public String toString() { + return username; + } + + public void addMiles(int miles) { + this.miles += miles; + } } diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Passenger.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Passenger.java index 3aeb628..462b167 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Passenger.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Passenger.java @@ -16,6 +16,7 @@ package org.springframework.ws.samples.airline.domain; import java.io.Serializable; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Ticket.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Ticket.java index da3593f..3e5abe2 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Ticket.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/Ticket.java @@ -19,6 +19,7 @@ package org.springframework.ws.samples.airline.domain; import java.io.Serializable; import java.util.HashSet; import java.util.Set; + import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; @@ -31,67 +32,67 @@ import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.Table; -import org.apache.openjpa.persistence.Persistent; import org.joda.time.LocalDate; +import org.springframework.data.annotation.Persistent; @Entity @Table(name = "TICKET") public class Ticket implements Serializable { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - @Column(name = "ISSUE_DATE") - @Persistent - private LocalDate issueDate; + @Column(name = "ISSUE_DATE") + @Persistent + private LocalDate issueDate; - @ManyToOne - @JoinColumn(name = "FLIGHT_ID", nullable = false) - private Flight flight; + @ManyToOne + @JoinColumn(name = "FLIGHT_ID", nullable = false) + private Flight flight; - @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) - @JoinTable(name = "PASSENGER_TICKET", - joinColumns = @JoinColumn(name = "TICKET_ID"), - inverseJoinColumns = @JoinColumn(name = "PASSENGER_ID")) - private Set passengers = new HashSet(); + @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) + @JoinTable(name = "PASSENGER_TICKET", + joinColumns = @JoinColumn(name = "TICKET_ID"), + inverseJoinColumns = @JoinColumn(name = "PASSENGER_ID")) + private Set passengers = new HashSet(); - public Ticket() { - } + public Ticket() { + } - public Ticket(Long id) { - this.id = id; - } + public Ticket(Long id) { + this.id = id; + } - public Long getId() { - return id; - } + public Long getId() { + return id; + } - public Flight getFlight() { - return flight; - } + public Flight getFlight() { + return flight; + } - public void setFlight(Flight flight) { - this.flight = flight; - } + public void setFlight(Flight flight) { + this.flight = flight; + } - public LocalDate getIssueDate() { - return issueDate; - } + public LocalDate getIssueDate() { + return issueDate; + } - public void setIssueDate(LocalDate issueDate) { - this.issueDate = issueDate; - } + public void setIssueDate(LocalDate issueDate) { + this.issueDate = issueDate; + } - public Set getPassengers() { - return passengers; - } + public Set getPassengers() { + return passengers; + } - public void setPassengers(Set passengers) { - this.passengers = passengers; - } + public void setPassengers(Set passengers) { + this.passengers = passengers; + } - public void addPassenger(Passenger passenger) { - passengers.add(passenger); - } + public void addPassenger(Passenger passenger) { + passengers.add(passenger); + } } diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/openjpa/DateTimeValueHandler.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/openjpa/DateTimeValueHandler.java deleted file mode 100644 index e3d4842..0000000 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/openjpa/DateTimeValueHandler.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.airline.domain.openjpa; - -import java.sql.Timestamp; - -import org.apache.openjpa.jdbc.kernel.JDBCStore; -import org.apache.openjpa.jdbc.meta.JavaSQLTypes; -import org.apache.openjpa.jdbc.meta.ValueMapping; -import org.apache.openjpa.jdbc.meta.strats.AbstractValueHandler; -import org.apache.openjpa.jdbc.schema.Column; -import org.apache.openjpa.jdbc.schema.ColumnIO; -import org.joda.time.DateTime; - -/** - * @author Arjen Poutsma - * @since 1.1.0 - */ -public class DateTimeValueHandler extends AbstractValueHandler { - - private static final DateTimeValueHandler instance = new DateTimeValueHandler(); - - public static DateTimeValueHandler getInstance() { - return instance; - } - - public Column[] map(ValueMapping vm, String name, ColumnIO io, boolean adapt) { - Column col = new Column(); - col.setName(name); - col.setJavaType(JavaSQLTypes.TIMESTAMP); - return new Column[]{col}; - } - - @Override - public Object toDataStoreValue(ValueMapping valueMapping, Object val, JDBCStore jdbcStore) { - return val == null ? null : new Timestamp(((DateTime) val).getMillis()); - } - - @Override - public Object toObjectValue(ValueMapping valueMapping, Object val) { - return val == null ? null : new DateTime(val); - } -} diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/openjpa/LocalDateValueHandler.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/openjpa/LocalDateValueHandler.java deleted file mode 100644 index b05a46b..0000000 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/openjpa/LocalDateValueHandler.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.airline.domain.openjpa; - -import java.sql.Date; - -import org.apache.openjpa.jdbc.kernel.JDBCStore; -import org.apache.openjpa.jdbc.meta.JavaSQLTypes; -import org.apache.openjpa.jdbc.meta.ValueMapping; -import org.apache.openjpa.jdbc.meta.strats.AbstractValueHandler; -import org.apache.openjpa.jdbc.schema.Column; -import org.apache.openjpa.jdbc.schema.ColumnIO; -import org.joda.time.LocalDate; - -/** - * @author Arjen Poutsma - * @since 1.1.0 - */ -public class LocalDateValueHandler extends AbstractValueHandler { - - public Column[] map(ValueMapping vm, String name, ColumnIO io, boolean adapt) { - Column col = new Column(); - col.setName(name); - col.setJavaType(JavaSQLTypes.DATE); - return new Column[]{col}; - } - - @Override - public Object toDataStoreValue(ValueMapping valueMapping, Object val, JDBCStore jdbcStore) { - return val == null ? null : new Date(((LocalDate) val).toDateMidnight().getMillis()); - } - - @Override - public Object toObjectValue(ValueMapping valueMapping, Object val) { - return val == null ? null : new LocalDate(val); - } -} diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/jms/JmsConfiguration.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/jms/JmsConfiguration.java new file mode 100644 index 0000000..b6f30af --- /dev/null +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/jms/JmsConfiguration.java @@ -0,0 +1,52 @@ +package org.springframework.ws.samples.airline.jms; + +import javax.jms.ConnectionFactory; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jms.listener.DefaultMessageListenerContainer; +import org.springframework.ws.WebServiceMessageFactory; +import org.springframework.ws.transport.WebServiceMessageReceiver; +import org.springframework.ws.transport.jms.WebServiceMessageListener; + +@Configuration +public class JmsConfiguration { + + @Bean(initMethod = "start") + BrokerService broker() throws Exception { + return BrokerFactory.createBroker("broker:tcp://localhost:61616?persistent=false"); + } + + @Bean + ActiveMQConnectionFactory connectionFactory() { + + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(); + connectionFactory.setBrokerURL("tcp://localhost:61616"); + return connectionFactory; + } + + @Bean + DefaultMessageListenerContainer containerFactory(ConnectionFactory connectionFactory, + WebServiceMessageListener messageListener) { + + DefaultMessageListenerContainer container = new DefaultMessageListenerContainer(); + container.setConnectionFactory(connectionFactory); + container.setDestination(new ActiveMQQueue("RequestQueue")); + container.setMessageListener(messageListener); + return container; + } + + @Bean + WebServiceMessageListener messageListener(WebServiceMessageFactory messageFactory, + WebServiceMessageReceiver messageReceiver) { + + WebServiceMessageListener messageListener = new WebServiceMessageListener(); + messageListener.setMessageFactory(messageFactory); + messageListener.setMessageReceiver(messageReceiver); + return messageListener; + } +} diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/schema/support/SchemaConversionUtils.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/schema/support/SchemaConversionUtils.java index 4335524..4f10522 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/schema/support/SchemaConversionUtils.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/schema/support/SchemaConversionUtils.java @@ -16,15 +16,16 @@ package org.springframework.ws.samples.airline.schema.support; -import java.util.ArrayList; +import java.time.ZonedDateTime; +import java.util.GregorianCalendar; import java.util.List; +import java.util.stream.Collectors; + import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeConstants; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; import org.joda.time.LocalDate; import org.springframework.ws.samples.airline.domain.Passenger; import org.springframework.ws.samples.airline.schema.Airport; @@ -36,112 +37,119 @@ import org.springframework.ws.samples.airline.schema.Ticket; /** @author Arjen Poutsma */ public abstract class SchemaConversionUtils { - private SchemaConversionUtils() { - } + private SchemaConversionUtils() {} - public static Flight toSchemaType(org.springframework.ws.samples.airline.domain.Flight domainFlight) - throws DatatypeConfigurationException { - Flight schemaFlight = new Flight(); - schemaFlight.setNumber(domainFlight.getNumber()); - schemaFlight.setDepartureTime(toXMLGregorianCalendar(domainFlight.getDepartureTime())); - schemaFlight.setFrom(toSchemaType(domainFlight.getFrom())); - schemaFlight.setArrivalTime(toXMLGregorianCalendar(domainFlight.getArrivalTime())); - schemaFlight.setTo(toSchemaType(domainFlight.getTo())); - schemaFlight.setServiceClass(toSchemaType(domainFlight.getServiceClass())); - return schemaFlight; - } + public static Flight toSchemaType(org.springframework.ws.samples.airline.domain.Flight domainFlight) + throws DatatypeConfigurationException { - public static List toSchemaType(List domainFlights) - throws DatatypeConfigurationException { - List schemaFlights = new ArrayList(domainFlights.size()); - for (org.springframework.ws.samples.airline.domain.Flight domainFlight : domainFlights) { - schemaFlights.add(toSchemaType(domainFlight)); - } - return schemaFlights; - } + Flight schemaFlight = new Flight(); + schemaFlight.setNumber(domainFlight.getNumber()); + schemaFlight.setDepartureTime(toXMLGregorianCalendar(domainFlight.getDepartureTime())); + schemaFlight.setFrom(toSchemaType(domainFlight.getFrom())); + schemaFlight.setArrivalTime(toXMLGregorianCalendar(domainFlight.getArrivalTime())); + schemaFlight.setTo(toSchemaType(domainFlight.getTo())); + schemaFlight.setServiceClass(toSchemaType(domainFlight.getServiceClass())); + return schemaFlight; + } - public static XMLGregorianCalendar toXMLGregorianCalendar(DateTime dateTime) throws DatatypeConfigurationException { - DatatypeFactory factory = DatatypeFactory.newInstance(); - return factory.newXMLGregorianCalendar(dateTime.toGregorianCalendar()); - } + public static List toSchemaType(List domainFlights) { - public static DateTime toDateTime(XMLGregorianCalendar calendar) { - int timeZoneMinutes = calendar.getTimezone(); - DateTimeZone timeZone = DateTimeZone.forOffsetHoursMinutes(timeZoneMinutes / 60, timeZoneMinutes % 60); - return new DateTime(calendar.getYear(), calendar.getMonth(), calendar.getDay(), calendar.getHour(), - calendar.getMinute(), calendar.getSecond(), calendar.getMillisecond(), timeZone); - } + return domainFlights.stream() // + .map(flight -> { + try { + return toSchemaType(flight); + } catch (DatatypeConfigurationException e) { + throw new RuntimeException(e); + } + }) // + .collect(Collectors.toList()); + } - public static XMLGregorianCalendar toXMLGregorianCalendar(LocalDate localDate) - throws DatatypeConfigurationException { - DatatypeFactory factory = DatatypeFactory.newInstance(); - return factory.newXMLGregorianCalendarDate(localDate.getYear(), localDate.getMonthOfYear(), - localDate.getDayOfMonth(), DatatypeConstants.FIELD_UNDEFINED); - } + public static XMLGregorianCalendar toXMLGregorianCalendar(ZonedDateTime dateTime) + throws DatatypeConfigurationException { - public static LocalDate toLocalDate(XMLGregorianCalendar calendar) { - return new LocalDate(calendar.getYear(), calendar.getMonth(), calendar.getDay()); - } + DatatypeFactory factory = DatatypeFactory.newInstance(); + return factory.newXMLGregorianCalendar(GregorianCalendar.from(dateTime)); + } - public static Airport toSchemaType(org.springframework.ws.samples.airline.domain.Airport domainAirport) { - if (domainAirport == null) { - return null; - } - Airport schemaAirport = new Airport(); - schemaAirport.setCode(domainAirport.getCode()); - schemaAirport.setName(domainAirport.getName()); - schemaAirport.setCity(domainAirport.getCity()); - return schemaAirport; - } + public static ZonedDateTime toDateTime(XMLGregorianCalendar calendar) { + return calendar.toGregorianCalendar().toZonedDateTime(); + } - public static ServiceClass toSchemaType(org.springframework.ws.samples.airline.domain.ServiceClass domainServiceClass) { - switch (domainServiceClass) { - case BUSINESS: - return ServiceClass.BUSINESS; - case ECONOMY: - return ServiceClass.ECONOMY; - case FIRST: - return ServiceClass.FIRST; - default: - throw new IllegalArgumentException("Invalid domain service class: [" + domainServiceClass + "]"); - } - } + public static XMLGregorianCalendar toXMLGregorianCalendar(LocalDate localDate) throws DatatypeConfigurationException { - public static org.springframework.ws.samples.airline.domain.ServiceClass toDomainType(ServiceClass schemaServiceClass) { - if (schemaServiceClass == null) { - return null; - } - switch (schemaServiceClass) { - case BUSINESS: - return org.springframework.ws.samples.airline.domain.ServiceClass.BUSINESS; - case ECONOMY: - return org.springframework.ws.samples.airline.domain.ServiceClass.ECONOMY; - case FIRST: - return org.springframework.ws.samples.airline.domain.ServiceClass.FIRST; - default: - throw new IllegalArgumentException("Invalid schema service class: [" + schemaServiceClass + "]"); - } - } + DatatypeFactory factory = DatatypeFactory.newInstance(); + return factory.newXMLGregorianCalendarDate(localDate.getYear(), localDate.getMonthOfYear(), + localDate.getDayOfMonth(), DatatypeConstants.FIELD_UNDEFINED); + } - public static Name toSchemaType(org.springframework.ws.samples.airline.domain.Passenger passenger) { - Name name = new Name(); - name.setFirst(passenger.getFirstName()); - name.setLast(passenger.getLastName()); - return name; - } + public static LocalDate toLocalDate(XMLGregorianCalendar calendar) { + return new LocalDate(calendar.getYear(), calendar.getMonth(), calendar.getDay()); + } - public static Ticket toSchemaType(org.springframework.ws.samples.airline.domain.Ticket domainTicket) - throws DatatypeConfigurationException { - Ticket schemaTicket = new Ticket(); - schemaTicket.setId(domainTicket.getId()); - schemaTicket.setFlight(toSchemaType(domainTicket.getFlight())); - schemaTicket.setIssueDate(toXMLGregorianCalendar(domainTicket.getIssueDate())); - if (!domainTicket.getPassengers().isEmpty()) { - schemaTicket.setPassengers(new Ticket.Passengers()); - } - for (Passenger passenger : domainTicket.getPassengers()) { - schemaTicket.getPassengers().getPassenger().add(toSchemaType(passenger)); - } - return schemaTicket; - } + public static Airport toSchemaType(org.springframework.ws.samples.airline.domain.Airport domainAirport) { + + if (domainAirport == null) { + return null; + } + + Airport schemaAirport = new Airport(); + schemaAirport.setCode(domainAirport.getCode()); + schemaAirport.setName(domainAirport.getName()); + schemaAirport.setCity(domainAirport.getCity()); + return schemaAirport; + } + + public static ServiceClass toSchemaType( + org.springframework.ws.samples.airline.domain.ServiceClass domainServiceClass) { + switch (domainServiceClass) { + case BUSINESS: + return ServiceClass.BUSINESS; + case ECONOMY: + return ServiceClass.ECONOMY; + case FIRST: + return ServiceClass.FIRST; + default: + throw new IllegalArgumentException("Invalid domain service class: [" + domainServiceClass + "]"); + } + } + + public static org.springframework.ws.samples.airline.domain.ServiceClass toDomainType( + ServiceClass schemaServiceClass) { + if (schemaServiceClass == null) { + return null; + } + switch (schemaServiceClass) { + case BUSINESS: + return org.springframework.ws.samples.airline.domain.ServiceClass.BUSINESS; + case ECONOMY: + return org.springframework.ws.samples.airline.domain.ServiceClass.ECONOMY; + case FIRST: + return org.springframework.ws.samples.airline.domain.ServiceClass.FIRST; + default: + throw new IllegalArgumentException("Invalid schema service class: [" + schemaServiceClass + "]"); + } + } + + public static Name toSchemaType(Passenger passenger) { + Name name = new Name(); + name.setFirst(passenger.getFirstName()); + name.setLast(passenger.getLastName()); + return name; + } + + public static Ticket toSchemaType(org.springframework.ws.samples.airline.domain.Ticket domainTicket) + throws DatatypeConfigurationException { + Ticket schemaTicket = new Ticket(); + schemaTicket.setId(domainTicket.getId()); + schemaTicket.setFlight(toSchemaType(domainTicket.getFlight())); + schemaTicket.setIssueDate(toXMLGregorianCalendar(domainTicket.getIssueDate())); + if (!domainTicket.getPassengers().isEmpty()) { + schemaTicket.setPassengers(new Ticket.Passengers()); + } + for (Passenger passenger : domainTicket.getPassengers()) { + schemaTicket.getPassengers().getPassenger().add(toSchemaType(passenger)); + } + return schemaTicket; + } } diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerDetails.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerDetails.java index 6bda1d7..82ca823 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerDetails.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerDetails.java @@ -20,7 +20,7 @@ import java.util.ArrayList; import java.util.Collection; import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.GrantedAuthorityImpl; +import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.ws.samples.airline.domain.FrequentFlyer; @@ -37,7 +37,7 @@ public class FrequentFlyerDetails implements UserDetails { public static final Collection GRANTED_AUTHORITIES = new ArrayList(); { - GRANTED_AUTHORITIES.add(new GrantedAuthorityImpl("ROLE_FREQUENT_FLYER")); + GRANTED_AUTHORITIES.add(new SimpleGrantedAuthority("ROLE_FREQUENT_FLYER")); }; public FrequentFlyerDetails(FrequentFlyer frequentFlyer) { diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SecurityConfiguration.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SecurityConfiguration.java new file mode 100644 index 0000000..63272b0 --- /dev/null +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SecurityConfiguration.java @@ -0,0 +1,37 @@ +package org.springframework.ws.samples.airline.security; + +import java.util.HashMap; +import java.util.Map; + +import net.bytebuddy.build.Plugin; +import org.springframework.context.annotation.Bean; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.crypto.password.DelegatingPasswordEncoder; +import org.springframework.security.crypto.password.NoOpPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.ws.samples.airline.dao.FrequentFlyerDao; + +@EnableGlobalMethodSecurity(securedEnabled = true) +public class SecurityConfiguration /*extends WebSecurityConfigurerAdapter*/ { + + @Bean + SpringFrequentFlyerSecurityService securityService(FrequentFlyerDao frequentFlyerDao) { + return new SpringFrequentFlyerSecurityService(frequentFlyerDao); + } + + @Bean + AuthenticationManager authenticationManager(SpringFrequentFlyerSecurityService securityService) { + + DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); + authenticationProvider.setUserDetailsService(securityService); + return new ProviderManager(authenticationProvider); + } + + @Bean + PasswordEncoder passwordEncoder() { + return NoOpPasswordEncoder.getInstance(); + } +} diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SpringFrequentFlyerSecurityService.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SpringFrequentFlyerSecurityService.java index 355d2a7..c709a84 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SpringFrequentFlyerSecurityService.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SpringFrequentFlyerSecurityService.java @@ -16,7 +16,6 @@ package org.springframework.ws.samples.airline.security; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; @@ -36,51 +35,48 @@ import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerExcepti */ public class SpringFrequentFlyerSecurityService implements FrequentFlyerSecurityService, UserDetailsService { - private FrequentFlyerDao frequentFlyerDao; + private FrequentFlyerDao frequentFlyerDao; - @Autowired - public SpringFrequentFlyerSecurityService(FrequentFlyerDao frequentFlyerDao) { - this.frequentFlyerDao = frequentFlyerDao; - } + public SpringFrequentFlyerSecurityService(FrequentFlyerDao frequentFlyerDao) { + this.frequentFlyerDao = frequentFlyerDao; + } - @Transactional - public FrequentFlyer getCurrentlyAuthenticatedFrequentFlyer() { - SecurityContext context = SecurityContextHolder.getContext(); - Authentication authentication = context.getAuthentication(); - if (authentication != null) { - if (authentication.getPrincipal() instanceof FrequentFlyerDetails) { - FrequentFlyerDetails details = (FrequentFlyerDetails) authentication.getPrincipal(); - return details.getFrequentFlyer(); - } - else { - return (FrequentFlyer) authentication.getPrincipal(); - } - } - else { - return null; - } - } + @Transactional + public FrequentFlyer getCurrentlyAuthenticatedFrequentFlyer() { - @Transactional - public FrequentFlyer getFrequentFlyer(String username) throws NoSuchFrequentFlyerException { - FrequentFlyer frequentFlyer = frequentFlyerDao.get(username); - if (frequentFlyer != null) { - return frequentFlyer; - } - else { - throw new NoSuchFrequentFlyerException(username); - } - } + SecurityContext context = SecurityContextHolder.getContext(); + Authentication authentication = context.getAuthentication(); + if (authentication != null) { + if (authentication.getPrincipal() instanceof FrequentFlyerDetails) { + FrequentFlyerDetails details = (FrequentFlyerDetails) authentication.getPrincipal(); + return details.getFrequentFlyer(); + } else { + return (FrequentFlyer) authentication.getPrincipal(); + } + } else { + return null; + } + } - @Transactional - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { - FrequentFlyer frequentFlyer = frequentFlyerDao.get(username); - if (frequentFlyer != null) { - return new FrequentFlyerDetails(frequentFlyer); - } - else { - throw new UsernameNotFoundException("Frequent flyer '" + username + "' not found"); - } - } + @Transactional + public FrequentFlyer getFrequentFlyer(String username) throws NoSuchFrequentFlyerException { + FrequentFlyer frequentFlyer = frequentFlyerDao.get(username); + if (frequentFlyer != null) { + return frequentFlyer; + } else { + throw new NoSuchFrequentFlyerException(username); + } + } + + @Transactional + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { + + FrequentFlyer frequentFlyer = frequentFlyerDao.get(username); + if (frequentFlyer != null) { + return new FrequentFlyerDetails(frequentFlyer); + } else { + throw new UsernameNotFoundException("Frequent flyer '" + username + "' not found"); + } + } } diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/service/AirlineService.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/service/AirlineService.java index 851a5a4..5835b99 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/service/AirlineService.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/service/AirlineService.java @@ -15,11 +15,10 @@ */ package org.springframework.ws.samples.airline.service; +import java.time.ZonedDateTime; import java.util.List; -import org.joda.time.DateTime; import org.joda.time.LocalDate; - import org.springframework.ws.samples.airline.domain.Flight; import org.springframework.ws.samples.airline.domain.FrequentFlyer; import org.springframework.ws.samples.airline.domain.Passenger; @@ -52,9 +51,9 @@ public interface AirlineService { * @return a list of flights */ List getFlights(String fromAirportCode, - String toAirportCode, - LocalDate departureDate, - ServiceClass serviceClass); + String toAirportCode, + LocalDate departureDate, + ServiceClass serviceClass); /** * Books a single flight for a number of passengers. Passengers can be either specified by name or by frequent flyer @@ -69,10 +68,10 @@ public interface AirlineService { * exist * @throws NoSeatAvailableException if not enough seats are available for the flight * @throws NoSuchFrequentFlyerException if a specified {@link FrequentFlyer} cannot be found - * @see org.springframework.ws.samples.airline.domain.Passenger - * @see org.springframework.ws.samples.airline.domain.FrequentFlyer + * @see Passenger + * @see FrequentFlyer */ - Ticket bookFlight(String flightNumber, DateTime departureTime, List passengers) + Ticket bookFlight(String flightNumber, ZonedDateTime departureTime, List passengers) throws NoSuchFlightException, NoSeatAvailableException, NoSuchFrequentFlyerException; /** diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/service/NoSuchFlightException.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/service/NoSuchFlightException.java index b79db40..e6681ca 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/service/NoSuchFlightException.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/service/NoSuchFlightException.java @@ -16,7 +16,8 @@ package org.springframework.ws.samples.airline.service; -import org.joda.time.DateTime; +import java.time.ZonedDateTime; + import org.springframework.ws.soap.server.endpoint.annotation.FaultCode; import org.springframework.ws.soap.server.endpoint.annotation.SoapFault; @@ -30,9 +31,9 @@ public class NoSuchFlightException extends Exception { private String flightNumber; - private DateTime departureTime; + private ZonedDateTime departureTime; - public NoSuchFlightException(String flightNumber, DateTime departureTime) { + public NoSuchFlightException(String flightNumber, ZonedDateTime departureTime) { super("No flight with number [" + flightNumber + "] and departure time [" + departureTime + "]"); this.flightNumber = flightNumber; this.departureTime = departureTime; @@ -46,7 +47,7 @@ public class NoSuchFlightException extends Exception { return flightNumber; } - public DateTime getDepartureTime() { + public ZonedDateTime getDepartureTime() { return departureTime; } } diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java index c9cfec1..9680689 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java @@ -15,8 +15,12 @@ */ package org.springframework.ws.samples.airline.service.impl; +import java.time.ZonedDateTime; import java.util.List; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.joda.time.LocalDate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.annotation.Secured; import org.springframework.stereotype.Service; @@ -36,11 +40,6 @@ import org.springframework.ws.samples.airline.service.NoSeatAvailableException; import org.springframework.ws.samples.airline.service.NoSuchFlightException; import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.joda.time.DateTime; -import org.joda.time.LocalDate; - /** * Default implementation of the AirlineService interface. * @@ -50,97 +49,96 @@ import org.joda.time.LocalDate; @Transactional(readOnly = true) public class AirlineServiceImpl implements AirlineService { - private static final Log logger = LogFactory.getLog(AirlineServiceImpl.class); + private static final Log logger = LogFactory.getLog(AirlineServiceImpl.class); - private FlightDao flightDao; + private FlightDao flightDao; - private TicketDao ticketDao; + private TicketDao ticketDao; - private FrequentFlyerSecurityService frequentFlyerSecurityService = new StubFrequentFlyerSecurityService(); + private FrequentFlyerSecurityService frequentFlyerSecurityService = new StubFrequentFlyerSecurityService(); - @Autowired - public AirlineServiceImpl(FlightDao flightDao, TicketDao ticketDao) { - this.flightDao = flightDao; - this.ticketDao = ticketDao; - } + @Autowired + public AirlineServiceImpl(FlightDao flightDao, TicketDao ticketDao) { - @Autowired(required = false) - public void setFrequentFlyerSecurityService(FrequentFlyerSecurityService frequentFlyerSecurityService) { - this.frequentFlyerSecurityService = frequentFlyerSecurityService; - } + this.flightDao = flightDao; + this.ticketDao = ticketDao; + } - @Transactional(readOnly = false, - rollbackFor = {NoSuchFlightException.class, NoSeatAvailableException.class, NoSuchFrequentFlyerException.class}) - public Ticket bookFlight(String flightNumber, DateTime departureTime, List passengers) - throws NoSuchFlightException, NoSeatAvailableException, NoSuchFrequentFlyerException { - Assert.notEmpty(passengers, "No passengers given"); - if (logger.isDebugEnabled()) { - logger.debug("Booking flight '" + flightNumber + "' on '" + departureTime + "' for " + passengers); - } - Flight flight = flightDao.getFlight(flightNumber, departureTime); - if (flight == null) { - throw new NoSuchFlightException(flightNumber, departureTime); - } - else if (flight.getSeatsAvailable() < passengers.size()) { - throw new NoSeatAvailableException(flight); - } - Ticket ticket = new Ticket(); - ticket.setIssueDate(new LocalDate()); - ticket.setFlight(flight); - for (Passenger passenger : passengers) { - // frequent flyer service is not required - if (passenger instanceof FrequentFlyer && frequentFlyerSecurityService != null) { - String username = ((FrequentFlyer) passenger).getUsername(); - Assert.hasLength(username, "No username specified"); - FrequentFlyer frequentFlyer = frequentFlyerSecurityService.getFrequentFlyer(username); - frequentFlyer.addMiles(flight.getMiles()); - ticket.addPassenger(frequentFlyer); - } - else { - ticket.addPassenger(passenger); - } - } - flight.substractSeats(passengers.size()); - flightDao.update(flight); - ticketDao.save(ticket); - return ticket; - } + @Autowired(required = false) + public void setFrequentFlyerSecurityService(FrequentFlyerSecurityService frequentFlyerSecurityService) { + this.frequentFlyerSecurityService = frequentFlyerSecurityService; + } - public Flight getFlight(Long id) throws NoSuchFlightException { - Flight flight = flightDao.getFlight(id); - if (flight != null) { - return flight; - } - else { - throw new NoSuchFlightException(id); - } - } + @Transactional(readOnly = false, + rollbackFor = { NoSuchFlightException.class, NoSeatAvailableException.class, NoSuchFrequentFlyerException.class }) + public Ticket bookFlight(String flightNumber, ZonedDateTime departureTime, List passengers) + throws NoSuchFlightException, NoSeatAvailableException, NoSuchFrequentFlyerException { - public List getFlights(String fromAirportCode, - String toAirportCode, - LocalDate departureDate, - ServiceClass serviceClass) { - if (serviceClass == null) { - serviceClass = ServiceClass.ECONOMY; - } - if (logger.isDebugEnabled()) { - logger.debug( - "Getting flights from '" + fromAirportCode + "' to '" + toAirportCode + "' on " + departureDate); - } - List flights = - flightDao.findFlights(fromAirportCode, toAirportCode, departureDate.toInterval(), serviceClass); - if (logger.isDebugEnabled()) { - logger.debug("Returning " + flights.size() + " flights"); - } - return flights; - } + Assert.notEmpty(passengers, "No passengers given"); + if (logger.isDebugEnabled()) { + logger.debug("Booking flight '" + flightNumber + "' on '" + departureTime + "' for " + passengers); + } + Flight flight = flightDao.getFlight(flightNumber, departureTime); + if (flight == null) { + throw new NoSuchFlightException(flightNumber, departureTime); + } else if (flight.getSeatsAvailable() < passengers.size()) { + throw new NoSeatAvailableException(flight); + } + Ticket ticket = new Ticket(); + ticket.setIssueDate(new LocalDate()); + ticket.setFlight(flight); + for (Passenger passenger : passengers) { + // frequent flyer service is not required + if (passenger instanceof FrequentFlyer && frequentFlyerSecurityService != null) { + String username = ((FrequentFlyer) passenger).getUsername(); + Assert.hasLength(username, "No username specified"); + FrequentFlyer frequentFlyer = frequentFlyerSecurityService.getFrequentFlyer(username); + frequentFlyer.addMiles(flight.getMiles()); + ticket.addPassenger(frequentFlyer); + } else { + ticket.addPassenger(passenger); + } + } + flight.substractSeats(passengers.size()); + flightDao.update(flight); + ticketDao.save(ticket); + return ticket; + } - @Secured({"ROLE_FREQUENT_FLYER"}) - public int getFrequentFlyerMileage() { - if (logger.isDebugEnabled()) { - logger.debug("Using " + frequentFlyerSecurityService + " for security"); - } - FrequentFlyer frequentFlyer = frequentFlyerSecurityService.getCurrentlyAuthenticatedFrequentFlyer(); - return frequentFlyer != null ? frequentFlyer.getMiles() : 0; - } + public Flight getFlight(Long id) throws NoSuchFlightException { + + Flight flight = flightDao.getFlight(id); + if (flight != null) { + return flight; + } else { + throw new NoSuchFlightException(id); + } + } + + public List getFlights(String fromAirportCode, String toAirportCode, LocalDate departureDate, + ServiceClass serviceClass) { + + if (serviceClass == null) { + serviceClass = ServiceClass.ECONOMY; + } + if (logger.isDebugEnabled()) { + logger.debug("Getting flights from '" + fromAirportCode + "' to '" + toAirportCode + "' on " + departureDate); + } + List flights = flightDao.findFlights(fromAirportCode, toAirportCode, departureDate.toInterval(), + serviceClass); + if (logger.isDebugEnabled()) { + logger.debug("Returning " + flights.size() + " flights"); + } + return flights; + } + + @Secured({ "ROLE_FREQUENT_FLYER" }) + public int getFrequentFlyerMileage() { + + if (logger.isDebugEnabled()) { + logger.debug("Using " + frequentFlyerSecurityService + " for security"); + } + FrequentFlyer frequentFlyer = frequentFlyerSecurityService.getCurrentlyAuthenticatedFrequentFlyer(); + return frequentFlyer != null ? frequentFlyer.getMiles() : 0; + } } diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/web/FlightsController.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/web/FlightsController.java index 19e8525..0518fd7 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/web/FlightsController.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/web/FlightsController.java @@ -16,65 +16,63 @@ package org.springframework.ws.samples.airline.web; -import org.springframework.beans.factory.annotation.Autowired; +import org.joda.time.LocalDate; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.ws.samples.airline.domain.Flight; import org.springframework.ws.samples.airline.domain.ServiceClass; import org.springframework.ws.samples.airline.service.AirlineService; import org.springframework.ws.samples.airline.service.NoSuchFlightException; -import org.joda.time.LocalDate; - /** @author Arjen Poutsma */ @Controller @RequestMapping("/flights") public class FlightsController { - private AirlineService airlineService; + private AirlineService airlineService; - @Autowired - public FlightsController(AirlineService airlineService) { - Assert.notNull(airlineService, "'airlineService' must not be null"); - this.airlineService = airlineService; - } + public FlightsController(AirlineService airlineService) { - @RequestMapping - public String flightList(@RequestParam(value = "from", required = false)String fromAirportCode, - @RequestParam(value = "to", required = false)String toAirportCode, - @RequestParam(value = "departureDate", required = false)String departureDateString, - @RequestParam(value = "serviceClass", required = false)String serviceClassString, - ModelMap model) { - if (!StringUtils.hasLength(departureDateString)) { - departureDateString = new LocalDate().toString(); - } - if (!StringUtils.hasLength(serviceClassString)) { - serviceClassString = "ECONOMY"; - } - ServiceClass serviceClass = ServiceClass.valueOf(serviceClassString); - LocalDate departureDate = new LocalDate(departureDateString); + Assert.notNull(airlineService, "'airlineService' must not be null"); + this.airlineService = airlineService; + } - if (StringUtils.hasLength(fromAirportCode) && StringUtils.hasLength(toAirportCode)) { - model.addAttribute("from", fromAirportCode); - model.addAttribute("to", toAirportCode); - model.addAttribute("departureDate", departureDateString); - model.addAttribute("serviceClass", serviceClassString); - model.addAttribute("flights", - airlineService.getFlights(fromAirportCode, toAirportCode, departureDate, serviceClass)); - } - return "flights"; - } + @GetMapping + public String flightList(@RequestParam(value = "from", required = false) String fromAirportCode, + @RequestParam(value = "to", required = false) String toAirportCode, + @RequestParam(value = "departureDate", required = false) String departureDateString, + @RequestParam(value = "serviceClass", required = false) String serviceClassString, ModelMap model) { - @RequestMapping(value = "{id}") - public String singleFlight(@PathVariable("id") long id, ModelMap model) throws NoSuchFlightException { - Flight flight = airlineService.getFlight(id); - model.addAttribute(flight); - return "flight"; - } + if (StringUtils.isEmpty(departureDateString)) { + departureDateString = new LocalDate().toString(); + } + if (StringUtils.isEmpty(serviceClassString)) { + serviceClassString = "ECONOMY"; + } + ServiceClass serviceClass = ServiceClass.valueOf(serviceClassString); + LocalDate departureDate = new LocalDate(departureDateString); + + if (StringUtils.hasLength(fromAirportCode) && StringUtils.hasLength(toAirportCode)) { + model.addAttribute("from", fromAirportCode); + model.addAttribute("to", toAirportCode); + model.addAttribute("departureDate", departureDateString); + model.addAttribute("serviceClass", serviceClassString); + model.addAttribute("flights", + airlineService.getFlights(fromAirportCode, toAirportCode, departureDate, serviceClass)); + } + return "flights"; + } + + @GetMapping(value = "{id}") + public String singleFlight(@PathVariable("id") long id, ModelMap model) throws NoSuchFlightException { + + model.addAttribute(airlineService.getFlight(id)); + return "flight"; + } } diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/ws/AirlineEndpoint.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/ws/AirlineEndpoint.java index e0c9f8d..203d539 100644 --- a/airline/server/src/main/java/org/springframework/ws/samples/airline/ws/AirlineEndpoint.java +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/ws/AirlineEndpoint.java @@ -16,15 +16,22 @@ package org.springframework.ws.samples.airline.ws; +import static org.springframework.ws.samples.airline.ws.AirlineWebServiceConstants.*; + +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Iterator; import java.util.List; + import javax.xml.bind.JAXBElement; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.joda.time.LocalDate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.ws.samples.airline.domain.FrequentFlyer; @@ -46,16 +53,9 @@ import org.springframework.ws.server.endpoint.annotation.PayloadRoot; import org.springframework.ws.server.endpoint.annotation.RequestPayload; import org.springframework.ws.server.endpoint.annotation.ResponsePayload; import org.springframework.ws.server.endpoint.annotation.XPathParam; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.joda.time.DateTime; -import org.joda.time.LocalDate; import org.w3c.dom.Document; import org.w3c.dom.Element; -import static org.springframework.ws.samples.airline.ws.AirlineWebServiceConstants.*; - /** * Endpoint that handles the Airline Web Service messages using a combination of JAXB2 marshalling and XPath * expressions. @@ -65,115 +65,122 @@ import static org.springframework.ws.samples.airline.ws.AirlineWebServiceConstan @Endpoint public class AirlineEndpoint { - private static final Log logger = LogFactory.getLog(AirlineEndpoint.class); + private static final Log logger = LogFactory.getLog(AirlineEndpoint.class); - private final ObjectFactory objectFactory = new ObjectFactory(); + private final ObjectFactory objectFactory = new ObjectFactory(); - private final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + private final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); - private final AirlineService airlineService; + private final AirlineService airlineService; - @Autowired - public AirlineEndpoint(AirlineService airlineService) { - this.airlineService = airlineService; - } + @Autowired + public AirlineEndpoint(AirlineService airlineService) { + this.airlineService = airlineService; + } - /** - * This endpoint method uses a combination of XPath expressions and marshalling to handle message with a - * <GetFlightsRequest> payload. - * - * @param from the from airport - * @param to the to airport - * @param departureDateString the string representation of the departure date - * @param serviceClassString the string representation of the service class - * @return the JAXB2 representation of a <GetFlightsResponse> - */ - @PayloadRoot(localPart = GET_FLIGHTS_REQUEST, namespace = MESSAGES_NAMESPACE) - @Namespace(prefix = "m", uri = MESSAGES_NAMESPACE) - @ResponsePayload - public GetFlightsResponse getFlights(@XPathParam("//m:from") String from, - @XPathParam("//m:to") String to, - @XPathParam("//m:departureDate") String departureDateString, - @XPathParam("//m:serviceClass") String serviceClassString) - throws DatatypeConfigurationException { - if (logger.isDebugEnabled()) { - logger.debug("Received GetFlightsRequest '" + from + "' to '" + to + "' on " + departureDateString); - } - LocalDate departureDate = new LocalDate(departureDateString); - ServiceClass serviceClass = null; - if (StringUtils.hasLength(serviceClassString)) { - serviceClass = ServiceClass.valueOf(serviceClassString.toUpperCase()); - } - List flights = - airlineService.getFlights(from, to, departureDate, serviceClass); + /** + * This endpoint method uses a combination of XPath expressions and marshalling to handle message with a + * <GetFlightsRequest> payload. + * + * @param from the from airport + * @param to the to airport + * @param departureDateString the string representation of the departure date + * @param serviceClassString the string representation of the service class + * @return the JAXB2 representation of a <GetFlightsResponse> + */ + @PayloadRoot(localPart = GET_FLIGHTS_REQUEST, namespace = MESSAGES_NAMESPACE) + @Namespace(prefix = "m", uri = MESSAGES_NAMESPACE) + @ResponsePayload + public GetFlightsResponse getFlights(@XPathParam("//m:from") String from, @XPathParam("//m:to") String to, + @XPathParam("//m:departureDate") String departureDateString, + @XPathParam("//m:serviceClass") String serviceClassString) throws DatatypeConfigurationException { - GetFlightsResponse response = objectFactory.createGetFlightsResponse(); - for (org.springframework.ws.samples.airline.domain.Flight domainFlight : flights) { - response.getFlight().add(SchemaConversionUtils.toSchemaType(domainFlight)); - } - return response; - } + if (logger.isDebugEnabled()) { + logger.debug("Received GetFlightsRequest '" + from + "' to '" + to + "' on " + departureDateString); + } - /** - * This endpoint method uses marshalling to handle message with a <BookFlightRequest> payload. - * - * @param request the JAXB2 representation of a <BookFlightRequest> - * @return the JAXB2 representation of a <BookFlightResponse> - */ - @PayloadRoot(localPart = BOOK_FLIGHT_REQUEST, namespace = MESSAGES_NAMESPACE) - @ResponsePayload - public JAXBElement bookFlight(@RequestPayload BookFlightRequest request) - throws NoSeatAvailableException, DatatypeConfigurationException, NoSuchFlightException, - NoSuchFrequentFlyerException { - if (logger.isDebugEnabled()) { - logger.debug("Received BookingFlightRequest '" + request.getFlightNumber() + "' on '" + - request.getDepartureTime() + "' for " + request.getPassengers().getPassengerOrUsername()); - } - Ticket ticket = bookSchemaFlight(request.getFlightNumber(), request.getDepartureTime(), - request.getPassengers().getPassengerOrUsername()); - return objectFactory.createBookFlightResponse(ticket); - } + LocalDate departureDate = new LocalDate(departureDateString); + ServiceClass serviceClass = null; - /** - * Converts between the domain and schema types. - */ - private Ticket bookSchemaFlight(String flightNumber, - XMLGregorianCalendar xmlDepartureTime, - List passengerOrUsernameList) - throws NoSeatAvailableException, NoSuchFlightException, NoSuchFrequentFlyerException, - DatatypeConfigurationException { - DateTime departureTime = SchemaConversionUtils.toDateTime(xmlDepartureTime); - List passengers = new ArrayList(passengerOrUsernameList.size()); - for (Iterator iterator = passengerOrUsernameList.iterator(); iterator.hasNext();) { - Object passengerOrUsername = iterator.next(); - if (passengerOrUsername instanceof Name) { - Name passengerName = (Name) passengerOrUsername; - Passenger passenger = new Passenger(passengerName.getFirst(), passengerName.getLast()); - passengers.add(passenger); - } - else if (passengerOrUsername instanceof String) { - String frequentFlyerUsername = (String) passengerOrUsername; - FrequentFlyer frequentFlyer = new FrequentFlyer(frequentFlyerUsername); - passengers.add(frequentFlyer); - } - } - org.springframework.ws.samples.airline.domain.Ticket domainTicket = - airlineService.bookFlight(flightNumber, departureTime, passengers); - return SchemaConversionUtils.toSchemaType(domainTicket); - } + if (StringUtils.hasLength(serviceClassString)) { + serviceClass = ServiceClass.valueOf(serviceClassString.toUpperCase()); + } + List flights = airlineService.getFlights(from, to, + departureDate, serviceClass); - @PayloadRoot(localPart = GET_FREQUENT_FLYER_MILEAGE_REQUEST, namespace = MESSAGES_NAMESPACE) - @ResponsePayload - public Element getFrequentFlyerMileage() throws Exception { - if (logger.isDebugEnabled()) { - logger.debug("Received GetFrequentFlyerMileageRequest"); - } - int mileage = airlineService.getFrequentFlyerMileage(); - DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); - Document document = documentBuilder.newDocument(); - Element response = document.createElementNS(MESSAGES_NAMESPACE, GET_FREQUENT_FLYER_MILEAGE_RESPONSE); - response.setTextContent(Integer.toString(mileage)); - return response; - } + GetFlightsResponse response = objectFactory.createGetFlightsResponse(); + for (org.springframework.ws.samples.airline.domain.Flight domainFlight : flights) { + response.getFlight().add(SchemaConversionUtils.toSchemaType(domainFlight)); + } + + return response; + } + + /** + * This endpoint method uses marshalling to handle message with a <BookFlightRequest> payload. + * + * @param request the JAXB2 representation of a <BookFlightRequest> + * @return the JAXB2 representation of a <BookFlightResponse> + */ + @PayloadRoot(localPart = BOOK_FLIGHT_REQUEST, namespace = MESSAGES_NAMESPACE) + @ResponsePayload + public JAXBElement bookFlight(@RequestPayload BookFlightRequest request) throws NoSeatAvailableException, + DatatypeConfigurationException, NoSuchFlightException, NoSuchFrequentFlyerException { + + if (logger.isDebugEnabled()) { + logger.debug("Received BookingFlightRequest '" + request.getFlightNumber() + "' on '" + request.getDepartureTime() + + "' for " + request.getPassengers().getPassengerOrUsername()); + } + + Ticket ticket = bookSchemaFlight(request.getFlightNumber(), request.getDepartureTime(), + request.getPassengers().getPassengerOrUsername()); + + return objectFactory.createBookFlightResponse(ticket); + } + + /** + * Converts between the domain and schema types. + */ + private Ticket bookSchemaFlight(String flightNumber, XMLGregorianCalendar xmlDepartureTime, + List passengerOrUsernameList) throws NoSeatAvailableException, NoSuchFlightException, + NoSuchFrequentFlyerException, DatatypeConfigurationException { + + ZonedDateTime departureTime = SchemaConversionUtils.toDateTime(xmlDepartureTime); + List passengers = new ArrayList(passengerOrUsernameList.size()); + + for (Iterator iterator = passengerOrUsernameList.iterator(); iterator.hasNext();) { + Object passengerOrUsername = iterator.next(); + if (passengerOrUsername instanceof Name) { + Name passengerName = (Name) passengerOrUsername; + Passenger passenger = new Passenger(passengerName.getFirst(), passengerName.getLast()); + passengers.add(passenger); + } else if (passengerOrUsername instanceof String) { + String frequentFlyerUsername = (String) passengerOrUsername; + FrequentFlyer frequentFlyer = new FrequentFlyer(frequentFlyerUsername); + passengers.add(frequentFlyer); + } + } + org.springframework.ws.samples.airline.domain.Ticket domainTicket = airlineService.bookFlight(flightNumber, + departureTime, passengers); + + return SchemaConversionUtils.toSchemaType(domainTicket); + } + + @PayloadRoot(localPart = GET_FREQUENT_FLYER_MILEAGE_REQUEST, namespace = MESSAGES_NAMESPACE) + @ResponsePayload + public Element getFrequentFlyerMileage() throws Exception { + + if (logger.isDebugEnabled()) { + logger.debug("Received GetFrequentFlyerMileageRequest"); + } + + int mileage = airlineService.getFrequentFlyerMileage(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + Document document = documentBuilder.newDocument(); + Element response = document.createElementNS(MESSAGES_NAMESPACE, GET_FREQUENT_FLYER_MILEAGE_RESPONSE); + response.setTextContent(Integer.toString(mileage)); + + return response; + } } diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/ws/WebServicesConfiguration.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/ws/WebServicesConfiguration.java new file mode 100644 index 0000000..e2daf54 --- /dev/null +++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/ws/WebServicesConfiguration.java @@ -0,0 +1,121 @@ +package org.springframework.ws.samples.airline.ws; + +import org.springframework.boot.web.server.MimeMappings; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.util.MimeTypeUtils; +import org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor; +import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; +import org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor; +import org.springframework.ws.soap.security.xwss.callback.SpringDigestPasswordValidationCallbackHandler; +import org.springframework.ws.soap.server.SoapMessageDispatcher; +import org.springframework.ws.soap.server.endpoint.interceptor.PayloadRootSmartSoapEndpointInterceptor; +import org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor; +import org.springframework.ws.transport.http.MessageDispatcherServlet; +import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition; +import org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection; + +@Configuration +public class WebServicesConfiguration { + + @Bean + WebServerFactoryCustomizer wsMimeMappings() { + + return factory -> { + MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT); + mappings.add("xsd", MimeTypeUtils.TEXT_XML_VALUE); + factory.setMimeMappings(mappings); + }; + } + + @Bean + ServletRegistrationBean webServicesRegistration(ApplicationContext ctx) { + + MessageDispatcherServlet messageDispatcherServlet = new MessageDispatcherServlet(); + messageDispatcherServlet.setApplicationContext(ctx); + messageDispatcherServlet.setTransformWsdlLocations(true); + + return new ServletRegistrationBean<>(messageDispatcherServlet, "/airline-server/*", "*.wsdl"); + } + + @Bean + PayloadLoggingInterceptor payloadLoggingInterceptor() { + return new PayloadLoggingInterceptor(); + } + + @Bean + PayloadValidatingInterceptor payloadValidatingInterceptor(CommonsXsdSchemaCollection xsdSchemaCollection) { + + PayloadValidatingInterceptor payloadValidatingInterceptor = new PayloadValidatingInterceptor(); + payloadValidatingInterceptor.setXsdSchemaCollection(xsdSchemaCollection); + payloadValidatingInterceptor.setValidateRequest(true); + payloadValidatingInterceptor.setValidateResponse(true); + + return payloadValidatingInterceptor; + } + + @Bean + XwsSecurityInterceptor securityInterceptor(UserDetailsService securityService) { + + XwsSecurityInterceptor securityInterceptor = new XwsSecurityInterceptor(); + securityInterceptor.setSecureResponse(false); + securityInterceptor.setPolicyConfiguration( + new ClassPathResource("org/springframework/ws/samples/airline/security/securityPolicy.xml")); + securityInterceptor.setCallbackHandler(springDigestPasswordValidationCallbackHandler(securityService)); + + return securityInterceptor; + } + + @Bean + PayloadRootSmartSoapEndpointInterceptor smartSoapEndpointInterceptor(XwsSecurityInterceptor securityInterceptor) { + + return new PayloadRootSmartSoapEndpointInterceptor(securityInterceptor, + "http://www.springframework.org/spring-ws/samples/airline/schemas/messages", "GetFrequentFlyerMileageRequest"); + } + + @Bean + SpringDigestPasswordValidationCallbackHandler springDigestPasswordValidationCallbackHandler( + UserDetailsService securityService) { + + SpringDigestPasswordValidationCallbackHandler handler = new SpringDigestPasswordValidationCallbackHandler(); + handler.setUserDetailsService(securityService); + return handler; + } + + @Bean + SaajSoapMessageFactory messageFactory() { + return new SaajSoapMessageFactory(); + } + + @Bean + SoapMessageDispatcher dispatcher() { + return new SoapMessageDispatcher(); + } + + @Bean + CommonsXsdSchemaCollection commonsXsdSchemaCollection() { + + CommonsXsdSchemaCollection commonsXsdSchemaCollection = new CommonsXsdSchemaCollection(); + commonsXsdSchemaCollection.setXsds(new ClassPathResource("messages.xsd")); + commonsXsdSchemaCollection.setInline(true); + return commonsXsdSchemaCollection; + } + + @Bean("services") + DefaultWsdl11Definition airline(CommonsXsdSchemaCollection schemaCollection) { + + DefaultWsdl11Definition definition = new DefaultWsdl11Definition(); + definition.setSchemaCollection(schemaCollection); + definition.setPortTypeName("Airline"); + definition.setLocationUri("http://localhost:8080/airline-server/services"); + definition.setTargetNamespace("http://www.springframework.org/spring-ws/samples/airline/definitions"); + return definition; + } + +} diff --git a/airline/server/src/main/resources/META-INF/persistence.xml b/airline/server/src/main/resources/META-INF/persistence.xml deleted file mode 100644 index 0834a67..0000000 --- a/airline/server/src/main/resources/META-INF/persistence.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - org.apache.openjpa.persistence.PersistenceProviderImpl - org.springframework.ws.samples.airline.domain.Airport - org.springframework.ws.samples.airline.domain.Flight - org.springframework.ws.samples.airline.domain.FrequentFlyer - org.springframework.ws.samples.airline.domain.Passenger - org.springframework.ws.samples.airline.domain.Ticket - - - diff --git a/airline/server/src/main/resources/application.properties b/airline/server/src/main/resources/application.properties new file mode 100644 index 0000000..0f447a3 --- /dev/null +++ b/airline/server/src/main/resources/application.properties @@ -0,0 +1,3 @@ +logging.level.org.springframework.data=DEBUG +logging.level.org.springframework.ws=DEBUG +logging.level.org.springframework.web=DEBUG diff --git a/airline/server/src/main/resources/log4j.properties b/airline/server/src/main/resources/log4j.properties deleted file mode 100644 index c44d7a4..0000000 --- a/airline/server/src/main/resources/log4j.properties +++ /dev/null @@ -1,8 +0,0 @@ -log4j.rootLogger=WARN, stdout -log4j.logger.org.springframework.ws=DEBUG -log4j.logger.org.springframework.xml=DEBUG -log4j.logger.openjpa=INFO - -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n \ No newline at end of file diff --git a/airline/server/src/main/webapp/messages.xsd b/airline/server/src/main/resources/messages.xsd similarity index 100% rename from airline/server/src/main/webapp/messages.xsd rename to airline/server/src/main/resources/messages.xsd diff --git a/airline/server/src/main/resources/org/springframework/ws/samples/airline/dao/jpa/applicationContext-jpa.xml b/airline/server/src/main/resources/org/springframework/ws/samples/airline/dao/jpa/applicationContext-jpa.xml deleted file mode 100644 index 20062a7..0000000 --- a/airline/server/src/main/resources/org/springframework/ws/samples/airline/dao/jpa/applicationContext-jpa.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - commons - buildSchema - - FieldStrategies='org.joda.time.DateTime=org.springframework.ws.samples.airline.domain.openjpa.DateTimeValueHandler, - org.joda.time.LocalDate=org.springframework.ws.samples.airline.domain.openjpa.LocalDateValueHandler' - - org.apache.openjpa.jdbc.sql.HSQLDictionary - - - - - - - - - - - - - - - - diff --git a/airline/server/src/main/resources/org/springframework/ws/samples/airline/jms/applicationContext-jms.xml b/airline/server/src/main/resources/org/springframework/ws/samples/airline/jms/applicationContext-jms.xml deleted file mode 100644 index 1fa957e..0000000 --- a/airline/server/src/main/resources/org/springframework/ws/samples/airline/jms/applicationContext-jms.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/airline/server/src/main/resources/org/springframework/ws/samples/airline/security/applicationContext-security.xml b/airline/server/src/main/resources/org/springframework/ws/samples/airline/security/applicationContext-security.xml deleted file mode 100644 index c51aee7..0000000 --- a/airline/server/src/main/resources/org/springframework/ws/samples/airline/security/applicationContext-security.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - This application context contains the WS-Security and Spring Security beans. - - - - - - - - - - - A security service used to obtain Frequent Flyer information. - - - - - \ No newline at end of file diff --git a/airline/server/src/main/resources/org/springframework/ws/samples/airline/security/securityPolicy.xml b/airline/server/src/main/resources/org/springframework/ws/samples/airline/security/securityPolicy.xml index 0d7140f..b6d644b 100644 --- a/airline/server/src/main/resources/org/springframework/ws/samples/airline/security/securityPolicy.xml +++ b/airline/server/src/main/resources/org/springframework/ws/samples/airline/security/securityPolicy.xml @@ -1,3 +1,3 @@ - + diff --git a/airline/server/src/main/resources/org/springframework/ws/samples/airline/service/applicationContext.xml b/airline/server/src/main/resources/org/springframework/ws/samples/airline/service/applicationContext.xml deleted file mode 100644 index 6cefe32..0000000 --- a/airline/server/src/main/resources/org/springframework/ws/samples/airline/service/applicationContext.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/airline/server/src/main/resources/org/springframework/ws/samples/airline/ws/applicationContext-ws.xml b/airline/server/src/main/resources/org/springframework/ws/samples/airline/ws/applicationContext-ws.xml deleted file mode 100644 index fd44eb4..0000000 --- a/airline/server/src/main/resources/org/springframework/ws/samples/airline/ws/applicationContext-ws.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - This bean wrap the messages.xsd (which imports types.xsd), and inlines them as a one. - - - - - - diff --git a/airline/server/src/main/resources/templates/flight.html b/airline/server/src/main/resources/templates/flight.html new file mode 100644 index 0000000..feb65e1 --- /dev/null +++ b/airline/server/src/main/resources/templates/flight.html @@ -0,0 +1,41 @@ + + +Flights + + + + + + + + + + + + + + + + + + + + + + +
Number: + +
From: + + () +
Departure: + +
To: + + () +
Departure: + +
+Flights + + \ No newline at end of file diff --git a/airline/server/src/main/resources/templates/flights.html b/airline/server/src/main/resources/templates/flights.html new file mode 100644 index 0000000..84d2792 --- /dev/null +++ b/airline/server/src/main/resources/templates/flights.html @@ -0,0 +1,62 @@ + + +Flights + +
+ + + + + + + + + + + + + + + + + + + + +
From:
To:
Departure Date:
Service Class: + +
+ +
+
+ + + + + + + + + + + + +
NumberDepartsArrives
+ + + + () + + + + () + +
+
+
+ + \ No newline at end of file diff --git a/airline/server/src/main/resources/templates/noSuchFlight.html b/airline/server/src/main/resources/templates/noSuchFlight.html new file mode 100644 index 0000000..598a823 --- /dev/null +++ b/airline/server/src/main/resources/templates/noSuchFlight.html @@ -0,0 +1,12 @@ + + +No Such Flight + + +

+ +

No such flight:

+Flights + + + \ No newline at end of file diff --git a/airline/server/src/main/webapp/types.xsd b/airline/server/src/main/resources/types.xsd similarity index 100% rename from airline/server/src/main/webapp/types.xsd rename to airline/server/src/main/resources/types.xsd diff --git a/airline/server/src/main/webapp/WEB-INF/jsp/error.jsp b/airline/server/src/main/webapp/WEB-INF/jsp/error.jsp deleted file mode 100644 index d7654d9..0000000 --- a/airline/server/src/main/webapp/WEB-INF/jsp/error.jsp +++ /dev/null @@ -1,13 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - -<% - Exception ex = (Exception) request.getAttribute("exception"); -%> -<%= ex.getMessage() %> - - -

<%= ex.getMessage() %> -

-Flights - - \ No newline at end of file diff --git a/airline/server/src/main/webapp/WEB-INF/jsp/flight.jsp b/airline/server/src/main/webapp/WEB-INF/jsp/flight.jsp deleted file mode 100644 index 7c76fc0..0000000 --- a/airline/server/src/main/webapp/WEB-INF/jsp/flight.jsp +++ /dev/null @@ -1,47 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="joda" uri="http://www.joda.org/joda/time/tags" %> - -Flights - - - - - - - - - - - - - - - - - - - - - - -
Number: - -
From: - - ( - - ) -
Departure: - -
To: - - ( - - ) -
Departure: - -
-Flights - - \ No newline at end of file diff --git a/airline/server/src/main/webapp/WEB-INF/jsp/flights.jsp b/airline/server/src/main/webapp/WEB-INF/jsp/flights.jsp deleted file mode 100644 index 441c92e..0000000 --- a/airline/server/src/main/webapp/WEB-INF/jsp/flights.jsp +++ /dev/null @@ -1,73 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> -<%@ taglib prefix="joda" uri="http://www.joda.org/joda/time/tags" %> - -Flights - -
- - - - - - - - - - - - - - - - - - - - -
From:
To:"/>
Departure Date:"/>
Service Class: - -
- -
- - - - - - - - - - - - - - -
NumberDepartsArrives
- - - - - - - ( - - ) - - - - ( - - ) - -
-
-
- - \ No newline at end of file diff --git a/airline/server/src/main/webapp/WEB-INF/jsp/noSuchFlight.jsp b/airline/server/src/main/webapp/WEB-INF/jsp/noSuchFlight.jsp deleted file mode 100644 index 2a6ede9..0000000 --- a/airline/server/src/main/webapp/WEB-INF/jsp/noSuchFlight.jsp +++ /dev/null @@ -1,13 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - -No Such Flight - -<% - Exception ex = (Exception) request.getAttribute("exception"); -%> -

No such flight: <%= ex.getMessage() %> -

-Flights - - - \ No newline at end of file diff --git a/airline/server/src/main/webapp/WEB-INF/mvc-servlet.xml b/airline/server/src/main/webapp/WEB-INF/mvc-servlet.xml deleted file mode 100644 index 9a71074..0000000 --- a/airline/server/src/main/webapp/WEB-INF/mvc-servlet.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - This web application context contains a simple Spring Web MVC web application that shows flights - - - - - - - - - - - - - - - - - - noSuchFlight - - - - - - \ No newline at end of file diff --git a/airline/server/src/main/webapp/WEB-INF/web.xml b/airline/server/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 12586dc..0000000 --- a/airline/server/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - Spring-WS Airline Sample - - contextConfigLocation - - classpath:org/springframework/ws/samples/airline/dao/jpa/applicationContext-jpa.xml - classpath:org/springframework/ws/samples/airline/service/applicationContext.xml - classpath:org/springframework/ws/samples/airline/security/applicationContext-security.xml - classpath:org/springframework/ws/samples/airline/ws/applicationContext-ws.xml - classpath:org/springframework/ws/samples/airline/jms/applicationContext-jms.xml - - - - org.springframework.web.context.ContextLoaderListener - - - ws - org.springframework.ws.transport.http.MessageDispatcherServlet - - - ws - /services - - - ws - *.wsdl - - - mvc - org.springframework.web.servlet.DispatcherServlet - - - mvc - *.html - - - xsd - text/xml - - - index.jsp - - \ No newline at end of file diff --git a/airline/server/src/main/webapp/WEB-INF/ws-servlet.xml b/airline/server/src/main/webapp/WEB-INF/ws-servlet.xml deleted file mode 100644 index eda6c0c..0000000 --- a/airline/server/src/main/webapp/WEB-INF/ws-servlet.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - Builds a WSDL from the airline.xsd.This bean definition represents the airline.wsdl file found - in the root of the web application. - - - - - - - - \ No newline at end of file diff --git a/airline/server/src/main/webapp/index.jsp b/airline/server/src/main/webapp/index.jsp deleted file mode 100644 index 0937555..0000000 --- a/airline/server/src/main/webapp/index.jsp +++ /dev/null @@ -1,3 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - \ No newline at end of file diff --git a/airline/server/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDaoTest.java b/airline/server/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDaoTest.java deleted file mode 100644 index 3637cdf..0000000 --- a/airline/server/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDaoTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2005-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. - */ - -package org.springframework.ws.samples.airline.dao.jpa; - -import java.util.List; -import javax.sql.DataSource; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.transaction.BeforeTransaction; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.ws.samples.airline.dao.FlightDao; -import org.springframework.ws.samples.airline.domain.Airport; -import org.springframework.ws.samples.airline.domain.Flight; -import org.springframework.ws.samples.airline.domain.ServiceClass; - -import org.joda.time.DateTime; -import org.joda.time.Interval; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration("applicationContext-jpa.xml") -@Transactional -public class JpaFlightDaoTest { - - private DateTime departureTime; - - private DateTime arrivalTime; - - private Interval interval; - - private Airport fromAirport; - - private Airport toAirport; - - @Autowired - private FlightDao flightDao; - - private JdbcTemplate jdbcTemplate; - - @Autowired - public void setDataSource(DataSource dataSource) { - jdbcTemplate = new JdbcTemplate(dataSource); - } - - @BeforeTransaction - public void createTestData() { - departureTime = new DateTime(2006, 1, 31, 10, 5, 0, 0); - arrivalTime = new DateTime(2006, 1, 31, 12, 25, 0, 0); - interval = departureTime.toLocalDate().toInterval(); - fromAirport = new Airport("RTM", "Rotterdam Airport", "Rotterdam"); - toAirport = new Airport("OSL", "Gardermoen", "Oslo"); - } - - @Before - public void insertTestData() { - jdbcTemplate.update("INSERT INTO AIRPORT(CODE, NAME, CITY) VALUES('RTM', 'Rotterdam Airport', 'Rotterdam')"); - jdbcTemplate.update("INSERT INTO AIRPORT(CODE, NAME, CITY) VALUES('OSL', 'Gardermoen', 'Oslo')"); - } - - @Test - public void getFlightsInPeriod() throws Exception { - jdbcTemplate - .update("INSERT INTO FLIGHT(NUMBER, DEPARTURE_TIME, FROM_AIRPORT_CODE, ARRIVAL_TIME, TO_AIRPORT_CODE, SERVICE_CLASS, SEATS_AVAILABLE, MILES) " + - "VALUES ('KL020','2006-01-31 10:05:00', 'RTM', '2006-01-31 12:25:00', 'OSL', 'BUSINESS', 90, 10)"); - List flights = flightDao.findFlights("RTM", "OSL", interval, ServiceClass.BUSINESS); - assertNotNull("Invalid result", flights); - assertEquals("Invalid amount of flights", 1, flights.size()); - } - - @Test - public void getFlightsOutOfPeriod() throws Exception { - jdbcTemplate - .update("INSERT INTO FLIGHT(NUMBER, DEPARTURE_TIME, FROM_AIRPORT_CODE, ARRIVAL_TIME, TO_AIRPORT_CODE, SERVICE_CLASS, SEATS_AVAILABLE, MILES) " + - "VALUES ('KL020','2006-01-31 10:05:00', 'RTM', '2006-01-31 12:25:00', 'OSL', 'BUSINESS', 90, 10)"); - DateTime dateTime = new DateTime(2006, 6, 1, 0, 0, 0, 0); - List flights = flightDao.findFlights("RTM", "OSL", new Interval(dateTime, dateTime), ServiceClass.BUSINESS); - assertNotNull("Invalid result", flights); - assertEquals("Invalid amount of flights", 0, flights.size()); - } - - @Test - public void getFlightByNumberDepartureTime() throws Exception { - jdbcTemplate - .update("INSERT INTO FLIGHT(NUMBER, DEPARTURE_TIME, FROM_AIRPORT_CODE, ARRIVAL_TIME, TO_AIRPORT_CODE, SERVICE_CLASS, SEATS_AVAILABLE, MILES) " + - "VALUES ('KL020','2006-01-31 10:05:00', 'RTM', '2006-01-31 12:25:00', 'OSL', 'BUSINESS', 90, 10)"); - Flight flight = flightDao.getFlight("KL020", departureTime); - assertNotNull("No flight returned", flight); - assertNotNull("Invalid flight id", flight.getId()); - assertEquals("Invalid flight number", "KL020", flight.getNumber()); - assertEquals("Invalid flight departure time", departureTime, flight.getDepartureTime()); - assertEquals("Invalid flight arrival time", arrivalTime, flight.getArrivalTime()); - assertEquals("Invalid flight from airport", fromAirport, flight.getFrom()); - assertEquals("Invalid flight to airport", toAirport, flight.getTo()); - assertEquals("Invalid flight service class", ServiceClass.BUSINESS, flight.getServiceClass()); - } - - @Test - public void noSuchFlight() { - Flight flight = flightDao.getFlight("INVALID", departureTime); - assertNull("Flight returned", flight); - } - -} \ No newline at end of file diff --git a/airline/server/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDaoTest.java b/airline/server/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDaoTest.java deleted file mode 100644 index b6e20c5..0000000 --- a/airline/server/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDaoTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2005-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. - */ - -package org.springframework.ws.samples.airline.dao.jpa; - -import javax.sql.DataSource; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.ws.samples.airline.domain.FrequentFlyer; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration("applicationContext-jpa.xml") -@Transactional -public class JpaFrequentFlyerDaoTest { - - @Autowired - private JpaFrequentFlyerDao frequentFlyerDao; - - private JdbcTemplate jdbcTemplate; - - @Autowired - public void setDataSource(DataSource dataSource) { - jdbcTemplate = new JdbcTemplate(dataSource); - } - - @Before - public void insertTestData() { - jdbcTemplate - .update("INSERT INTO PASSENGER(ID, FIRST_NAME, LAST_NAME) " + "VALUES (42, 'Arjen', 'Poutsma')"); - jdbcTemplate - .update("INSERT INTO FREQUENT_FLYER(PASSENGER_ID, USERNAME, PASSWORD, MILES) " + - "VALUES (42, 'arjen', 'changeme', 0)"); - } - - @Test - public void getByUsername() throws Exception { - FrequentFlyer flyer = frequentFlyerDao.get("arjen"); - assertNotNull("No frequent flyer returned", flyer); - assertEquals("Invalid username", "arjen", flyer.getUsername()); - assertEquals("Invalid password", "changeme", flyer.getPassword()); - assertEquals("Invalid first name", "Arjen", flyer.getFirstName()); - assertEquals("Invalid last name", "Poutsma", flyer.getLastName()); - } - - @Test - public void noSuchUsername() { - FrequentFlyer flyer = frequentFlyerDao.get("invalid"); - assertNull("FrequentFlyer returned", flyer); - } -} \ No newline at end of file diff --git a/airline/server/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaTicketDaoTest.java b/airline/server/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaTicketDaoTest.java deleted file mode 100644 index 2e4a5f7..0000000 --- a/airline/server/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaTicketDaoTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2005-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. - */ - -package org.springframework.ws.samples.airline.dao.jpa; - -import javax.sql.DataSource; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.ws.samples.airline.domain.Flight; -import org.springframework.ws.samples.airline.domain.Passenger; -import org.springframework.ws.samples.airline.domain.Ticket; - -import org.joda.time.LocalDate; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration("applicationContext-jpa.xml") -@Transactional -public class JpaTicketDaoTest { - - @Autowired - private JpaTicketDao ticketDao; - - @Autowired - private JpaFlightDao flightDao; - - private JdbcTemplate jdbcTemplate; - - @Autowired - public void setDataSource(DataSource dataSource) { - jdbcTemplate = new JdbcTemplate(dataSource); - } - - @Before - public void insertTestData() { - jdbcTemplate.update("INSERT INTO AIRPORT(CODE, NAME, CITY) VALUES('RTM', 'Rotterdam Airport', 'Rotterdam')"); - jdbcTemplate.update("INSERT INTO AIRPORT(CODE, NAME, CITY) VALUES('OSL', 'Gardermoen', 'Oslo')"); - jdbcTemplate - .update("INSERT INTO FLIGHT(ID, NUMBER, DEPARTURE_TIME, FROM_AIRPORT_CODE, ARRIVAL_TIME, TO_AIRPORT_CODE, SERVICE_CLASS, SEATS_AVAILABLE, MILES) " + - "VALUES (42, 'KL020','2006-01-31 10:05:00', 'RTM', '2006-01-31 12:25:00', 'OSL', 'BUSINESS', 90, 10)"); - } - - @Test - public void save() throws Exception { - Passenger passenger = new Passenger("Arjen", "Poutsma"); - Flight flight = flightDao.getFlight(42L); - Ticket ticket = new Ticket(); - ticket.addPassenger(passenger); - ticket.setFlight(flight); - ticket.setIssueDate(new LocalDate()); - int startTicketCount = jdbcTemplate.queryForInt("SELECT COUNT(0) FROM TICKET"); - int startPassengerCount = jdbcTemplate.queryForInt("SELECT COUNT(0) FROM PASSENGER"); - ticketDao.save(ticket); - assertNotNull("No Id generated", ticket.getId()); - int endTicketCount = jdbcTemplate.queryForInt("SELECT COUNT(0) FROM TICKET"); - int endPassengerCount = jdbcTemplate.queryForInt("SELECT COUNT(0) FROM PASSENGER"); - assertEquals("Flight not inserted", 1, endTicketCount - startTicketCount); - assertEquals("Passenger not inserted", 1, endPassengerCount - startPassengerCount); - } - -} \ No newline at end of file diff --git a/airline/server/src/test/java/org/springframework/ws/samples/airline/security/SpringFrequentFlyerSecurityServiceTest.java b/airline/server/src/test/java/org/springframework/ws/samples/airline/security/SpringFrequentFlyerSecurityServiceTest.java deleted file mode 100644 index 6cbf555..0000000 --- a/airline/server/src/test/java/org/springframework/ws/samples/airline/security/SpringFrequentFlyerSecurityServiceTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2005-2012 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.airline.security; - -import org.springframework.security.authentication.TestingAuthenticationToken; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.context.SecurityContextImpl; -import org.springframework.ws.samples.airline.dao.FrequentFlyerDao; -import org.springframework.ws.samples.airline.domain.FrequentFlyer; - -import junit.framework.TestCase; - -import static org.easymock.EasyMock.*; - -public class SpringFrequentFlyerSecurityServiceTest extends TestCase { - - private SpringFrequentFlyerSecurityService securityService; - - private FrequentFlyerDao flyerDaoMock; - - @Override - protected void setUp() throws Exception { - flyerDaoMock = createMock(FrequentFlyerDao.class); - securityService = new SpringFrequentFlyerSecurityService(flyerDaoMock); - } - - public void testGetCurrentlyAuthenticatedFrequentFlyer() throws Exception { - FrequentFlyer frequentFlyer = new FrequentFlyer("john"); - FrequentFlyerDetails detail = new FrequentFlyerDetails(frequentFlyer); - TestingAuthenticationToken token = new TestingAuthenticationToken(detail, null); - SecurityContext context = new SecurityContextImpl(); - context.setAuthentication(token); - SecurityContextHolder.setContext(context); - replay(flyerDaoMock); - FrequentFlyer result = securityService.getCurrentlyAuthenticatedFrequentFlyer(); - assertEquals("Invalid result", frequentFlyer, result); - verify(flyerDaoMock); - } - - public void testGetFrequentFlyer() throws Exception { - FrequentFlyer frequentFlyer = new FrequentFlyer("john"); - expect(flyerDaoMock.get("john")).andReturn(frequentFlyer); - replay(flyerDaoMock); - FrequentFlyer result = securityService.getFrequentFlyer("john"); - assertEquals("Invalid result", frequentFlyer, result); - verify(flyerDaoMock); - } -} diff --git a/airline/server/src/test/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImplTest.java b/airline/server/src/test/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImplTest.java deleted file mode 100644 index db5cb71..0000000 --- a/airline/server/src/test/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImplTest.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright 2005-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. - */ - -package org.springframework.ws.samples.airline.service.impl; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import junit.framework.TestCase; -import static org.easymock.EasyMock.*; -import org.joda.time.DateTime; -import org.joda.time.LocalDate; -import org.springframework.ws.samples.airline.dao.FlightDao; -import org.springframework.ws.samples.airline.dao.TicketDao; -import org.springframework.ws.samples.airline.domain.Flight; -import org.springframework.ws.samples.airline.domain.FrequentFlyer; -import org.springframework.ws.samples.airline.domain.Passenger; -import org.springframework.ws.samples.airline.domain.ServiceClass; -import org.springframework.ws.samples.airline.domain.Ticket; -import org.springframework.ws.samples.airline.security.FrequentFlyerSecurityService; -import org.springframework.ws.samples.airline.service.NoSeatAvailableException; -import org.springframework.ws.samples.airline.service.NoSuchFlightException; - -public class AirlineServiceImplTest extends TestCase { - - private AirlineServiceImpl airlineService; - - private FlightDao flightDaoMock; - - private TicketDao ticketDaoMock; - - private FrequentFlyerSecurityService securityServiceMock; - - private String flightNumber; - - @Override - protected void setUp() throws Exception { - flightDaoMock = createMock(FlightDao.class); - ticketDaoMock = createMock(TicketDao.class); - airlineService = new AirlineServiceImpl(flightDaoMock, ticketDaoMock); - securityServiceMock = createMock(FrequentFlyerSecurityService.class); - airlineService.setFrequentFlyerSecurityService(securityServiceMock); - flightNumber = "AB1234"; - } - - public void testBookFlight() throws Exception { - DateTime departureTime = new DateTime(); - Passenger passenger = new Passenger("John", "Doe"); - List passengers = new ArrayList(); - passengers.add(passenger); - Flight flight = new Flight(); - flight.setNumber(flightNumber); - flight.setSeatsAvailable(10); - expect(flightDaoMock.getFlight(flightNumber, departureTime)).andReturn(flight); - expect(flightDaoMock.update(flight)).andReturn(flight); - Ticket ticket = new Ticket(); - ticket.setFlight(flight); - ticketDaoMock.save(isA(Ticket.class)); - - replay(flightDaoMock, ticketDaoMock, securityServiceMock); - - ticket = airlineService.bookFlight(flightNumber, departureTime, passengers); - assertNotNull("Invalid ticket", ticket); - assertEquals("Invalid flight", flight, ticket.getFlight()); - assertEquals("Invalid seats available", 9, flight.getSeatsAvailable()); - assertEquals("Invalid passengers count", 1, ticket.getPassengers().size()); - - verify(flightDaoMock, ticketDaoMock, securityServiceMock); - } - - public void testBookFlightFrequentFlyer() throws Exception { - DateTime departureTime = new DateTime(); - FrequentFlyer frequentFlyer = new FrequentFlyer("John", "Doe", "john", "changeme"); - List passengers = new ArrayList(); - passengers.add(frequentFlyer); - Flight flight = new Flight(); - flight.setNumber(flightNumber); - flight.setSeatsAvailable(1); - flight.setMiles(10); - expect(securityServiceMock.getFrequentFlyer("john")).andReturn(frequentFlyer); - expect(flightDaoMock.getFlight(flightNumber, departureTime)).andReturn(flight); - expect(flightDaoMock.update(flight)).andReturn(flight); - ticketDaoMock.save(isA(Ticket.class)); - - replay(flightDaoMock, ticketDaoMock, securityServiceMock); - - Ticket ticket = airlineService.bookFlight(flightNumber, departureTime, passengers); - assertNotNull("Invalid ticket", ticket); - assertEquals("Invalid flight", flight, ticket.getFlight()); - assertEquals("Invalid amount of miles", 10, frequentFlyer.getMiles()); - - verify(flightDaoMock, ticketDaoMock, securityServiceMock); - } - - public void testBookFlightNoSeatAvailable() throws Exception { - DateTime departureTime = new DateTime(); - List passengers = Collections.singletonList(new Passenger()); - Flight flight = new Flight(); - flight.setNumber("AB1234"); - flight.setDepartureTime(new DateTime()); - expect(flightDaoMock.getFlight(flightNumber, departureTime)).andReturn(flight); - - replay(flightDaoMock, ticketDaoMock, securityServiceMock); - - try { - airlineService.bookFlight(flightNumber, departureTime, passengers); - fail("Should have thrown an NoSeatAvailableException"); - } - catch (NoSeatAvailableException ex) { - } - - verify(flightDaoMock, ticketDaoMock, securityServiceMock); - } - - public void testBookFlightNoSuchFlight() throws Exception { - String flightNumber = "AB1234"; - DateTime departureTime = new DateTime(); - List passengers = Collections.singletonList(new Passenger()); - expect(flightDaoMock.getFlight(flightNumber, departureTime)).andReturn(null); - - replay(flightDaoMock, ticketDaoMock, securityServiceMock); - try { - airlineService.bookFlight(flightNumber, departureTime, passengers); - fail("Should have thrown an NoSuchFlightException"); - } - catch (NoSuchFlightException ex) { - } - - verify(flightDaoMock, ticketDaoMock, securityServiceMock); - } - - public void testGetFlights() throws Exception { - LocalDate departureDate = new LocalDate(2006, 1, 31); - Flight flight = new Flight(); - List flights = new ArrayList(); - flights.add(flight); - String toCode = "to"; - String fromCode = "from"; - - expect(flightDaoMock.findFlights(fromCode, toCode, departureDate.toInterval(), ServiceClass.ECONOMY)) - .andReturn(flights); - - replay(flightDaoMock, ticketDaoMock, securityServiceMock); - - List result = airlineService.getFlights(fromCode, toCode, departureDate, ServiceClass.ECONOMY); - assertEquals("Invalid result", flights, result); - - verify(flightDaoMock, ticketDaoMock, securityServiceMock); - } - - public void testGetFlightsDefaultServiceClass() throws Exception { - LocalDate departureDate = new LocalDate(2006, 1, 31); - Flight flight = new Flight(); - List flights = new ArrayList(); - flights.add(flight); - String toCode = "to"; - String fromCode = "from"; - - expect(flightDaoMock.findFlights(fromCode, toCode, departureDate.toInterval(), ServiceClass.ECONOMY)) - .andReturn(flights); - - replay(flightDaoMock, ticketDaoMock, securityServiceMock); - - List result = airlineService.getFlights(fromCode, toCode, departureDate, null); - assertEquals("Invalid result", flights, result); - - verify(flightDaoMock, ticketDaoMock, securityServiceMock); - - } -} diff --git a/airline/server/src/test/java/org/springframework/ws/samples/airline/web/FlightsControllerTest.java b/airline/server/src/test/java/org/springframework/ws/samples/airline/web/FlightsControllerTest.java deleted file mode 100644 index b527afd..0000000 --- a/airline/server/src/test/java/org/springframework/ws/samples/airline/web/FlightsControllerTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2005-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. - */ - -package org.springframework.ws.samples.airline.web; - -import java.util.ArrayList; -import java.util.List; - -import junit.framework.TestCase; -import static org.easymock.EasyMock.*; -import org.joda.time.LocalDate; - -import org.springframework.ui.ModelMap; -import org.springframework.ws.samples.airline.domain.Flight; -import org.springframework.ws.samples.airline.domain.ServiceClass; -import org.springframework.ws.samples.airline.service.AirlineService; - -public class FlightsControllerTest extends TestCase { - - private FlightsController flightsController; - - private AirlineService airlineServiceMock; - - @Override - protected void setUp() throws Exception { - airlineServiceMock = createMock(AirlineService.class); - flightsController = new FlightsController(airlineServiceMock); - } - - public void testFlightList() throws Exception { - String from = "AMS"; - String to = "VCE"; - LocalDate departureDate = new LocalDate(); - ServiceClass serviceClass = ServiceClass.FIRST; - List flights = new ArrayList(); - flights.add(new Flight()); - expect(airlineServiceMock.getFlights(from, to, departureDate, serviceClass)).andReturn(flights); - - replay(airlineServiceMock); - - ModelMap model = new ModelMap(); - String view = flightsController - .flightList(from, to, departureDate.toString(), serviceClass.toString(), model); - assertNotNull("No view returned", view); - assertEquals("Invalid view name", "flights", view); - assertTrue("No flights in ModelAndView", model.containsAttribute("flights")); - verify(airlineServiceMock); - } -} \ No newline at end of file diff --git a/airline/server/src/test/java/org/springframework/ws/samples/airline/ws/AirlineEndpointTest.java b/airline/server/src/test/java/org/springframework/ws/samples/airline/ws/AirlineEndpointTest.java deleted file mode 100644 index 870c443..0000000 --- a/airline/server/src/test/java/org/springframework/ws/samples/airline/ws/AirlineEndpointTest.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2005-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. - */ - -package org.springframework.ws.samples.airline.ws; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import javax.xml.bind.JAXBElement; -import javax.xml.datatype.DatatypeConstants; -import javax.xml.datatype.DatatypeFactory; - -import org.springframework.ws.samples.airline.domain.Airport; -import org.springframework.ws.samples.airline.domain.FrequentFlyer; -import org.springframework.ws.samples.airline.domain.Passenger; -import org.springframework.ws.samples.airline.schema.BookFlightRequest; -import org.springframework.ws.samples.airline.schema.Flight; -import org.springframework.ws.samples.airline.schema.GetFlightsResponse; -import org.springframework.ws.samples.airline.schema.Name; -import org.springframework.ws.samples.airline.schema.ObjectFactory; -import org.springframework.ws.samples.airline.schema.ServiceClass; -import org.springframework.ws.samples.airline.schema.Ticket; -import org.springframework.ws.samples.airline.service.AirlineService; - -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.joda.time.LocalDate; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.w3c.dom.Element; - -import static org.easymock.EasyMock.*; -import static org.junit.Assert.assertNotNull; - -public class AirlineEndpointTest { - - private AirlineEndpoint endpoint; - - private AirlineService airlineServiceMock; - - private DatatypeFactory datatypeFactory; - - private ObjectFactory objectFactory; - - @Before - public void setUp() throws Exception { - airlineServiceMock = createMock(AirlineService.class); - endpoint = new AirlineEndpoint(airlineServiceMock); - datatypeFactory = DatatypeFactory.newInstance(); - objectFactory = new ObjectFactory(); - } - - @Test - public void testGetFlights() throws Exception { - org.springframework.ws.samples.airline.domain.Flight domainFlight = createDomainFlight(); - - expect(airlineServiceMock.getFlights("ABC", "DEF", new LocalDate(2007, 6, 13), - org.springframework.ws.samples.airline.domain.ServiceClass.FIRST)) - .andReturn(Collections.singletonList(domainFlight)); - - replay(airlineServiceMock); - - GetFlightsResponse response = endpoint.getFlights("ABC", "DEF", "2007-06-13", "first"); - Assert.assertEquals("Invalid amount of flights received", 1, response.getFlight().size()); - Flight schemaFlight = response.getFlight().get(0); - verifySchemaFlight(schemaFlight); - - verify(airlineServiceMock); - } - - private void verifySchemaFlight(Flight schemaFlight) { - Assert.assertEquals("Invalid number", "ABC1234", schemaFlight.getNumber()); - Assert.assertEquals("Invalid departure time", - datatypeFactory.newXMLGregorianCalendar(2007, 6, 13, 12, 0, 0, 0, 0), schemaFlight.getDepartureTime()); - Assert.assertEquals("Invalid from code", "ABC", schemaFlight.getFrom().getCode()); - Assert.assertEquals("Invalid from name", "ABC Airport", schemaFlight.getFrom().getName()); - Assert.assertEquals("Invalid from city", "ABC City", schemaFlight.getFrom().getCity()); - Assert.assertEquals("Invalid arrival time", - datatypeFactory.newXMLGregorianCalendar(2007, 6, 13, 14, 0, 0, 0, 0), schemaFlight.getArrivalTime()); - Assert.assertEquals("Invalid to code", "DEF", schemaFlight.getTo().getCode()); - Assert.assertEquals("Invalid to name", "DEF Airport", schemaFlight.getTo().getName()); - Assert.assertEquals("Invalid to city", "DEF City", schemaFlight.getTo().getCity()); - Assert.assertEquals("Invalid service class", ServiceClass.FIRST, schemaFlight.getServiceClass()); - } - - private org.springframework.ws.samples.airline.domain.Flight createDomainFlight() { - org.springframework.ws.samples.airline.domain.Flight domainFlight = - new org.springframework.ws.samples.airline.domain.Flight(); - domainFlight.setNumber("ABC1234"); - domainFlight.setDepartureTime(new DateTime(2007, 6, 13, 12, 0, 0, 0, DateTimeZone.UTC)); - domainFlight.setFrom(new Airport("ABC", "ABC Airport", "ABC City")); - domainFlight.setArrivalTime(new DateTime(2007, 6, 13, 14, 0, 0, 0, DateTimeZone.UTC)); - domainFlight.setTo(new Airport("DEF", "DEF Airport", "DEF City")); - domainFlight.setServiceClass(org.springframework.ws.samples.airline.domain.ServiceClass.FIRST); - return domainFlight; - } - - @Test - public void bookFlightPassenger() throws Exception { - BookFlightRequest request = objectFactory.createBookFlightRequest(); - request.setDepartureTime(datatypeFactory.newXMLGregorianCalendar(2007, 6, 13, 12, 0, 0, 0, 0)); - request.setFlightNumber("ABC1234"); - Name passengerName = new Name(); - passengerName.setFirst("John"); - passengerName.setLast("Doe"); - BookFlightRequest.Passengers passengers = new BookFlightRequest.Passengers(); - passengers.getPassengerOrUsername().add(passengerName); - request.setPassengers(passengers); - - Passenger domainPassenger = new Passenger("John", "Doe"); - - org.springframework.ws.samples.airline.domain.Ticket domainTicket = - new org.springframework.ws.samples.airline.domain.Ticket(42L); - domainTicket.setFlight(createDomainFlight()); - domainTicket.setIssueDate(new LocalDate(2007, 6, 13)); - domainTicket.setPassengers(Collections.singleton(domainPassenger)); - - expect(airlineServiceMock.bookFlight("ABC1234", new DateTime(2007, 6, 13, 12, 0, 0, 0, DateTimeZone.UTC), - Collections.singletonList(domainPassenger))).andReturn(domainTicket); - - replay(airlineServiceMock); - - JAXBElement response = endpoint.bookFlight(request); - Ticket schemaTicket = response.getValue(); - Assert.assertEquals("Invalid id", 42L, schemaTicket.getId()); - Assert.assertEquals("Invalid issue date", - datatypeFactory.newXMLGregorianCalendarDate(2007, 6, 13, DatatypeConstants.FIELD_UNDEFINED), - schemaTicket.getIssueDate()); - Assert.assertEquals("Invalid amount of passengers", 1, schemaTicket.getPassengers().getPassenger().size()); - Name schemaPassenger = schemaTicket.getPassengers().getPassenger().get(0); - Assert.assertEquals("Invalid passenger first name", "John", schemaPassenger.getFirst()); - Assert.assertEquals("Invalid passenger first name", "Doe", schemaPassenger.getLast()); - verifySchemaFlight(schemaTicket.getFlight()); - - verify(airlineServiceMock); - } - - @Test - public void testBookFlightFrequentFlyer() throws Exception { - BookFlightRequest request = objectFactory.createBookFlightRequest(); - request.setDepartureTime(datatypeFactory.newXMLGregorianCalendar(2007, 6, 13, 12, 0, 0, 0, 0)); - request.setFlightNumber("ABC1234"); - BookFlightRequest.Passengers passengers = new BookFlightRequest.Passengers(); - passengers.getPassengerOrUsername().add("john"); - request.setPassengers(passengers); - - FrequentFlyer domainFrequentFlyer = new FrequentFlyer("John", "Doe", "john", "changeme"); - Set domainPassengers = new HashSet(); - domainPassengers.add(domainFrequentFlyer); - - org.springframework.ws.samples.airline.domain.Ticket domainTicket = - new org.springframework.ws.samples.airline.domain.Ticket(42L); - domainTicket.setFlight(createDomainFlight()); - domainTicket.setIssueDate(new LocalDate(2007, 6, 13)); - domainTicket.setPassengers(domainPassengers); - - List domainPassengerList = new ArrayList(domainPassengers); - expect(airlineServiceMock - .bookFlight("ABC1234", new DateTime(2007, 6, 13, 12, 0, 0, 0, DateTimeZone.UTC), domainPassengerList)) - .andReturn(domainTicket); - - replay(airlineServiceMock); - - JAXBElement response = endpoint.bookFlight(request); - Ticket schemaTicket = response.getValue(); - Assert.assertEquals("Invalid id", 42L, schemaTicket.getId()); - Assert.assertEquals("Invalid issue date", - datatypeFactory.newXMLGregorianCalendarDate(2007, 6, 13, DatatypeConstants.FIELD_UNDEFINED), - schemaTicket.getIssueDate()); - Assert.assertEquals("Invalid amount of passengers", 1, schemaTicket.getPassengers().getPassenger().size()); - Name schemaPassenger = schemaTicket.getPassengers().getPassenger().get(0); - Assert.assertEquals("Invalid passenger first name", "John", schemaPassenger.getFirst()); - Assert.assertEquals("Invalid passenger first name", "Doe", schemaPassenger.getLast()); - verifySchemaFlight(schemaTicket.getFlight()); - - verify(airlineServiceMock); - } - - @Test - public void testGetFrequentFlyerMileage() throws Exception { - expect(airlineServiceMock.getFrequentFlyerMileage()).andReturn(42); - - replay(airlineServiceMock); - - Element response = endpoint.getFrequentFlyerMileage(); - assertNotNull("Invalid response", response); - - verify(airlineServiceMock); - } - -} \ No newline at end of file diff --git a/airline/settings.gradle b/airline/settings.gradle deleted file mode 100644 index aaeb3fd..0000000 --- a/airline/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ - -include "server", "client:axis1", "client:jax-ws", "client:jms", "client:saaj", "client:spring-ws" diff --git a/echo/build.gradle b/echo/build.gradle deleted file mode 100644 index c90a772..0000000 --- a/echo/build.gradle +++ /dev/null @@ -1,17 +0,0 @@ -ext.springWsVersion = '2.2.0.RELEASE' - -subprojects { - apply plugin: 'java' - apply plugin: 'eclipse' - apply plugin: 'idea' - - repositories { - maven { url 'https://repo.spring.io/libs-release' } - } - - dependencies { - testCompile("junit:junit:4.10") - testCompile("org.easymock:easymock:3.1") - } - -} diff --git a/echo/client/saaj/build.gradle b/echo/client/saaj/build.gradle deleted file mode 100644 index 5987bbd..0000000 --- a/echo/client/saaj/build.gradle +++ /dev/null @@ -1,4 +0,0 @@ -task runClient(dependsOn: 'classes', type:JavaExec) { - main = "org.springframework.ws.samples.echo.client.saaj.EchoClient" - classpath = sourceSets.main.runtimeClasspath -} \ No newline at end of file diff --git a/echo/client/saaj/pom.xml b/echo/client/saaj/pom.xml new file mode 100644 index 0000000..7a4fcea --- /dev/null +++ b/echo/client/saaj/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws-samples + 1.0.0.BUILD-SNAPSHOT + ../../../ + + + echo-client-saaj + 0.0.1-SNAPSHOT + Spring Web Services Samples - Echo - Client - SAAJ + Demo project for Spring Web Services + + + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web-services + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/echo/client/saaj/src/main/java/org/springframework/ws/samples/echo/client/saaj/EchoClient.java b/echo/client/saaj/src/main/java/org/springframework/ws/samples/echo/client/saaj/EchoClient.java index a8ee4f2..2d77eb0 100644 --- a/echo/client/saaj/src/main/java/org/springframework/ws/samples/echo/client/saaj/EchoClient.java +++ b/echo/client/saaj/src/main/java/org/springframework/ws/samples/echo/client/saaj/EchoClient.java @@ -16,7 +16,6 @@ package org.springframework.ws.samples.echo.client.saaj; -import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -29,8 +28,9 @@ import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPFault; import javax.xml.soap.SOAPMessage; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A client for the Echo Web Service that uses SAAJ. @@ -40,64 +40,57 @@ import javax.xml.transform.TransformerFactory; */ public class EchoClient { - public static final String NAMESPACE_URI = "http://www.springframework.org/spring-ws/samples/echo"; + public static final String NAMESPACE_URI = "http://www.springframework.org/spring-ws/samples/echo"; - public static final String PREFIX = "tns"; + public static final String PREFIX = "tns"; - private SOAPConnectionFactory connectionFactory; + private static final Logger logger = LoggerFactory.getLogger(EchoClient.class); - private MessageFactory messageFactory; + private SOAPConnectionFactory connectionFactory; - private URL url; + private MessageFactory messageFactory; - public EchoClient(String url) throws SOAPException, MalformedURLException { - connectionFactory = SOAPConnectionFactory.newInstance(); - messageFactory = MessageFactory.newInstance(); - this.url = new URL(url); - } + private URL url; - private SOAPMessage createEchoRequest() throws SOAPException { - SOAPMessage message = messageFactory.createMessage(); - SOAPEnvelope envelope = message.getSOAPPart().getEnvelope(); - Name echoRequestName = envelope.createName("echoRequest", PREFIX, NAMESPACE_URI); - SOAPBodyElement echoRequestElement = message.getSOAPBody() - .addBodyElement(echoRequestName); - echoRequestElement.setValue("Hello"); - return message; - } + public EchoClient(String url) throws SOAPException, MalformedURLException { - public void callWebService() throws SOAPException, IOException { - SOAPMessage request = createEchoRequest(); - SOAPConnection connection = connectionFactory.createConnection(); - SOAPMessage response = connection.call(request, url); - if (!response.getSOAPBody().hasFault()) { - writeEchoResponse(response); - } - else { - SOAPFault fault = response.getSOAPBody().getFault(); - System.err.println("Received SOAP Fault"); - System.err.println("SOAP Fault Code :" + fault.getFaultCode()); - System.err.println("SOAP Fault String :" + fault.getFaultString()); - } - } + connectionFactory = SOAPConnectionFactory.newInstance(); + messageFactory = MessageFactory.newInstance(); + this.url = new URL(url); + } - private void writeEchoResponse(SOAPMessage message) throws SOAPException { - SOAPEnvelope envelope = message.getSOAPPart().getEnvelope(); - Name echoResponseName = envelope.createName("echoResponse", PREFIX, NAMESPACE_URI); - SOAPBodyElement echoResponseElement = (SOAPBodyElement) message - .getSOAPBody().getChildElements(echoResponseName).next(); - String echoValue = echoResponseElement.getTextContent(); - System.out.println(); - System.out.println("Echo Response [" + echoValue + "]"); - System.out.println(); - } + private SOAPMessage createEchoRequest() throws SOAPException { - public static void main(String[] args) throws Exception { - String url = "http://localhost:8080/echo-server/services"; - if (args.length > 0) { - url = args[0]; - } - EchoClient echoClient = new EchoClient(url); - echoClient.callWebService(); - } -} \ No newline at end of file + SOAPMessage message = messageFactory.createMessage(); + SOAPEnvelope envelope = message.getSOAPPart().getEnvelope(); + Name echoRequestName = envelope.createName("echoRequest", PREFIX, NAMESPACE_URI); + SOAPBodyElement echoRequestElement = message.getSOAPBody().addBodyElement(echoRequestName); + echoRequestElement.setValue("Hello"); + return message; + } + + public void callWebService() throws SOAPException { + + SOAPMessage request = createEchoRequest(); + SOAPConnection connection = connectionFactory.createConnection(); + SOAPMessage response = connection.call(request, url); + if (!response.getSOAPBody().hasFault()) { + writeEchoResponse(response); + } else { + SOAPFault fault = response.getSOAPBody().getFault(); + logger.error("Received SOAP Fault"); + logger.error("SOAP Fault Code :" + fault.getFaultCode()); + logger.error("SOAP Fault String :" + fault.getFaultString()); + } + } + + private void writeEchoResponse(SOAPMessage message) throws SOAPException { + + SOAPEnvelope envelope = message.getSOAPPart().getEnvelope(); + Name echoResponseName = envelope.createName("echoResponse", PREFIX, NAMESPACE_URI); + SOAPBodyElement echoResponseElement = (SOAPBodyElement) message.getSOAPBody().getChildElements(echoResponseName) + .next(); + String echoValue = echoResponseElement.getTextContent(); + logger.info("Echo Response [" + echoValue + "]"); + } +} diff --git a/echo/client/saaj/src/main/java/org/springframework/ws/samples/echo/client/saaj/SaajEchoClient.java b/echo/client/saaj/src/main/java/org/springframework/ws/samples/echo/client/saaj/SaajEchoClient.java new file mode 100644 index 0000000..96cdb99 --- /dev/null +++ b/echo/client/saaj/src/main/java/org/springframework/ws/samples/echo/client/saaj/SaajEchoClient.java @@ -0,0 +1,24 @@ +package org.springframework.ws.samples.echo.client.saaj; + +import java.net.MalformedURLException; + +import javax.xml.soap.SOAPException; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SaajEchoClient { + + public static void main(String[] args) throws MalformedURLException, SOAPException { + SpringApplication.run(SaajEchoClient.class); + + String url = "http://localhost:8080/echo-server/services"; + if (args.length > 0) { + url = args[0]; + } + + EchoClient echoClient = new EchoClient(url); + echoClient.callWebService(); + } +} diff --git a/echo/client/spring-ws/build.gradle b/echo/client/spring-ws/build.gradle deleted file mode 100644 index 688d104..0000000 --- a/echo/client/spring-ws/build.gradle +++ /dev/null @@ -1,9 +0,0 @@ -dependencies { - compile("org.springframework.ws:spring-ws-core:$springWsVersion") - runtime("log4j:log4j:1.2.16") -} - -task runClient(dependsOn: 'classes', type:JavaExec) { - main = "org.springframework.ws.samples.echo.client.sws.EchoClient" - classpath = sourceSets.main.runtimeClasspath -} diff --git a/echo/client/spring-ws/pom.xml b/echo/client/spring-ws/pom.xml new file mode 100644 index 0000000..4d56172 --- /dev/null +++ b/echo/client/spring-ws/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws-samples + 1.0.0.BUILD-SNAPSHOT + ../../../ + + + org.springframework.ws + echo-client-spring-ws + 0.0.1-SNAPSHOT + Spring Web Services Samples - Echo - Client - Spring WS + Demo project for Spring Web Services + + + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web-services + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/echo/client/spring-ws/src/main/java/org/springframework/ws/samples/echo/client/sws/EchoClient.java b/echo/client/spring-ws/src/main/java/org/springframework/ws/samples/echo/client/sws/EchoClient.java index 764e21f..40e5f94 100644 --- a/echo/client/spring-ws/src/main/java/org/springframework/ws/samples/echo/client/sws/EchoClient.java +++ b/echo/client/spring-ws/src/main/java/org/springframework/ws/samples/echo/client/sws/EchoClient.java @@ -17,40 +17,34 @@ package org.springframework.ws.samples.echo.client.sws; import java.io.IOException; + import javax.xml.transform.Source; -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.core.io.ClassPathResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; +import org.springframework.stereotype.Service; import org.springframework.ws.client.core.support.WebServiceGatewaySupport; import org.springframework.xml.transform.ResourceSource; import org.springframework.xml.transform.StringResult; +@Service public class EchoClient extends WebServiceGatewaySupport { - private Resource request; + private static final Logger logger = LoggerFactory.getLogger(EchoClient.class); - public void setRequest(Resource request) { - this.request = request; - } + private Resource request; - public void echo() throws IOException { - Source requestSource = new ResourceSource(request); - StringResult result = new StringResult(); - getWebServiceTemplate().sendSourceAndReceiveToResult(requestSource, result); - System.out.println(); - System.out.println(result); - System.out.println(); - } + public void setRequest(Resource request) { + this.request = request; + } - public static void main(String[] args) throws IOException { - EchoClient echoClient = new EchoClient(); - echoClient.setDefaultUri("http://localhost:8080/echo-server/services"); - echoClient.setRequest(new ClassPathResource( - "org/springframework/ws/samples/echo/client/sws/echoRequest.xml")); + public void echo() throws IOException { - echoClient.echo(); - } + Source requestSource = new ResourceSource(request); + StringResult result = new StringResult(); + getWebServiceTemplate().sendSourceAndReceiveToResult(requestSource, result); + logger.info(result.toString()); + } } diff --git a/echo/client/spring-ws/src/main/java/org/springframework/ws/samples/echo/client/sws/SpringWsEchoClient.java b/echo/client/spring-ws/src/main/java/org/springframework/ws/samples/echo/client/sws/SpringWsEchoClient.java new file mode 100644 index 0000000..6507859 --- /dev/null +++ b/echo/client/spring-ws/src/main/java/org/springframework/ws/samples/echo/client/sws/SpringWsEchoClient.java @@ -0,0 +1,41 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.samples.echo.client.sws; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.core.io.ClassPathResource; + +@SpringBootApplication +public class SpringWsEchoClient { + + public static void main(String[] args) { + SpringApplication.run(SpringWsEchoClient.class, args); + } + + @Bean + CommandLineRunner invoke(EchoClient echoClient) { + + return args -> { + echoClient.setDefaultUri("http://localhost:8080/echo-server/services"); + echoClient.setRequest(new ClassPathResource("echoRequest.xml")); + echoClient.echo(); + }; + } +} diff --git a/echo/client/spring-ws/src/main/resources/application.yml b/echo/client/spring-ws/src/main/resources/application.yml new file mode 100644 index 0000000..cf866a4 --- /dev/null +++ b/echo/client/spring-ws/src/main/resources/application.yml @@ -0,0 +1,6 @@ +logging: + level: + org.springframework: + ws: TRACE + web: TRACE + xml: DEBUG \ No newline at end of file diff --git a/echo/client/spring-ws/src/main/resources/org/springframework/ws/samples/echo/client/sws/echoRequest.xml b/echo/client/spring-ws/src/main/resources/echoRequest.xml similarity index 100% rename from echo/client/spring-ws/src/main/resources/org/springframework/ws/samples/echo/client/sws/echoRequest.xml rename to echo/client/spring-ws/src/main/resources/echoRequest.xml diff --git a/echo/client/spring-ws/src/main/resources/log4j.properties b/echo/client/spring-ws/src/main/resources/log4j.properties deleted file mode 100644 index 0f73a75..0000000 --- a/echo/client/spring-ws/src/main/resources/log4j.properties +++ /dev/null @@ -1,7 +0,0 @@ -log4j.rootLogger=WARN, stdout -log4j.logger.org.springframework.ws=DEBUG -log4j.logger.org.springframework.xml=DEBUG - -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n \ No newline at end of file diff --git a/echo/server/build.gradle b/echo/server/build.gradle deleted file mode 100644 index 43f6e53..0000000 --- a/echo/server/build.gradle +++ /dev/null @@ -1,38 +0,0 @@ -buildscript { - repositories { - maven { url 'https://repo.springsource.org/plugins-release' } - } - - dependencies { - classpath 'org.gradle.api.plugins:gradle-tomcat-plugin:0.9.9' - } -} - -ext.springVersion = '4.0.2.RELEASE' -ext.tomcatVersion = '7.0.42' - -apply plugin: 'war' -apply plugin: 'maven' -apply plugin: 'tomcat' - -tomcatRun { - contextPath = 'echo-server' -} -repositories { - mavenLocal() -} - -dependencies { - compile("org.springframework.ws:spring-ws-core:$springWsVersion") - compile("org.springframework:spring-context:$springVersion") - runtime("log4j:log4j:1.2.16") - - providedCompile("javax.servlet:javax.servlet-api:3.0.1") - runtime("wsdl4j:wsdl4j:1.6.1") - - tomcat("org.apache.tomcat.embed:tomcat-embed-core:$tomcatVersion", - "org.apache.tomcat.embed:tomcat-embed-logging-juli:$tomcatVersion") - tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:$tomcatVersion") { - exclude group: 'org.eclipse.jdt.core.compiler', module: 'ecj' - } -} diff --git a/echo/server/pom.xml b/echo/server/pom.xml new file mode 100644 index 0000000..e35301b --- /dev/null +++ b/echo/server/pom.xml @@ -0,0 +1,121 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.3.1.RELEASE + + + + org.springframework.ws + echo-server + 0.0.1-SNAPSHOT + Spring Web Services Samples - Echo - Server + Demo project for Spring Web Services + + + 1.8 + 2.10.6 + 1.2.16 + ${project.basedir}/target/generated-sources/axis + ${project.basedir}/target/classes + ${project.basedir}/../airline.wsdl + 2.0.2 + + + + + + org.springframework.boot + spring-boot-starter-web-services + + + + wsdl4j + wsdl4j + + + + org.apache.ws.xmlschema + xmlschema-core + ${xmlschema.version} + runtime + + + + org.springframework + spring-test + test + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.codehaus.mojo + jaxb2-maven-plugin + 2.5.0 + + + xjc + + xjc + + + + + ${project.basedir}/src/main/resources/echo.xsd + org.springframework.ws.samples.airline.schema + 2.1 + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.1 + + + add-source + process-sources + + add-source + + + + target/generated-sources/xjc + + + + + + + + + + + + diff --git a/echo/server/src/main/java/org/springframework/ws/samples/echo/EchoApplication.java b/echo/server/src/main/java/org/springframework/ws/samples/echo/EchoApplication.java new file mode 100644 index 0000000..775d859 --- /dev/null +++ b/echo/server/src/main/java/org/springframework/ws/samples/echo/EchoApplication.java @@ -0,0 +1,12 @@ +package org.springframework.ws.samples.echo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class EchoApplication { + + public static void main(String[] args) { + SpringApplication.run(EchoApplication.class, args); + } +} diff --git a/echo/server/src/main/java/org/springframework/ws/samples/echo/config/EchoConfig.java b/echo/server/src/main/java/org/springframework/ws/samples/echo/config/EchoConfig.java index 068cd2e..5f77ffa 100644 --- a/echo/server/src/main/java/org/springframework/ws/samples/echo/config/EchoConfig.java +++ b/echo/server/src/main/java/org/springframework/ws/samples/echo/config/EchoConfig.java @@ -19,10 +19,8 @@ package org.springframework.ws.samples.echo.config; import java.util.List; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; -import org.springframework.ws.config.annotation.EnableWs; import org.springframework.ws.config.annotation.WsConfigurerAdapter; import org.springframework.ws.server.EndpointInterceptor; import org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor; @@ -35,9 +33,7 @@ import org.springframework.xml.xsd.SimpleXsdSchema; * * @author Arjen Poutsma */ -@EnableWs @Configuration -@ComponentScan("org.springframework.ws.samples.echo") public class EchoConfig extends WsConfigurerAdapter { @Bean @@ -47,7 +43,9 @@ public class EchoConfig extends WsConfigurerAdapter { @Override public void addInterceptors(List interceptors) { + PayloadValidatingInterceptor validatingInterceptor = new PayloadValidatingInterceptor(); + validatingInterceptor.setXsdSchema(echoXsd()); validatingInterceptor.setValidateRequest(true); validatingInterceptor.setValidateResponse(true); @@ -56,12 +54,13 @@ public class EchoConfig extends WsConfigurerAdapter { interceptors.add(new PayloadLoggingInterceptor()); } - @Bean - public DefaultWsdl11Definition echo() { + @Bean("echo-server") + public DefaultWsdl11Definition echo(SimpleXsdSchema echoXsd) { + DefaultWsdl11Definition definition = new DefaultWsdl11Definition(); definition.setPortTypeName("Echo"); - definition.setLocationUri("http://localhost:8080/echo/services"); - definition.setSchema(echoXsd()); + definition.setLocationUri("http://localhost:8080/echo-server/services"); + definition.setSchema(echoXsd); return definition; } diff --git a/echo/server/src/main/java/org/springframework/ws/samples/echo/config/EchoServletInitializer.java b/echo/server/src/main/java/org/springframework/ws/samples/echo/config/EchoServletInitializer.java deleted file mode 100644 index 30469bc..0000000 --- a/echo/server/src/main/java/org/springframework/ws/samples/echo/config/EchoServletInitializer.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2005-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.echo.config; - -import org.springframework.web.WebApplicationInitializer; -import org.springframework.ws.transport.http.support.AbstractAnnotationConfigMessageDispatcherServletInitializer; - -/** - * {@link WebApplicationInitializer} for the echo sample. - * @author Arjen Poutsma - */ -public class EchoServletInitializer - extends AbstractAnnotationConfigMessageDispatcherServletInitializer { - - @Override - protected Class[] getRootConfigClasses() { - return null; - } - - @Override - protected Class[] getServletConfigClasses() { - return new Class[]{EchoConfig.class}; - } - - @Override - public boolean isTransformWsdlLocations() { - return true; - } -} diff --git a/echo/server/src/main/java/org/springframework/ws/samples/echo/service/EchoService.java b/echo/server/src/main/java/org/springframework/ws/samples/echo/service/EchoService.java index 602adee..a4de3bd 100644 --- a/echo/server/src/main/java/org/springframework/ws/samples/echo/service/EchoService.java +++ b/echo/server/src/main/java/org/springframework/ws/samples/echo/service/EchoService.java @@ -24,10 +24,10 @@ package org.springframework.ws.samples.echo.service; */ public interface EchoService { - /** - * Returns the given string. - * - * @return s - */ - String echo(String s); + /** + * Returns the given string. + * + * @return message + */ + String echo(String message); } diff --git a/echo/server/src/main/java/org/springframework/ws/samples/echo/service/impl/EchoServiceImpl.java b/echo/server/src/main/java/org/springframework/ws/samples/echo/service/impl/EchoServiceImpl.java index 7be65d2..266681f 100755 --- a/echo/server/src/main/java/org/springframework/ws/samples/echo/service/impl/EchoServiceImpl.java +++ b/echo/server/src/main/java/org/springframework/ws/samples/echo/service/impl/EchoServiceImpl.java @@ -28,7 +28,7 @@ import org.springframework.ws.samples.echo.service.EchoService; @Service public class EchoServiceImpl implements EchoService { - public String echo(String s) { - return s; - } + public String echo(String message) { + return message; + } } diff --git a/echo/server/src/main/java/org/springframework/ws/samples/echo/ws/EchoEndpoint.java b/echo/server/src/main/java/org/springframework/ws/samples/echo/ws/EchoEndpoint.java index f1e7327..b0b6136 100755 --- a/echo/server/src/main/java/org/springframework/ws/samples/echo/ws/EchoEndpoint.java +++ b/echo/server/src/main/java/org/springframework/ws/samples/echo/ws/EchoEndpoint.java @@ -20,14 +20,12 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.Assert; import org.springframework.ws.samples.echo.service.EchoService; import org.springframework.ws.server.endpoint.annotation.Endpoint; import org.springframework.ws.server.endpoint.annotation.PayloadRoot; import org.springframework.ws.server.endpoint.annotation.RequestPayload; import org.springframework.ws.server.endpoint.annotation.ResponsePayload; - import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -43,62 +41,64 @@ import org.w3c.dom.Text; @Endpoint public class EchoEndpoint { - /** - * Namespace of both request and response. - */ - public static final String NAMESPACE_URI = "http://www.springframework.org/spring-ws/samples/echo"; + /** + * Namespace of both request and response. + */ + public static final String NAMESPACE_URI = "http://www.springframework.org/spring-ws/samples/echo"; - /** - * The local name of the expected request. - */ - public static final String ECHO_REQUEST_LOCAL_NAME = "echoRequest"; + /** + * The local name of the expected request. + */ + public static final String ECHO_REQUEST_LOCAL_NAME = "echoRequest"; - /** - * The local name of the created response. - */ - public static final String ECHO_RESPONSE_LOCAL_NAME = "echoResponse"; + /** + * The local name of the created response. + */ + public static final String ECHO_RESPONSE_LOCAL_NAME = "echoResponse"; - private final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + private final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); - private final EchoService echoService; + private final EchoService echoService; - @Autowired - public EchoEndpoint(EchoService echoService) { - this.echoService = echoService; - } + public EchoEndpoint(EchoService echoService) { + this.echoService = echoService; + } + /** + * Reads the given requestElement, and sends a the response back. + * + * @param requestElement the contents of the SOAP message as DOM elements + * @return the response element + */ + @PayloadRoot(localPart = ECHO_REQUEST_LOCAL_NAME, namespace = NAMESPACE_URI) + @ResponsePayload + public Element handleEchoRequest(@RequestPayload Element requestElement) throws ParserConfigurationException { - /** - * Reads the given requestElement, and sends a the response back. - * - * @param requestElement the contents of the SOAP message as DOM elements - * @return the response element - */ - @PayloadRoot(localPart = ECHO_REQUEST_LOCAL_NAME, namespace = NAMESPACE_URI) - @ResponsePayload - public Element handleEchoRequest(@RequestPayload Element requestElement) throws ParserConfigurationException { - Assert.isTrue(NAMESPACE_URI.equals(requestElement.getNamespaceURI()), "Invalid namespace"); - Assert.isTrue(ECHO_REQUEST_LOCAL_NAME.equals(requestElement.getLocalName()), "Invalid local name"); + Assert.isTrue(NAMESPACE_URI.equals(requestElement.getNamespaceURI()), "Invalid namespace"); + Assert.isTrue(ECHO_REQUEST_LOCAL_NAME.equals(requestElement.getLocalName()), "Invalid local name"); - NodeList children = requestElement.getChildNodes(); - Text requestText = null; - for (int i = 0; i < children.getLength(); i++) { - if (children.item(i).getNodeType() == Node.TEXT_NODE) { - requestText = (Text) children.item(i); - break; - } - } - if (requestText == null) { - throw new IllegalArgumentException("Could not find request text node"); - } + NodeList children = requestElement.getChildNodes(); + Text requestText = null; - String echo = echoService.echo(requestText.getNodeValue()); + for (int i = 0; i < children.getLength(); i++) { + if (children.item(i).getNodeType() == Node.TEXT_NODE) { + requestText = (Text) children.item(i); + break; + } + } - DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); - Document document = documentBuilder.newDocument(); - Element responseElement = document.createElementNS(NAMESPACE_URI, ECHO_RESPONSE_LOCAL_NAME); - Text responseText = document.createTextNode(echo); - responseElement.appendChild(responseText); - return responseElement; - } + if (requestText == null) { + throw new IllegalArgumentException("Could not find request text node"); + } + + String echo = echoService.echo(requestText.getNodeValue()); + + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + Document document = documentBuilder.newDocument(); + Element responseElement = document.createElementNS(NAMESPACE_URI, ECHO_RESPONSE_LOCAL_NAME); + Text responseText = document.createTextNode(echo); + responseElement.appendChild(responseText); + + return responseElement; + } } diff --git a/echo/server/src/main/resources/application.yml b/echo/server/src/main/resources/application.yml new file mode 100644 index 0000000..2f47459 --- /dev/null +++ b/echo/server/src/main/resources/application.yml @@ -0,0 +1,9 @@ +logging: + level: + org.springframework: + ws: TRACE + web: TRACE + xml: DEBUG +spring: + webservices: + path: /echo-server \ No newline at end of file diff --git a/echo/server/src/main/resources/log4j.properties b/echo/server/src/main/resources/log4j.properties deleted file mode 100644 index 0f73a75..0000000 --- a/echo/server/src/main/resources/log4j.properties +++ /dev/null @@ -1,7 +0,0 @@ -log4j.rootLogger=WARN, stdout -log4j.logger.org.springframework.ws=DEBUG -log4j.logger.org.springframework.xml=DEBUG - -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n \ No newline at end of file diff --git a/echo/server/src/test/java/org/springframework/ws/samples/echo/ws/EchoEndpointTest.java b/echo/server/src/test/java/org/springframework/ws/samples/echo/ws/EchoEndpointTest.java index 6ce3af3..d5dab28 100644 --- a/echo/server/src/test/java/org/springframework/ws/samples/echo/ws/EchoEndpointTest.java +++ b/echo/server/src/test/java/org/springframework/ws/samples/echo/ws/EchoEndpointTest.java @@ -16,60 +16,56 @@ package org.springframework.ws.samples.echo.ws; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.ws.samples.echo.service.EchoService; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Text; -import static org.easymock.EasyMock.*; - public class EchoEndpointTest { - private EchoEndpoint endpoint; + private EchoEndpoint endpoint; - private Document requestDocument; + private Document requestDocument; - private Document responseDocument; + private Document responseDocument; - private EchoService mock; + private EchoService echoServiceMock; - @Before - public void setUp() throws Exception { - DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); - documentBuilderFactory.setNamespaceAware(true); - DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); - requestDocument = documentBuilder.newDocument(); - responseDocument = documentBuilder.newDocument(); - mock = createMock(EchoService.class); - endpoint = new EchoEndpoint(mock); - } + @BeforeEach + public void setUp() throws Exception { - @Test - public void testInvokeInternal() throws Exception { - Element echoRequest = - requestDocument.createElementNS(EchoEndpoint.NAMESPACE_URI, EchoEndpoint.ECHO_REQUEST_LOCAL_NAME); - String content = "ABC"; - Text requestText = requestDocument.createTextNode(content); - echoRequest.appendChild(requestText); - String result = "DEF"; - expect(mock.echo(content)).andReturn(result); + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + requestDocument = documentBuilder.newDocument(); + responseDocument = documentBuilder.newDocument(); + echoServiceMock = mock(EchoService.class); + endpoint = new EchoEndpoint(echoServiceMock); + } - replay(mock); + @Test + public void testInvokeInternal() throws Exception { - Element echoResponse = endpoint.handleEchoRequest(echoRequest); - Assert.assertEquals("Invalid namespace", EchoEndpoint.NAMESPACE_URI, echoResponse.getNamespaceURI()); - Assert.assertEquals("Invalid namespace", EchoEndpoint.ECHO_RESPONSE_LOCAL_NAME, echoResponse.getLocalName()); - Text responseText = (Text) echoResponse.getChildNodes().item(0); - Assert.assertEquals("Invalid content", result, responseText.getNodeValue()); + Element echoRequest = requestDocument.createElementNS(EchoEndpoint.NAMESPACE_URI, + EchoEndpoint.ECHO_REQUEST_LOCAL_NAME); + Text requestText = requestDocument.createTextNode("ABC"); + echoRequest.appendChild(requestText); + when(echoServiceMock.echo("ABC")).thenReturn("DEF"); - verify(mock); - } + Element echoResponse = endpoint.handleEchoRequest(echoRequest); -} \ No newline at end of file + assertThat(echoResponse.getNamespaceURI()).isEqualTo(EchoEndpoint.NAMESPACE_URI); + assertThat(echoResponse.getLocalName()).isEqualTo(EchoEndpoint.ECHO_RESPONSE_LOCAL_NAME); + assertThat(echoResponse.getChildNodes().item(0).getNodeValue()).isEqualTo("DEF"); + + verify(echoServiceMock); + } +} diff --git a/echo/settings.gradle b/echo/settings.gradle deleted file mode 100644 index 72c6a98..0000000 --- a/echo/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ - -include "server", "client:saaj", "client:spring-ws" diff --git a/mtom/build.gradle b/mtom/build.gradle deleted file mode 100644 index 37c9698..0000000 --- a/mtom/build.gradle +++ /dev/null @@ -1,23 +0,0 @@ -ext.springWsVersion = '2.2.0.RELEASE' -ext.springVersion = '4.0.5.RELEASE' - - -subprojects { - apply plugin: 'java' - apply plugin: 'eclipse' - apply plugin: 'idea' - - repositories { - maven { url 'https://repo.spring.io/libs-release' } - } - - dependencies { - testCompile("junit:junit:4.10") - testCompile("org.easymock:easymock:3.1") - } - -} - -task wrapper(type: Wrapper) { - gradleVersion = '1.8' -} diff --git a/mtom/client/jax-ws/build.gradle b/mtom/client/jax-ws/build.gradle deleted file mode 100644 index 5d7bf51..0000000 --- a/mtom/client/jax-ws/build.gradle +++ /dev/null @@ -1,39 +0,0 @@ -configurations { - wsimport -} - -ext.springWsVersion = '2.1.4.RELEASE' - -task wsImport { - ext.outputDir = "${buildDir}/classes/wsimport" - ext.wsdl = "${projectDir}/mtom.wsdl" - - inputs.files wsdl - outputs.dir outputDir - - doLast() { - project.ant { - taskdef name: "wsimport", classname: "com.sun.tools.ws.ant.WsImport", - classpath: configurations.wsimport.asPath - mkdir(dir: outputDir) - - wsimport(destdir: outputDir, wsdl: wsdl, - package: "org.springframework.ws.samples.mtom.client.jaxws") { - produces(dir: outputDir, includes: "**/*.class") - } - } - } -} - -dependencies { - compile("org.springframework.ws:spring-ws-core:$springWsVersion") - compile(files(wsImport.outputDir).builtBy(wsImport)) - runtime("log4j:log4j:1.2.16") - wsimport "com.sun.xml.ws:jaxws-tools:2.1.7" -} - -task runClient(dependsOn: 'classes', type:JavaExec) { - main = "org.springframework.ws.samples.mtom.client.jaxws.Main" - classpath = sourceSets.main.runtimeClasspath - systemProperty("java.awt.headless", "true") -} \ No newline at end of file diff --git a/mtom/client/jax-ws/mtom.wsdl b/mtom/client/jax-ws/mtom.wsdl deleted file mode 100644 index 86a2b42..0000000 --- a/mtom/client/jax-ws/mtom.wsdl +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/mtom/client/jax-ws/src/main/java/org/springframework/ws/samples/mtom/client/jaxws/Main.java b/mtom/client/jax-ws/src/main/java/org/springframework/ws/samples/mtom/client/jaxws/Main.java deleted file mode 100644 index 85ebca1..0000000 --- a/mtom/client/jax-ws/src/main/java/org/springframework/ws/samples/mtom/client/jaxws/Main.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2006 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.mtom.client.jaxws; - -import java.io.File; -import java.io.IOException; -import java.awt.image.RenderedImage; -import java.awt.Toolkit; -import javax.activation.DataHandler; -import javax.xml.ws.BindingProvider; -import javax.xml.ws.soap.SOAPBinding; -import javax.xml.ws.soap.SOAPFaultException; - -import org.springframework.util.StopWatch; - -/** - * Simple client that calls the GetFlights and BookFlight operations using JAX-WS. - * - * @author Arjen Poutsma - */ -public class Main { - - public static void main(String[] args) throws IOException { - try { - - String fileName = "../spring-ws-logo.png"; - if (args.length > 0) { - fileName = args[0]; - } - - ImageRepositoryService service = new ImageRepositoryService(); - ImageRepository imageRepository = service.getImageRepositorySoap11(); - SOAPBinding binding = (SOAPBinding) ((BindingProvider) imageRepository).getBinding(); - binding.setMTOMEnabled(true); - - Image request = new Image(); - File file = new File(fileName); - if (!file.exists()) { - System.err.println("File [" + fileName + "] does not exist"); - System.exit(-1); - } - request.setName(file.getName()); - request.setImage(Toolkit.getDefaultToolkit().getImage(file.getAbsolutePath())); - StopWatch stopWatch = new StopWatch(); - stopWatch.start("store"); - imageRepository.storeImage(request); - stopWatch.stop(); - - stopWatch.start("load"); - Image response = imageRepository.loadImage(file.getName()); - stopWatch.stop(); - System.out.println(stopWatch.prettyPrint()); - } - catch (SOAPFaultException ex) { - System.err.format("SOAP Fault Code %1s%n", ex.getFault().getFaultCodeAsQName()); - System.err.format("SOAP Fault String: %1s%n", ex.getFault().getFaultString()); - } - - } - - -} diff --git a/mtom/client/spring-ws/build.gradle b/mtom/client/spring-ws/build.gradle deleted file mode 100644 index 6947de7..0000000 --- a/mtom/client/spring-ws/build.gradle +++ /dev/null @@ -1,58 +0,0 @@ -configurations { - jaxb -} - -task genJaxb { - ext.sourcesDir = "${buildDir}/generated-sources/jaxb" - ext.classesDir = "${buildDir}/classes/jaxb" - ext.schema = "${projectDir}/../../server/src/main/resources/schema.xsd" - - inputs.files schema - outputs.dir classesDir - - doLast() { - project.ant { - taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask", - classpath: configurations.jaxb.asPath - mkdir(dir: sourcesDir) - mkdir(dir: classesDir) - - xjc(destdir: sourcesDir, schema: schema, - package: "org.springframework.ws.samples.mtom.client.sws") { - produces(dir: sourcesDir, includes: "**/*.java") - } - - javac(destdir: classesDir, source: 1.6, target: 1.6, debug: true, - debugLevel: "lines,vars,source", - classpath: configurations.jaxb.asPath) { - src(path: sourcesDir) - include(name: "**/*.java") - include(name: "*.java") - } - - copy(todir: classesDir) { - fileset(dir: sourcesDir, erroronmissingdir: false) { - exclude(name: "**/*.java") - } - } - } - } -} - -dependencies { - compile("org.springframework.ws:spring-ws-core:$springWsVersion") - compile("org.springframework:spring-context:$springVersion") - compile("org.apache.ws.commons.axiom:axiom-api:1.2.14") - compile(files(genJaxb.classesDir).builtBy(genJaxb)) - - runtime("log4j:log4j:1.2.16") - runtime("org.apache.ws.commons.axiom:axiom-impl:1.2.14") - - jaxb "com.sun.xml.bind:jaxb-xjc:2.1.7" -} - -task runClient(dependsOn: 'classes', type:JavaExec) { - main = "org.springframework.ws.samples.mtom.client.sws.Driver" - classpath = sourceSets.main.runtimeClasspath - systemProperty("java.awt.headless", "true") -} \ No newline at end of file diff --git a/mtom/client/spring-ws/pom.xml b/mtom/client/spring-ws/pom.xml new file mode 100644 index 0000000..0f38c57 --- /dev/null +++ b/mtom/client/spring-ws/pom.xml @@ -0,0 +1,112 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws-samples + 1.0.0.BUILD-SNAPSHOT + ../../../ + + + org.springframework.ws + mtom-client-spring-ws + 0.0.1-SNAPSHOT + Spring Web Services Samples - MTOM - Client - Spring WS + Demo project for Spring Web Services + + + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web-services + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.codehaus.mojo + jaxb2-maven-plugin + 2.5.0 + + + xjc + + xjc + + + + + WSDL + ${project.basedir}/../../server/src/main/resources/contentStore.wsdl + org.springframework.ws.samples.mtom.client.sws + 2.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.1 + + + add-source + process-sources + + add-source + + + + ${project.basedir}/target/generated-sources/jaxb + + + + + + + + + + diff --git a/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/AxiomMtomClient.java b/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/AxiomMtomClient.java deleted file mode 100644 index a6ec661..0000000 --- a/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/AxiomMtomClient.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.mtom.client.sws; - -import java.io.IOException; -import java.util.Iterator; -import javax.activation.DataHandler; -import javax.activation.DataSource; -import javax.activation.FileDataSource; -import javax.imageio.ImageIO; -import javax.xml.transform.TransformerException; - -import org.apache.axiom.om.OMElement; -import org.apache.axiom.om.OMNamespace; -import org.apache.axiom.om.OMOutputFormat; -import org.apache.axiom.om.OMText; -import org.apache.axiom.soap.SOAPBody; -import org.apache.axiom.soap.SOAPFactory; -import org.apache.axiom.soap.SOAPMessage; - -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.StopWatch; -import org.springframework.util.StringUtils; -import org.springframework.ws.WebServiceMessage; -import org.springframework.ws.client.core.WebServiceMessageCallback; -import org.springframework.ws.client.core.WebServiceMessageExtractor; -import org.springframework.ws.client.core.support.WebServiceGatewaySupport; -import org.springframework.ws.soap.axiom.AxiomSoapMessage; -import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory; -import org.springframework.ws.soap.client.SoapFaultClientException; - -/** - * Simple client that demonstartes MTOM by invoking StoreImage and LoadImage using a - * WebServiceTemplate and Axiom. - * - * @author Arjen Poutsma - */ -public class AxiomMtomClient extends WebServiceGatewaySupport { - - private StopWatch stopWatch = new StopWatch(ClassUtils.getShortName(getClass())); - - public AxiomMtomClient(AxiomSoapMessageFactory messageFactory) { - super(messageFactory); - } - - public void doIt(String path) { - try { - store(path); - load(path); - System.out.println(stopWatch.prettyPrint()); - } - catch (SoapFaultClientException ex) { - System.err.format("SOAP Fault Code %1s%n", ex.getFaultCode()); - System.err.format("SOAP Fault String: %1s%n", ex.getFaultStringOrReason()); - } - - } - - private void store(final String path) { - stopWatch.start("store"); - getWebServiceTemplate().sendAndReceive(new WebServiceMessageCallback() { - public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException { - AxiomSoapMessage soapMessage = (AxiomSoapMessage) message; - SOAPMessage axiomMessage = soapMessage.getAxiomMessage(); - SOAPFactory factory = (SOAPFactory) axiomMessage.getOMFactory(); - SOAPBody body = axiomMessage.getSOAPEnvelope().getBody(); - - OMNamespace ns = - factory.createOMNamespace("http://www.springframework.org/spring-ws/samples/mtom", "tns"); - - OMElement storeImageRequestElement = factory.createOMElement("StoreImageRequest", ns); - body.addChild(storeImageRequestElement); - OMElement nameElement = factory.createOMElement("name", ns); - storeImageRequestElement.addChild(nameElement); - nameElement.setText(StringUtils.getFilename(path)); - OMElement imageElement = factory.createOMElement("image", ns); - storeImageRequestElement.addChild(imageElement); - DataSource dataSource = new FileDataSource(path); - DataHandler dataHandler = new DataHandler(dataSource); - OMText text = factory.createOMText(dataHandler, true); - imageElement.addChild(text); - - OMOutputFormat outputFormat = new OMOutputFormat(); - outputFormat.setSOAP11(true); - outputFormat.setDoOptimize(true); - soapMessage.setOutputFormat(outputFormat); - } - }, new WebServiceMessageExtractor() { - public Object extractData(WebServiceMessage message) throws IOException, TransformerException { - return null; - } - }); - stopWatch.stop(); - } - - private void load(final String path) { - final StringBuilder name = new StringBuilder(); - stopWatch.start("load"); - java.awt.Image image = (java.awt.Image) getWebServiceTemplate().sendAndReceive(new WebServiceMessageCallback() { - public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException { - SOAPMessage axiomMessage = ((AxiomSoapMessage) message).getAxiomMessage(); - SOAPFactory factory = (SOAPFactory) axiomMessage.getOMFactory(); - SOAPBody body = axiomMessage.getSOAPEnvelope().getBody(); - - OMNamespace ns = - factory.createOMNamespace("http://www.springframework.org/spring-ws/samples/mtom", "tns"); - - OMElement loadImageRequestElement = factory.createOMElement("LoadImageRequest", ns); - loadImageRequestElement.setText(StringUtils.getFilename(path)); - body.addChild(loadImageRequestElement); - } - }, new WebServiceMessageExtractor() { - public Object extractData(WebServiceMessage message) throws IOException, TransformerException { - SOAPMessage axiomMessage = ((AxiomSoapMessage) message).getAxiomMessage(); - SOAPBody body = axiomMessage.getSOAPEnvelope().getBody(); - OMElement loadImageResponseElement = (OMElement) body.getChildElements().next(); - Assert.isTrue("LoadImageResponse".equals(loadImageResponseElement.getLocalName())); - Iterator childElements = loadImageResponseElement.getChildElements(); - OMElement nameElement = (OMElement) childElements.next(); - Assert.isTrue("name".equals(nameElement.getLocalName())); - name.append(nameElement.getText()); - OMElement imageElement = (OMElement) childElements.next(); - Assert.isTrue("image".equals(imageElement.getLocalName())); - OMText text = (OMText) imageElement.getFirstOMChild(); - - DataHandler dataHandler = (DataHandler) text.getDataHandler(); - return ImageIO.read(dataHandler.getInputStream()); - } - }); - stopWatch.stop(); - logger.info("Received image " + name + " [" + image.getWidth(null) + "x" + image.getHeight(null) + "]"); - } - - -} diff --git a/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/Driver.java b/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/Driver.java deleted file mode 100644 index 8bea663..0000000 --- a/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/Driver.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.mtom.client.sws; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -public class Driver { - - public static void main(String[] args) { - String fileName = "../spring-ws-logo.png"; - if (args.length > 0) { - fileName = args[0]; - } - ApplicationContext applicationContext = - new AnnotationConfigApplicationContext(MtomClientConfig.class); - - SaajMtomClient saajClient = applicationContext.getBean("saajClient", SaajMtomClient.class); - saajClient.doIt(fileName); - - AxiomMtomClient axiomClient = applicationContext.getBean("axiomClient", AxiomMtomClient.class); - axiomClient.doIt(fileName); - } - -} diff --git a/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/MtomClientConfig.java b/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/MtomClientConfig.java index 6e18eac..04de5f7 100644 --- a/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/MtomClientConfig.java +++ b/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/MtomClientConfig.java @@ -3,7 +3,6 @@ package org.springframework.ws.samples.mtom.client.sws; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.oxm.jaxb.Jaxb2Marshaller; -import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory; import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; /** @@ -13,11 +12,12 @@ import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; public class MtomClientConfig { @Bean - public SaajMtomClient saajClient() { - SaajMtomClient client = new SaajMtomClient(saajSoapMessageFactory()); + public SaajMtomClient saajClient(SaajSoapMessageFactory messageFactory, Jaxb2Marshaller marshaller) { + + SaajMtomClient client = new SaajMtomClient(messageFactory); client.setDefaultUri("http://localhost:8080/mtom-server/services"); - client.setMarshaller(marshaller()); - client.setUnmarshaller(marshaller()); + client.setMarshaller(marshaller); + client.setUnmarshaller(marshaller); return client; } @@ -26,20 +26,9 @@ public class MtomClientConfig { return new SaajSoapMessageFactory(); } - @Bean - public AxiomMtomClient axiomClient() { - AxiomMtomClient client = new AxiomMtomClient(axiomSoapMessageFactory()); - client.setDefaultUri("http://localhost:8080/mtom-server/services"); - return client; - } - - @Bean - public AxiomSoapMessageFactory axiomSoapMessageFactory() { - return new AxiomSoapMessageFactory(); - } - @Bean public Jaxb2Marshaller marshaller() { + Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setContextPath("org.springframework.ws.samples.mtom.client.sws"); marshaller.setMtomEnabled(true); diff --git a/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/SaajMtomClient.java b/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/SaajMtomClient.java index b891979..e70e4f0 100644 --- a/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/SaajMtomClient.java +++ b/mtom/client/spring-ws/src/main/java/org/springframework/ws/samples/mtom/client/sws/SaajMtomClient.java @@ -16,68 +16,121 @@ package org.springframework.ws.samples.mtom.client.sws; -import java.awt.Toolkit; -import javax.xml.bind.JAXBElement; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import javax.activation.DataHandler; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; import org.springframework.util.ClassUtils; import org.springframework.util.StopWatch; -import org.springframework.util.StringUtils; import org.springframework.ws.client.core.support.WebServiceGatewaySupport; -import org.springframework.ws.soap.client.SoapFaultClientException; import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; /** - * Simple client that demonstrates MTOM by invoking {@code StoreImage} and {@code LoadImage} using a - * WebServiceTemplate and SAAJ. + * Simple client that demonstrates MTOM by invoking {@code StoreImage} and {@code LoadImage} using a WebServiceTemplate + * and SAAJ. * * @author Tareq Abed Rabbo * @author Arjen Poutsma */ +@SpringBootApplication public class SaajMtomClient extends WebServiceGatewaySupport { - private ObjectFactory objectFactory = new ObjectFactory(); + public static void main(String[] args) { + SpringApplication.run(SaajMtomClient.class, args); + } - private StopWatch stopWatch = new StopWatch(ClassUtils.getShortName(getClass())); + @Bean + CommandLineRunner invoke(SaajMtomClient saajClient) { - public SaajMtomClient(SaajSoapMessageFactory messageFactory) { - super(messageFactory); - } + return args -> { + saajClient.storeContent(); + saajClient.loadContent(); + }; + } - public void doIt(String path) { - try { - store(path); - load(path); - System.out.println(stopWatch.prettyPrint()); - } - catch (SoapFaultClientException ex) { - System.err.format("SOAP Fault Code %1s%n", ex.getFaultCode()); - System.err.format("SOAP Fault String: %1s%n", ex.getFaultStringOrReason()); - } + private static final Logger logger = LoggerFactory.getLogger(SaajMtomClient.class); - } + private ObjectFactory objectFactory = new ObjectFactory(); + private StopWatch stopWatch = new StopWatch(ClassUtils.getShortName(getClass())); - private void store(String path) { - Image image = objectFactory.createImage(); - image.setName(StringUtils.getFilename(path)); - image.setImage(Toolkit.getDefaultToolkit().getImage(path)); - JAXBElement storeImageRequest = objectFactory.createStoreImageRequest(image); - stopWatch.start("store"); - getWebServiceTemplate().marshalSendAndReceive(storeImageRequest); - stopWatch.stop(); - } + public SaajMtomClient(SaajSoapMessageFactory messageFactory) { + super(messageFactory); + } - @SuppressWarnings("unchecked") - private void load(String path) { - JAXBElement loadImageRequest = objectFactory.createLoadImageRequest(StringUtils.getFilename(path)); + public void storeContent() { - stopWatch.start("load"); - JAXBElement loadImageResponse = - (JAXBElement) getWebServiceTemplate().marshalSendAndReceive(loadImageRequest); - stopWatch.stop(); - Image image = loadImageResponse.getValue(); - logger.info("Received image " + image.getName() + " [" + image.getImage().getWidth(null) + "x" + - image.getImage().getHeight(null) + "]"); + StoreContentRequest storeContentRequest = this.objectFactory.createStoreContentRequest(); - } + storeContentRequest.setName("spring-ws-logo"); + storeContentRequest + .setContent(new DataHandler(Thread.currentThread().getContextClassLoader().getResource("spring-ws-logo.png"))); + this.stopWatch.start("store"); + + getWebServiceTemplate().marshalSendAndReceive(storeContentRequest); + + this.stopWatch.stop(); + + logger.info(this.stopWatch.prettyPrint()); + } + + public void loadContent() throws IOException { + + LoadContentRequest loadContentRequest = this.objectFactory.createLoadContentRequest(); + loadContentRequest.setName("spring-ws-logo"); + + String tmpDir = System.getProperty("java.io.tmpdir"); + File out = new File(tmpDir, "spring_mtom_tmp.bin"); + + long freeBefore = Runtime.getRuntime().freeMemory(); + + this.stopWatch.start("load"); + + LoadContentResponse loadContentResponse = (LoadContentResponse) getWebServiceTemplate() + .marshalSendAndReceive(loadContentRequest); + + this.stopWatch.stop(); + + DataHandler content = loadContentResponse.getContent(); + long freeAfter = Runtime.getRuntime().freeMemory(); + + logger.info("Memory usage [kB]: " + ((freeAfter - freeBefore) / 1024)); + + this.stopWatch.start("loadAttachmentContent"); + + long size = saveContentToFile(content, out); + + this.stopWatch.stop(); + + logger.info("Received file size [kB]: " + size); + logger.info("Stored at " + out.getAbsolutePath()); + logger.info(this.stopWatch.prettyPrint()); + } + + private static long saveContentToFile(DataHandler content, File outFile) throws IOException { + + long size = 0; + + byte[] buffer = new byte[1024]; + try (InputStream in = content.getInputStream()) { + try (OutputStream out = new FileOutputStream(outFile)) { + for (int readBytes; (readBytes = in.read(buffer, 0, buffer.length)) > 0;) { + size += readBytes; + out.write(buffer, 0, readBytes); + } + } + } + + return size; + } } diff --git a/mtom/client/spring-ws/src/main/resources/application.yml b/mtom/client/spring-ws/src/main/resources/application.yml new file mode 100644 index 0000000..a74a6c1 --- /dev/null +++ b/mtom/client/spring-ws/src/main/resources/application.yml @@ -0,0 +1,3 @@ +logging: + level: + org.springframework.ws: DEBUG \ No newline at end of file diff --git a/mtom/client/spring-ws/src/main/resources/log4j.properties b/mtom/client/spring-ws/src/main/resources/log4j.properties deleted file mode 100644 index ecbc6e2..0000000 --- a/mtom/client/spring-ws/src/main/resources/log4j.properties +++ /dev/null @@ -1,6 +0,0 @@ -log4j.rootLogger=WARN, stdout -log4j.logger.org.springframework.ws.samples=INFO - -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n diff --git a/mtom/client/spring-ws-logo.png b/mtom/client/spring-ws/src/main/resources/spring-ws-logo.png similarity index 100% rename from mtom/client/spring-ws-logo.png rename to mtom/client/spring-ws/src/main/resources/spring-ws-logo.png diff --git a/mtom/server/build.gradle b/mtom/server/build.gradle deleted file mode 100644 index c87f111..0000000 --- a/mtom/server/build.gradle +++ /dev/null @@ -1,78 +0,0 @@ -configurations { - jaxb -} - -buildscript { - repositories { - mavenCentral() - } - - dependencies { - classpath 'org.gradle.api.plugins:gradle-tomcat-plugin:0.9.9' - } -} - -ext.tomcatVersion = '7.0.42' - - -apply plugin: 'war' -apply plugin: 'tomcat' - -task genJaxb { - ext.sourcesDir = "${buildDir}/generated-sources/jaxb" - ext.classesDir = "${buildDir}/classes/jaxb" - ext.schema = "${projectDir}/src/main/resources/schema.xsd" - - inputs.files schema - outputs.dir classesDir - - doLast() { - project.ant { - taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask", - classpath: configurations.jaxb.asPath - mkdir(dir: sourcesDir) - mkdir(dir: classesDir) - - xjc(destdir: sourcesDir, schema: schema, - package: "org.springframework.ws.samples.mtom.schema") { - produces(dir: sourcesDir, includes: "**/*.java") - } - - javac(destdir: classesDir, source: 1.6, target: 1.6, debug: true, - debugLevel: "lines,vars,source", - classpath: configurations.jaxb.asPath) { - src(path: sourcesDir) - include(name: "**/*.java") - include(name: "*.java") - } - - copy(todir: classesDir) { - fileset(dir: sourcesDir, erroronmissingdir: false) { - exclude(name: "**/*.java") - } - } - } - } -} - - -tomcatRun { - contextPath = 'mtom-server' -} - -dependencies { - compile("org.springframework.ws:spring-ws-core:$springWsVersion") - compile("org.springframework:spring-context:$springVersion") - compile(files(genJaxb.classesDir).builtBy(genJaxb)) - - runtime("log4j:log4j:1.2.16") - runtime("wsdl4j:wsdl4j:1.6.1") - - jaxb "com.sun.xml.bind:jaxb-xjc:2.1.7" - - tomcat("org.apache.tomcat.embed:tomcat-embed-core:$tomcatVersion", - "org.apache.tomcat.embed:tomcat-embed-logging-juli:$tomcatVersion") - tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:$tomcatVersion") { - exclude group: 'org.eclipse.jdt.core.compiler', module: 'ecj' - } -} diff --git a/mtom/server/pom.xml b/mtom/server/pom.xml new file mode 100644 index 0000000..7298b3a --- /dev/null +++ b/mtom/server/pom.xml @@ -0,0 +1,119 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.3.1.RELEASE + + + + org.springframework.ws + mtom-server + 0.0.1-SNAPSHOT + Spring Web Services Samples - MTOM - Server + Demo project for Spring Web Services + + + 1.8 + 2.10.6 + 1.2.16 + 2.0.2 + + + + + + org.springframework.boot + spring-boot-starter-web-services + + + + wsdl4j + wsdl4j + + + + org.apache.ws.xmlschema + xmlschema-core + ${xmlschema.version} + runtime + + + + org.springframework + spring-test + test + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.codehaus.mojo + jaxb2-maven-plugin + 2.5.0 + + + xjc + + xjc + + + + + WSDL + ${project.basedir}/src/main/resources/contentStore.wsdl + org.springframework.ws.samples.mtom.schema + 2.1 + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.1 + + + add-source + process-sources + + add-source + + + + target/generated-sources/jaxb + + + + + + + + + + + + diff --git a/mtom/server/src/main/java/org/springframework/ws/samples/mtom/MtomServer.java b/mtom/server/src/main/java/org/springframework/ws/samples/mtom/MtomServer.java new file mode 100644 index 0000000..8ab8042 --- /dev/null +++ b/mtom/server/src/main/java/org/springframework/ws/samples/mtom/MtomServer.java @@ -0,0 +1,12 @@ +package org.springframework.ws.samples.mtom; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MtomServer { + + public static void main(String[] args) { + SpringApplication.run(MtomServer.class, args); + } +} diff --git a/mtom/server/src/main/java/org/springframework/ws/samples/mtom/config/MtomServerConfiguration.java b/mtom/server/src/main/java/org/springframework/ws/samples/mtom/config/MtomServerConfiguration.java index 307d942..8013e0b 100644 --- a/mtom/server/src/main/java/org/springframework/ws/samples/mtom/config/MtomServerConfiguration.java +++ b/mtom/server/src/main/java/org/springframework/ws/samples/mtom/config/MtomServerConfiguration.java @@ -1,66 +1,37 @@ package org.springframework.ws.samples.mtom.config; -import java.util.ArrayList; -import java.util.List; +import java.util.Collections; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.oxm.jaxb.Jaxb2Marshaller; -import org.springframework.ws.config.annotation.EnableWs; -import org.springframework.ws.config.annotation.WsConfigurationSupport; -import org.springframework.ws.samples.mtom.service.ImageRepository; -import org.springframework.ws.samples.mtom.service.StubImageRepository; -import org.springframework.ws.samples.mtom.ws.ImageRepositoryEndpoint; import org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter; import org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor; -import org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver; -import org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler; -import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition; -import org.springframework.xml.xsd.SimpleXsdSchema; +import org.springframework.ws.transport.http.MessageDispatcherServlet; +import org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition; /** * @author Arjen Poutsma */ -@EnableWs @Configuration -public class MtomServerConfiguration extends WsConfigurationSupport { +public class MtomServerConfiguration { @Bean - public ImageRepository imageRepository() { - return new StubImageRepository(); - } + ServletRegistrationBean webServicesRegistration(ApplicationContext ctx) { - @Bean - public ImageRepositoryEndpoint imageRepositoryEndpoint() { - return new ImageRepositoryEndpoint(imageRepository()); - } + MessageDispatcherServlet messageDispatcherServlet = new MessageDispatcherServlet(); + messageDispatcherServlet.setApplicationContext(ctx); + messageDispatcherServlet.setTransformWsdlLocations(true); - @Bean - @Override - public DefaultMethodEndpointAdapter defaultMethodEndpointAdapter() { - List argumentResolvers = - new ArrayList(); - argumentResolvers.add(methodProcessor()); - - List returnValueHandlers = - new ArrayList(); - returnValueHandlers.add(methodProcessor()); - - DefaultMethodEndpointAdapter adapter = new DefaultMethodEndpointAdapter(); - adapter.setMethodArgumentResolvers(argumentResolvers); - adapter.setMethodReturnValueHandlers(returnValueHandlers); - - return adapter; - } - - @Bean - public MarshallingPayloadMethodProcessor methodProcessor() { - return new MarshallingPayloadMethodProcessor(marshaller()); + return new ServletRegistrationBean<>(messageDispatcherServlet, "/mtom-server/*", "*.wsdl"); } @Bean public Jaxb2Marshaller marshaller() { + Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setContextPath("org.springframework.ws.samples.mtom.schema"); marshaller.setMtomEnabled(true); @@ -68,17 +39,25 @@ public class MtomServerConfiguration extends WsConfigurationSupport { } @Bean - public DefaultWsdl11Definition mtom() { - DefaultWsdl11Definition definition = new DefaultWsdl11Definition(); - definition.setSchema(schema()); - definition.setPortTypeName("ImageRepository"); - definition.setLocationUri("http://localhost:8080/mtom-server/"); - return definition; + public MarshallingPayloadMethodProcessor methodProcessor(Jaxb2Marshaller marshaller) { + return new MarshallingPayloadMethodProcessor(marshaller); } @Bean - public SimpleXsdSchema schema() { - return new SimpleXsdSchema(new ClassPathResource("/schema.xsd")); + DefaultMethodEndpointAdapter endpointAdapter(MarshallingPayloadMethodProcessor methodProcessor) { + + DefaultMethodEndpointAdapter adapter = new DefaultMethodEndpointAdapter(); + adapter.setMethodArgumentResolvers(Collections.singletonList(methodProcessor)); + adapter.setMethodReturnValueHandlers(Collections.singletonList(methodProcessor)); + return adapter; + } + + @Bean + public SimpleWsdl11Definition contentStore() { + + SimpleWsdl11Definition definition = new SimpleWsdl11Definition(); + definition.setWsdl(new ClassPathResource("/contentStore.wsdl")); + return definition; } } diff --git a/mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/ImageRepository.java b/mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/ContentRepository.java similarity index 78% rename from mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/ImageRepository.java rename to mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/ContentRepository.java index 3107214..f02ecc2 100644 --- a/mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/ImageRepository.java +++ b/mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/ContentRepository.java @@ -16,14 +16,16 @@ package org.springframework.ws.samples.mtom.service; -import java.awt.Image; +import java.io.File; import java.io.IOException; +import javax.activation.DataHandler; + /** @author Arjen Poutsma */ -public interface ImageRepository { +public interface ContentRepository { - Image readImage(String name) throws IOException; + File loadContent(String name); - void storeImage(String name, Image image) throws IOException; + void storeContent(String name, DataHandler content) throws IOException; } diff --git a/mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/ContentRepositoryImpl.java b/mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/ContentRepositoryImpl.java new file mode 100644 index 0000000..174301a --- /dev/null +++ b/mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/ContentRepositoryImpl.java @@ -0,0 +1,63 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.samples.mtom.service; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import javax.activation.DataHandler; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** @author Arjen Poutsma */ +@Service +class ContentRepositoryImpl implements ContentRepository { + + private static final Logger logger = LoggerFactory.getLogger(ContentRepositoryImpl.class); + + @Value(value = "#{ systemProperties['java.io.tmpdir'] }") // + private String fileStorePath; + + @Override + public File loadContent(String name) { + return new File(this.fileStorePath, name + ".tmp"); + } + + @Override + public void storeContent(String name, DataHandler content) throws IOException { + + File outFile = new File(this.fileStorePath, name + ".tmp"); + logger.info("Storing content in file: {}", outFile.getAbsolutePath()); + + int i = 0; + byte[] buffer = new byte[1024]; + try (InputStream in = content.getInputStream()) { + try (OutputStream out = new FileOutputStream(outFile)) { + while ((i = in.read(buffer, 0, buffer.length)) > 0) { + out.write(buffer, 0, i); + } + } + } + logger.info("Content stored."); + } +} diff --git a/mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/StubImageRepository.java b/mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/StubImageRepository.java deleted file mode 100644 index abdd25f..0000000 --- a/mtom/server/src/main/java/org/springframework/ws/samples/mtom/service/StubImageRepository.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.mtom.service; - -import java.awt.Image; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** @author Arjen Poutsma */ -public class StubImageRepository implements ImageRepository { - - private static final Log logger = LogFactory.getLog(StubImageRepository.class); - - private Map images = new HashMap(); - - @Override - public Image readImage(String name) throws IOException { - logger.info("Loading image " + name); - return images.get(name); - } - - @Override - public void storeImage(String name, Image image) throws IOException { - logger.info("Storing image " + name + " [" + image.getWidth(null) + "x" + image.getHeight(null) + "]"); - images.put(name, image); - } -} diff --git a/mtom/server/src/main/java/org/springframework/ws/samples/mtom/ws/ContentRepositoryEndpoint.java b/mtom/server/src/main/java/org/springframework/ws/samples/mtom/ws/ContentRepositoryEndpoint.java new file mode 100644 index 0000000..dab267e --- /dev/null +++ b/mtom/server/src/main/java/org/springframework/ws/samples/mtom/ws/ContentRepositoryEndpoint.java @@ -0,0 +1,76 @@ +/* + * Copyright 2005-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.samples.mtom.ws; + +import java.io.File; +import java.io.IOException; + +import javax.activation.DataHandler; +import javax.activation.FileDataSource; + +import org.springframework.util.Assert; +import org.springframework.ws.samples.mtom.schema.LoadContentRequest; +import org.springframework.ws.samples.mtom.schema.LoadContentResponse; +import org.springframework.ws.samples.mtom.schema.ObjectFactory; +import org.springframework.ws.samples.mtom.schema.StoreContentRequest; +import org.springframework.ws.samples.mtom.schema.StoreContentResponse; +import org.springframework.ws.samples.mtom.service.ContentRepository; +import org.springframework.ws.server.endpoint.annotation.Endpoint; +import org.springframework.ws.server.endpoint.annotation.PayloadRoot; +import org.springframework.ws.server.endpoint.annotation.RequestPayload; +import org.springframework.ws.server.endpoint.annotation.ResponsePayload; + +/** @author Arjen Poutsma */ +@Endpoint +public class ContentRepositoryEndpoint { + + private ContentRepository contentRepository; + + private ObjectFactory objectFactory; + + public ContentRepositoryEndpoint(ContentRepository contentRepository) { + + Assert.notNull(contentRepository, "'imageRepository' must not be null"); + + this.contentRepository = contentRepository; + this.objectFactory = new ObjectFactory(); + } + + @PayloadRoot(localPart = "StoreContentRequest", namespace = "http://www.springframework.org/spring-ws/samples/mtom") + @ResponsePayload + public StoreContentResponse store(@RequestPayload StoreContentRequest storeContentRequest) throws IOException { + + this.contentRepository.storeContent(storeContentRequest.getName(), storeContentRequest.getContent()); + StoreContentResponse response = this.objectFactory.createStoreContentResponse(); + response.setMessage("Success"); + return response; + } + + @PayloadRoot(localPart = "LoadContentRequest", namespace = "http://www.springframework.org/spring-ws/samples/mtom") + @ResponsePayload + public LoadContentResponse load(@RequestPayload LoadContentRequest loadContentRequest) throws IOException { + + LoadContentResponse response = this.objectFactory.createLoadContentResponse(); + + File contentFile = this.contentRepository.loadContent(loadContentRequest.getName()); + DataHandler dataHandler = new DataHandler(new FileDataSource(contentFile)); + response.setName(loadContentRequest.getName()); + response.setContent(dataHandler); + return response; + } + +} diff --git a/mtom/server/src/main/java/org/springframework/ws/samples/mtom/ws/ImageRepositoryEndpoint.java b/mtom/server/src/main/java/org/springframework/ws/samples/mtom/ws/ImageRepositoryEndpoint.java deleted file mode 100644 index bacba4c..0000000 --- a/mtom/server/src/main/java/org/springframework/ws/samples/mtom/ws/ImageRepositoryEndpoint.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2005-2012 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.mtom.ws; - -import java.io.IOException; -import javax.xml.bind.JAXBElement; - -import org.springframework.util.Assert; -import org.springframework.ws.samples.mtom.schema.Image; -import org.springframework.ws.samples.mtom.schema.ObjectFactory; -import org.springframework.ws.samples.mtom.service.ImageRepository; -import org.springframework.ws.server.endpoint.annotation.Endpoint; -import org.springframework.ws.server.endpoint.annotation.PayloadRoot; -import org.springframework.ws.server.endpoint.annotation.RequestPayload; -import org.springframework.ws.server.endpoint.annotation.ResponsePayload; - -/** @author Arjen Poutsma */ -@Endpoint -public class ImageRepositoryEndpoint { - - private ImageRepository imageRepository; - - private ObjectFactory objectFactory; - - public ImageRepositoryEndpoint(ImageRepository imageRepository) { - Assert.notNull(imageRepository, "'imageRepository' must not be null"); - this.imageRepository = imageRepository; - this.objectFactory = new ObjectFactory(); - } - - @PayloadRoot(localPart = "StoreImageRequest", namespace = "http://www.springframework.org/spring-ws/samples/mtom") - @ResponsePayload - public void store(@RequestPayload JAXBElement requestElement) throws IOException { - Image request = requestElement.getValue(); - imageRepository.storeImage(request.getName(), request.getImage()); - } - - @PayloadRoot(localPart = "LoadImageRequest", namespace = "http://www.springframework.org/spring-ws/samples/mtom") - @ResponsePayload - public JAXBElement load(@RequestPayload JAXBElement requestElement) throws IOException { - String name = requestElement.getValue(); - Image response = new Image(); - response.setName(name); - response.setImage(imageRepository.readImage(name)); - return objectFactory.createLoadImageResponse(response); - } - - -} diff --git a/mtom/server/src/main/resources/application.yml b/mtom/server/src/main/resources/application.yml new file mode 100644 index 0000000..a74a6c1 --- /dev/null +++ b/mtom/server/src/main/resources/application.yml @@ -0,0 +1,3 @@ +logging: + level: + org.springframework.ws: DEBUG \ No newline at end of file diff --git a/mtom/server/src/main/resources/contentStore.wsdl b/mtom/server/src/main/resources/contentStore.wsdl new file mode 100644 index 0000000..8226e9b --- /dev/null +++ b/mtom/server/src/main/resources/contentStore.wsdl @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mtom/server/src/main/resources/log4j.properties b/mtom/server/src/main/resources/log4j.properties deleted file mode 100644 index 5bb7c90..0000000 --- a/mtom/server/src/main/resources/log4j.properties +++ /dev/null @@ -1,8 +0,0 @@ -log4j.rootLogger=WARN, stdout -log4j.logger.org.springframework.ws=DEBUG -log4j.logger.org.springframework.xml=DEBUG -log4j.logger.org.springframework.ws.samples=INFO - -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n diff --git a/mtom/server/src/main/resources/schema.xsd b/mtom/server/src/main/resources/schema.xsd deleted file mode 100644 index 54c033e..0000000 --- a/mtom/server/src/main/resources/schema.xsd +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/mtom/server/src/main/webapp/WEB-INF/web.xml b/mtom/server/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index b843902..0000000 --- a/mtom/server/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - MyCompany HR Holiday Service - - - spring-ws - org.springframework.ws.transport.http.MessageDispatcherServlet - - contextClass - org.springframework.web.context.support.AnnotationConfigWebApplicationContext - - - contextConfigLocation - org.springframework.ws.samples.mtom.config.MtomServerConfiguration - - - - - spring-ws - /* - - - diff --git a/mtom/settings.gradle b/mtom/settings.gradle deleted file mode 100644 index b3428de..0000000 --- a/mtom/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ - -include "server", "client:jax-ws", "client:spring-ws" diff --git a/mvnw b/mvnw new file mode 100755 index 0000000..5551fde --- /dev/null +++ b/mvnw @@ -0,0 +1,286 @@ +#!/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 Mingw, 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 + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + wget "$jarUrl" -O "$wrapperJarPath" + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + curl -o "$wrapperJarPath" "$jarUrl" + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +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 0000000..e5cfb0a --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,161 @@ +@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 set title of command window +title %0 +@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 + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" +FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%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 0000000..8872957 --- /dev/null +++ b/pom.xml @@ -0,0 +1,83 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.3.1.RELEASE + + + + org.springframework.ws + spring-ws-samples + 1.0.0.BUILD-SNAPSHOT + pom + + Spring Web Services Samples + + 2019 + + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0 + + Copyright 2020 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. + + + + + + airline/client/axis1 + airline/client/jax-ws + airline/client/jms + airline/client/saaj + airline/client/spring-ws + airline/server + echo/client/saaj + echo/client/spring-ws + echo/server + mtom/client/spring-ws + mtom/server + tutorial + weather + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + org.springframework + spring-test + test + + + + + \ No newline at end of file diff --git a/stockquote/README.md b/stockquote/README.md deleted file mode 100644 index a2a5deb..0000000 --- a/stockquote/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Stock Quote Sample - -This sample shows a Stock Quote service. Incoming messages are routed via -WS-Addressing, and SOAP message content is handled using JAXB2. Additionally, -this sample uses the HTTP server built into Java 6. - -## Running the Server - -The server can be built and run using the following command from -within the ``server`` folder. - - ```sh - $ ./gradlew runServer - ``` - -## Running the Client(s) - -There is a separate ``client`` directory containing clients that connect to the -server. You can run these clients by using the following command from within -each of client subdirectories: - - ```sh - $ gradle runClient - ``` - -## License - -[Spring Web Services] is released under version 2.0 of the [Apache License]. - -[Spring Web Services]: https://projects.spring.io/spring-ws -[Apache License]: http://www.apache.org/licenses/LICENSE-2.0 \ No newline at end of file diff --git a/stockquote/build.gradle b/stockquote/build.gradle deleted file mode 100644 index 33585ee..0000000 --- a/stockquote/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -ext.springWsVersion = '2.2.0.RELEASE' -ext.springVersion = '4.0.5.RELEASE' - -subprojects { - apply plugin: 'java' - apply plugin: 'eclipse' - apply plugin: 'idea' - - repositories { - maven { url 'https://repo.spring.io/libs-release' } - } - - dependencies { - testCompile("junit:junit:4.10") - testCompile("org.easymock:easymock:3.1") - } - -} diff --git a/stockquote/client/jax-ws/build.gradle b/stockquote/client/jax-ws/build.gradle deleted file mode 100644 index f89b89c..0000000 --- a/stockquote/client/jax-ws/build.gradle +++ /dev/null @@ -1,38 +0,0 @@ -configurations { - wsimport -} - -ext.springWsVersion = '2.1.4.RELEASE' - -task wsImport { - ext.outputDir = "${buildDir}/classes/wsimport" - ext.wsdl = "${projectDir}/../../server//src/main/resources/org/springframework/ws/samples/stockquote/ws/stockquote.wsdl" - - inputs.files wsdl - outputs.dir outputDir - - doLast() { - project.ant { - taskdef name: "wsimport", classname: "com.sun.tools.ws.ant.WsImport", - classpath: configurations.wsimport.asPath - mkdir(dir: outputDir) - - wsimport(destdir: outputDir, wsdl: wsdl, - package: "org.springframework.ws.samples.stockquote.client.jaxws") { - produces(dir: outputDir, includes: "**/*.class") - } - } - } -} - -dependencies { - compile("org.springframework.ws:spring-ws-core:$springWsVersion") - compile(files(wsImport.outputDir).builtBy(wsImport)) - runtime("log4j:log4j:1.2.16") - wsimport "com.sun.xml.ws:jaxws-tools:2.1.7" -} - -task runClient(dependsOn: 'classes', type:JavaExec) { - main = "org.springframework.ws.samples.stockquote.client.jaxws.Main" - classpath = sourceSets.main.runtimeClasspath -} \ No newline at end of file diff --git a/stockquote/client/jax-ws/src/main/java/org/springframework/ws/samples/stockquote/client/jaxws/Main.java b/stockquote/client/jax-ws/src/main/java/org/springframework/ws/samples/stockquote/client/jaxws/Main.java deleted file mode 100644 index 8931d2f..0000000 --- a/stockquote/client/jax-ws/src/main/java/org/springframework/ws/samples/stockquote/client/jaxws/Main.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2006 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.stockquote.client.jaxws; - -import java.net.URL; -import javax.xml.namespace.QName; - -/** - * Simple client that calls the StockQuote operations using JAX-WS. - * - * @author Arjen Poutsma - */ -public class Main { - - public static void main(String[] args) throws Exception { - StockService service; - if (args.length == 0) { - service = new StockService(); - } - else { - QName serviceName = new QName("http://www.springframework.org/spring-ws/samples/stockquote", "StockSoap11"); - service = new StockService(new URL(args[0]), serviceName); - } - Stock stock = service.getStockSoap11(); - StockQuoteRequest request = new StockQuoteRequest(); - request.getSymbol().add("FABRIKAM"); - request.getSymbol().add("CONTOSO"); - - System.out.format("Requesting quotes for %s%n", request.getSymbol()); - - StockQuoteResponse response = stock.stockQuote(request); - - System.out.format("Got %d results%n", response.getStockQuote().size()); - for (StockQuote quote : response.getStockQuote()) { - System.out.println(); - System.out.println("Symbol: " + quote.getSymbol()); - System.out.println("\tName:\t\t\t" + quote.getName()); - System.out.println("\tLast Price:\t\t" + quote.getLast()); - System.out.println("\tPrevious Change:\t" + quote.getChange() + "%"); - } - } - -} diff --git a/stockquote/client/spring-ws/build.gradle b/stockquote/client/spring-ws/build.gradle deleted file mode 100644 index b441968..0000000 --- a/stockquote/client/spring-ws/build.gradle +++ /dev/null @@ -1,9 +0,0 @@ -dependencies { - compile("org.springframework.ws:spring-ws-core:$springWsVersion") - runtime("log4j:log4j:1.2.16") -} - -task runClient(dependsOn: 'classes', type:JavaExec) { - main = "org.springframework.ws.samples.stockquote.client.sws.StockClient" - classpath = sourceSets.main.runtimeClasspath -} \ No newline at end of file diff --git a/stockquote/client/spring-ws/src/main/java/org/springframework/ws/samples/stockquote/client/sws/StockClient.java b/stockquote/client/spring-ws/src/main/java/org/springframework/ws/samples/stockquote/client/sws/StockClient.java deleted file mode 100644 index fafd272..0000000 --- a/stockquote/client/spring-ws/src/main/java/org/springframework/ws/samples/stockquote/client/sws/StockClient.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.stockquote.client.sws; - -import java.io.IOException; -import java.net.URI; -import javax.xml.transform.Source; - -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.ws.client.core.support.WebServiceGatewaySupport; -import org.springframework.ws.soap.addressing.client.ActionCallback; -import org.springframework.xml.transform.ResourceSource; -import org.springframework.xml.transform.StringResult; - -public class StockClient extends WebServiceGatewaySupport { - - private Resource request; - - private URI action; - - public void setRequest(Resource request) { - this.request = request; - } - - public void setAction(URI action) { - this.action = action; - } - - public void quotes() throws IOException { - Source requestSource = new ResourceSource(request); - StringResult result = new StringResult(); - getWebServiceTemplate().sendSourceAndReceiveToResult(requestSource, new ActionCallback(action), result); - System.out.println(); - System.out.println(result); - System.out.println(); - } - - public static void main(String[] args) throws Exception { - StockClient stockClient = new StockClient(); - stockClient.setDefaultUri("http://localhost:8080/StockService"); - stockClient.setRequest(new ClassPathResource("/org/springframework/ws/samples/stockquote/client/sws/quotesRequest.xml")); - stockClient.setAction(new URI("http://www.springframework.org/spring-ws/samples/stockquote/StockService/GetQuote")); - - stockClient.quotes(); - } - -} diff --git a/stockquote/client/spring-ws/src/main/resources/log4j.properties b/stockquote/client/spring-ws/src/main/resources/log4j.properties deleted file mode 100644 index 0f73a75..0000000 --- a/stockquote/client/spring-ws/src/main/resources/log4j.properties +++ /dev/null @@ -1,7 +0,0 @@ -log4j.rootLogger=WARN, stdout -log4j.logger.org.springframework.ws=DEBUG -log4j.logger.org.springframework.xml=DEBUG - -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n \ No newline at end of file diff --git a/stockquote/client/spring-ws/src/main/resources/org/springframework/ws/samples/stockquote/client/sws/quotesRequest.xml b/stockquote/client/spring-ws/src/main/resources/org/springframework/ws/samples/stockquote/client/sws/quotesRequest.xml deleted file mode 100644 index b40a2dc..0000000 --- a/stockquote/client/spring-ws/src/main/resources/org/springframework/ws/samples/stockquote/client/sws/quotesRequest.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - FABRIKAM - CONTOSO - diff --git a/stockquote/server/build.gradle b/stockquote/server/build.gradle deleted file mode 100644 index 38c3e36..0000000 --- a/stockquote/server/build.gradle +++ /dev/null @@ -1,57 +0,0 @@ -configurations { - jaxb -} - -task genJaxb { - ext.sourcesDir = "${buildDir}/generated-sources/jaxb" - ext.classesDir = "${buildDir}/classes/jaxb" - ext.schema = "${projectDir}/src/main/resources/org/springframework/ws/samples/stockquote/ws/stockquote.wsdl" - - inputs.files schema - outputs.dir classesDir - - doLast() { - project.ant { - taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask", - classpath: configurations.jaxb.asPath - mkdir(dir: sourcesDir) - mkdir(dir: classesDir) - - xjc(destdir: sourcesDir, schema: schema, - package: "org.springframework.ws.samples.stockquote.schema") { - arg(value: "-wsdl") - produces(dir: sourcesDir, includes: "**/*.java") - } - - javac(destdir: classesDir, source: 1.6, target: 1.6, debug: true, - debugLevel: "lines,vars,source", - classpath: configurations.jaxb.asPath) { - src(path: sourcesDir) - include(name: "**/*.java") - include(name: "*.java") - } - - copy(todir: classesDir) { - fileset(dir: sourcesDir, erroronmissingdir: false) { - exclude(name: "**/*.java") - } - } - } - } -} - -task runServer(dependsOn: 'classes', type:JavaExec) { - main = "org.springframework.ws.samples.stockquote.Driver" - standardInput = System.in - classpath = sourceSets.main.runtimeClasspath -} - -dependencies { - compile("org.springframework.ws:spring-ws-core:$springWsVersion") - compile("org.springframework.ws:spring-ws-support:$springWsVersion") - compile(files(genJaxb.classesDir).builtBy(genJaxb)) - - runtime("log4j:log4j:1.2.16") - - jaxb "com.sun.xml.bind:jaxb-xjc:2.1.7" -} \ No newline at end of file diff --git a/stockquote/server/src/main/java/org/springframework/ws/samples/stockquote/Driver.java b/stockquote/server/src/main/java/org/springframework/ws/samples/stockquote/Driver.java deleted file mode 100644 index d938957..0000000 --- a/stockquote/server/src/main/java/org/springframework/ws/samples/stockquote/Driver.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2008 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.stockquote; - -import java.io.IOException; -import java.net.InetSocketAddress; - -import com.sun.net.httpserver.HttpServer; - -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.ws.samples.stockquote.ws.StockServiceConfiguration; -import org.springframework.ws.transport.http.WebServiceMessageReceiverHttpHandler; -import org.springframework.ws.transport.http.WsdlDefinitionHttpHandler; - -public class Driver { - - public static void main(String[] args) throws IOException { - AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext( - StockServiceConfiguration.class); - - HttpServer httpServer = HttpServer.create(new InetSocketAddress(8080), -1); - httpServer.createContext("/StockService", applicationContext.getBean( - WebServiceMessageReceiverHttpHandler.class)); - httpServer.createContext("/StockService.wsdl", applicationContext.getBean( - WsdlDefinitionHttpHandler.class)); - - httpServer.start(); - System.out.println(); - System.out.println("Press [Enter] to shut down..."); - System.in.read(); - httpServer.stop(0); - } - -} diff --git a/stockquote/server/src/main/java/org/springframework/ws/samples/stockquote/ws/StockService.java b/stockquote/server/src/main/java/org/springframework/ws/samples/stockquote/ws/StockService.java deleted file mode 100644 index 7f09ae4..0000000 --- a/stockquote/server/src/main/java/org/springframework/ws/samples/stockquote/ws/StockService.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2008 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.stockquote.ws; - -import java.util.GregorianCalendar; -import javax.xml.datatype.DatatypeConfigurationException; -import javax.xml.datatype.DatatypeFactory; -import javax.xml.datatype.XMLGregorianCalendar; - -import org.springframework.ws.samples.stockquote.schema.StockQuote; -import org.springframework.ws.samples.stockquote.schema.StockQuoteRequest; -import org.springframework.ws.samples.stockquote.schema.StockQuoteResponse; -import org.springframework.ws.server.endpoint.annotation.Endpoint; -import org.springframework.ws.server.endpoint.annotation.RequestPayload; -import org.springframework.ws.server.endpoint.annotation.ResponsePayload; -import org.springframework.ws.soap.addressing.server.annotation.Action; -import org.springframework.ws.soap.addressing.server.annotation.Address; - -@Endpoint -@Address("http://localhost:8080/StockService") // optional -public class StockService { - - private DatatypeFactory datatypeFactory; - - public StockService() throws DatatypeConfigurationException { - datatypeFactory = DatatypeFactory.newInstance(); - } - - @Action(value = "http://www.springframework.org/spring-ws/samples/stockquote/StockService/GetQuote", - output = "http://www.springframework.org/spring-ws/samples/stockquote/StockService/Quotes") - @ResponsePayload - public StockQuoteResponse getStockQuotes(@RequestPayload StockQuoteRequest request) { - StockQuoteResponse response = new StockQuoteResponse(); - - XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(new GregorianCalendar()); - for (String symbol : request.getSymbol()) { - StockQuote quote = new StockQuote(); - quote.setSymbol(symbol); - quote.setDate(now); - if ("FABRIKAM".equals(symbol)) { - quote.setName("Fabrikam, Inc."); - quote.setLast(120.00); - quote.setChange(5.5); - } - else { - quote.setName("Contoso Corp."); - quote.setLast(50.07); - quote.setChange(1.15); - } - response.getStockQuote().add(quote); - } - - return response; - } - -} diff --git a/stockquote/server/src/main/java/org/springframework/ws/samples/stockquote/ws/StockServiceConfiguration.java b/stockquote/server/src/main/java/org/springframework/ws/samples/stockquote/ws/StockServiceConfiguration.java deleted file mode 100644 index 5d9f0dd..0000000 --- a/stockquote/server/src/main/java/org/springframework/ws/samples/stockquote/ws/StockServiceConfiguration.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.springframework.ws.samples.stockquote.ws; - -import java.util.Collections; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.ClassPathResource; -import org.springframework.ws.server.EndpointAdapter; -import org.springframework.ws.server.EndpointInterceptor; -import org.springframework.ws.server.EndpointMapping; -import org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter; -import org.springframework.ws.soap.addressing.server.AnnotationActionEndpointMapping; -import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; -import org.springframework.ws.soap.server.SoapMessageDispatcher; -import org.springframework.ws.soap.server.endpoint.interceptor.SoapEnvelopeLoggingInterceptor; -import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; -import org.springframework.ws.transport.http.WebServiceMessageReceiverHttpHandler; -import org.springframework.ws.transport.http.WsdlDefinitionHttpHandler; -import org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition; - -/** - * @author Arjen Poutsma - */ -@Configuration -@ComponentScan("org.springframework.ws.samples.stockquote.ws") -public class StockServiceConfiguration { - - @Bean - public WebServiceMessageReceiverHttpHandler soapHandler() { - WebServiceMessageReceiverHttpHandler soapHandler = new WebServiceMessageReceiverHttpHandler(); - soapHandler.setMessageFactory(messageFactory()); - soapHandler.setMessageReceiver(messageReceiver()); - return soapHandler; - } - - @Bean - public SaajSoapMessageFactory messageFactory() { - return new SaajSoapMessageFactory(); - } - - @Bean - public SoapMessageDispatcher messageReceiver() { - SoapMessageDispatcher messageReceiver = new SoapMessageDispatcher(); - messageReceiver.setEndpointAdapters( - Collections.singletonList(endpointAdapter())); - messageReceiver.setEndpointMappings( - Collections.singletonList(endpointMapping())); - return messageReceiver; - } - - @Bean - public DefaultMethodEndpointAdapter endpointAdapter() { - return new DefaultMethodEndpointAdapter(); - } - - @Bean - public AnnotationActionEndpointMapping endpointMapping() { - AnnotationActionEndpointMapping endpointMapping = new AnnotationActionEndpointMapping(); - endpointMapping.setMessageSender(messageSender()); - endpointMapping.setPreInterceptors(new EndpointInterceptor[] { new SoapEnvelopeLoggingInterceptor()}); - return endpointMapping; - } - - @Bean - public HttpUrlConnectionMessageSender messageSender() { - return new HttpUrlConnectionMessageSender(); - } - - @Bean - public WsdlDefinitionHttpHandler wsdlHandler() { - return new WsdlDefinitionHttpHandler(wsdlDefinition()); - } - - @Bean - public SimpleWsdl11Definition wsdlDefinition() { - return new SimpleWsdl11Definition(new ClassPathResource("/org/springframework/ws/samples/stockquote/ws/stockquote.wsdl")); - } - - -} diff --git a/stockquote/server/src/main/resources/log4j.properties b/stockquote/server/src/main/resources/log4j.properties deleted file mode 100644 index 0f73a75..0000000 --- a/stockquote/server/src/main/resources/log4j.properties +++ /dev/null @@ -1,7 +0,0 @@ -log4j.rootLogger=WARN, stdout -log4j.logger.org.springframework.ws=DEBUG -log4j.logger.org.springframework.xml=DEBUG - -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n \ No newline at end of file diff --git a/stockquote/server/src/main/resources/org/springframework/ws/samples/stockquote/ws/stockquote.wsdl b/stockquote/server/src/main/resources/org/springframework/ws/samples/stockquote/ws/stockquote.wsdl deleted file mode 100644 index 81d404e..0000000 --- a/stockquote/server/src/main/resources/org/springframework/ws/samples/stockquote/ws/stockquote.wsdl +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/stockquote/settings.gradle b/stockquote/settings.gradle deleted file mode 100644 index b3428de..0000000 --- a/stockquote/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ - -include "server", "client:jax-ws", "client:spring-ws" diff --git a/tutorial/build.gradle b/tutorial/build.gradle deleted file mode 100644 index 7055368..0000000 --- a/tutorial/build.gradle +++ /dev/null @@ -1,47 +0,0 @@ -buildscript { - repositories { - mavenCentral() - } - - dependencies { - classpath 'org.gradle.api.plugins:gradle-tomcat-plugin:0.9.9' - } -} - -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'war' -apply plugin: 'tomcat' - -ext.springVersion = '4.0.2.RELEASE' -ext.springWsVersion = '2.2.0.BUILD-SNAPSHOT' -ext.tomcatVersion = '7.0.42' - -dependencies { - compile("org.springframework.ws:spring-ws-core:$springWsVersion") - compile("org.jdom:jdom:2.0.1") - runtime("jaxen:jaxen:1.1.4") - runtime("log4j:log4j:1.2.16") - runtime("org.apache.ws.xmlschema:xmlschema-core:2.1.0") - runtime("wsdl4j:wsdl4j:1.6.1") - - providedCompile("javax.servlet:javax.servlet-api:3.0.1") - - testCompile("junit:junit:4.10") - testCompile("org.easymock:easymock:3.1") - - tomcat("org.apache.tomcat.embed:tomcat-embed-core:$tomcatVersion", - "org.apache.tomcat.embed:tomcat-embed-logging-juli:$tomcatVersion") - tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:$tomcatVersion") { - exclude group: 'org.eclipse.jdt.core.compiler', module: 'ecj' - } -} - -repositories { - maven { url 'https://repo.spring.io/libs-release' } - maven { url 'https://repo.spring.io/libs-snapshot' } -} - -task wrapper(type: Wrapper) { - gradleVersion = '1.8' -} \ No newline at end of file diff --git a/tutorial/gradle/wrapper/gradle-wrapper.jar b/tutorial/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 667288ad6c2b3b87c990ece1267e56f0bcbf3622..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50514 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/tutorial/gradlew.bat b/tutorial/gradlew.bat deleted file mode 100644 index 8a0b282..0000000 --- a/tutorial/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/tutorial/pom.xml b/tutorial/pom.xml new file mode 100644 index 0000000..6c051da --- /dev/null +++ b/tutorial/pom.xml @@ -0,0 +1,143 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.3.1.RELEASE + + + + org.springframework.ws + tutorial + 0.0.1-SNAPSHOT + Spring Web Services Samples - Tutorial + Demo project for Spring Web Services + + + 1.8 + 1.1.4 + 2.0.1 + 2.10.6 + 1.2.16 + ${project.basedir}/target/generated-sources/axis + ${project.basedir}/target/classes + ${project.basedir}/../airline.wsdl + 1.6.1 + 2.1.0 + + + + + + org.springframework.boot + spring-boot-starter-web-services + + + + org.jdom + jdom + ${jdom.version} + + + + jaxen + jaxen + ${jaxen.version} + + + + org.apache.ws.xmlschema + xmlschema-core + ${xmlschema.version} + runtime + + + + wsdl4j + wsdl4j + ${wsdl4j.version} + runtime + + + + org.springframework.ws + spring-ws-support + + + + org.springframework + spring-test + test + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.codehaus.mojo + jaxb2-maven-plugin + 2.5.0 + + + xjc + + xjc + + + + + ${project.basedir}/src/main/resources/hr.xsd + org.springframework.ws.samples.tutorial.schema + 2.1 + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.1 + + + add-source + process-sources + + add-source + + + + target/generated-sources/xjc + + + + + + + + + + + + diff --git a/tutorial/src/main/java/com/mycompany/hr/HrApplication.java b/tutorial/src/main/java/com/mycompany/hr/HrApplication.java new file mode 100644 index 0000000..bb79949 --- /dev/null +++ b/tutorial/src/main/java/com/mycompany/hr/HrApplication.java @@ -0,0 +1,12 @@ +package com.mycompany.hr; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class HrApplication { + + public static void main(String[] args) { + SpringApplication.run(HrApplication.class, args); + } +} diff --git a/tutorial/src/main/java/com/mycompany/hr/config/HRConfiguration.java b/tutorial/src/main/java/com/mycompany/hr/config/HRConfiguration.java index 941b1fd..1927da0 100644 --- a/tutorial/src/main/java/com/mycompany/hr/config/HRConfiguration.java +++ b/tutorial/src/main/java/com/mycompany/hr/config/HRConfiguration.java @@ -1,24 +1,20 @@ package com.mycompany.hr.config; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.ws.config.annotation.EnableWs; import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition; import org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection; /** * @author Arjen Poutsma */ -@EnableWs @Configuration -@ComponentScan("com.mycompany.hr") public class HRConfiguration { @Bean public DefaultWsdl11Definition holiday() { + DefaultWsdl11Definition definition = new DefaultWsdl11Definition(); definition.setPortTypeName("HumanResource"); definition.setLocationUri("/holidayService/"); @@ -29,12 +25,9 @@ public class HRConfiguration { @Bean public CommonsXsdSchemaCollection holidayXsd() { - CommonsXsdSchemaCollection collection = - new CommonsXsdSchemaCollection(new Resource[] { new ClassPathResource("/hr.xsd")}); + + CommonsXsdSchemaCollection collection = new CommonsXsdSchemaCollection(new ClassPathResource("/hr.xsd")); collection.setInline(true); return collection; } - - - } diff --git a/tutorial/src/main/java/com/mycompany/hr/config/HRServletInitializer.java b/tutorial/src/main/java/com/mycompany/hr/config/HRServletInitializer.java deleted file mode 100644 index 54b9bcb..0000000 --- a/tutorial/src/main/java/com/mycompany/hr/config/HRServletInitializer.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.mycompany.hr.config; - -import org.springframework.ws.transport.http.support.AbstractAnnotationConfigMessageDispatcherServletInitializer; - -/** - * @author Arjen Poutsma - */ -public class HRServletInitializer - extends AbstractAnnotationConfigMessageDispatcherServletInitializer { - - @Override - protected Class[] getRootConfigClasses() { - return null; - } - - @Override - protected Class[] getServletConfigClasses() { - return new Class[]{HRConfiguration.class}; - } - - @Override - public boolean isTransformWsdlLocations() { - return true; - } - - @Override - protected String[] getServletMappings() { - return new String[]{"/*"}; - } -} diff --git a/tutorial/src/main/java/com/mycompany/hr/ws/HolidayEndpoint.java b/tutorial/src/main/java/com/mycompany/hr/ws/HolidayEndpoint.java index 8442a8a..00e5442 100644 --- a/tutorial/src/main/java/com/mycompany/hr/ws/HolidayEndpoint.java +++ b/tutorial/src/main/java/com/mycompany/hr/ws/HolidayEndpoint.java @@ -18,21 +18,19 @@ package com.mycompany.hr.ws; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.Arrays; import java.util.Date; +import org.jdom2.Element; +import org.jdom2.Namespace; +import org.jdom2.filter.Filters; +import org.jdom2.xpath.XPathExpression; +import org.jdom2.xpath.XPathFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ws.server.endpoint.annotation.Endpoint; import org.springframework.ws.server.endpoint.annotation.PayloadRoot; import org.springframework.ws.server.endpoint.annotation.RequestPayload; import com.mycompany.hr.service.HumanResourceService; -import org.jdom2.Element; -import org.jdom2.JDOMException; -import org.jdom2.Namespace; -import org.jdom2.filter.Filters; -import org.jdom2.xpath.XPathExpression; -import org.jdom2.xpath.XPathFactory; /** * This endpoint handles holiday requests. It uses a combination of JDOM and XPath to extract interesting pieces of XML @@ -43,46 +41,51 @@ import org.jdom2.xpath.XPathFactory; @Endpoint public class HolidayEndpoint { - private static final String NAMESPACE_URI = "http://mycompany.com/hr/schemas"; + private static final String NAMESPACE_URI = "http://mycompany.com/hr/schemas"; - private XPathExpression startDateExpression; + private XPathExpression startDateExpression; - private XPathExpression endDateExpression; + private XPathExpression endDateExpression; - private XPathExpression firstNameExpression; + private XPathExpression firstNameExpression; - private XPathExpression lastNameExpression; + private XPathExpression lastNameExpression; - private HumanResourceService humanResourceService; + private HumanResourceService humanResourceService; - @Autowired - public HolidayEndpoint(HumanResourceService humanResourceService) throws JDOMException { - this.humanResourceService = humanResourceService; - Namespace namespace = Namespace.getNamespace("hr", NAMESPACE_URI); - XPathFactory xPathFactory = XPathFactory.instance(); - startDateExpression = xPathFactory.compile("//hr:StartDate", Filters.element(), null, namespace); - endDateExpression = xPathFactory.compile("//hr:EndDate", Filters.element(), null, namespace); - firstNameExpression = xPathFactory.compile("//hr:FirstName", Filters.element(), null, namespace); - lastNameExpression = xPathFactory.compile("//hr:LastName", Filters.element(), null, namespace); - } + @Autowired + public HolidayEndpoint(HumanResourceService humanResourceService) { - @PayloadRoot(namespace = NAMESPACE_URI, localPart = "HolidayRequest") - public void handleHolidayRequest(@RequestPayload Element holidayRequest) throws Exception { - Date startDate = parseDate(startDateExpression, holidayRequest); - Date endDate = parseDate(endDateExpression, holidayRequest); - String name = firstNameExpression.evaluateFirst(holidayRequest).getText() + " " + lastNameExpression.evaluateFirst(holidayRequest).getText(); + this.humanResourceService = humanResourceService; + Namespace namespace = Namespace.getNamespace("hr", NAMESPACE_URI); + XPathFactory xPathFactory = XPathFactory.instance(); + startDateExpression = xPathFactory.compile("//hr:StartDate", Filters.element(), null, namespace); + endDateExpression = xPathFactory.compile("//hr:EndDate", Filters.element(), null, namespace); + firstNameExpression = xPathFactory.compile("//hr:FirstName", Filters.element(), null, namespace); + lastNameExpression = xPathFactory.compile("//hr:LastName", Filters.element(), null, namespace); + } - humanResourceService.bookHoliday(startDate, endDate, name); - } + @PayloadRoot(namespace = NAMESPACE_URI, localPart = "HolidayRequest") + public void handleHolidayRequest(@RequestPayload Element holidayRequest) throws Exception { - private Date parseDate(XPathExpression expression, Element element) throws ParseException { - Element result = expression.evaluateFirst(element); - if (result != null) { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - return dateFormat.parse(result.getText()); - } else { - throw new IllegalArgumentException("Could not evaluate [" + expression + "] on [" + element + "]"); - } - } + Date startDate = parseDate(startDateExpression, holidayRequest); + Date endDate = parseDate(endDateExpression, holidayRequest); + String name = firstNameExpression.evaluateFirst(holidayRequest).getText() + " " + + lastNameExpression.evaluateFirst(holidayRequest).getText(); + + humanResourceService.bookHoliday(startDate, endDate, name); + } + + private Date parseDate(XPathExpression expression, Element element) throws ParseException { + + Element result = expression.evaluateFirst(element); + + if (result != null) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + return dateFormat.parse(result.getText()); + } else { + throw new IllegalArgumentException("Could not evaluate [" + expression + "] on [" + element + "]"); + } + } } diff --git a/tutorial/src/test/java/com/mycompany/hr/ws/HolidayEndpointTest.java b/tutorial/src/test/java/com/mycompany/hr/ws/HolidayEndpointTest.java index 7471790..d1fcca6 100644 --- a/tutorial/src/test/java/com/mycompany/hr/ws/HolidayEndpointTest.java +++ b/tutorial/src/test/java/com/mycompany/hr/ws/HolidayEndpointTest.java @@ -16,56 +16,58 @@ package com.mycompany.hr.ws; +import static org.mockito.Mockito.*; + import java.io.InputStream; import java.util.Calendar; -import com.mycompany.hr.service.HumanResourceService; import org.jdom2.Document; import org.jdom2.input.SAXBuilder; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.easymock.EasyMock.*; +import com.mycompany.hr.service.HumanResourceService; public class HolidayEndpointTest { - private Document holidayRequest; + private Document holidayRequest; - private HolidayEndpoint endpoint; + private HolidayEndpoint endpoint; - private HumanResourceService serviceMock; + private HumanResourceService serviceMock; - private Calendar startCalendar; + private Calendar startCalendar; - private Calendar endCalendar; + private Calendar endCalendar; - @Before - public void setUp() throws Exception { - serviceMock = createMock(HumanResourceService.class); - SAXBuilder builder = new SAXBuilder(); - InputStream is = getClass().getResourceAsStream("holidayRequest.xml"); - try { - holidayRequest = builder.build(is); - } - finally { - is.close(); - } - endpoint = new HolidayEndpoint(serviceMock); - startCalendar = Calendar.getInstance(); - startCalendar.clear(); - startCalendar.set(2006, Calendar.JULY, 3); - endCalendar = Calendar.getInstance(); - endCalendar.clear(); - endCalendar.set(2006, Calendar.JULY, 7); - } + @BeforeEach + public void setUp() throws Exception { - @Test - public void handleHolidayRequest() throws Exception { - serviceMock.bookHoliday(startCalendar.getTime(), endCalendar.getTime(), "John Doe"); - replay(serviceMock); - endpoint.handleHolidayRequest(holidayRequest.getRootElement()); - verify(serviceMock); - } + serviceMock = mock(HumanResourceService.class); + SAXBuilder builder = new SAXBuilder(); + InputStream is = getClass().getResourceAsStream("holidayRequest.xml"); + try { + holidayRequest = builder.build(is); + } finally { + is.close(); + } + endpoint = new HolidayEndpoint(serviceMock); + startCalendar = Calendar.getInstance(); + startCalendar.clear(); + startCalendar.set(2006, Calendar.JULY, 3); + endCalendar = Calendar.getInstance(); + endCalendar.clear(); + endCalendar.set(2006, Calendar.JULY, 7); + } + @Test + public void handleHolidayRequest() throws Exception { + + serviceMock.bookHoliday(startCalendar.getTime(), endCalendar.getTime(), "John Doe"); + + endpoint.handleHolidayRequest(holidayRequest.getRootElement()); + + verify(serviceMock); + } } diff --git a/weather/build.gradle b/weather/build.gradle deleted file mode 100644 index ea0379b..0000000 --- a/weather/build.gradle +++ /dev/null @@ -1,65 +0,0 @@ -configurations { - jaxb -} - -ext.springVersion = '3.2.4.RELEASE' -ext.springWsVersion = '2.1.4.RELEASE' - -apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' - -repositories { - maven { url 'https://repo.spring.io/libs-release' } -} - -task genJaxb { - ext.sourcesDir = "${buildDir}/generated-sources/jaxb" - ext.classesDir = "${buildDir}/classes/jaxb" - ext.schema = "http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl" - - outputs.dir classesDir - - doLast() { - project.ant { - taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask", - classpath: configurations.jaxb.asPath - mkdir(dir: sourcesDir) - mkdir(dir: classesDir) - - xjc(destdir: sourcesDir, schema: schema, - package: "org.springframework.ws.samples.weather") { - arg(value: "-wsdl") - produces(dir: sourcesDir, includes: "**/*.java") - } - - javac(destdir: classesDir, source: 1.6, target: 1.6, debug: true, - debugLevel: "lines,vars,source", - classpath: configurations.jaxb.asPath) { - src(path: sourcesDir) - include(name: "**/*.java") - include(name: "*.java") - } - - copy(todir: classesDir) { - fileset(dir: sourcesDir, erroronmissingdir: false) { - exclude(name: "**/*.java") - } - } - } - } -} - -dependencies { - compile("org.springframework.ws:spring-ws-core:$springWsVersion") - compile(files(genJaxb.classesDir).builtBy(genJaxb)) - - runtime("log4j:log4j:1.2.16") - - jaxb "com.sun.xml.bind:jaxb-xjc:2.1.7" -} - -task runClient(dependsOn: 'classes', type:JavaExec) { - main = "org.springframework.ws.samples.weather.WeatherClient" - classpath = sourceSets.main.runtimeClasspath -} diff --git a/weather/pom.xml b/weather/pom.xml new file mode 100644 index 0000000..c6368a4 --- /dev/null +++ b/weather/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + + + org.springframework.ws + spring-ws-samples + 1.0.0.BUILD-SNAPSHOT + ../ + + + org.springframework.ws + weather-client-spring-ws + 0.0.1-SNAPSHOT + Spring Web Services Samples - Weather - Client - Spring WS + Demo project for Spring Web Services + + + 1.8 + ${project.basedir}/target/generated-sources/xjc + ${project.basedir}/target/classes + ${project.basedir}/../../server/src/main/resources + http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl + + + + + + org.springframework.ws + spring-ws-core + + + + + + + + + + org.jvnet.jaxb2.maven2 + maven-jaxb2-plugin + 0.14.0 + + + + generate + + + + + WSDL + + + ${wsdl} + + + org.springframework.ws.samples.weather + true + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.1 + + + add-source + process-sources + + add-source + + + + ${sourcesDir} + + + + + + + + + + diff --git a/weather/src/main/java/org/springframework/ws/samples/weather/WeatherClient.java b/weather/src/main/java/org/springframework/ws/samples/weather/WeatherClient.java index 3b5c5b7..d7f4d48 100644 --- a/weather/src/main/java/org/springframework/ws/samples/weather/WeatherClient.java +++ b/weather/src/main/java/org/springframework/ws/samples/weather/WeatherClient.java @@ -26,39 +26,35 @@ import org.springframework.ws.soap.client.core.SoapActionCallback; public class WeatherClient extends WebServiceGatewaySupport { public GetCityForecastByZIPResponse getCityForecastByZip(String zipCode) { + GetCityForecastByZIP request = new GetCityForecastByZIP(); request.setZIP(zipCode); System.out.println(); System.out.println("Requesting forecast for " + zipCode); - GetCityForecastByZIPResponse response = - (GetCityForecastByZIPResponse) getWebServiceTemplate() - .marshalSendAndReceive(request, new SoapActionCallback( - "https://ws.cdyne.com/WeatherWS/GetCityForecastByZIP")); + GetCityForecastByZIPResponse response = (GetCityForecastByZIPResponse) getWebServiceTemplate() + .marshalSendAndReceive(request, new SoapActionCallback("http://ws.cdyne.com/WeatherWS/GetCityForecastByZIP")); return response; } public void printResponse(GetCityForecastByZIPResponse response) { - ForecastReturn forecastReturn = response.getGetCityForecastByZIPResult(); + ForecastReturn forecastReturn = response.getGetCityForecastByZIPResult(); if (forecastReturn.isSuccess()) { System.out.println(); - System.out.println("Forecast for " + forecastReturn.getCity() + ", " + - forecastReturn.getState()); + System.out.println("Forecast for " + forecastReturn.getCity() + ", " + forecastReturn.getState()); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); for (Forecast forecast : forecastReturn.getForecastResult().getForecast()) { - System.out.print(format - .format(forecast.getDate().toGregorianCalendar().getTime())); + System.out.print(format.format(forecast.getDate().toGregorianCalendar().getTime())); System.out.print(" "); System.out.print(forecast.getDesciption()); System.out.print(" "); Temp temperature = forecast.getTemperatures(); - System.out.print(temperature.getMorningLow() + "\u00b0-" + - temperature.getDaytimeHigh() + "\u00b0 "); + System.out.print(temperature.getMorningLow() + "\u00b0-" + temperature.getDaytimeHigh() + "\u00b0 "); System.out.println(); } } else { @@ -68,8 +64,8 @@ public class WeatherClient extends WebServiceGatewaySupport { } public static void main(String[] args) { - ApplicationContext context = - new AnnotationConfigApplicationContext(WeatherConfiguration.class); + + ApplicationContext context = new AnnotationConfigApplicationContext(WeatherConfiguration.class); WeatherClient client = context.getBean(WeatherClient.class); String zipCode = "94304"; @@ -79,7 +75,5 @@ public class WeatherClient extends WebServiceGatewaySupport { GetCityForecastByZIPResponse response = client.getCityForecastByZip(zipCode); client.printResponse(response); - } - } diff --git a/weather/src/main/java/org/springframework/ws/samples/weather/WeatherConfiguration.java b/weather/src/main/java/org/springframework/ws/samples/weather/WeatherConfiguration.java index 2453adf..0c4cda8 100644 --- a/weather/src/main/java/org/springframework/ws/samples/weather/WeatherConfiguration.java +++ b/weather/src/main/java/org/springframework/ws/samples/weather/WeatherConfiguration.java @@ -25,18 +25,21 @@ public class WeatherConfiguration { @Bean public Jaxb2Marshaller marshaller() { + Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setContextPath("org.springframework.ws.samples.weather"); return marshaller; } @Bean - public WeatherClient weatherClient() { + public WeatherClient weatherClient(Jaxb2Marshaller marshaller) { + WeatherClient client = new WeatherClient(); client.setDefaultUri("http://wsf.cdyne.com/WeatherWS/Weather.asmx"); - Jaxb2Marshaller marshaller = marshaller(); + client.setMarshaller(marshaller); client.setUnmarshaller(marshaller); + return client; } diff --git a/weather/src/main/resources/log4j.properties b/weather/src/main/resources/log4j.properties deleted file mode 100644 index f50b419..0000000 --- a/weather/src/main/resources/log4j.properties +++ /dev/null @@ -1,5 +0,0 @@ -log4j.rootLogger=WARN, stdout - -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n \ No newline at end of file