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/axis1/src/main/resources/log4j.properties b/airline/client/axis1/src/main/resources/log4j.properties
new file mode 100644
index 0000000..ef74297
--- /dev/null
+++ b/airline/client/axis1/src/main/resources/log4j.properties
@@ -0,0 +1,7 @@
+log4j.rootLogger=WARN, stdout
+log4j.logger.org.springframework.ws=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/airline/client/jax-ws/build.gradle b/airline/client/jax-ws/build.gradle
new file mode 100644
index 0000000..5179794
--- /dev/null
+++ b/airline/client/jax-ws/build.gradle
@@ -0,0 +1,38 @@
+configurations {
+ wsimport
+}
+
+ext.springWsVersion = '2.1.4.RELEASE'
+
+task wsImport {
+ ext.outputDir = "${buildDir}/classes/wsimport"
+ ext.wsdl = "${projectDir}/../airline.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.airline.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.airline.client.jaxws.Main"
+ classpath = sourceSets.main.runtimeClasspath
+}
\ No newline at end of file
diff --git a/airline/client/jax-ws/readme.txt b/airline/client/jax-ws/readme.txt
new file mode 100644
index 0000000..89a04c4
--- /dev/null
+++ b/airline/client/jax-ws/readme.txt
@@ -0,0 +1,11 @@
+SPRING WEB SERVICES
+
+This directory contains a Java client for the Airline Web Service that uses JAX-WS.
+The client can be run from the provided ant file, by calling "ant run".
+Note that the airline sample has to be running before invoking this target.
+
+Client Sample table of contents
+---------------------------------------------------
+* src - The source files for the client
+* build.xml - Ant build file with a 'build' and a 'run' target
+
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
new file mode 100644
index 0000000..12e2d2b
--- /dev/null
+++ b/airline/client/jax-ws/src/main/java/org/springframework/ws/samples/airline/client/jaxws/Main.java
@@ -0,0 +1,104 @@
+/*
+ * 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
new file mode 100644
index 0000000..e2cf3a8
--- /dev/null
+++ b/airline/client/jms/build.gradle
@@ -0,0 +1,14 @@
+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/readme.txt b/airline/client/jms/readme.txt
new file mode 100644
index 0000000..36aa269
--- /dev/null
+++ b/airline/client/jms/readme.txt
@@ -0,0 +1,10 @@
+SPRING WEB SERVICES
+
+This directory contains a client for the Airline Web Service that uses JMS: Java Message Service. The client can be run
+from the provided ant file, by calling "ant run".
+
+JMS Client Sample table of contents
+---------------------------------------------------
+* src - The source files for the client
+* build.xml - Ant build file with a 'build' and a 'run' target
+
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
new file mode 100644
index 0000000..34c5f68
--- /dev/null
+++ b/airline/client/jms/src/main/java/org/springframework/ws/samples/airline/client/jms/JmsClient.java
@@ -0,0 +1,48 @@
+/*
+ * 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.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;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
+import org.springframework.xml.transform.StringSource;
+
+/** @author Arjen Poutsma */
+public class JmsClient extends WebServiceGatewaySupport {
+
+ private static final String PAYLOAD =
+ "GetFlights operation using SAAJ.
+ *
+ * @author Arjen Poutsma
+ */
+public class GetFlights {
+
+ public static final String NAMESPACE_URI = "http://www.springframework.org/spring-ws/samples/airline/schemas/messages";
+
+ public static final String PREFIX = "airline";
+
+ private SOAPConnectionFactory connectionFactory;
+
+ private MessageFactory messageFactory;
+
+ private URL url;
+
+ private TransformerFactory transfomerFactory;
+
+ public GetFlights(String url) throws SOAPException, MalformedURLException {
+ connectionFactory = SOAPConnectionFactory.newInstance();
+ messageFactory = MessageFactory.newInstance();
+ transfomerFactory = TransformerFactory.newInstance();
+ this.url = new URL(url);
+ }
+
+ private SOAPMessage createGetFlightsRequest() throws SOAPException {
+ SOAPMessage message = messageFactory.createMessage();
+ SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
+ Name getFlightsRequestName = envelope.createName("GetFlightsRequest", PREFIX, NAMESPACE_URI);
+ SOAPBodyElement getFlightsRequestElement = message.getSOAPBody().addBodyElement(getFlightsRequestName);
+ Name fromName = envelope.createName("from", PREFIX, NAMESPACE_URI);
+ SOAPElement fromElement = getFlightsRequestElement.addChildElement(fromName);
+ fromElement.setValue("AMS");
+ Name toName = envelope.createName("to", PREFIX, NAMESPACE_URI);
+ SOAPElement toElement = getFlightsRequestElement.addChildElement(toName);
+ toElement.setValue("VCE");
+ Name departureDateName = envelope.createName("departureDate", PREFIX, NAMESPACE_URI);
+ SOAPElement departureDateElement = getFlightsRequestElement.addChildElement(departureDateName);
+ departureDateElement.setValue("2006-01-31");
+ return message;
+ }
+
+ public void getFlights() throws SOAPException, IOException, TransformerException {
+ SOAPMessage request = createGetFlightsRequest();
+ SOAPConnection connection = connectionFactory.createConnection();
+ SOAPMessage response = connection.call(request, url);
+ if (!response.getSOAPBody().hasFault()) {
+ writeGetFlightsResponse(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());
+ }
+ }
+
+ private void writeGetFlightsResponse(SOAPMessage message) throws SOAPException, TransformerException {
+ SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
+ Name getFlightsResponseName = envelope.createName("GetFlightsResponse", PREFIX, NAMESPACE_URI);
+ SOAPBodyElement getFlightsResponseElement =
+ (SOAPBodyElement) message.getSOAPBody().getChildElements(getFlightsResponseName).next();
+ Name flightName = envelope.createName("flight", PREFIX, NAMESPACE_URI);
+ Iterator iterator = getFlightsResponseElement.getChildElements(flightName);
+ Transformer transformer = transfomerFactory.newTransformer();
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ int count = 1;
+ while (iterator.hasNext()) {
+ System.out.println("Flight " + count);
+ System.out.println("--------");
+ SOAPElement flightElement = (SOAPElement) iterator.next();
+ DOMSource source = new DOMSource(flightElement);
+ transformer.transform(source, new StreamResult(System.out));
+ }
+ }
+}
diff --git a/airline/client/saaj/src/main/java/org/springframework/ws/samples/airline/client/saaj/GetFrequentFlyerMileage.java b/airline/client/saaj/src/main/java/org/springframework/ws/samples/airline/client/saaj/GetFrequentFlyerMileage.java
new file mode 100644
index 0000000..8c27d41
--- /dev/null
+++ b/airline/client/saaj/src/main/java/org/springframework/ws/samples/airline/client/saaj/GetFrequentFlyerMileage.java
@@ -0,0 +1,128 @@
+/*
+ * 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.saaj;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.xml.soap.MessageFactory;
+import javax.xml.soap.Name;
+import javax.xml.soap.SOAPBodyElement;
+import javax.xml.soap.SOAPConnection;
+import javax.xml.soap.SOAPConnectionFactory;
+import javax.xml.soap.SOAPEnvelope;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPFault;
+import javax.xml.soap.SOAPMessage;
+
+import com.sun.xml.wss.ProcessingContext;
+import com.sun.xml.wss.XWSSProcessor;
+import com.sun.xml.wss.XWSSProcessorFactory;
+import com.sun.xml.wss.XWSSecurityException;
+import com.sun.xml.wss.impl.callback.PasswordCallback;
+import com.sun.xml.wss.impl.callback.UsernameCallback;
+
+/**
+ * Simple client that calls the WS-Security GetFrequentFlyerMileage operation using SAAJ and XWSS.
+ *
+ * @author Arjen Poutsma
+ */
+public class GetFrequentFlyerMileage {
+
+ public static final String NAMESPACE_URI = "http://www.springframework.org/spring-ws/samples/airline/schemas/messages";
+
+ public static final String PREFIX = "airline";
+
+ private SOAPConnectionFactory connectionFactory;
+
+ private MessageFactory messageFactory;
+
+ private URL url;
+
+ private XWSSProcessorFactory processorFactory;
+
+ public GetFrequentFlyerMileage(String url) throws SOAPException, MalformedURLException, XWSSecurityException {
+ connectionFactory = SOAPConnectionFactory.newInstance();
+ messageFactory = MessageFactory.newInstance();
+ processorFactory = XWSSProcessorFactory.newInstance();
+ this.url = new URL(url);
+ }
+
+ private SOAPMessage createGetMileageRequest() throws SOAPException {
+ SOAPMessage message = messageFactory.createMessage();
+ SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
+ Name getFlightsRequestName = envelope.createName("GetFrequentFlyerMileageRequest", GetFrequentFlyerMileage.PREFIX,
+ GetFrequentFlyerMileage.NAMESPACE_URI);
+ message.getSOAPBody().addBodyElement(getFlightsRequestName);
+ return message;
+ }
+
+ private SOAPMessage secureMessage(SOAPMessage message, final String username, final String password)
+ throws IOException, XWSSecurityException {
+ CallbackHandler callbackHandler = new CallbackHandler() {
+ public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
+ for (int i = 0; i < callbacks.length; i++) {
+ if (callbacks[i] instanceof UsernameCallback) {
+ UsernameCallback callback = (UsernameCallback) callbacks[i];
+ callback.setUsername(username);
+ }
+ else if (callbacks[i] instanceof PasswordCallback) {
+ PasswordCallback callback = (PasswordCallback) callbacks[i];
+ callback.setPassword(password);
+ }
+ else {
+ throw new UnsupportedCallbackException(callbacks[i]);
+ }
+ }
+ }
+ };
+ InputStream policyStream = null;
+ XWSSProcessor processor = null;
+ try {
+ policyStream = getClass().getResourceAsStream("securityPolicy.xml");
+ processor = processorFactory.createProcessorForSecurityConfiguration(policyStream, callbackHandler);
+ }
+ finally {
+ if (policyStream != null) {
+ policyStream.close();
+ }
+ }
+ ProcessingContext context = processor.createProcessingContext(message);
+ return processor.secureOutboundMessage(context);
+ }
+
+ public void getMileage(String username, String password) throws SOAPException, IOException, XWSSecurityException {
+ SOAPMessage request = createGetMileageRequest();
+ request = secureMessage(request, username, password);
+ SOAPConnection connection = connectionFactory.createConnection();
+ SOAPMessage response = connection.call(request, url);
+ if (!response.getSOAPBody().hasFault()) {
+ SOAPBodyElement mileage = (SOAPBodyElement) response.getSOAPBody().getChildElements().next();
+ System.out.println("'" + username + "' has " + mileage.getValue() + " frequent flyer miles");
+ }
+ 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());
+ }
+ }
+}
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
new file mode 100644
index 0000000..8509073
--- /dev/null
+++ b/airline/client/saaj/src/main/resources/org/springframework/ws/samples/airline/client/saaj/securityPolicy.xml
@@ -0,0 +1,3 @@
+FrequentFlyer which provides extra functionality needed to implement the
+ * UserDetails interface.
+ *
+ * @author Arjen Poutsma
+ */
+public class FrequentFlyerDetails implements UserDetails {
+
+ private FrequentFlyer frequentFlyer;
+
+ public static final CollectionFrequentFlyer with the given username.
+ *
+ * @param username the username
+ * @return the frequent flyer with the given username, or null if not found
+ * @throws NoSuchFrequentFlyerException when the frequent flyer cannot be found
+ */
+ FrequentFlyer getFrequentFlyer(String username) throws NoSuchFrequentFlyerException;
+
+ /**
+ * Returns the FrequentFlyer that is currently logged in.
+ *
+ * @return the frequent flyer that is currently logged in, or null if not found
+ */
+ FrequentFlyer getCurrentlyAuthenticatedFrequentFlyer();
+
+}
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
new file mode 100644
index 0000000..355d2a7
--- /dev/null
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SpringFrequentFlyerSecurityService.java
@@ -0,0 +1,86 @@
+/*
+ * 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.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;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.ws.samples.airline.dao.FrequentFlyerDao;
+import org.springframework.ws.samples.airline.domain.FrequentFlyer;
+import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerException;
+
+/**
+ * Implementation of the FrequentFlyerSecurityService that uses Spring Security.
+ *
+ * @author Arjen Poutsma
+ */
+public class SpringFrequentFlyerSecurityService implements FrequentFlyerSecurityService, UserDetailsService {
+
+ private FrequentFlyerDao frequentFlyerDao;
+
+ @Autowired
+ 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 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/security/StubFrequentFlyerSecurityService.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/StubFrequentFlyerSecurityService.java
new file mode 100644
index 0000000..b4c1f56
--- /dev/null
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/StubFrequentFlyerSecurityService.java
@@ -0,0 +1,50 @@
+/*
+ * 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.security;
+
+import org.springframework.ws.samples.airline.domain.FrequentFlyer;
+import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerException;
+
+/**
+ * Stub implementation of FrequentFlyerSecurityService. This implementation is used by default by {@link
+ * org.springframework.ws.samples.airline.service.impl.AirlineServiceImpl}, to allow it to run without depending on
+ * Spring Security.
+ *
+ * @author Arjen Poutsma
+ */
+public class StubFrequentFlyerSecurityService implements FrequentFlyerSecurityService {
+
+ private FrequentFlyer john;
+
+ public StubFrequentFlyerSecurityService() {
+ john = new FrequentFlyer("John", "Doe", "john", "changeme");
+ john.setMiles(10);
+ }
+
+ public FrequentFlyer getFrequentFlyer(String username) throws NoSuchFrequentFlyerException {
+ if (john.getUsername().equals(username)) {
+ return john;
+ }
+ else {
+ throw new NoSuchFrequentFlyerException(username);
+ }
+ }
+
+ public FrequentFlyer getCurrentlyAuthenticatedFrequentFlyer() {
+ return john;
+ }
+}
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
new file mode 100644
index 0000000..851a5a4
--- /dev/null
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/service/AirlineService.java
@@ -0,0 +1,84 @@
+/*
+ * 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.service;
+
+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;
+import org.springframework.ws.samples.airline.domain.ServiceClass;
+import org.springframework.ws.samples.airline.domain.Ticket;
+
+/**
+ * Defines the business logic of the Airline application.
+ *
+ * @author Arjen Poutsma
+ */
+public interface AirlineService {
+
+ /**
+ * Returns a single Flight with the given id.
+ *
+ * @param id the flight identifier
+ * @return the flight
+ * @throws NoSuchFlightException if a flight with the specified flight iddoes not exist
+ */
+ Flight getFlight(Long id) throws NoSuchFlightException;
+
+ /**
+ * Returns a list of Flight objects that fall within the specified criteria.
+ *
+ * @param fromAirportCode the three-letter airport code to get flights from
+ * @param toAirportCode the three-letter airport code to get flights to
+ * @param departureDate the date of the flights
+ * @param serviceClass the desired service class level. May be null
+ * @return a list of flights
+ */
+ ListAirlineService interface.
+ *
+ * @author Arjen Poutsma
+ */
+@Service
+@Transactional(readOnly = true)
+public class AirlineServiceImpl implements AirlineService {
+
+ private static final Log logger = LogFactory.getLog(AirlineServiceImpl.class);
+
+ private FlightDao flightDao;
+
+ private TicketDao ticketDao;
+
+ private FrequentFlyerSecurityService frequentFlyerSecurityService = new StubFrequentFlyerSecurityService();
+
+ @Autowired
+ public AirlineServiceImpl(FlightDao flightDao, TicketDao ticketDao) {
+ this.flightDao = flightDao;
+ this.ticketDao = ticketDao;
+ }
+
+ @Autowired(required = false)
+ public void setFrequentFlyerSecurityService(FrequentFlyerSecurityService frequentFlyerSecurityService) {
+ this.frequentFlyerSecurityService = frequentFlyerSecurityService;
+ }
+
+ @Transactional(readOnly = false,
+ rollbackFor = {NoSuchFlightException.class, NoSeatAvailableException.class, NoSuchFrequentFlyerException.class})
+ public Ticket bookFlight(String flightNumber, DateTime departureTime, List<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<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