diff --git a/samples/airline/client/jms/build.xml b/samples/airline/client/jms/build.xml
new file mode 100644
index 00000000..dd4415f0
--- /dev/null
+++ b/samples/airline/client/jms/build.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/airline/client/jms/readme.txt b/samples/airline/client/jms/readme.txt
new file mode 100644
index 00000000..b05cc94a
--- /dev/null
+++ b/samples/airline/client/jms/readme.txt
@@ -0,0 +1,13 @@
+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".
+
+NOTE that the client uses ActiveMQ 2.1, and needs to be changed for other versions of ActiveMQ, or other JMS providers.
+Also note that ActiveMQ needs to be running before this sample is started.
+
+SAJA 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/samples/airline/client/jms/src/org/springframework/ws/samples/airline/client/jms/GetFlights.java b/samples/airline/client/jms/src/org/springframework/ws/samples/airline/client/jms/GetFlights.java
new file mode 100644
index 00000000..2e884c7f
--- /dev/null
+++ b/samples/airline/client/jms/src/org/springframework/ws/samples/airline/client/jms/GetFlights.java
@@ -0,0 +1,195 @@
+/*
+ * 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.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Iterator;
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+import javax.jms.TopicSubscriber;
+import javax.xml.soap.MessageFactory;
+import javax.xml.soap.MimeHeaders;
+import javax.xml.soap.Name;
+import javax.xml.soap.SOAPBodyElement;
+import javax.xml.soap.SOAPElement;
+import javax.xml.soap.SOAPEnvelope;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPMessage;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.codehaus.activemq.ActiveMQConnection;
+import org.codehaus.activemq.ActiveMQConnectionFactory;
+
+/**
+ * @author Arjen Poutsma
+ */
+public class GetFlights implements MessageListener {
+
+ public static final String NAMESPACE_URI = "http://www.springframework.org/spring-ws/samples/airline/schemas";
+
+ public static final String PREFIX = "airline";
+
+ private static final String CORRELATION_ID = "correlationId";
+
+ private static final String REQUEST_TOPIC = "org.springframework.ws.samples.airline.RequestTopic";
+
+ private static final String RESPONSE_TOPIC = "org.springframework.ws.samples.airline.ResponseTopic";
+
+ private TopicConnection connection;
+
+ private MessageFactory messageFactory;
+
+ private Topic responseTopic;
+
+ private TopicSession session;
+
+ private TransformerFactory transfomerFactory;
+
+ public GetFlights(TopicConnectionFactory connectionFactory) throws SOAPException, JMSException {
+ messageFactory = MessageFactory.newInstance();
+ transfomerFactory = TransformerFactory.newInstance();
+ connection = connectionFactory.createTopicConnection();
+ session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
+ responseTopic = session.createTopic(RESPONSE_TOPIC);
+ TopicSubscriber subscriber = session.createSubscriber(responseTopic);
+ subscriber.setMessageListener(this);
+ connection.start();
+ }
+
+ public void onMessage(Message message) {
+ try {
+ System.out.println("Received message");
+ BytesMessage bytesMessage = (BytesMessage) message;
+ byte[] buf = new byte[(int) bytesMessage.getBodyLength()];
+ bytesMessage.readBytes(buf);
+ ByteArrayInputStream is = new ByteArrayInputStream(buf);
+ SOAPMessage saajMessage = messageFactory.createMessage(new MimeHeaders(), is);
+ writeGetFlightsResponse(saajMessage);
+ System.exit(0);
+ }
+ catch (Exception e) {
+ e.printStackTrace(System.err);
+ }
+ }
+
+ public void close() {
+ if (session != null) {
+ try {
+ session.close();
+ }
+ catch (JMSException ex) {
+ ex.printStackTrace(System.err);
+ }
+ }
+ if (connection != null) {
+ try {
+ connection.close();
+ }
+ catch (JMSException ex) {
+ ex.printStackTrace(System.err);
+ }
+ }
+ }
+
+ 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, JMSException {
+ SOAPMessage request = createGetFlightsRequest();
+ Topic requestTopic = session.createTopic(REQUEST_TOPIC);
+ TopicPublisher publisher = session.createPublisher(requestTopic);
+ BytesMessage message = session.createBytesMessage();
+ message.setJMSCorrelationID(CORRELATION_ID);
+ message.setJMSReplyTo(responseTopic);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ request.writeTo(os);
+ os.flush();
+ message.writeBytes(os.toByteArray());
+ publisher.publish(message);
+ System.out.println("Written GetFlights request to " + requestTopic);
+ }
+
+ 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));
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ String url = ActiveMQConnection.DEFAULT_URL;
+ if (args.length > 0) {
+ url = args[0];
+ }
+ TopicConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
+ GetFlights getFlights = null;
+ try {
+ getFlights = new GetFlights(connectionFactory);
+ getFlights.getFlights();
+ while (true) {
+ // keep running until we receive a response message in onMessage
+ }
+ }
+ finally {
+ if (getFlights != null) {
+ getFlights.close();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/airline/pom.xml b/samples/airline/pom.xml
index 3e275aaa..2f429696 100644
--- a/samples/airline/pom.xml
+++ b/samples/airline/pom.xml
@@ -1,4 +1,5 @@
-
+
spring-ws-samples
org.springframework.ws
@@ -19,7 +20,7 @@
-
+
${project.build.directory}/generated-sources/main/java
@@ -46,10 +47,15 @@
org.springframework.ws
spring-ws-security
+
+ org.springframework.ws
+ spring-ws-sandbox
+ ${project.version}
+
org.springframework
- spring-hibernate
+ spring-hibernate3
org.springframework
@@ -59,6 +65,10 @@
org.springframework
spring-mock
+
+ org.springframework
+ spring-jms
+
jdom
@@ -150,11 +160,26 @@
mysql-connector-java
3.1.11
+
- hsqldb
- hsqldb
- 1.8.0.4
- test
+ javax.jms
+ jms
+ 1.1
+ runtime
+
+
+ geronimo-spec
+ geronimo-spec-j2ee-management
+ 1.0-rc4
+
+
+ activemq
+ activemq
+
+
+ concurrent
+ concurrent
+ 1.3.4
@@ -167,6 +192,5 @@
joda-time-hibernate
0.8
-
\ No newline at end of file
diff --git a/samples/airline/readme.txt b/samples/airline/readme.txt
index daffa7cf..1699a78e 100644
--- a/samples/airline/readme.txt
+++ b/samples/airline/readme.txt
@@ -6,27 +6,31 @@
Features a web service on top of an airline reservation system, backed by a database. The web service works by using XML
Marshalling techniques (JAXB 1), and JDOM in combination with XPath queries to pull information from a message. All
-messages follow following the airline.xsd schema in src/webapp.
+messages follow the airline.xsd schema in src/main/webapp.
-A C# client is available in the client directory.
+Multiple clients are available, showing interoperability with Axis 1, SAAJ, C#, JMS and more.
2. INSTALLATION
The Airline sample is a normal web application that connects to a database of your choice.
1. Create a database using one of the scripts in src/etc/db. First, initialize the database using either the MySQL or
- PostgreSQL initDB.sql script, and after that run populateDb.sql.
+ PostgreSQL initDB.sql script, and after that run src/etc/db/populateDb.sql.
2. Adjust the jdbc.properties in src/main/resources/org/springframework/ws/samples/airline/dao
- to reflect your database connection settings
-3. Adjust the hibernate.properties in src/main/resources/org/springframework/ws/samples/airline/dao/hibernate
+ to reflect your database connection settings. By default MySQL is used.
+3. Adjust the hibernate.properties in src/main/resources/org/springframework/ws/samples/airline/dao/hibernate. By
+ default MySQL is used.
+4. (Optional) Adjust the applicationContext-ws-jms.xml in src/main/resources/org/springframework/ws/samples/airline/ws/
+ to reflect your JMS connections settings. By default ActiveMQ 2.1 is used. Make sure to start ActiveMQ before
4. run "mvn package" and deploy the war file generated in target; or run "mvn jetty:run" to run the sample
using the Jetty Web container built into Maven 2.
+5.
Note that both MySQL drivers are linked in using Maven so you don't have include these in your server if you're using
this database.
3. THE CLIENTS
-The client directory contains two sample clients: one in C# and one using SAAJ. More instructions are provided in the
-readme files in the directories.
+The client directory contains a number of sample clients. More instructions are provided in the readme files in the
+directories.
diff --git a/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/StubFrequentFlyerSecurityService.java b/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/StubFrequentFlyerSecurityService.java
new file mode 100644
index 00000000..e9c5b029
--- /dev/null
+++ b/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/StubFrequentFlyerSecurityService.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+/**
+ * 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
+ * Acegi Security.
+ *
+ * @author Arjen Poutsma
+ */
+public class StubFrequentFlyerSecurityService implements FrequentFlyerSecurityService {
+
+ private FrequentFlyer john;
+
+ public StubFrequentFlyerSecurityService() {
+ john = new FrequentFlyer();
+ john.setUsername("john");
+ john.setFirstName("John");
+ john.setLastName("Doe");
+ john.setPassword("changeme");
+ john.setMiles(10);
+ }
+
+ public FrequentFlyer getFrequentFlyer(String username) {
+ if (john.getUsername().equals(username)) {
+ return john;
+ }
+ else {
+ return null;
+ }
+ }
+
+ public FrequentFlyer getCurrentlyAuthenticatedFrequentFlyer() {
+ return john;
+ }
+}
diff --git a/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java b/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java
index 0a0bf6ce..0964634e 100644
--- a/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java
+++ b/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java
@@ -22,7 +22,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTime;
import org.joda.time.YearMonthDay;
-
import org.springframework.util.Assert;
import org.springframework.ws.samples.airline.dao.FlightDao;
import org.springframework.ws.samples.airline.dao.TicketDao;
@@ -32,6 +31,7 @@ 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.security.StubFrequentFlyerSecurityService;
import org.springframework.ws.samples.airline.service.AirlineService;
import org.springframework.ws.samples.airline.service.NoSeatAvailableException;
import org.springframework.ws.samples.airline.service.NoSuchFlightException;
@@ -43,13 +43,13 @@ import org.springframework.ws.samples.airline.service.NoSuchFlightException;
*/
public class AirlineServiceImpl implements AirlineService {
- private final static Log logger = LogFactory.getLog(AirlineServiceImpl.class);
+ private static final Log logger = LogFactory.getLog(AirlineServiceImpl.class);
private FlightDao flightDao;
private TicketDao ticketDao;
- private FrequentFlyerSecurityService frequentFlyerSecurityService;
+ private FrequentFlyerSecurityService frequentFlyerSecurityService = new StubFrequentFlyerSecurityService();
public void setFlightDao(FlightDao flightDao) {
this.flightDao = flightDao;
diff --git a/samples/airline/src/main/resources/org/springframework/ws/samples/airline/dao/hibernate/applicationContext-hibernate.xml b/samples/airline/src/main/resources/org/springframework/ws/samples/airline/dao/hibernate/applicationContext-hibernate.xml
index fd5e3993..e19014c2 100644
--- a/samples/airline/src/main/resources/org/springframework/ws/samples/airline/dao/hibernate/applicationContext-hibernate.xml
+++ b/samples/airline/src/main/resources/org/springframework/ws/samples/airline/dao/hibernate/applicationContext-hibernate.xml
@@ -1,8 +1,9 @@
-
-
-
+
@@ -24,10 +25,8 @@
-
-
-
+
diff --git a/samples/airline/src/main/resources/org/springframework/ws/samples/airline/service/applicationContext.xml b/samples/airline/src/main/resources/org/springframework/ws/samples/airline/service/applicationContext.xml
index a287297b..4849e80d 100644
--- a/samples/airline/src/main/resources/org/springframework/ws/samples/airline/service/applicationContext.xml
+++ b/samples/airline/src/main/resources/org/springframework/ws/samples/airline/service/applicationContext.xml
@@ -1,8 +1,8 @@
-
+
-
diff --git a/samples/airline/src/main/resources/org/springframework/ws/samples/airline/ws/applicationContext-ws-jms.xml b/samples/airline/src/main/resources/org/springframework/ws/samples/airline/ws/applicationContext-ws-jms.xml
new file mode 100644
index 00000000..c856d3a9
--- /dev/null
+++ b/samples/airline/src/main/resources/org/springframework/ws/samples/airline/ws/applicationContext-ws-jms.xml
@@ -0,0 +1,42 @@
+
+
+
+ This application context contains a Spring-WS JMS transport.
+
+
+
+
+ The JMS connection factory to use for receiving request JMS message, and sending response messages. Replace
+ this bean with a JNDI Pooled connection factory, or change the wrapped "targetConnectionFactory" bean.
+
+
+
+
+
+
+
+
+
+
+ A Spring 2.0 MessageListenerContainer which listens for incoming messages on the Request Topic. When a
+ message is received, the messageListener defined below is invoked.
+
+
+
+
+
+
+
+
+
+ Spring 2.0 SessionAwareMessageListener that creates a SOAP message from the invoming JMS message using
+ a messageFactory, and forwards it to the message to the messageDispatcher. Both of these beans are defined
+ in applicationContext-ws.xml.
+
+
+
+
+
+
diff --git a/samples/airline/src/main/resources/org/springframework/ws/samples/airline/ws/applicationContext-ws.xml b/samples/airline/src/main/resources/org/springframework/ws/samples/airline/ws/applicationContext-ws.xml
index 5f6a416d..1f7708be 100644
--- a/samples/airline/src/main/resources/org/springframework/ws/samples/airline/ws/applicationContext-ws.xml
+++ b/samples/airline/src/main/resources/org/springframework/ws/samples/airline/ws/applicationContext-ws.xml
@@ -1,16 +1,23 @@
-
-
-
+
This application context contains the Spring-WS beans.
+
+
+ The MessageFactory is used to create new SOAP messages from incoming requests. It is referenced in
+ airline-servlet.xml and applicationContext-ws-jms.xml.
+
+
+
The MessageDispatcher is responsible for routing messages to endpoints. It uses three endpoint mappings to
- determine the endpoint suitable for handling a particular incoming request. This is not a recommended
- approach, it's done here only for illustration purposes.
+ determine the endpoint suitable for handling a particular incoming request. Having three mappings is not a
+ recommended approach, it's done here only for illustration purposes.
diff --git a/samples/airline/src/main/webapp/WEB-INF/airline-servlet.xml b/samples/airline/src/main/webapp/WEB-INF/airline-servlet.xml
index c312b673..b5586cf2 100644
--- a/samples/airline/src/main/webapp/WEB-INF/airline-servlet.xml
+++ b/samples/airline/src/main/webapp/WEB-INF/airline-servlet.xml
@@ -7,13 +7,10 @@
The handlerAdapter makes sure that Spring's DispatcherServlet
supports MessageEndpoints instances as handlers.
- It uses a SAAJ to construct SoapMessageContexts (and SoapMessages).
-
-
This handler adapter adds support for WsdlDefinitions to Spring's DispatcherServlet. It transforms location
diff --git a/samples/airline/src/main/webapp/WEB-INF/web.xml b/samples/airline/src/main/webapp/WEB-INF/web.xml
index cbb3f63d..51173c38 100644
--- a/samples/airline/src/main/webapp/WEB-INF/web.xml
+++ b/samples/airline/src/main/webapp/WEB-INF/web.xml
@@ -20,6 +20,8 @@
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-jms.xml
classpath:org/springframework/ws/samples/airline/ws/applicationContext-ws.xml
diff --git a/samples/airline/src/main/webapp/airline.wsdl b/samples/airline/src/main/webapp/airline.wsdl
index 38a5897f..25dc1d43 100644
--- a/samples/airline/src/main/webapp/airline.wsdl
+++ b/samples/airline/src/main/webapp/airline.wsdl
@@ -1,8 +1,8 @@