From 0314f978c45188086e15bbec0c2fd50acf39c2e4 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Sat, 29 Sep 2007 02:37:50 +0000 Subject: [PATCH] Javadoc --- .../jms/BytesMessageInputStream.java | 3 +- .../jms/BytesMessageOutputStream.java | 3 +- .../ws/transport/jms/JmsMessageReceiver.java | 14 +- .../ws/transport/jms/JmsMessageSender.java | 69 +++----- .../transport/jms/JmsReceiverConnection.java | 37 ++-- .../ws/transport/jms/JmsSenderConnection.java | 19 ++- .../transport/jms/JmsTransportConstants.java | 7 +- .../transport/jms/JmsTransportException.java | 8 +- .../ws/transport/jms/JmsUri.java | 62 ++----- .../jms/WebServiceMessageDrivenBean.java | 158 ++++++++++++++++++ .../jms/WebServiceMessageListener.java | 11 +- .../ws/transport/jms/package.html | 5 + ...ebServiceMessageReceiverObjectSupport.java | 18 +- .../jms/applicationContext-ws-jms.xml | 41 ----- .../jms/JmsMessageSenderIntegrationTest.java | 72 ++++---- .../ws/transport/jms/JmsUriTest.java | 3 - ...ServiceMessageListenerIntegrationTest.java | 70 ++++++++ sandbox/src/test/resources/log4j.properties | 6 +- .../jms/jms-receiver-applicationContext.xml | 2 +- .../jms/jms-sender-applicationContext.xml | 23 +++ 20 files changed, 410 insertions(+), 221 deletions(-) create mode 100644 sandbox/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageDrivenBean.java create mode 100644 sandbox/src/main/java/org/springframework/ws/transport/jms/package.html delete mode 100644 sandbox/src/main/resources/org/springframework/ws/transport/jms/applicationContext-ws-jms.xml create mode 100644 sandbox/src/test/java/org/springframework/ws/transport/jms/WebServiceMessageListenerIntegrationTest.java create mode 100644 sandbox/src/test/resources/org/springframework/ws/transport/jms/jms-sender-applicationContext.xml diff --git a/sandbox/src/main/java/org/springframework/ws/transport/jms/BytesMessageInputStream.java b/sandbox/src/main/java/org/springframework/ws/transport/jms/BytesMessageInputStream.java index 8e267bc6..8a7e929f 100644 --- a/sandbox/src/main/java/org/springframework/ws/transport/jms/BytesMessageInputStream.java +++ b/sandbox/src/main/java/org/springframework/ws/transport/jms/BytesMessageInputStream.java @@ -23,9 +23,10 @@ import javax.jms.JMSException; import javax.jms.MessageEOFException; /** - * Input stream that wraps a {@link javax.jms.BytesMessage}. + * Input stream that wraps a {@link BytesMessage}. * * @author Arjen Poutsma + * @since 1.1.0 */ class BytesMessageInputStream extends InputStream { diff --git a/sandbox/src/main/java/org/springframework/ws/transport/jms/BytesMessageOutputStream.java b/sandbox/src/main/java/org/springframework/ws/transport/jms/BytesMessageOutputStream.java index 25d09f7d..a5886ffa 100644 --- a/sandbox/src/main/java/org/springframework/ws/transport/jms/BytesMessageOutputStream.java +++ b/sandbox/src/main/java/org/springframework/ws/transport/jms/BytesMessageOutputStream.java @@ -22,9 +22,10 @@ import javax.jms.BytesMessage; import javax.jms.JMSException; /** - * Output stream that wraps a {@link javax.jms.BytesMessage}. + * Output stream that wraps a {@link BytesMessage}. * * @author Arjen Poutsma + * @since 1.1.0 */ class BytesMessageOutputStream extends OutputStream { diff --git a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsMessageReceiver.java b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsMessageReceiver.java index 0a377402..258e331b 100644 --- a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsMessageReceiver.java +++ b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsMessageReceiver.java @@ -26,26 +26,26 @@ import org.springframework.ws.transport.support.SimpleWebServiceMessageReceiverO /** * Convenience base class for JMS server-side transport objects. Contains a {@link WebServiceMessageReceiver}, and has - * methods for handling incoming JMS Message requests. + * methods for handling incoming JMS {@link Message} requests. *

- * Used by {@link WebServiceMessageListener} and {@link WebServiceMessageBean}. + * Used by {@link WebServiceMessageListener} and {@link WebServiceMessageDrivenBean}. * * @author Arjen Poutsma - * @see #handleMessage(javax.jms.Message,javax.jms.Session) + * @since 1.1.0 */ public class JmsMessageReceiver extends SimpleWebServiceMessageReceiverObjectSupport { /** - * Handles an incoming Messages. Uses the given Session to create a response request. + * Handles an incoming messages. Uses the given session to create a response message. * * @param request the incoming message * @param session the JMS session used to create a response - * @throws IllegalArgumentException when request is not a BytesMessage + * @throws IllegalArgumentException when request is not a {@link BytesMessage} */ protected final void handleMessage(Message request, Session session) throws Exception { if (request instanceof BytesMessage) { - WebServiceConnection connection = new JmsReceiverConnection((BytesMessage) request, session, logger); - handleConnection(connection, getMessageReceiver()); + WebServiceConnection connection = new JmsReceiverConnection((BytesMessage) request, session); + handleConnection(connection); } else { throw new IllegalArgumentException( diff --git a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsMessageSender.java b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsMessageSender.java index bca36897..144182d6 100644 --- a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsMessageSender.java +++ b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsMessageSender.java @@ -17,23 +17,17 @@ package org.springframework.ws.transport.jms; import java.io.IOException; -import java.util.Properties; import javax.jms.BytesMessage; import javax.jms.ConnectionFactory; import javax.jms.JMSException; -import javax.jms.Queue; -import javax.naming.Context; -import javax.naming.NamingException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.jndi.JndiTemplate; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.ws.transport.WebServiceConnection; import org.springframework.ws.transport.WebServiceMessageSender; /** - * WebServiceMessageSender implementation that uses JMS {@link Queue}. + * {@link WebServiceMessageSender} implementation that uses JMS. *

* This message sender sends the request message of the queue configured with either the queue or * queueName property. It creates a temporary queue for the response message. For both request and response @@ -41,41 +35,43 @@ import org.springframework.ws.transport.WebServiceMessageSender; * * @author Arjen Poutsma */ -public class JmsMessageSender implements WebServiceMessageSender { +public class JmsMessageSender implements WebServiceMessageSender, JmsTransportConstants { - private static final Log logger = LogFactory.getLog(JmsMessageSender.class); - - /** Default timeout for receive operations: -1 indicates a blocking receive without timeout. */ + /** + * Default timeout for receive operations: -1 indicates a blocking receive without timeout. + */ public static final long DEFAULT_RECEIVE_TIMEOUT = -1; - private static final String JMS_SCHEME = "jms:"; - - private ConnectionFactory defaultConnectionFactory; + private ConnectionFactory connectionFactory; private long receiveTimeout = DEFAULT_RECEIVE_TIMEOUT; public JmsMessageSender() { } - public JmsMessageSender(ConnectionFactory defaultConnectionFactory) { - this.defaultConnectionFactory = defaultConnectionFactory; + public JmsMessageSender(ConnectionFactory connectionFactory) { + this.connectionFactory = connectionFactory; } - /** Set the default ConnectionFactory to use for obtaining JMS Connections. */ - public void setDefaultConnectionFactory(ConnectionFactory defaultConnectionFactory) { - this.defaultConnectionFactory = defaultConnectionFactory; + /** + * Set the default ConnectionFactory to use for obtaining JMS Connections. + */ + public void setConnectionFactory(ConnectionFactory connectionFactory) { + this.connectionFactory = connectionFactory; } - /** Set the timeout to use for receive calls. The default is 0, which means no timeout. */ + /** + * 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); - ConnectionFactory connectionFactory = resolveConnectionFactory(uri); connection = new JmsSenderConnection(uri, connectionFactory, receiveTimeout); return connection; } @@ -88,34 +84,7 @@ public class JmsMessageSender implements WebServiceMessageSender { } public boolean supports(String uri) { - return StringUtils.hasLength(uri) && uri.startsWith(JMS_SCHEME); - } - - protected ConnectionFactory resolveConnectionFactory(JmsUri uri) { - if (uri.hasConnectionFactoryName()) { - Properties environment = new Properties(); - if (uri.hasInitialContextFactory()) { - environment.setProperty(Context.INITIAL_CONTEXT_FACTORY, uri.getInitialContextFactory()); - } - if (uri.hasJndiUrl()) { - environment.setProperty(Context.PROVIDER_URL, uri.getJndiUrl()); - } - try { - JndiTemplate jndiTemplate = new JndiTemplate(environment); - return (ConnectionFactory) jndiTemplate.lookup(uri.getConnectionFactoryName(), ConnectionFactory.class); - } - catch (NamingException ex) { - logger.debug("ConnectionFactory [" + uri.getConnectionFactoryName() + "] not found in JNDI", ex); - // fall through to the default - } - } - if (defaultConnectionFactory != null) { - return defaultConnectionFactory; - } - else { - throw new IllegalStateException("Could not resolve JMS ConnectionFactory. " + - "Specify a 'defaultConnectionFactory' or 'connectionFactoryName' in the URI."); - } + return StringUtils.hasLength(uri) && uri.startsWith(URI_SCHEME + ":"); } } diff --git a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsReceiverConnection.java b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsReceiverConnection.java index b6f82057..d5ae27dc 100644 --- a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsReceiverConnection.java +++ b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsReceiverConnection.java @@ -29,34 +29,52 @@ import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.Session; -import org.apache.commons.logging.Log; 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; -/** @author Arjen Poutsma */ +/** + * 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 Log logger; - private final BytesMessage requestMessage; private final Session session; private BytesMessage responseMessage; - protected JmsReceiverConnection(BytesMessage requestMessage, Session session, Log logger) { + /** + * 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"); - Assert.notNull(logger, "'logger' must not be null"); this.requestMessage = requestMessage; this.session = session; - this.logger = logger; + } + + /** + * 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 { @@ -144,9 +162,6 @@ public class JmsReceiverConnection extends AbstractReceiverConnection messageProducer.setPriority(requestMessage.getJMSPriority()); messageProducer.send(responseMessage); } - else { - logger.warn("Incoming message has no ReplyTo set, not sending response"); - } } catch (JMSException ex) { throw new JmsTransportException(ex); @@ -175,7 +190,7 @@ public class JmsReceiverConnection extends AbstractReceiverConnection public void setFault(boolean fault) throws IOException { if (responseMessage != null) { try { - responseMessage.setBooleanProperty(JmsTransportConstants.PROPERTY_IS_FAULT, true); + responseMessage.setBooleanProperty(JmsTransportConstants.PROPERTY_IS_FAULT, fault); } catch (JMSException ex) { throw new JmsTransportException(ex); diff --git a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsSenderConnection.java b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsSenderConnection.java index 175e1e7d..ce52085b 100644 --- a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsSenderConnection.java +++ b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsSenderConnection.java @@ -41,9 +41,15 @@ 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; -/** @author Arjen Poutsma */ +/** + * 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 { @@ -65,6 +71,9 @@ public class JmsSenderConnection extends AbstractSenderConnection private long receiveTimeout; + /** + * Constructs a new JMS connection with the given parameters. + */ protected JmsSenderConnection(JmsUri uri, ConnectionFactory connectionFactory, long receiveTimeout) throws JMSException { Assert.notNull(uri, "'uri' must not be null"); @@ -82,10 +91,16 @@ public class JmsSenderConnection extends AbstractSenderConnection 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; } @@ -253,7 +268,7 @@ public class JmsSenderConnection extends AbstractSenderConnection public void setFault(boolean fault) throws IOException { try { - requestMessage.setBooleanProperty(JmsTransportConstants.PROPERTY_IS_FAULT, true); + requestMessage.setBooleanProperty(JmsTransportConstants.PROPERTY_IS_FAULT, fault); } catch (JMSException ex) { throw new JmsTransportException(ex); diff --git a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsTransportConstants.java b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsTransportConstants.java index 9d8d024b..5ce69c9a 100644 --- a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsTransportConstants.java +++ b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsTransportConstants.java @@ -18,7 +18,12 @@ package org.springframework.ws.transport.jms; import org.springframework.ws.transport.TransportConstants; -/** @author Arjen Poutsma */ +/** + * Declares JMS-specific transport constants. + * + * @author Arjen Poutsma + * @since 1.1.0 + */ public interface JmsTransportConstants extends TransportConstants { String URI_SCHEME = "jms"; diff --git a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsTransportException.java b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsTransportException.java index 1c8839c9..e1ce05bd 100644 --- a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsTransportException.java +++ b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsTransportException.java @@ -20,7 +20,13 @@ import javax.jms.JMSException; import org.springframework.ws.transport.TransportException; -/** @author Arjen Poutsma */ +/** + * 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; diff --git a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsUri.java b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsUri.java index 199a9a4c..bb967691 100644 --- a/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsUri.java +++ b/sandbox/src/main/java/org/springframework/ws/transport/jms/JmsUri.java @@ -16,15 +16,11 @@ package org.springframework.ws.transport.jms; -import java.util.HashMap; -import java.util.Map; -import java.util.StringTokenizer; import javax.jms.DeliveryMode; import javax.jms.Destination; import javax.jms.Message; import javax.jms.Queue; import javax.jms.Topic; -import javax.naming.Context; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -47,13 +43,16 @@ public class JmsUri extends ParameterizedUri implements JmsTransportConstants { validateIntegerParameter(PARAM_PRIORITY); validateIntegerParameter(PARAM_TIME_TO_LIVE); String destinationType = getDestinationType(); - 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 + "'"); + 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 = (String) getParameter(paramName); + String paramValue = getParameter(paramName); if (StringUtils.hasLength(paramValue)) { try { Integer.parseInt(paramValue); @@ -95,9 +94,12 @@ public class JmsUri extends ParameterizedUri implements JmsTransportConstants { return getIntegerParameter(PARAM_PRIORITY, Message.DEFAULT_PRIORITY); } - /** Returns the lifetime, in milliseconds, of the request message. */ - public int getTimeToLive() { - return getIntegerParameter(PARAM_TIME_TO_LIVE, (int) Message.DEFAULT_TIME_TO_LIVE); + /** + * 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) { @@ -105,45 +107,9 @@ public class JmsUri extends ParameterizedUri implements JmsTransportConstants { return paramValue != null ? Integer.parseInt(paramValue) : defaultValue; } - /** Indicates whether this URI has a connection factory name. */ - public boolean hasConnectionFactoryName() { - return StringUtils.hasLength(getConnectionFactoryName()); - } - - /** Returns the JNDI name of the Java class providing the connection factory. */ - public String getConnectionFactoryName() { - return getParameter(PARAM_CONNECTION_FACTORY_NAME); - } - - /** Indicates whether this URI has a "InitialContextFactory". */ - public boolean hasInitialContextFactory() { - return StringUtils.hasLength(getInitialContextFactory()); - } - /** - * Returns the fully qualified Java class name of the "InitialContextFactory" implementation class to use. - * - * @see Context#INITIAL_CONTEXT_FACTORY + * Indicates whether this URI has a reply-to name. */ - public String getInitialContextFactory() { - return getParameter(PARAM_INITIAL_CONTEXT_FACTORY); - } - - /** Indicates whether this URI has a JNDI provider URL. */ - public boolean hasJndiUrl() { - return StringUtils.hasLength(getJndiUrl()); - } - - /** - * Returns the JNDI provider URL. - * - * @see Context#PROVIDER_URL - */ - public String getJndiUrl() { - return getParameter(PARAM_JNDI_URL); - } - - /** Indicates whether this URI has a reply-to name. */ public boolean hasReplyTo() { return StringUtils.hasLength(getReplyTo()); } diff --git a/sandbox/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageDrivenBean.java b/sandbox/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageDrivenBean.java new file mode 100644 index 00000000..84a96f73 --- /dev/null +++ b/sandbox/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageDrivenBean.java @@ -0,0 +1,158 @@ +/* + * 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.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 #createConnection() + * @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 Connection connection; + + /** + * Delegates to {@link JmsMessageReceiver#handleMessage(Message,Session)}. + */ + public void onMessage(Message message) { + Session session = null; + try { + 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); + } + } + + /** + * Creates a new {@link Connection}, {@link WebServiceMessageFactory}, and {@link WebServiceMessageReceiver}. + * + * @see #createConnection() + * @see #createMessageFactory() + * @see #createMessageReceiver() + */ + protected void onEjbCreate() { + try { + connection = createConnection(); + 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); + } + } + + /** + * Closes the connection. + */ + protected void onEjbRemove() { + JmsUtils.closeConnection(connection); + } + + /** + * Creates a connection factory. Default implemantion does a bean lookup for {@link #CONNECTION_FACTORY_BEAN_NAME}. + */ + protected Connection createConnection() throws Exception { + // TODO: ask Juergen if we need one Connection per MDB, or create a new one for each onMessage() + ConnectionFactory connectionFactory = + (ConnectionFactory) getBeanFactory().getBean(CONNECTION_FACTORY_BEAN_NAME, ConnectionFactory.class); + return connectionFactory.createConnection(); + } + + /** + * 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); + } + + /** + * Creates a session. Default implemantion creates a non-transactional, {@link Session#AUTO_ACKNOWLEDGE auto + * acknowledged} session. + * + * @see Connection#createSession(boolean,int) + */ + protected Session createSession(Connection connection) throws JMSException { + return connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + +} diff --git a/sandbox/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageListener.java b/sandbox/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageListener.java index 98976b6f..4d94a213 100644 --- a/sandbox/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageListener.java +++ b/sandbox/src/main/java/org/springframework/ws/transport/jms/WebServiceMessageListener.java @@ -27,15 +27,16 @@ import org.springframework.ws.WebServiceMessageFactory; import org.springframework.ws.transport.WebServiceMessageReceiver; /** - * Spring-2.0 {@link SessionAwareMessageListener} that can be used to handleMessage incoming JMS messages. Requires a - * {@link WebServiceMessageFactory} which is used to convert the incoming JMS {@link BytesMessage}s into a {@link - * WebServiceMessage}, and passes that context to the {@link WebServiceMessageReceiver} set with the property - * messageReceiver. If a response is created, it is sent using the {@link BytesMessage#getJMSReplyTo() - * reply to header} of the request message. + * 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 { diff --git a/sandbox/src/main/java/org/springframework/ws/transport/jms/package.html b/sandbox/src/main/java/org/springframework/ws/transport/jms/package.html new file mode 100644 index 00000000..2b58664e --- /dev/null +++ b/sandbox/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/sandbox/src/main/java/org/springframework/ws/transport/support/SimpleWebServiceMessageReceiverObjectSupport.java b/sandbox/src/main/java/org/springframework/ws/transport/support/SimpleWebServiceMessageReceiverObjectSupport.java index 1ae3924f..eeaec2f9 100644 --- a/sandbox/src/main/java/org/springframework/ws/transport/support/SimpleWebServiceMessageReceiverObjectSupport.java +++ b/sandbox/src/main/java/org/springframework/ws/transport/support/SimpleWebServiceMessageReceiverObjectSupport.java @@ -21,18 +21,28 @@ import org.springframework.util.Assert; import org.springframework.ws.transport.WebServiceConnection; import org.springframework.ws.transport.WebServiceMessageReceiver; -/** @author Arjen Poutsma */ -public class SimpleWebServiceMessageReceiverObjectSupport extends WebServiceMessageReceiverObjectSupport +/** + * 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. */ + /** + * Returns the WebServiceMessageReceiver used by this listener. + */ public WebServiceMessageReceiver getMessageReceiver() { return messageReceiver; } - /** Sets the WebServiceMessageReceiver used by this listener. */ + /** + * Sets the WebServiceMessageReceiver used by this listener. + */ public void setMessageReceiver(WebServiceMessageReceiver messageReceiver) { this.messageReceiver = messageReceiver; } diff --git a/sandbox/src/main/resources/org/springframework/ws/transport/jms/applicationContext-ws-jms.xml b/sandbox/src/main/resources/org/springframework/ws/transport/jms/applicationContext-ws-jms.xml deleted file mode 100644 index 8daf7253..00000000 --- a/sandbox/src/main/resources/org/springframework/ws/transport/jms/applicationContext-ws-jms.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - 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/sandbox/src/test/java/org/springframework/ws/transport/jms/JmsMessageSenderIntegrationTest.java b/sandbox/src/test/java/org/springframework/ws/transport/jms/JmsMessageSenderIntegrationTest.java index cc0aac6d..75db21a9 100644 --- a/sandbox/src/test/java/org/springframework/ws/transport/jms/JmsMessageSenderIntegrationTest.java +++ b/sandbox/src/test/java/org/springframework/ws/transport/jms/JmsMessageSenderIntegrationTest.java @@ -19,24 +19,21 @@ package org.springframework.ws.transport.jms; import java.io.ByteArrayOutputStream; import java.io.IOException; import javax.jms.BytesMessage; -import javax.jms.ConnectionFactory; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.Session; import javax.xml.soap.MessageFactory; import javax.xml.soap.SOAPConstants; -import javax.xml.soap.SOAPMessage; -import junit.framework.TestCase; -import org.apache.activemq.ActiveMQConnectionFactory; 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 TestCase { +public class JmsMessageSenderIntegrationTest extends AbstractDependencyInjectionSpringContextTests { private JmsMessageSender messageSender; @@ -44,55 +41,30 @@ public class JmsMessageSenderIntegrationTest extends TestCase { private MessageFactory messageFactory; - private static final String URI = "jms:RequestQueue"; + private static final String REQUEST_QUEUE_URI = "jms:RequestQueue"; private static final String SOAP_ACTION = "http://springframework.org/DoIt"; - protected void setUp() throws Exception { - ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); - jmsTemplate = new JmsTemplate(connectionFactory); - jmsTemplate.setDefaultDestinationName("RequestQueue"); - messageSender = new JmsMessageSender(connectionFactory); + protected void onSetUp() throws Exception { messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL); } - public void testSendAndReceiveQueueNoResponse() throws Exception { - WebServiceConnection connection = null; - try { - connection = messageSender.createConnection(URI); - SOAPMessage saajMessage = messageFactory.createMessage(); - SoapMessage soapRequest = new SaajSoapMessage(saajMessage); - soapRequest.setSoapAction(SOAP_ACTION); - connection.send(soapRequest); - BytesMessage jmsRequest = (BytesMessage) jmsTemplate.receive(); - validateMessage(jmsRequest); - } - finally { - if (connection != null) { - connection.close(); - } - } + protected String[] getConfigLocations() { + return new String[]{"classpath:org/springframework/ws/transport/jms/jms-sender-applicationContext.xml"}; } - 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", 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); + public void setJmsTemplate(JmsTemplate jmsTemplate) { + this.jmsTemplate = jmsTemplate; + } + public void setMessageSender(JmsMessageSender messageSender) { + this.messageSender = messageSender; } public void testSendAndReceiveResponse() throws Exception { WebServiceConnection connection = null; try { - connection = messageSender.createConnection(URI); + connection = messageSender.createConnection(REQUEST_QUEUE_URI); SoapMessage soapRequest = new SaajSoapMessage(messageFactory.createMessage()); soapRequest.setSoapAction(SOAP_ACTION); connection.send(soapRequest); @@ -110,7 +82,7 @@ public class JmsMessageSenderIntegrationTest extends TestCase { 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, URI); + response.setStringProperty(JmsTransportConstants.PROPERTY_REQUEST_IRI, REQUEST_QUEUE_URI); response.setStringProperty(JmsTransportConstants.PROPERTY_SOAP_ACTION, SOAP_ACTION); response.writeBytes(buf); @@ -129,10 +101,26 @@ public class JmsMessageSenderIntegrationTest extends TestCase { } } + 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 = -1; + int bytesRead; while ((bytesRead = message.readBytes(buffer)) != -1) { out.write(buffer, 0, bytesRead); } diff --git a/sandbox/src/test/java/org/springframework/ws/transport/jms/JmsUriTest.java b/sandbox/src/test/java/org/springframework/ws/transport/jms/JmsUriTest.java index 87f6465a..4924a1a3 100644 --- a/sandbox/src/test/java/org/springframework/ws/transport/jms/JmsUriTest.java +++ b/sandbox/src/test/java/org/springframework/ws/transport/jms/JmsUriTest.java @@ -25,13 +25,10 @@ public class JmsUriTest extends TestCase { "destinationType=topic&" + "initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory&" + "jndiURL=theJndiURL&" + "priority=8&" + "timeToLive=10&" + "replyToName=interested&" + "userprop=mystuff"); - assertEquals("Invalid connection factory name", "SOAPJMSFactory", uri.getConnectionFactoryName()); 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 initial context factory", "com.sun.jndi.ldap.LdapCtxFactory", - uri.getInitialContextFactory()); assertEquals("Invalid prority", 8, uri.getPriority()); assertEquals("Invalid time to live", 10, uri.getTimeToLive()); assertEquals("Invalid reply to name", "interested", uri.getReplyTo()); diff --git a/sandbox/src/test/java/org/springframework/ws/transport/jms/WebServiceMessageListenerIntegrationTest.java b/sandbox/src/test/java/org/springframework/ws/transport/jms/WebServiceMessageListenerIntegrationTest.java new file mode 100644 index 00000000..97d60c34 --- /dev/null +++ b/sandbox/src/test/java/org/springframework/ws/transport/jms/WebServiceMessageListenerIntegrationTest.java @@ -0,0 +1,70 @@ +/* + * 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 javax.jms.BytesMessage; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Queue; +import javax.jms.Session; + +import org.springframework.jms.core.JmsTemplate; +import org.springframework.jms.core.MessageCreator; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +/** + * @author Arjen Poutsma + */ +public class WebServiceMessageListenerIntegrationTest extends AbstractDependencyInjectionSpringContextTests { + + private static final String CONTENT = + "" + "\n" + + "\n" + + "DIS\n" + "\n" + ""; + + private JmsTemplate jmsTemplate; + + private Queue responseQueue; + + public void setJmsTemplate(JmsTemplate jmsTemplate) { + this.jmsTemplate = jmsTemplate; + } + + public void setResponseQueue(Queue responseQueue) { + this.responseQueue = responseQueue; + } + + protected String[] getConfigLocations() { + return new String[]{"classpath:org/springframework/ws/transport/jms/jms-receiver-applicationContext.xml"}; + } + + public void testIt() throws JMSException, IOException { + final byte[] b = CONTENT.getBytes("UTF-8"); + jmsTemplate.send(new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + BytesMessage request = session.createBytesMessage(); + request.setJMSReplyTo(responseQueue); + request.writeBytes(b); + return request; + } + }); + BytesMessage response = (BytesMessage) jmsTemplate.receive(responseQueue); + assertNotNull("No response received", response); + } + +} diff --git a/sandbox/src/test/resources/log4j.properties b/sandbox/src/test/resources/log4j.properties index 0e307524..8e32525b 100644 --- a/sandbox/src/test/resources/log4j.properties +++ b/sandbox/src/test/resources/log4j.properties @@ -1,6 +1,6 @@ -log4j.rootCategory=INFO, stdout -#log4j.logger.org.springframework.ws=DEBUG -log4j.logger.org.springframework=DEBUG +log4j.rootCategory=WARN, stdout +log4j.logger.org.springframework.ws=DEBUG +log4j.logger.org.springframework.jms=DEBUG log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout diff --git a/sandbox/src/test/resources/org/springframework/ws/transport/jms/jms-receiver-applicationContext.xml b/sandbox/src/test/resources/org/springframework/ws/transport/jms/jms-receiver-applicationContext.xml index 24108581..5fbff11d 100644 --- a/sandbox/src/test/resources/org/springframework/ws/transport/jms/jms-receiver-applicationContext.xml +++ b/sandbox/src/test/resources/org/springframework/ws/transport/jms/jms-receiver-applicationContext.xml @@ -15,7 +15,7 @@ - + diff --git a/sandbox/src/test/resources/org/springframework/ws/transport/jms/jms-sender-applicationContext.xml b/sandbox/src/test/resources/org/springframework/ws/transport/jms/jms-sender-applicationContext.xml new file mode 100644 index 00000000..f91a61b9 --- /dev/null +++ b/sandbox/src/test/resources/org/springframework/ws/transport/jms/jms-sender-applicationContext.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file