diff --git a/pom.xml b/pom.xml
index 6a83a16a..791d7add 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,5 +1,5 @@
-
queue or
+ * queueName property. It creates a temporary queue for the response message. For both request and response
+ * {@link BytesMessage}s are used.
+ *
+ * @author Arjen Poutsma
+ * @since 1.1.0
+ */
+public class JmsMessageSender implements WebServiceMessageSender, JmsTransportConstants {
+
+ /**
+ * Default timeout for receive operations: -1 indicates a blocking receive without timeout.
+ */
+ public static final long DEFAULT_RECEIVE_TIMEOUT = -1;
+
+ private ConnectionFactory connectionFactory;
+
+ private DestinationResolver destinationResolver = new DynamicDestinationResolver();
+
+ private long receiveTimeout = DEFAULT_RECEIVE_TIMEOUT;
+
+ public JmsMessageSender() {
+ }
+
+ public JmsMessageSender(ConnectionFactory connectionFactory) {
+ this.connectionFactory = connectionFactory;
+ }
+
+ /**
+ * Set the ConnectionFactory to use for obtaining JMS {@link Connection}s.
+ */
+ public void setConnectionFactory(ConnectionFactory connectionFactory) {
+ this.connectionFactory = connectionFactory;
+ }
+
+ public void setDestinationResolver(DestinationResolver destinationResolver) {
+ this.destinationResolver = destinationResolver;
+ }
+
+ /**
+ * Set the timeout to use for receive calls. The default is 0, which means no timeout.
+ */
+ public void setReceiveTimeout(long receiveTimeout) {
+ this.receiveTimeout = receiveTimeout;
+ }
+
+ public WebServiceConnection createConnection(String uriString) throws IOException {
+ Assert.notNull(connectionFactory, "connectionFactory must not be null");
+ JmsSenderConnection connection = null;
+ try {
+ JmsUri uri = new JmsUri(uriString);
+ connection = new JmsSenderConnection(uri, connectionFactory, destinationResolver, receiveTimeout);
+ return connection;
+ }
+ catch (JMSException ex) {
+ if (connection != null) {
+ connection.close();
+ }
+ throw new JmsTransportException(ex);
+ }
+ }
+
+ public boolean supports(String uri) {
+ return StringUtils.hasLength(uri) && uri.startsWith(URI_SCHEME + ":");
+ }
+
+}
diff --git a/support/src/main/java/org/springframework/ws/transport/jms/JmsReceiverConnection.java b/support/src/main/java/org/springframework/ws/transport/jms/JmsReceiverConnection.java
new file mode 100644
index 00000000..d5ae27dc
--- /dev/null
+++ b/support/src/main/java/org/springframework/ws/transport/jms/JmsReceiverConnection.java
@@ -0,0 +1,202 @@
+/*
+ * 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.transport.jms;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.util.Assert;
+import org.springframework.ws.FaultAwareWebServiceMessage;
+import org.springframework.ws.WebServiceMessage;
+import org.springframework.ws.transport.AbstractReceiverConnection;
+import org.springframework.ws.transport.FaultAwareWebServiceConnection;
+import org.springframework.ws.transport.WebServiceConnection;
+import org.springframework.ws.transport.jms.support.JmsTransportUtils;
+
+/**
+ * Implementation of {@link WebServiceConnection} that is used for server-side JMS access.
+ *
+ * @author Arjen Poutsma
+ * @since 1.1.0
+ */
+public class JmsReceiverConnection extends AbstractReceiverConnection
+ implements JmsTransportConstants, FaultAwareWebServiceConnection {
+
+ private final BytesMessage requestMessage;
+
+ private final Session session;
+
+ private BytesMessage responseMessage;
+
+ /**
+ * Constructs a new JMS connection with the given parameters.
+ */
+ protected JmsReceiverConnection(BytesMessage requestMessage, Session session) {
+ Assert.notNull(requestMessage, "requestMessage must not be null");
+ Assert.notNull(session, "session must not be null");
+ this.requestMessage = requestMessage;
+ this.session = session;
+ }
+
+ /**
+ * Returns the request message for this connection.
+ */
+ public BytesMessage getRequestMessage() {
+ return requestMessage;
+ }
+
+ /**
+ * Returns the response message, if any, for this connection.
+ */
+ public BytesMessage getResponseMessage() {
+ return responseMessage;
+ }
+
+ public String getErrorMessage() throws IOException {
+ return null;
+ }
+
+ public boolean hasError() throws IOException {
+ return false;
+ }
+
+ /*
+ * Receiving
+ */
+
+ protected Iterator getRequestHeaderNames() throws IOException {
+ try {
+ Enumeration headers = requestMessage.getPropertyNames();
+ List results = new ArrayList();
+ while (headers.hasMoreElements()) {
+ String header = (String) headers.nextElement();
+ if (header.startsWith(JmsTransportConstants.PROPERTY_PREFIX)) {
+ results.add(header);
+ }
+ }
+ return results.iterator();
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException("Could not get property names", ex);
+ }
+ }
+
+ protected Iterator getRequestHeaders(String name) throws IOException {
+ try {
+ String value = requestMessage.getStringProperty(name);
+ return Collections.singletonList(value).iterator();
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException("Could not get property value", ex);
+ }
+ }
+
+ protected InputStream getRequestInputStream() throws IOException {
+ return new BytesMessageInputStream(requestMessage);
+ }
+
+ /*
+ * Sending
+ */
+
+ protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
+ try {
+ responseMessage = session.createBytesMessage();
+ responseMessage.setJMSCorrelationID(requestMessage.getJMSMessageID());
+ responseMessage.setStringProperty(PROPERTY_BINDING_VERSION, "1.0");
+ if (message instanceof FaultAwareWebServiceMessage) {
+ FaultAwareWebServiceMessage faultMessage = (FaultAwareWebServiceMessage) message;
+ responseMessage.setBooleanProperty(PROPERTY_IS_FAULT, faultMessage.hasFault());
+ }
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException("Could not create response message", ex);
+ }
+ }
+
+ protected void addResponseHeader(String name, String value) throws IOException {
+ try {
+ String property = JmsTransportUtils.headerToJmsProperty(name);
+ responseMessage.setStringProperty(property, value);
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException("Could not set property", ex);
+ }
+ }
+
+ protected OutputStream getResponseOutputStream() throws IOException {
+ return new BytesMessageOutputStream(responseMessage);
+ }
+
+ protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
+ MessageProducer messageProducer = null;
+ try {
+ if (requestMessage.getJMSReplyTo() != null) {
+ messageProducer = session.createProducer(requestMessage.getJMSReplyTo());
+ messageProducer.setDeliveryMode(requestMessage.getJMSDeliveryMode());
+ messageProducer.setPriority(requestMessage.getJMSPriority());
+ messageProducer.send(responseMessage);
+ }
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException(ex);
+ }
+ finally {
+ JmsUtils.closeMessageProducer(messageProducer);
+ }
+ }
+
+ public void close() throws IOException {
+ }
+
+ /*
+ * Faults
+ */
+
+ public boolean hasFault() throws IOException {
+ try {
+ return requestMessage.getBooleanProperty(JmsTransportConstants.PROPERTY_IS_FAULT);
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException(ex);
+ }
+ }
+
+ public void setFault(boolean fault) throws IOException {
+ if (responseMessage != null) {
+ try {
+ responseMessage.setBooleanProperty(JmsTransportConstants.PROPERTY_IS_FAULT, fault);
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException(ex);
+ }
+ }
+ }
+
+
+}
diff --git a/support/src/main/java/org/springframework/ws/transport/jms/JmsSenderConnection.java b/support/src/main/java/org/springframework/ws/transport/jms/JmsSenderConnection.java
new file mode 100644
index 00000000..8e1d8827
--- /dev/null
+++ b/support/src/main/java/org/springframework/ws/transport/jms/JmsSenderConnection.java
@@ -0,0 +1,276 @@
+/*
+ * 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.transport.jms;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import javax.jms.BytesMessage;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TemporaryQueue;
+
+import org.springframework.jms.connection.ConnectionFactoryUtils;
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.jms.support.destination.DestinationResolver;
+import org.springframework.util.Assert;
+import org.springframework.ws.FaultAwareWebServiceMessage;
+import org.springframework.ws.WebServiceMessage;
+import org.springframework.ws.transport.AbstractSenderConnection;
+import org.springframework.ws.transport.FaultAwareWebServiceConnection;
+import org.springframework.ws.transport.WebServiceConnection;
+import org.springframework.ws.transport.jms.support.JmsTransportUtils;
+
+/**
+ * Implementation of {@link WebServiceConnection} that is used for client-side JMS access.
+ *
+ * @author Arjen Poutsma
+ * @since 1.1.0
+ */
+public class JmsSenderConnection extends AbstractSenderConnection
+ implements FaultAwareWebServiceConnection, JmsTransportConstants {
+
+ private final ConnectionFactory connectionFactory;
+
+ private final DestinationResolver destinationResolver;
+
+ private final Connection connection;
+
+ private final Session session;
+
+ private final Destination requestDestination;
+
+ private final JmsUri uri;
+
+ private final long receiveTimeout;
+
+ private Destination responseDestination;
+
+ private BytesMessage requestMessage;
+
+ private BytesMessage responseMessage;
+
+ /**
+ * Constructs a new JMS connection with the given parameters.
+ */
+ protected JmsSenderConnection(JmsUri uri,
+ ConnectionFactory connectionFactory,
+ DestinationResolver destinationResolver,
+ long receiveTimeout) throws JMSException {
+ Assert.notNull(uri, "'uri' must not be null");
+ Assert.notNull(connectionFactory, "'connectionFactory' must not be null");
+ Assert.notNull(destinationResolver, "destinationResolver must not be null");
+ this.connectionFactory = connectionFactory;
+ this.destinationResolver = destinationResolver;
+ connection = connectionFactory.createConnection();
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ requestDestination =
+ destinationResolver.resolveDestinationName(session, uri.getDestination(), uri.isPubSubDomain());
+ this.uri = uri;
+ this.receiveTimeout = receiveTimeout;
+ }
+
+ /**
+ * Returns the request message for this connection.
+ */
+ public BytesMessage getRequestMessage() {
+ return requestMessage;
+ }
+
+ /**
+ * Returns the response message, if any, for this connection.
+ */
+ public BytesMessage getResponseMessage() {
+ return responseMessage;
+ }
+
+ public boolean hasError() throws IOException {
+ return false;
+ }
+
+ public String getErrorMessage() throws IOException {
+ return null;
+ }
+
+ /*
+ * Sending
+ */
+
+ protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
+ try {
+ requestMessage = session.createBytesMessage();
+ requestMessage.setStringProperty(PROPERTY_BINDING_VERSION, "1.0");
+ if (message instanceof FaultAwareWebServiceMessage) {
+ FaultAwareWebServiceMessage faultMessage = (FaultAwareWebServiceMessage) message;
+ requestMessage.setBooleanProperty(PROPERTY_IS_FAULT, faultMessage.hasFault());
+ }
+ requestMessage.setStringProperty(PROPERTY_REQUEST_IRI, uri.toString());
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException(ex);
+ }
+ }
+
+ protected void addRequestHeader(String name, String value) throws IOException {
+ try {
+ String property = JmsTransportUtils.headerToJmsProperty(name);
+ requestMessage.setStringProperty(property, value);
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException("Could not set property", ex);
+ }
+ }
+
+ protected OutputStream getRequestOutputStream() throws IOException {
+ return new BytesMessageOutputStream(requestMessage);
+ }
+
+ protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
+ MessageProducer messageProducer = null;
+ try {
+ messageProducer = session.createProducer(requestDestination);
+ messageProducer.setDeliveryMode(uri.getDeliveryMode());
+ messageProducer.setTimeToLive(uri.getTimeToLive());
+ messageProducer.setPriority(uri.getPriority());
+ if (uri.hasReplyTo()) {
+ responseDestination =
+ destinationResolver.resolveDestinationName(session, uri.getReplyTo(), uri.isPubSubDomain());
+ }
+ else {
+ responseDestination = session.createTemporaryQueue();
+ }
+ requestMessage.setJMSReplyTo(responseDestination);
+ connection.start();
+ messageProducer.send(requestMessage);
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException(ex);
+ }
+ finally {
+ JmsUtils.closeMessageProducer(messageProducer);
+ }
+ }
+
+ /*
+ * Receiving
+ */
+
+ protected void onReceiveBeforeRead() throws IOException {
+ MessageConsumer messageConsumer = null;
+ try {
+ messageConsumer = session.createConsumer(responseDestination);
+ responseMessage = (BytesMessage) (receiveTimeout >= 0 ? messageConsumer.receive(receiveTimeout) :
+ messageConsumer.receive());
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException(ex);
+ }
+ finally {
+ JmsUtils.closeMessageConsumer(messageConsumer);
+ if (responseDestination instanceof TemporaryQueue) {
+ try {
+ ((TemporaryQueue) responseDestination).delete();
+ }
+ catch (JMSException e) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ protected boolean hasResponse() throws IOException {
+ return responseMessage != null;
+ }
+
+ protected Iterator getResponseHeaderNames() throws IOException {
+ try {
+ List headerNames = new ArrayList();
+ Enumeration propertyNames = responseMessage.getPropertyNames();
+ while (propertyNames.hasMoreElements()) {
+ String propertyName = (String) propertyNames.nextElement();
+ headerNames.add(JmsTransportUtils.jmsPropertyToHeader(propertyName));
+ }
+ return headerNames.iterator();
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException("Could not get property names", ex);
+ }
+ }
+
+ protected Iterator getResponseHeaders(String name) throws IOException {
+ try {
+ String propertyName = JmsTransportUtils.headerToJmsProperty(name);
+ String value = responseMessage.getStringProperty(propertyName);
+ if (value != null) {
+ return Collections.singletonList(value).iterator();
+ }
+ else {
+ return Collections.EMPTY_LIST.iterator();
+ }
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException("Could not get property value", ex);
+ }
+ }
+
+ protected InputStream getResponseInputStream() throws IOException {
+ return new BytesMessageInputStream(responseMessage);
+ }
+
+ public void close() throws IOException {
+ JmsUtils.closeSession(session);
+ ConnectionFactoryUtils.releaseConnection(connection, connectionFactory, true);
+ }
+
+ /*
+ * Faults
+ */
+
+ public boolean hasFault() throws IOException {
+ if (responseMessage != null) {
+ try {
+ return responseMessage.getBooleanProperty(JmsTransportConstants.PROPERTY_IS_FAULT);
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException(ex);
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ public void setFault(boolean fault) throws IOException {
+ try {
+ requestMessage.setBooleanProperty(JmsTransportConstants.PROPERTY_IS_FAULT, fault);
+ }
+ catch (JMSException ex) {
+ throw new JmsTransportException(ex);
+ }
+ }
+
+}
diff --git a/support/src/main/java/org/springframework/ws/transport/jms/JmsTransportConstants.java b/support/src/main/java/org/springframework/ws/transport/jms/JmsTransportConstants.java
new file mode 100644
index 00000000..5ce69c9a
--- /dev/null
+++ b/support/src/main/java/org/springframework/ws/transport/jms/JmsTransportConstants.java
@@ -0,0 +1,68 @@
+/*
+ * 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.transport.jms;
+
+import org.springframework.ws.transport.TransportConstants;
+
+/**
+ * Declares JMS-specific transport constants.
+ *
+ * @author Arjen Poutsma
+ * @since 1.1.0
+ */
+public interface JmsTransportConstants extends TransportConstants {
+
+ String URI_SCHEME = "jms";
+
+ String PARAM_DELIVERY_MODE = "deliveryMode";
+
+ String PARAM_CONNECTION_FACTORY_NAME = "connectionFactoryName";
+
+ String PARAM_INITIAL_CONTEXT_FACTORY = "initialContextFactory";
+
+ String PARAM_JNDI_URL = "jndiURL";
+
+ String PARAM_TIME_TO_LIVE = "timeToLive";
+
+ String PARAM_PRIORITY = "priority";
+
+ String PARAM_DESTINATION_TYPE = "destinationType";
+
+ String PARAM_REPLY_TO_NAME = "replyToName";
+
+ String DESTINATION_TYPE_QUEUE = "queue";
+
+ String DESTINATION_TYPE_TOPIC = "topic";
+
+ String PROPERTY_PREFIX = "SOAPJMS_";
+
+ String PROPERTY_IS_FAULT = PROPERTY_PREFIX + "isFault";
+
+ String PROPERTY_SOAP_ACTION = PROPERTY_PREFIX + "soapAction";
+
+ String PROPERTY_CONTENT_LENGTH = PROPERTY_PREFIX + "contentLength";
+
+ String PROPERTY_CONTENT_TYPE = PROPERTY_PREFIX + "contentType";
+
+ String PROPERTY_BINDING_VERSION = PROPERTY_PREFIX + "bindingVersion";
+
+ String PROPERTY_TARGET_SERVICE = PROPERTY_PREFIX + "targetService";
+
+ String PROPERTY_REQUEST_IRI = PROPERTY_PREFIX + "requestIRI";
+
+ String PROPERTY_SOAP_MEP = PROPERTY_PREFIX + "soapMEP";
+}
diff --git a/support/src/main/java/org/springframework/ws/transport/jms/JmsTransportException.java b/support/src/main/java/org/springframework/ws/transport/jms/JmsTransportException.java
new file mode 100644
index 00000000..e1ce05bd
--- /dev/null
+++ b/support/src/main/java/org/springframework/ws/transport/jms/JmsTransportException.java
@@ -0,0 +1,47 @@
+/*
+ * 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.transport.jms;
+
+import javax.jms.JMSException;
+
+import org.springframework.ws.transport.TransportException;
+
+/**
+ * Exception that is thrown when an error occurs in the JMS transport.
+ *
+ * @author Arjen Poutsma
+ * @since 1.1.0
+ */
+
+public class JmsTransportException extends TransportException {
+
+ private final JMSException jmsException;
+
+ public JmsTransportException(String msg, JMSException ex) {
+ super(msg + ": " + ex.getMessage());
+ jmsException = ex;
+ }
+
+ public JmsTransportException(JMSException ex) {
+ super(ex.getMessage());
+ jmsException = ex;
+ }
+
+ public JMSException getJmsException() {
+ return jmsException;
+ }
+}
diff --git a/support/src/main/java/org/springframework/ws/transport/jms/JmsUri.java b/support/src/main/java/org/springframework/ws/transport/jms/JmsUri.java
new file mode 100644
index 00000000..bb967691
--- /dev/null
+++ b/support/src/main/java/org/springframework/ws/transport/jms/JmsUri.java
@@ -0,0 +1,134 @@
+/*
+ * 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.transport.jms;
+
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.Queue;
+import javax.jms.Topic;
+
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+import org.springframework.ws.transport.support.ParameterizedUri;
+
+/**
+ * @author Arjen Poutsma
+ * @see RI
+ * Scheme for Java Message Service 1.0 RC1
+ */
+public class JmsUri extends ParameterizedUri implements JmsTransportConstants {
+
+ public JmsUri(String uri) {
+ super(uri);
+ validateParameters();
+ }
+
+ private void validateParameters() {
+ validateIntegerParameter(PARAM_DELIVERY_MODE);
+ validateIntegerParameter(PARAM_PRIORITY);
+ validateIntegerParameter(PARAM_TIME_TO_LIVE);
+ String destinationType = getDestinationType();
+ if (StringUtils.hasLength(destinationType)) {
+ Assert.isTrue(
+ DESTINATION_TYPE_QUEUE.equals(destinationType) || DESTINATION_TYPE_TOPIC.equals(destinationType),
+ "Invalid " + PARAM_DESTINATION_TYPE + ": [" + destinationType + "]. Expected '" +
+ DESTINATION_TYPE_QUEUE + "' or '" + DESTINATION_TYPE_TOPIC + "'");
+ }
+ }
+
+ private void validateIntegerParameter(String paramName) {
+ String paramValue = getParameter(paramName);
+ if (StringUtils.hasLength(paramValue)) {
+ try {
+ Integer.parseInt(paramValue);
+ }
+ catch (NumberFormatException ex) {
+ throw new IllegalArgumentException("Invalid " + paramName + ": [" + paramValue + "]. Not an integer.");
+ }
+ }
+ }
+
+ /**
+ * Returns whether the request message is persistent or not.
+ *
+ * @see DeliveryMode#NON_PERSISTENT
+ * @see DeliveryMode#PERSISTENT
+ */
+ public int getDeliveryMode() {
+ return getIntegerParameter(PARAM_DELIVERY_MODE, Message.DEFAULT_DELIVERY_MODE);
+ }
+
+ public String getDestination() {
+ return super.getDestination();
+ }
+
+ /**
+ * Specifies whether the destination is a {@link Queue} or a {@link Topic}, with the value "queue" or
+ * "topic", respectively.
+ */
+ public String getDestinationType() {
+ return getParameter(PARAM_DESTINATION_TYPE);
+ }
+
+ /**
+ * Returns the JMS priority associated with the request message.
+ *
+ * @see Message#setJMSPriority(int)
+ */
+ public int getPriority() {
+ return getIntegerParameter(PARAM_PRIORITY, Message.DEFAULT_PRIORITY);
+ }
+
+ /**
+ * Returns the lifetime, in milliseconds, of the request message.
+ */
+ public long getTimeToLive() {
+ String paramValue = getParameter(PARAM_TIME_TO_LIVE);
+ return paramValue != null ? Long.parseLong(paramValue) : Message.DEFAULT_TIME_TO_LIVE;
+ }
+
+ private int getIntegerParameter(String paramName, int defaultValue) {
+ String paramValue = getParameter(paramName);
+ return paramValue != null ? Integer.parseInt(paramValue) : defaultValue;
+ }
+
+ /**
+ * Indicates whether this URI has a reply-to name.
+ */
+ public boolean hasReplyTo() {
+ return StringUtils.hasLength(getReplyTo());
+ }
+
+ /**
+ * Returns the reply-to name.
+ *
+ * @see Message#setJMSReplyTo(Destination)
+ */
+ public String getReplyTo() {
+ return getParameter(PARAM_REPLY_TO_NAME);
+ }
+
+ /**
+ * Return whether the Publish/Subscribe domain ({@link javax.jms.Topic Topics}) is used. Otherwise, the
+ * Point-to-Point domain ({@link javax.jms.Queue Queues}) is used.
+ */
+ public boolean isPubSubDomain() {
+ return DESTINATION_TYPE_TOPIC.equals(getDestinationType());
+ }
+
+}
diff --git a/support/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageDrivenBean.java b/support/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageDrivenBean.java
new file mode 100644
index 00000000..e39982bb
--- /dev/null
+++ b/support/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageDrivenBean.java
@@ -0,0 +1,157 @@
+/*
+ * 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.transport.jms;
+
+import javax.ejb.EJBException;
+import javax.ejb.MessageDrivenBean;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+import javax.naming.NamingException;
+
+import org.springframework.ejb.support.AbstractJmsMessageDrivenBean;
+import org.springframework.jms.connection.ConnectionFactoryUtils;
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.jndi.JndiLookupFailureException;
+import org.springframework.ws.WebServiceMessageFactory;
+import org.springframework.ws.transport.WebServiceMessageReceiver;
+
+/**
+ * EJB {@link MessageDrivenBean} that can be used to handleMessage incoming JMS messages.
+ *
+ * This class needs a JMS {@link ConnectionFactory}, and a {@link WebServiceMessageFactory} and {@link
+ * WebServiceMessageReceiver} to operate. By default, these are obtained by doing a bean lookup on the bean factory
+ * provided by {@link #getBeanFactory()} the super class.
+ *
+ * @author Arjen Poutsma
+ * @see #createConnectionFactory()
+ * @see #createMessageFactory()
+ * @see #createMessageReceiver()
+ */
+public class WebServiceMessageDrivenBean extends AbstractJmsMessageDrivenBean {
+
+ /** Well-known name for the {@link ConnectionFactory} object in the bean factory for this bean. */
+ public static final String CONNECTION_FACTORY_BEAN_NAME = "connectionFactory";
+
+ /** Well-known name for the {@link WebServiceMessageFactory} bean in the bean factory for this bean. */
+ public static final String MESSAGE_FACTORY_BEAN_NAME = "messageFactory";
+
+ /** Well-known name for the {@link WebServiceMessageReceiver} object in the bean factory for this bean. */
+ public static final String MESSAGE_RECEIVER_BEAN_NAME = "messageReceiver";
+
+ private JmsMessageReceiver delegate;
+
+ private ConnectionFactory connectionFactory;
+
+ /** Delegates to {@link JmsMessageReceiver#handleMessage(Message,Session)}. */
+ public void onMessage(Message message) {
+ Connection connection = null;
+ Session session = null;
+ try {
+ connection = createConnection(connectionFactory);
+ session = createSession(connection);
+ delegate.handleMessage(message, session);
+ }
+ catch (JmsTransportException ex) {
+ throw JmsUtils.convertJmsAccessException(ex.getJmsException());
+ }
+ catch (JMSException ex) {
+ throw JmsUtils.convertJmsAccessException(ex);
+ }
+ catch (Exception ex) {
+ throw new EJBException(ex);
+ }
+ finally {
+ JmsUtils.closeSession(session);
+ ConnectionFactoryUtils.releaseConnection(connection, connectionFactory, true);
+ }
+ }
+
+ /**
+ * Creates a new {@link Connection}, {@link WebServiceMessageFactory}, and {@link WebServiceMessageReceiver}.
+ *
+ * @see #createConnectionFactory()
+ * @see #createMessageFactory()
+ * @see #createMessageReceiver()
+ */
+ protected void onEjbCreate() {
+ try {
+ connectionFactory = createConnectionFactory();
+ delegate = new JmsMessageReceiver();
+ delegate.setMessageFactory(createMessageFactory());
+ delegate.setMessageReceiver(createMessageReceiver());
+ }
+ catch (NamingException ex) {
+ throw new JndiLookupFailureException("Could not create connection", ex);
+ }
+ catch (JMSException ex) {
+ throw JmsUtils.convertJmsAccessException(ex);
+ }
+ catch (Exception ex) {
+ throw new EJBException(ex);
+ }
+ }
+
+ /** Creates a connection factory. Default implemantion does a bean lookup for {@link #CONNECTION_FACTORY_BEAN_NAME}. */
+ protected ConnectionFactory createConnectionFactory() throws Exception {
+ return (ConnectionFactory) getBeanFactory().getBean(CONNECTION_FACTORY_BEAN_NAME, ConnectionFactory.class);
+ }
+
+ /** Creates a message factory. Default implemantion does a bean lookup for {@link #MESSAGE_FACTORY_BEAN_NAME}. */
+ protected WebServiceMessageFactory createMessageFactory() {
+ return (WebServiceMessageFactory) getBeanFactory()
+ .getBean(MESSAGE_FACTORY_BEAN_NAME, WebServiceMessageFactory.class);
+ }
+
+ /** Creates a connection factory. Default implemantion does a bean lookup for {@link #MESSAGE_RECEIVER_BEAN_NAME}. */
+ protected WebServiceMessageReceiver createMessageReceiver() {
+ return (WebServiceMessageReceiver) getBeanFactory()
+ .getBean(MESSAGE_RECEIVER_BEAN_NAME, WebServiceMessageReceiver.class);
+ }
+
+ /**
+ * Create a JMS {@link Connection} using the given {@link ConnectionFactory}.
+ *
+ * This implementation uses JMS 1.1 API.
+ *
+ * @param connectionFactory the JMS ConnectionFactory to create a Connection with
+ * @return the new JMS Connection
+ * @throws JMSException if thrown by JMS API methods
+ * @see ConnectionFactory#createConnection()
+ */
+ protected Connection createConnection(ConnectionFactory connectionFactory) throws JMSException {
+ return connectionFactory.createConnection();
+ }
+
+ /**
+ * Creates a JMS {@link Session}. Default implemantion creates a non-transactional, {@link Session#AUTO_ACKNOWLEDGE
+ * auto acknowledged} session.
+ *
+ * This implementation uses JMS 1.1 API.
+ *
+ * @param connection the JMS Connection to create a Session for
+ * @return the new JMS Session
+ * @throws JMSException if thrown by JMS API methods
+ * @see Connection#createSession(boolean,int)
+ */
+ protected Session createSession(Connection connection) throws JMSException {
+ return connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ }
+
+}
diff --git a/support/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageListener.java b/support/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageListener.java
new file mode 100644
index 00000000..4d94a213
--- /dev/null
+++ b/support/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageListener.java
@@ -0,0 +1,57 @@
+/*
+ * 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.transport.jms;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+
+import org.springframework.jms.listener.SessionAwareMessageListener;
+import org.springframework.ws.WebServiceMessage;
+import org.springframework.ws.WebServiceMessageFactory;
+import org.springframework.ws.transport.WebServiceMessageReceiver;
+
+/**
+ * Spring-2.0 {@link SessionAwareMessageListener} that can be used to handle incoming JMS messages.
+ *
+ * Requires a {@link WebServiceMessageFactory} which is used to convert the incoming JMS {@link BytesMessage} into a
+ * {@link WebServiceMessage}, and passes that to the {@link WebServiceMessageReceiver} {@link
+ * #setMessageReceiver(WebServiceMessageReceiver) registered}.
+ *
+ * @author Arjen Poutsma
+ * @see #setMessageFactory(org.springframework.ws.WebServiceMessageFactory)
+ * @see #setMessageReceiver(org.springframework.ws.transport.WebServiceMessageReceiver)
+ * @since 1.1.0
+ */
+public class WebServiceMessageListener extends JmsMessageReceiver implements SessionAwareMessageListener {
+
+ public void onMessage(Message message, Session session) throws JMSException {
+ try {
+ handleMessage(message, session);
+ }
+ catch (JmsTransportException ex) {
+ throw ex.getJmsException();
+ }
+ catch (Exception ex) {
+ JMSException jmsException = new JMSException(ex.getMessage());
+ jmsException.setLinkedException(ex);
+ throw jmsException;
+ }
+ }
+
+}
diff --git a/support/src/main/java/org/springframework/ws/transport/jms/package.html b/support/src/main/java/org/springframework/ws/transport/jms/package.html
new file mode 100644
index 00000000..2b58664e
--- /dev/null
+++ b/support/src/main/java/org/springframework/ws/transport/jms/package.html
@@ -0,0 +1,5 @@
+
+
+Package providing support for handling messages via JMS.
+
+
diff --git a/support/src/main/java/org/springframework/ws/transport/jms/support/JmsTransportUtils.java b/support/src/main/java/org/springframework/ws/transport/jms/support/JmsTransportUtils.java
new file mode 100644
index 00000000..fa672f9f
--- /dev/null
+++ b/support/src/main/java/org/springframework/ws/transport/jms/support/JmsTransportUtils.java
@@ -0,0 +1,69 @@
+/*
+ * 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.transport.jms.support;
+
+import org.springframework.ws.transport.jms.JmsTransportConstants;
+
+/**
+ * Collection of utility methods to work with JMS transports. Includes methods to convert from transport header names to
+ * JMS Properties and vice-versa.
+ *
+ * @author Arjen Poutsma
+ * @since 1.1.0
+ */
+public class JmsTransportUtils {
+
+ private static final String[] CONVERSION_TABLE = new String[]{JmsTransportConstants.HEADER_CONTENT_TYPE,
+ JmsTransportConstants.PROPERTY_CONTENT_TYPE, JmsTransportConstants.HEADER_CONTENT_LENGTH,
+ JmsTransportConstants.PROPERTY_CONTENT_LENGTH, JmsTransportConstants.HEADER_SOAP_ACTION,
+ JmsTransportConstants.PROPERTY_SOAP_ACTION};
+
+ private JmsTransportUtils() {
+ }
+
+ /**
+ * Converts the given transport header to a JMS property name. Returns the given header name if no match is found.
+ *
+ * @param headerName the header name to transform
+ * @return the JMS property name
+ */
+ public static String headerToJmsProperty(String headerName) {
+ for (int i = 0; i < CONVERSION_TABLE.length; i = i + 2) {
+ if (CONVERSION_TABLE[i].equals(headerName)) {
+ return CONVERSION_TABLE[i + 1];
+ }
+ }
+ return headerName;
+ }
+
+ /**
+ * Converts the given JMS property name to a transport header name. Returns the given property name if no match is
+ * found.
+ *
+ * @param propertyName the JMS property name to transform
+ * @return the transport header name
+ */
+ public static String jmsPropertyToHeader(String propertyName) {
+ for (int i = 1; i < CONVERSION_TABLE.length; i = i + 2) {
+ if (CONVERSION_TABLE[i].equals(propertyName)) {
+ return CONVERSION_TABLE[i - 1];
+ }
+ }
+ return propertyName;
+ }
+
+}
diff --git a/support/src/main/java/org/springframework/ws/transport/jms/support/package.html b/support/src/main/java/org/springframework/ws/transport/jms/support/package.html
new file mode 100644
index 00000000..8c2ac138
--- /dev/null
+++ b/support/src/main/java/org/springframework/ws/transport/jms/support/package.html
@@ -0,0 +1,5 @@
+
+
+Classes supporting the org.springframework.ws.transport.jms package.
+
+
\ No newline at end of file
diff --git a/support/src/main/java/org/springframework/ws/transport/support/ParameterizedUri.java b/support/src/main/java/org/springframework/ws/transport/support/ParameterizedUri.java
new file mode 100644
index 00000000..58be7494
--- /dev/null
+++ b/support/src/main/java/org/springframework/ws/transport/support/ParameterizedUri.java
@@ -0,0 +1,84 @@
+/*
+ * 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.transport.support;
+
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.springframework.core.CollectionFactory;
+import org.springframework.util.Assert;
+
+/** @author Arjen Poutsma */
+public class ParameterizedUri {
+
+ private final String uri;
+
+ private final String scheme;
+
+ // keys are string parameter names; values are string parameter values
+ private final Map parameters = CollectionFactory.createLinkedCaseInsensitiveMapIfPossible(5);
+
+ private final String destination;
+
+ public ParameterizedUri(String uri) {
+ Assert.hasLength(uri, "'uri' must not be empty");
+ this.uri = uri;
+ int scIdx = uri.indexOf(':');
+ Assert.isTrue(scIdx != -1, uri + " does contain scheme");
+ scheme = uri.substring(0, scIdx);
+ Assert.isTrue(uri.length() > scheme.length(), uri + " does not have a destination");
+ int paramStart = uri.indexOf('?');
+ if (paramStart == -1) {
+ destination = uri.substring(scIdx + 1);
+ }
+ else {
+ destination = uri.substring(scIdx + 1, paramStart);
+ parseParameters(uri.substring(paramStart + 1));
+ }
+ }
+
+ private void parseParameters(String parametersString) {
+ StringTokenizer params = new StringTokenizer(parametersString, "&");
+ while (params.hasMoreTokens()) {
+ String param = params.nextToken();
+ int paramSep = param.indexOf('=');
+ if (paramSep == -1) {
+ throw new IllegalArgumentException(param + " is not a valid parameter: it has no '='");
+ }
+ String paramName = param.substring(0, paramSep);
+ String paramValue = param.substring(paramSep + 1);
+ parameters.put(paramName, paramValue);
+ }
+ }
+
+ /** Returns the destination of the uri. */
+ protected String getDestination() {
+ return destination;
+ }
+
+ public String toString() {
+ return uri;
+ }
+
+ protected String getParameter(String paramName) {
+ return (String) parameters.get(paramName);
+ }
+
+ protected boolean hasParameter(String paramName) {
+ return parameters.containsKey(paramName);
+ }
+}
diff --git a/support/src/main/java/org/springframework/ws/transport/support/SimpleWebServiceMessageReceiverObjectSupport.java b/support/src/main/java/org/springframework/ws/transport/support/SimpleWebServiceMessageReceiverObjectSupport.java
new file mode 100644
index 00000000..eeaec2f9
--- /dev/null
+++ b/support/src/main/java/org/springframework/ws/transport/support/SimpleWebServiceMessageReceiverObjectSupport.java
@@ -0,0 +1,59 @@
+/*
+ * 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.transport.support;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.Assert;
+import org.springframework.ws.transport.WebServiceConnection;
+import org.springframework.ws.transport.WebServiceMessageReceiver;
+
+/**
+ * Base class for server-side transport objects which have a predefined {@link WebServiceMessageReceiver}.
+ *
+ * @author Arjen Poutsma
+ * @see #handleConnection(WebServiceConnection)
+ * @since 1.1.0
+ */
+public abstract class SimpleWebServiceMessageReceiverObjectSupport extends WebServiceMessageReceiverObjectSupport
+ implements InitializingBean {
+
+ private WebServiceMessageReceiver messageReceiver;
+
+ /**
+ * Returns the WebServiceMessageReceiver used by this listener.
+ */
+ public WebServiceMessageReceiver getMessageReceiver() {
+ return messageReceiver;
+ }
+
+ /**
+ * Sets the WebServiceMessageReceiver used by this listener.
+ */
+ public void setMessageReceiver(WebServiceMessageReceiver messageReceiver) {
+ this.messageReceiver = messageReceiver;
+ }
+
+ public void afterPropertiesSet() throws Exception {
+ super.afterPropertiesSet();
+ Assert.notNull(getMessageReceiver(), "messageReceiver must not be null");
+ }
+
+ protected final void handleConnection(WebServiceConnection connection) throws Exception {
+ handleConnection(connection, getMessageReceiver());
+ }
+
+}
diff --git a/support/src/test/java/org/springframework/ws/transport/SimpleTestingMessageReceiver.java b/support/src/test/java/org/springframework/ws/transport/SimpleTestingMessageReceiver.java
new file mode 100644
index 00000000..aff2af56
--- /dev/null
+++ b/support/src/test/java/org/springframework/ws/transport/SimpleTestingMessageReceiver.java
@@ -0,0 +1,34 @@
+/*
+ * 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.transport;
+
+import javax.xml.transform.Transformer;
+
+import org.springframework.ws.context.MessageContext;
+import org.springframework.xml.transform.TransformerObjectSupport;
+import org.springframework.util.Assert;
+
+public class SimpleTestingMessageReceiver extends TransformerObjectSupport implements WebServiceMessageReceiver {
+
+ public void receive(MessageContext messageContext) throws Exception {
+ Assert.notNull(messageContext, "MessageContext is null");
+ logger.info("Received message");
+ Transformer transformer = createTransformer();
+ transformer.transform(messageContext.getRequest().getPayloadSource(),
+ messageContext.getResponse().getPayloadResult());
+ }
+}
diff --git a/support/src/test/java/org/springframework/ws/transport/jms/JmsMessageSenderIntegrationTest.java b/support/src/test/java/org/springframework/ws/transport/jms/JmsMessageSenderIntegrationTest.java
new file mode 100644
index 00000000..3d5d76fd
--- /dev/null
+++ b/support/src/test/java/org/springframework/ws/transport/jms/JmsMessageSenderIntegrationTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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.transport.jms;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+import javax.xml.soap.MessageFactory;
+import javax.xml.soap.SOAPConstants;
+
+import org.springframework.jms.core.JmsTemplate;
+import org.springframework.jms.core.MessageCreator;
+import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
+import org.springframework.ws.soap.SoapMessage;
+import org.springframework.ws.soap.saaj.SaajSoapMessage;
+import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
+import org.springframework.ws.transport.WebServiceConnection;
+
+public class JmsMessageSenderIntegrationTest extends AbstractDependencyInjectionSpringContextTests {
+
+ private JmsMessageSender messageSender;
+
+ private JmsTemplate jmsTemplate;
+
+ private MessageFactory messageFactory;
+
+ private static final String REQUEST_QUEUE_URI = "jms:RequestQueue";
+
+ private static final String SOAP_ACTION = "\"http://springframework.org/DoIt\"";
+
+ protected void onSetUp() throws Exception {
+ messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
+ }
+
+ protected String[] getConfigLocations() {
+ return new String[]{"classpath:org/springframework/ws/transport/jms/jms-sender-applicationContext.xml"};
+ }
+
+ public void setJmsTemplate(JmsTemplate jmsTemplate) {
+ this.jmsTemplate = jmsTemplate;
+ }
+
+ public void setMessageSender(JmsMessageSender messageSender) {
+ this.messageSender = messageSender;
+ }
+
+ public void testSendAndReceiveQueue() throws Exception {
+ WebServiceConnection connection = null;
+ try {
+ connection = messageSender.createConnection(REQUEST_QUEUE_URI);
+ SoapMessage soapRequest = new SaajSoapMessage(messageFactory.createMessage());
+ soapRequest.setSoapAction(SOAP_ACTION);
+ connection.send(soapRequest);
+
+ BytesMessage request = (BytesMessage) jmsTemplate.receive();
+ validateMessage(request);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ messageFactory.createMessage().writeTo(bos);
+ final byte[] buf = bos.toByteArray();
+ jmsTemplate.send(request.getJMSReplyTo(), new MessageCreator() {
+
+ public Message createMessage(Session session) throws JMSException {
+ BytesMessage response = session.createBytesMessage();
+ response.setStringProperty(JmsTransportConstants.PROPERTY_BINDING_VERSION, "1.0");
+ response.setIntProperty(JmsTransportConstants.PROPERTY_CONTENT_LENGTH, buf.length);
+ response.setStringProperty(JmsTransportConstants.PROPERTY_CONTENT_TYPE, "text/xml");
+ response.setBooleanProperty(JmsTransportConstants.PROPERTY_IS_FAULT, false);
+ response.setStringProperty(JmsTransportConstants.PROPERTY_REQUEST_IRI, REQUEST_QUEUE_URI);
+ response.setStringProperty(JmsTransportConstants.PROPERTY_SOAP_ACTION, SOAP_ACTION);
+
+ response.writeBytes(buf);
+ return response;
+ }
+ });
+ SoapMessage response = (SoapMessage) connection.receive(new SaajSoapMessageFactory(messageFactory));
+ assertNotNull("No response received", response);
+ assertEquals("Invalid SOAPAction", SOAP_ACTION, response.getSoapAction());
+ assertFalse("Message is fault", response.hasFault());
+ }
+ finally {
+ if (connection != null) {
+ connection.close();
+ }
+ }
+ }
+
+ private void validateMessage(BytesMessage message) throws JMSException, IOException {
+ assertEquals("Invalid SOAPAction", SOAP_ACTION,
+ message.getStringProperty(JmsTransportConstants.PROPERTY_SOAP_ACTION));
+ assertEquals("Invalid binding version", "1.0",
+ message.getStringProperty(JmsTransportConstants.PROPERTY_BINDING_VERSION));
+ assertEquals("Invalid service IRI", REQUEST_QUEUE_URI,
+ message.getStringProperty(JmsTransportConstants.PROPERTY_REQUEST_IRI));
+ assertFalse("Message is Fault", message.getBooleanProperty(JmsTransportConstants.PROPERTY_IS_FAULT));
+ assertTrue("Invalid Content Type",
+ message.getStringProperty(JmsTransportConstants.PROPERTY_CONTENT_TYPE).indexOf("text/xml") != -1);
+ assertTrue("No Content Length", message.getIntProperty(JmsTransportConstants.PROPERTY_CONTENT_LENGTH) > 0);
+
+ assertTrue("Message has no contents", getMessageContents(message).length() > 0);
+
+ }
+
+ private String getMessageContents(BytesMessage message) throws JMSException, IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int bytesRead;
+ while ((bytesRead = message.readBytes(buffer)) != -1) {
+ out.write(buffer, 0, bytesRead);
+ }
+ out.flush();
+ return out.toString("UTF-8");
+ }
+}
\ No newline at end of file
diff --git a/support/src/test/java/org/springframework/ws/transport/jms/JmsUriTest.java b/support/src/test/java/org/springframework/ws/transport/jms/JmsUriTest.java
new file mode 100644
index 00000000..49e6bafe
--- /dev/null
+++ b/support/src/test/java/org/springframework/ws/transport/jms/JmsUriTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.transport.jms;
+
+import junit.framework.TestCase;
+
+public class JmsUriTest extends TestCase {
+
+ public void testJmsUri() {
+ JmsUri uri = new JmsUri("jms:news?connectionFactoryName=SOAPJMSFactory&" + "deliveryMode=2&" +
+ "destinationType=topic&" + "initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory&" +
+ "jndiURL=theJndiURL&" + "priority=8&" + "timeToLive=10&" + "replyToName=interested&" +
+ "userprop=mystuff");
+ assertEquals("Invalid delivery mode", 2, uri.getDeliveryMode());
+ assertEquals("Invalid destination", "news", uri.getDestination());
+ assertEquals("Invalid destination type", "topic", uri.getDestinationType());
+ assertTrue("Invalid pub sub domain", uri.isPubSubDomain());
+ assertEquals("Invalid prority", 8, uri.getPriority());
+ assertEquals("Invalid time to live", 10, uri.getTimeToLive());
+ assertEquals("Invalid reply to name", "interested", uri.getReplyTo());
+
+ }
+
+ public void testGetDestinationNoParams() {
+ JmsUri uri = new JmsUri("jms:news");
+ assertEquals("Invalid destination", "news", uri.getDestination());
+ }
+
+ public void testInvalidDeliveryMode() {
+ testIllegalArgument("jms:news?deliveryMode=abc");
+ }
+
+ public void testInvalidPriority() {
+ testIllegalArgument("jms:news?priority=abc");
+ }
+
+ public void testInvalidTimeToLive() {
+ testIllegalArgument("jms:news?timeToLive=abc");
+ }
+
+ public void testInvalidDestinationType() {
+ testIllegalArgument("jms:news?destinationType=abc");
+ }
+
+ public void testEmpty() {
+ testIllegalArgument("");
+ }
+
+ public void testIllegalParam() {
+ testIllegalArgument("jms:news?bla");
+ }
+
+ private void testIllegalArgument(String uri) {
+ try {
+ new JmsUri(uri);
+ fail("Expected IllegalArgumentException for uri [" + uri + "]");
+ }
+ catch (IllegalArgumentException ex) {
+ //expected
+ }
+ }
+}
\ No newline at end of file
diff --git a/support/src/test/java/org/springframework/ws/transport/jms/MessageEndpointMessageListenerTest.java b/support/src/test/java/org/springframework/ws/transport/jms/MessageEndpointMessageListenerTest.java
new file mode 100644
index 00000000..72b7cd5e
--- /dev/null
+++ b/support/src/test/java/org/springframework/ws/transport/jms/MessageEndpointMessageListenerTest.java
@@ -0,0 +1,116 @@
+/*
+*/
+/*
+ * 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.transport.jms;
+
+import javax.jms.BytesMessage;
+import javax.jms.Destination;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.StreamMessage;
+
+import junit.framework.TestCase;
+import org.codehaus.activemq.message.ActiveMQBytesMessage;
+import org.codehaus.activemq.message.ActiveMQTopic;
+import org.easymock.MockControl;
+import org.springframework.ws.MockWebServiceMessageFactory;
+import org.springframework.ws.context.MessageContext;
+import org.springframework.ws.server.endpoint.MessageEndpoint;
+
+public class MessageEndpointMessageListenerTest extends TestCase {
+
+ private static final String REQUEST = "