Migrated to Gradle build

This commit migrates from a Maven-based build system to a Gradle-based
one. Changes include:

- Removed archetype & parent
- Renamed core, support, test, security and xml directories to
  spring-ws-core, spring-ws-test, spring-ws-security, spring-xml
  respectively.
- Moved samples to separate project
  (https://github.com/spring-projects/spring-ws-samples)
This commit is contained in:
Arjen Poutsma
2013-11-05 10:55:44 +01:00
committed by Arjen Poutsma
parent a8c1d2ad97
commit 843ca6d2ef
1362 changed files with 798 additions and 13079 deletions

View File

@@ -0,0 +1,171 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.http;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.transport.AbstractReceiverConnection;
import org.springframework.ws.transport.EndpointAwareWebServiceConnection;
import org.springframework.ws.transport.FaultAwareWebServiceConnection;
import org.springframework.ws.transport.WebServiceConnection;
import com.sun.net.httpserver.HttpExchange;
/**
* Implementation of {@link WebServiceConnection} that is based on the Java 6 HttpServer {@link HttpExchange}.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public class HttpExchangeConnection extends AbstractReceiverConnection
implements EndpointAwareWebServiceConnection, FaultAwareWebServiceConnection {
private final HttpExchange httpExchange;
private ByteArrayOutputStream responseBuffer;
private int responseStatusCode = HttpTransportConstants.STATUS_ACCEPTED;
private boolean chunkedEncoding;
/** Constructs a new exchange connection with the given <code>HttpExchange</code>. */
protected HttpExchangeConnection(HttpExchange httpExchange) {
Assert.notNull(httpExchange, "'httpExchange' must not be null");
this.httpExchange = httpExchange;
}
/** Returns the <code>HttpExchange</code> for this connection. */
public HttpExchange getHttpExchange() {
return httpExchange;
}
public URI getUri() throws URISyntaxException {
return httpExchange.getRequestURI();
}
void setChunkedEncoding(boolean chunkedEncoding) {
this.chunkedEncoding = chunkedEncoding;
}
public void endpointNotFound() {
responseStatusCode = HttpTransportConstants.STATUS_NOT_FOUND;
}
/*
* Errors
*/
public boolean hasError() throws IOException {
return false;
}
public String getErrorMessage() throws IOException {
return null;
}
/*
* Receiving request
*/
@Override
protected Iterator<String> getRequestHeaderNames() throws IOException {
return httpExchange.getRequestHeaders().keySet().iterator();
}
@Override
protected Iterator<String> getRequestHeaders(String name) throws IOException {
List<String> headers = httpExchange.getRequestHeaders().get(name);
return headers != null ? headers.iterator() : Collections.<String>emptyList().iterator();
}
@Override
protected InputStream getRequestInputStream() throws IOException {
return httpExchange.getRequestBody();
}
/*
* Sending response
*/
@Override
protected void addResponseHeader(String name, String value) throws IOException {
httpExchange.getResponseHeaders().add(name, value);
}
@Override
protected OutputStream getResponseOutputStream() throws IOException {
if (chunkedEncoding) {
httpExchange.sendResponseHeaders(responseStatusCode, 0);
return httpExchange.getResponseBody();
}
else {
if (responseBuffer == null) {
responseBuffer = new ByteArrayOutputStream();
}
return responseBuffer;
}
}
@Override
protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
if (!chunkedEncoding) {
byte[] buf = responseBuffer.toByteArray();
httpExchange.sendResponseHeaders(responseStatusCode, buf.length);
OutputStream responseBody = httpExchange.getResponseBody();
FileCopyUtils.copy(buf, responseBody);
}
responseBuffer = null;
}
@Override
public void onClose() throws IOException {
if (responseStatusCode == HttpTransportConstants.STATUS_ACCEPTED ||
responseStatusCode == HttpTransportConstants.STATUS_NOT_FOUND) {
httpExchange.sendResponseHeaders(responseStatusCode, -1);
}
httpExchange.close();
}
/*
* Faults
*/
public boolean hasFault() throws IOException {
return responseStatusCode == HttpTransportConstants.STATUS_INTERNAL_SERVER_ERROR;
}
public void setFault(boolean fault) throws IOException {
if (fault) {
responseStatusCode = HttpTransportConstants.STATUS_INTERNAL_SERVER_ERROR;
}
else {
responseStatusCode = HttpTransportConstants.STATUS_OK;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.http;
/**
* Exception that is thrown when an error occurs in the HTTP transport.
*
* @author Arjen Poutsma
* @since 1.5.8
*/
public class HttpsTransportException extends HttpTransportException {
public HttpsTransportException(String msg) {
super(msg);
}
public HttpsTransportException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,179 @@
/*
* Copyright 2005-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.http;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* Extension of {@link HttpUrlConnectionMessageSender} that adds support for (self-signed) HTTPS certificates.
*
* @author Alex Marshall
* @author Arjen Poutsma
* @since 1.5.8
*/
public class HttpsUrlConnectionMessageSender extends HttpUrlConnectionMessageSender implements InitializingBean {
/** The default SSL protocol. */
public static final String DEFAULT_SSL_PROTOCOL = "ssl";
private String sslProtocol = DEFAULT_SSL_PROTOCOL;
private String sslProvider;
private KeyManager[] keyManagers;
private TrustManager[] trustManagers;
private HostnameVerifier hostnameVerifier;
private SecureRandom rnd;
private SSLSocketFactory sslSocketFactory;
/**
* Sets the SSL protocol to use. Default is {@code ssl}.
*
* @see SSLContext#getInstance(String, String)
*/
public void setSslProtocol(String sslProtocol) {
Assert.hasLength(sslProtocol, "'sslProtocol' must not be empty");
this.sslProtocol = sslProtocol;
}
/**
* Sets the SSL provider to use. Default is empty, to use the default provider.
*
* @see SSLContext#getInstance(String, String)
*/
public void setSslProvider(String sslProvider) {
this.sslProvider = sslProvider;
}
/**
* Specifies the key managers to use for this message sender.
* <p/>
* Setting either this property or {@link #setTrustManagers(TrustManager[]) trustManagers} is required.
*
* @see SSLContext#init(KeyManager[], TrustManager[], SecureRandom)
*/
public void setKeyManagers(KeyManager[] keyManagers) {
this.keyManagers = keyManagers;
}
/**
* Specifies the trust managers to use for this message sender.
* <p/>
* Setting either this property or {@link #setKeyManagers(KeyManager[]) keyManagers} is required.
*
* @see SSLContext#init(KeyManager[], TrustManager[], SecureRandom)
*/
public void setTrustManagers(TrustManager[] trustManagers) {
this.trustManagers = trustManagers;
}
/**
* Specifies the host name verifier to use for this message sender.
*
* @see HttpsURLConnection#setHostnameVerifier(HostnameVerifier)
*/
public void setHostnameVerifier(HostnameVerifier hostnameVerifier) {
this.hostnameVerifier = hostnameVerifier;
}
/**
* Specifies the secure random to use for this message sender.
*
* @see SSLContext#init(KeyManager[], TrustManager[], SecureRandom)
*/
public void setSecureRandom(SecureRandom rnd) {
this.rnd = rnd;
}
/**
* Specifies the SSLSocketFactory to use for this message sender.
*
* @see HttpsURLConnection#setSSLSocketFactory(SSLSocketFactory sf)
*/
public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
this.sslSocketFactory = sslSocketFactory;
}
public void afterPropertiesSet() throws Exception {
Assert.isTrue(
!(ObjectUtils.isEmpty(keyManagers) && ObjectUtils.isEmpty(trustManagers) && (sslSocketFactory == null)),
"Setting either 'keyManagers', 'trustManagers' or 'sslSocketFactory' is required");
}
@Override
protected void prepareConnection(HttpURLConnection connection) throws IOException {
super.prepareConnection(connection);
if (connection instanceof HttpsURLConnection) {
HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
httpsConnection.setSSLSocketFactory(createSslSocketFactory());
if (hostnameVerifier != null) {
httpsConnection.setHostnameVerifier(hostnameVerifier);
}
}
}
private SSLSocketFactory createSslSocketFactory() throws HttpsTransportException {
if (this.sslSocketFactory != null) {
return this.sslSocketFactory;
}
try {
SSLContext sslContext =
StringUtils.hasLength(sslProvider) ? SSLContext.getInstance(sslProtocol, sslProvider) :
SSLContext.getInstance(sslProtocol);
sslContext.init(keyManagers, trustManagers, rnd);
if (logger.isDebugEnabled()) {
logger.debug("Initialized SSL Context with key managers [" +
StringUtils.arrayToCommaDelimitedString(keyManagers) + "] trust managers [" +
StringUtils.arrayToCommaDelimitedString(trustManagers) + "] secure random [" + rnd +
"]");
}
return sslContext.getSocketFactory();
}
catch (NoSuchAlgorithmException ex) {
throw new HttpsTransportException("Could not create SSLContext: " + ex.getMessage(), ex);
}
catch (NoSuchProviderException ex) {
throw new HttpsTransportException("Could not create SSLContext: " + ex.getMessage(), ex);
}
catch (KeyManagementException ex) {
throw new HttpsTransportException("Could not initialize SSLContext: " + ex.getMessage(), ex);
}
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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.http;
import java.io.IOException;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import org.springframework.ws.transport.support.SimpleWebServiceMessageReceiverObjectSupport;
/**
* {@link HttpHandler} that can be used to handle incoming {@link HttpExchange} service requests. Designed for Sun's JRE
* 1.6 HTTP server.
* <p/>
* Requires a {@link org.springframework.ws.WebServiceMessageFactory} which is used to convert the incoming {@link
* HttpExchange} into a {@link org.springframework.ws.WebServiceMessage}, and passes that to the {@link
* org.springframework.ws.transport.WebServiceMessageReceiver} {@link #setMessageReceiver(org.springframework.ws.transport.WebServiceMessageReceiver)
* registered}.
*
* @author Arjen Poutsma
* @see org.springframework.remoting.support.SimpleHttpServerFactoryBean
* @since 1.5.0
*/
public class WebServiceMessageReceiverHttpHandler extends SimpleWebServiceMessageReceiverObjectSupport
implements HttpHandler {
private boolean chunkedEncoding = false;
/** Enables chunked encoding on response bodies. Defaults to <code>false</code>. */
public void setChunkedEncoding(boolean chunkedEncoding) {
this.chunkedEncoding = chunkedEncoding;
}
public void handle(HttpExchange httpExchange) throws IOException {
if (HttpTransportConstants.METHOD_POST.equals(httpExchange.getRequestMethod())) {
HttpExchangeConnection connection = new HttpExchangeConnection(httpExchange);
connection.setChunkedEncoding(chunkedEncoding);
try {
handleConnection(connection);
}
catch (Exception ex) {
logger.error(ex);
}
}
else {
httpExchange.sendResponseHeaders(HttpTransportConstants.STATUS_METHOD_NOT_ALLOWED, -1);
httpExchange.close();
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.http;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.ws.wsdl.WsdlDefinition;
import org.springframework.xml.transform.TransformerObjectSupport;
/**
* @author Arjen Poutsma
* @since 1.5.0
*/
public class WsdlDefinitionHttpHandler extends TransformerObjectSupport implements HttpHandler, InitializingBean {
private static final String CONTENT_TYPE = "text/xml";
private WsdlDefinition definition;
public WsdlDefinitionHttpHandler() {
}
public WsdlDefinitionHttpHandler(WsdlDefinition definition) {
this.definition = definition;
}
public void setDefinition(WsdlDefinition definition) {
this.definition = definition;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(definition, "'definition' is required");
}
public void handle(HttpExchange httpExchange) throws IOException {
try {
if (HttpTransportConstants.METHOD_GET.equals(httpExchange.getRequestMethod())) {
Headers headers = httpExchange.getResponseHeaders();
headers.set(HttpTransportConstants.HEADER_CONTENT_TYPE, CONTENT_TYPE);
ByteArrayOutputStream os = new ByteArrayOutputStream();
transform(definition.getSource(), new StreamResult(os));
byte[] buf = os.toByteArray();
httpExchange.sendResponseHeaders(HttpTransportConstants.STATUS_OK, buf.length);
FileCopyUtils.copy(buf, httpExchange.getResponseBody());
}
else {
httpExchange.sendResponseHeaders(HttpTransportConstants.STATUS_METHOD_NOT_ALLOWED, -1);
}
}
catch (TransformerException ex) {
logger.error(ex, ex);
}
finally {
httpExchange.close();
}
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
import java.io.IOException;
import java.io.InputStream;
import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.MessageEOFException;
import org.springframework.util.Assert;
/**
* Input stream that wraps a {@link BytesMessage}.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
class BytesMessageInputStream extends InputStream {
private final BytesMessage message;
BytesMessageInputStream(BytesMessage message) {
Assert.notNull(message, "'message' must not be null");
this.message = message;
}
@Override
public int read(byte b[]) throws IOException {
try {
return message.readBytes(b);
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
}
@Override
public int read(byte b[], int off, int len) throws IOException {
if (off == 0) {
try {
return message.readBytes(b, len);
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
}
else {
return super.read(b, off, len);
}
}
@Override
public int read() throws IOException {
try {
return message.readByte();
}
catch (MessageEOFException ex) {
return -1;
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
import java.io.IOException;
import java.io.OutputStream;
import javax.jms.BytesMessage;
import javax.jms.JMSException;
import org.springframework.util.Assert;
/**
* Output stream that wraps a {@link BytesMessage}.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
class BytesMessageOutputStream extends OutputStream {
private final BytesMessage message;
BytesMessageOutputStream(BytesMessage message) {
Assert.notNull(message, "'message' must not be null");
this.message = message;
}
@Override
public void write(byte b[]) throws IOException {
try {
message.writeBytes(b);
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
}
@Override
public void write(byte b[], int off, int len) throws IOException {
try {
message.writeBytes(b, off, len);
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
}
@Override
public void write(int b) throws IOException {
try {
message.writeByte((byte) b);
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2005-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
import javax.jms.BytesMessage;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.springframework.jms.core.MessagePostProcessor;
import org.springframework.ws.transport.WebServiceMessageReceiver;
import org.springframework.ws.transport.support.SimpleWebServiceMessageReceiverObjectSupport;
/**
* Convenience base class for JMS server-side transport objects. Contains a {@link WebServiceMessageReceiver}, and has
* methods for handling incoming JMS {@link BytesMessage} and {@link TextMessage} requests. Also contains a
* <code>textMessageEncoding</code> property, which determines the encoding used to read from and write to
* <code>TextMessages</code>. This property defaults to <code>UTF-8</code>.
* <p/>
* Used by {@link WebServiceMessageListener} and {@link WebServiceMessageDrivenBean}.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public class JmsMessageReceiver extends SimpleWebServiceMessageReceiverObjectSupport {
/** Default encoding used to read from and write to {@link TextMessage} messages. */
public static final String DEFAULT_TEXT_MESSAGE_ENCODING = "UTF-8";
private String textMessageEncoding = DEFAULT_TEXT_MESSAGE_ENCODING;
private MessagePostProcessor postProcessor;
/** Sets the encoding used to read from and write to {@link TextMessage} messages. Defaults to <code>UTF-8</code>. */
public void setTextMessageEncoding(String textMessageEncoding) {
this.textMessageEncoding = textMessageEncoding;
}
/**
* Sets the optional {@link MessagePostProcessor} to further modify outgoing messages after the XML contents has
* been set.
*/
public void setPostProcessor(MessagePostProcessor postProcessor) {
this.postProcessor = postProcessor;
}
/**
* Handles an incoming message. 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 {@link BytesMessage}
*/
protected final void handleMessage(Message request, Session session) throws Exception {
JmsReceiverConnection connection;
if (request instanceof BytesMessage) {
connection = new JmsReceiverConnection((BytesMessage) request, session);
}
else if (request instanceof TextMessage) {
connection = new JmsReceiverConnection((TextMessage) request, textMessageEncoding, session);
}
else {
throw new IllegalArgumentException("Wrong message type: [" + request.getClass() +
"]. Only BytesMessages or TextMessages can be handled.");
}
connection.setPostProcessor(postProcessor);
handleConnection(connection);
}
}

View File

@@ -0,0 +1,210 @@
/*
* Copyright 2005-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
import java.io.IOException;
import java.net.URI;
import javax.jms.BytesMessage;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import org.springframework.jms.connection.ConnectionFactoryUtils;
import org.springframework.jms.core.MessagePostProcessor;
import org.springframework.jms.support.JmsUtils;
import org.springframework.jms.support.destination.JmsDestinationAccessor;
import org.springframework.util.StringUtils;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.ws.transport.jms.support.JmsTransportUtils;
/**
* {@link WebServiceMessageSender} implementation that uses JMS {@link Message}s. Requires a JMS {@link
* ConnectionFactory} to operate.
* <p/>
* This message sender supports URI's of the following format: <blockquote> <tt><b>jms:</b></tt><i>destination</i>[<tt><b>?</b></tt><i>param-name</i><tt><b>=</b></tt><i>param-value</i>][<tt><b>&amp;</b></tt><i>param-name</i><tt><b>=</b></tt><i>param-value</i>]*
* </blockquote> where the characters <tt><b>:</b></tt>, <tt><b>?</b></tt>, and <tt><b>&amp;</b></tt> stand for
* themselves. The <i>destination</i> represents the name of the {@link Queue} or {@link Topic} that will be resolved by
* the {@link #getDestinationResolver() destination resolver}. Valid <i>param-name</i> include:
* <p/>
* <blockquote>
* <table>
* <tr><th><i>param-name</i></th><th><i>Description</i></th></tr>
* <tr>
* <td><tt>deliveryMode</tt></td>
* <td>Indicates whether the request message is persistent or not. This may be <tt>PERSISTENT</tt> or
* <tt>NON_PERSISTENT</tt>. See {@link MessageProducer#setDeliveryMode(int)}</td>
* </tr>
* <tr>
* <td><tt>messageType</tt></td>
* <td>The message type. This may be <tt>BINARY_MESSAGE</tt> (the default) or <tt>TEXT_MESSAGE</tt></td>
* </tr>
* <tr>
* <td><tt>priority</tt></td>
* <td>The JMS priority (0-9) associated with the request message. See
* {@link MessageProducer#setPriority(int)}</td>
* </tr>
* <tr>
* <td><tt>replyToName</tt></td>
* <td>The name of the destination to which the response message must be sent, that will be resolved by
* the {@link #getDestinationResolver() destination resolver}.</td>
* </tr>
* <tr>
* <td><tt>timeToLive</tt></td>
* <td>The lifetime, in milliseconds, of the request message. See
* {@link MessageProducer#setTimeToLive(long)}</td>
* </tr>
* </table>
* </blockquote>
* <p/>
* If the <tt>replyToName</tt> is not set, a {@link Session#createTemporaryQueue() temporary queue} is used.
* <p/>
* This class uses {@link BytesMessage} messages by default, but can be configured to send {@link TextMessage} messages
* instead. <b>Note</b> that <code>BytesMessages</code> are preferred, since <code>TextMessages</code> do not support
* attachments and character encodings reliably.
* <p/>
* Some examples of JMS URIs are:
* <p/>
* <blockquote> <tt>jms:SomeQueue</tt><br> <tt>jms:SomeTopic?priority=3&deliveryMode=NON_PERSISTENT</tt><br>
* <tt>jms:RequestQueue?replyToName=ResponseQueueName</tt><br> <tt>jms:Queue?messageType=TEXT_MESSAGE</blockquote>
*
* @author Arjen Poutsma
* @see <a href="http://tools.ietf.org/id/draft-merrick-jms-iri-00.txt">IRI Scheme for Java(tm) Message Service 1.0</a>
* @since 1.5.0
*/
public class JmsMessageSender extends JmsDestinationAccessor implements WebServiceMessageSender {
/** Default timeout for receive operations: -1 indicates a blocking receive without timeout. */
public static final long DEFAULT_RECEIVE_TIMEOUT = -1;
/** Default encoding used to read fromn and write to {@link TextMessage} messages. */
public static final String DEFAULT_TEXT_MESSAGE_ENCODING = "UTF-8";
private long receiveTimeout = DEFAULT_RECEIVE_TIMEOUT;
private String textMessageEncoding = DEFAULT_TEXT_MESSAGE_ENCODING;
private MessagePostProcessor postProcessor;
/**
* Create a new <code>JmsMessageSender</code>
* <p/>
* <b>Note</b>: The ConnectionFactory has to be set before using the instance. This constructor can be used to
* prepare a JmsTemplate via a BeanFactory, typically setting the ConnectionFactory via {@link
* #setConnectionFactory(ConnectionFactory)}.
*
* @see #setConnectionFactory(ConnectionFactory)
*/
public JmsMessageSender() {
}
/**
* Create a new <code>JmsMessageSender</code>, given a ConnectionFactory.
*
* @param connectionFactory the ConnectionFactory to obtain Connections from
*/
public JmsMessageSender(ConnectionFactory connectionFactory) {
setConnectionFactory(connectionFactory);
}
/**
* Set the timeout to use for receive calls. The default is -1, which means no timeout.
*
* @see MessageConsumer#receive(long)
*/
public void setReceiveTimeout(long receiveTimeout) {
this.receiveTimeout = receiveTimeout;
}
/** Sets the encoding used to read from {@link TextMessage} messages. Defaults to <code>UTF-8</code>. */
public void setTextMessageEncoding(String textMessageEncoding) {
this.textMessageEncoding = textMessageEncoding;
}
/**
* Sets the optional {@link MessagePostProcessor} to further modify outgoing messages after the XML contents has
* been set.
*/
public void setPostProcessor(MessagePostProcessor postProcessor) {
this.postProcessor = postProcessor;
}
public WebServiceConnection createConnection(URI uri) throws IOException {
Connection jmsConnection = null;
Session jmsSession = null;
try {
jmsConnection = createConnection();
jmsSession = createSession(jmsConnection);
Destination requestDestination = resolveRequestDestination(jmsSession, uri);
Message requestMessage = createRequestMessage(jmsSession, uri);
JmsSenderConnection wsConnection =
new JmsSenderConnection(getConnectionFactory(), jmsConnection, jmsSession, requestDestination,
requestMessage);
wsConnection.setDeliveryMode(JmsTransportUtils.getDeliveryMode(uri));
wsConnection.setPriority(JmsTransportUtils.getPriority(uri));
wsConnection.setReceiveTimeout(receiveTimeout);
wsConnection.setResponseDestination(resolveResponseDestination(jmsSession, uri));
wsConnection.setTimeToLive(JmsTransportUtils.getTimeToLive(uri));
wsConnection.setTextMessageEncoding(textMessageEncoding);
wsConnection.setSessionTransacted(isSessionTransacted());
wsConnection.setPostProcessor(postProcessor);
return wsConnection;
}
catch (JMSException ex) {
JmsUtils.closeSession(jmsSession);
ConnectionFactoryUtils.releaseConnection(jmsConnection, getConnectionFactory(), true);
throw new JmsTransportException(ex);
}
}
public boolean supports(URI uri) {
return uri.getScheme().equals(JmsTransportConstants.JMS_URI_SCHEME);
}
private Destination resolveRequestDestination(Session session, URI uri) throws JMSException {
return resolveDestinationName(session, JmsTransportUtils.getDestinationName(uri));
}
private Destination resolveResponseDestination(Session session, URI uri) throws JMSException {
String destinationName = JmsTransportUtils.getReplyToName(uri);
return StringUtils.hasLength(destinationName) ? resolveDestinationName(session, destinationName) : null;
}
private Message createRequestMessage(Session session, URI uri) throws JMSException {
int messageType = JmsTransportUtils.getMessageType(uri);
if (messageType == JmsTransportConstants.BYTES_MESSAGE_TYPE) {
return session.createBytesMessage();
}
else if (messageType == JmsTransportConstants.TEXT_MESSAGE_TYPE) {
return session.createTextMessage();
}
else {
throw new IllegalArgumentException("Invalid message type [" + messageType + "].");
}
}
}

View File

@@ -0,0 +1,244 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.springframework.jms.core.MessagePostProcessor;
import org.springframework.jms.support.JmsUtils;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.transport.AbstractReceiverConnection;
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. Exposes a {@link
* BytesMessage} or {@link TextMessage} request and response message.
* <p/>
* The response message type is equal to the request message type, i.e. if a <code>BytesMessage</code> is received as
* request, a <code>BytesMessage</code> is created as response, and if a <code>TextMessage</code> is received, a
* <code>TextMessage</code> response is created.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public class JmsReceiverConnection extends AbstractReceiverConnection {
private final Message requestMessage;
private final Session session;
private Message responseMessage;
private String textMessageEncoding;
private MessagePostProcessor postProcessor;
private JmsReceiverConnection(Message 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;
}
/**
* Constructs a new JMS connection with the given {@link BytesMessage}.
*
* @param requestMessage the JMS request message
* @param session the JMS session
*/
protected JmsReceiverConnection(BytesMessage requestMessage, Session session) {
this((Message) requestMessage, session);
}
/**
* Constructs a new JMS connection with the given {@link TextMessage}.
*
* @param requestMessage the JMS request message
* @param session the JMS session
*/
protected JmsReceiverConnection(TextMessage requestMessage, String encoding, Session session) {
this(requestMessage, session);
this.textMessageEncoding = encoding;
}
void setPostProcessor(MessagePostProcessor postProcessor) {
this.postProcessor = postProcessor;
}
/** Returns the request message for this connection. Returns either a {@link BytesMessage} or a {@link TextMessage}. */
public Message getRequestMessage() {
return requestMessage;
}
/**
* Returns the response message, if any, for this connection. Returns either a {@link BytesMessage} or a {@link
* TextMessage}.
*/
public Message getResponseMessage() {
return responseMessage;
}
/*
* URI
*/
public URI getUri() throws URISyntaxException {
try {
return JmsTransportUtils.toUri(requestMessage.getJMSDestination());
}
catch (JMSException ex) {
throw new URISyntaxException("", ex.getMessage());
}
}
/*
* Errors
*/
public String getErrorMessage() throws IOException {
return null;
}
public boolean hasError() throws IOException {
return false;
}
/*
* Receiving
*/
@Override
protected Iterator<String> getRequestHeaderNames() throws IOException {
try {
return JmsTransportUtils.getHeaderNames(requestMessage);
}
catch (JMSException ex) {
throw new JmsTransportException("Could not get property names", ex);
}
}
@Override
protected Iterator<String> getRequestHeaders(String name) throws IOException {
try {
return JmsTransportUtils.getHeaders(requestMessage, name);
}
catch (JMSException ex) {
throw new JmsTransportException("Could not get property value", ex);
}
}
@Override
protected InputStream getRequestInputStream() throws IOException {
if (requestMessage instanceof BytesMessage) {
return new BytesMessageInputStream((BytesMessage) requestMessage);
}
else if (requestMessage instanceof TextMessage) {
return new TextMessageInputStream((TextMessage) requestMessage, textMessageEncoding);
}
else {
throw new IllegalStateException("Unknown request message type [" + requestMessage + "]");
}
}
/*
* Sending
*/
@Override
protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
try {
if (requestMessage instanceof BytesMessage) {
responseMessage = session.createBytesMessage();
}
else if (requestMessage instanceof TextMessage) {
responseMessage = session.createTextMessage();
}
else {
throw new IllegalStateException("Unknown request message type [" + requestMessage + "]");
}
String correlation = requestMessage.getJMSCorrelationID();
if (correlation == null) {
correlation = requestMessage.getJMSMessageID();
}
responseMessage.setJMSCorrelationID(correlation);
}
catch (JMSException ex) {
throw new JmsTransportException("Could not create response message", ex);
}
}
@Override
protected void addResponseHeader(String name, String value) throws IOException {
try {
JmsTransportUtils.addHeader(responseMessage, name, value);
}
catch (JMSException ex) {
throw new JmsTransportException("Could not set property", ex);
}
}
@Override
protected OutputStream getResponseOutputStream() throws IOException {
if (responseMessage instanceof BytesMessage) {
return new BytesMessageOutputStream((BytesMessage) responseMessage);
}
else if (responseMessage instanceof TextMessage) {
return new TextMessageOutputStream((TextMessage) responseMessage, textMessageEncoding);
}
else {
throw new IllegalStateException("Unknown response message type [" + responseMessage + "]");
}
}
@Override
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());
if (postProcessor != null) {
responseMessage = postProcessor.postProcessMessage(responseMessage);
}
messageProducer.send(responseMessage);
}
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
finally {
JmsUtils.closeMessageProducer(messageProducer);
}
}
}

View File

@@ -0,0 +1,327 @@
/*
* Copyright 2005-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import javax.jms.BytesMessage;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TemporaryQueue;
import javax.jms.TextMessage;
import org.springframework.jms.connection.ConnectionFactoryUtils;
import org.springframework.jms.core.MessagePostProcessor;
import org.springframework.jms.support.JmsUtils;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.transport.AbstractSenderConnection;
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. Exposes a {@link
* BytesMessage} request and response message.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public class JmsSenderConnection extends AbstractSenderConnection {
private final ConnectionFactory connectionFactory;
private final Connection connection;
private final Session session;
private final Destination requestDestination;
private Message requestMessage;
private Destination responseDestination;
private Message responseMessage;
private long receiveTimeout;
private int deliveryMode;
private long timeToLive;
private int priority;
private String textMessageEncoding;
private MessagePostProcessor postProcessor;
private boolean sessionTransacted = false;
private boolean temporaryResponseQueueCreated = false;
/** Constructs a new JMS connection with the given parameters. */
protected JmsSenderConnection(ConnectionFactory connectionFactory,
Connection connection,
Session session,
Destination requestDestination,
Message requestMessage) throws JMSException {
Assert.notNull(connectionFactory, "'connectionFactory' must not be null");
Assert.notNull(connection, "'connection' must not be null");
Assert.notNull(session, "'session' must not be null");
Assert.notNull(requestDestination, "'requestDestination' must not be null");
Assert.notNull(requestMessage, "'requestMessage' must not be null");
this.connectionFactory = connectionFactory;
this.connection = connection;
this.session = session;
this.requestDestination = requestDestination;
this.requestMessage = requestMessage;
}
/** Returns the request message for this connection. Returns either a {@link BytesMessage} or a {@link TextMessage}. */
public Message getRequestMessage() {
return requestMessage;
}
/**
* Returns the response message, if any, for this connection. Returns either a {@link BytesMessage} or a {@link
* TextMessage}.
*/
public Message getResponseMessage() {
return responseMessage;
}
/*
* Package-friendly setters
*/
void setResponseDestination(Destination responseDestination) {
this.responseDestination = responseDestination;
}
void setTimeToLive(long timeToLive) {
this.timeToLive = timeToLive;
}
void setDeliveryMode(int deliveryMode) {
this.deliveryMode = deliveryMode;
}
void setPriority(int priority) {
this.priority = priority;
}
void setReceiveTimeout(long receiveTimeout) {
this.receiveTimeout = receiveTimeout;
}
void setTextMessageEncoding(String textMessageEncoding) {
this.textMessageEncoding = textMessageEncoding;
}
void setPostProcessor(MessagePostProcessor postProcessor) {
this.postProcessor = postProcessor;
}
void setSessionTransacted(boolean sessionTransacted) {
this.sessionTransacted = sessionTransacted;
}
/*
* URI
*/
public URI getUri() throws URISyntaxException {
try {
return JmsTransportUtils.toUri(requestDestination);
}
catch (JMSException ex) {
throw new URISyntaxException("", ex.getMessage());
}
}
/*
* Errors
*/
public boolean hasError() throws IOException {
return false;
}
public String getErrorMessage() throws IOException {
return null;
}
/*
* Sending
*/
@Override
protected void addRequestHeader(String name, String value) throws IOException {
try {
JmsTransportUtils.addHeader(requestMessage, name, value);
}
catch (JMSException ex) {
throw new JmsTransportException("Could not set property", ex);
}
}
@Override
protected OutputStream getRequestOutputStream() throws IOException {
if (requestMessage instanceof BytesMessage) {
return new BytesMessageOutputStream((BytesMessage) requestMessage);
}
else if (requestMessage instanceof TextMessage) {
return new TextMessageOutputStream((TextMessage) requestMessage, textMessageEncoding);
}
else {
throw new IllegalStateException("Unknown request message type [" + requestMessage + "]");
}
}
@Override
protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
MessageProducer messageProducer = null;
try {
messageProducer = session.createProducer(requestDestination);
messageProducer.setDeliveryMode(deliveryMode);
messageProducer.setTimeToLive(timeToLive);
messageProducer.setPriority(priority);
if (responseDestination == null) {
responseDestination = session.createTemporaryQueue();
temporaryResponseQueueCreated = true;
}
requestMessage.setJMSReplyTo(responseDestination);
if (postProcessor != null) {
requestMessage = postProcessor.postProcessMessage(requestMessage);
}
connection.start();
messageProducer.send(requestMessage);
if (session.getTransacted() && isSessionLocallyTransacted(session)) {
JmsUtils.commitIfNecessary(session);
}
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
finally {
JmsUtils.closeMessageProducer(messageProducer);
}
}
/** @see org.springframework.jms.core.JmsTemplate#isSessionLocallyTransacted(Session) */
private boolean isSessionLocallyTransacted(Session session) {
return sessionTransacted && !ConnectionFactoryUtils.isSessionTransactional(session, connectionFactory);
}
/*
* Receiving
*/
@Override
protected void onReceiveBeforeRead() throws IOException {
MessageConsumer messageConsumer = null;
try {
if (temporaryResponseQueueCreated) {
messageConsumer = session.createConsumer(responseDestination);
}
else {
String messageId = requestMessage.getJMSMessageID().replaceAll("'", "''");
String messageSelector = "JMSCorrelationID = '" + messageId + "'";
messageConsumer = session.createConsumer(responseDestination, messageSelector);
}
Message message = receiveTimeout >= 0 ? messageConsumer.receive(receiveTimeout) : messageConsumer.receive();
if (message instanceof BytesMessage || message instanceof TextMessage) {
responseMessage = message;
}
else if (message != null) {
throw new IllegalArgumentException(
"Wrong message type: [" + message.getClass() + "]. " +
"Only BytesMessages or TextMessages can be handled.");
}
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
finally {
JmsUtils.closeMessageConsumer(messageConsumer);
if (temporaryResponseQueueCreated) {
try {
((TemporaryQueue) responseDestination).delete();
}
catch (JMSException ex) {
// ignore
}
}
}
}
@Override
protected boolean hasResponse() throws IOException {
return responseMessage != null;
}
@Override
protected Iterator<String> getResponseHeaderNames() throws IOException {
try {
return JmsTransportUtils.getHeaderNames(responseMessage);
}
catch (JMSException ex) {
throw new JmsTransportException("Could not get property names", ex);
}
}
@Override
protected Iterator<String> getResponseHeaders(String name) throws IOException {
try {
return JmsTransportUtils.getHeaders(responseMessage, name);
}
catch (JMSException ex) {
throw new JmsTransportException("Could not get property value", ex);
}
}
@Override
protected InputStream getResponseInputStream() throws IOException {
if (responseMessage instanceof BytesMessage) {
return new BytesMessageInputStream((BytesMessage) responseMessage);
}
else if (responseMessage instanceof TextMessage) {
return new TextMessageInputStream((TextMessage) responseMessage, textMessageEncoding);
}
else {
throw new IllegalStateException("Unknown response message type [" + responseMessage + "]");
}
}
@Override
protected void onClose() throws IOException {
JmsUtils.closeSession(session);
ConnectionFactoryUtils.releaseConnection(connection, connectionFactory, true);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2005-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
import javax.jms.BytesMessage;
import javax.jms.TextMessage;
import org.springframework.ws.transport.TransportConstants;
/**
* Declares JMS-specific transport constants.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public interface JmsTransportConstants extends TransportConstants {
/** The "jms" URI scheme" */
String JMS_URI_SCHEME = "jms";
/** Indicates a {@link BytesMessage} type. */
int BYTES_MESSAGE_TYPE = 1;
/** Indicates a {@link TextMessage} type. */
int TEXT_MESSAGE_TYPE = 2;
/** Prefix for JMS properties that map to transport headers. */
String PROPERTY_PREFIX = "SOAPJMS_";
/** JMS property used for storing {@link #HEADER_ACCEPT_ENCODING}. */
String PROPERTY_ACCEPT_ENCODING = PROPERTY_PREFIX + "acceptEncoding";
/** JMS property used for storing {@link #HEADER_SOAP_ACTION}. */
String PROPERTY_SOAP_ACTION = PROPERTY_PREFIX + "soapAction";
/** JMS property used for storing {@link #HEADER_CONTENT_LENGTH}. */
String PROPERTY_CONTENT_LENGTH = PROPERTY_PREFIX + "contentLength";
/** JMS property used for storing {@link #HEADER_CONTENT_TYPE}. */
String PROPERTY_CONTENT_TYPE = PROPERTY_PREFIX + "contentType";
}

View File

@@ -0,0 +1,48 @@
/*
* 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.5.0
*/
public class JmsTransportException extends TransportException {
private final JMSException jmsException;
public JmsTransportException(String msg, JMSException ex) {
super(msg + ": " + ex.getMessage());
initCause(ex);
jmsException = ex;
}
public JmsTransportException(JMSException ex) {
super(ex.getMessage());
initCause(ex);
jmsException = ex;
}
public JMSException getJmsException() {
return jmsException;
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
import java.io.ByteArrayInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.jms.JMSException;
import javax.jms.TextMessage;
import org.springframework.util.Assert;
/**
* Input stream that wraps a {@link javax.jms.TextMessage}.
*
* @author Arjen Poutsma
* @since 1.5.3
*/
class TextMessageInputStream extends FilterInputStream {
TextMessageInputStream(TextMessage message, String encoding) throws IOException {
super(createInputStream(message, encoding));
}
private static InputStream createInputStream(TextMessage message, String encoding) throws IOException {
Assert.notNull(message, "'message' must not be null");
Assert.notNull(encoding, "'encoding' must not be null");
try {
String text = message.getText();
byte[] contents = text != null ? text.getBytes(encoding) : new byte[0];
return new ByteArrayInputStream(contents);
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
import java.io.ByteArrayOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import javax.jms.JMSException;
import javax.jms.TextMessage;
import org.springframework.util.Assert;
/**
* Writer that wraps a {@link javax.jms.TextMessage}.
*
* @author Arjen Poutsma
* @since 1.5.3
*/
class TextMessageOutputStream extends FilterOutputStream {
private final TextMessage message;
private final String encoding;
TextMessageOutputStream(TextMessage message, String encoding) {
super(new ByteArrayOutputStream());
Assert.notNull(message, "'message' must not be null");
Assert.notNull(encoding, "'encoding' must not be null");
this.message = message;
this.encoding = encoding;
}
@Override
public void flush() throws IOException {
super.flush();
try {
ByteArrayOutputStream baos = (ByteArrayOutputStream) out;
String text = new String(baos.toByteArray(), encoding);
message.setText(text);
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
}
}

View File

@@ -0,0 +1,170 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.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.core.MessagePostProcessor;
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.
* <p/>
* This class needs a JMS {@link ConnectionFactory}, 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()
*/
@Override
protected void onEjbCreate() {
try {
connectionFactory = createConnectionFactory();
delegate = new JmsMessageReceiver();
delegate.setMessageFactory(createMessageFactory());
delegate.setMessageReceiver(createMessageReceiver());
delegate.setPostProcessor(createPostProcessor());
}
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 implementation 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 implementation 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 implementation 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}.
* <p/>
* 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 implementation creates a non-transactional, {@link Session#AUTO_ACKNOWLEDGE
* auto acknowledged} session.
* <p/>
* 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);
}
/**
* Creates a JMS {@link MessagePostProcessor} to process JMS messages. Default
* implementation returns {@code null}, meaning that no post processor is used.
*
* @return a message post processor
*/
protected MessagePostProcessor createPostProcessor() {
return null;
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.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 {@link SessionAwareMessageListener} that can be used to handle incoming {@link Message} service requests.
* <p/>
* 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.5.0
*/
public class WebServiceMessageListener extends JmsMessageReceiver implements SessionAwareMessageListener<Message> {
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;
}
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Package providing support for handling messages via JMS.
</body>
</html>

View File

@@ -0,0 +1,259 @@
/*
* Copyright 2005-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms.support;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.Topic;
import org.springframework.ws.transport.jms.JmsTransportConstants;
/**
* Collection of utility methods to work with JMS transports. Includes methods to retrieve JMS properties from an {@link
* URI}.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public abstract 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, JmsTransportConstants.HEADER_ACCEPT_ENCODING,
JmsTransportConstants.PROPERTY_ACCEPT_ENCODING};
private static final Pattern DESTINATION_NAME_PATTERN = Pattern.compile("^([^\\?]+)");
private static final Pattern DELIVERY_MODE_PATTERN = Pattern.compile("deliveryMode=(PERSISTENT|NON_PERSISTENT)");
private static final Pattern MESSAGE_TYPE_PATTERN = Pattern.compile("messageType=(BYTES_MESSAGE|TEXT_MESSAGE)");
private static final Pattern TIME_TO_LIVE_PATTERN = Pattern.compile("timeToLive=(\\d+)");
private static final Pattern PRIORITY_PATTERN = Pattern.compile("priority=(\\d)");
private static final Pattern REPLY_TO_NAME_PATTERN = Pattern.compile("replyToName=([^&]+)");
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;
}
/**
* Converts the given JMS destination into a <code>jms</code> URI.
*
* @param destination the destination
* @return a jms URI
*/
public static URI toUri(Destination destination) throws URISyntaxException, JMSException {
String destinationName;
if (destination instanceof Queue) {
destinationName = ((Queue) destination).getQueueName();
}
else if (destination instanceof Topic) {
Topic topic = (Topic) destination;
destinationName = topic.getTopicName();
}
else {
throw new IllegalArgumentException("Destination [ " + destination + "] is neither Queue nor Topic");
}
return new URI(JmsTransportConstants.JMS_URI_SCHEME, destinationName, null);
}
/** Returns the destination name of the given URI. */
public static String getDestinationName(URI uri) {
return getStringParameter(DESTINATION_NAME_PATTERN, uri);
}
/** Adds the given header to the specified message. */
public static void addHeader(Message message, String name, String value) throws JMSException {
String propertyName = JmsTransportUtils.headerToJmsProperty(name);
message.setStringProperty(propertyName, value);
}
/**
* Returns an iterator over all header names in the given message. Delegates to {@link
* #jmsPropertyToHeader(String)}.
*/
public static Iterator<String> getHeaderNames(Message message) throws JMSException {
Enumeration<?> properties = message.getPropertyNames();
List<String> results = new ArrayList<String>();
while (properties.hasMoreElements()) {
String property = (String) properties.nextElement();
if (property.startsWith(JmsTransportConstants.PROPERTY_PREFIX)) {
String header = jmsPropertyToHeader(property);
results.add(header);
}
}
return results.iterator();
}
/**
* Returns an iterator over all the header values of the given message and header name. Delegates to {@link
* #headerToJmsProperty(String)}.
*/
public static Iterator<String> getHeaders(Message message, String name) throws JMSException {
String propertyName = headerToJmsProperty(name);
String value = message.getStringProperty(propertyName);
if (value != null) {
return Collections.singletonList(value).iterator();
}
else {
return Collections.<String>emptyList().iterator();
}
}
/**
* Returns the delivery mode of the given URI.
*
* @see DeliveryMode#NON_PERSISTENT
* @see DeliveryMode#PERSISTENT
* @see Message#DEFAULT_DELIVERY_MODE
*/
public static int getDeliveryMode(URI uri) {
String deliveryMode = getStringParameter(DELIVERY_MODE_PATTERN, uri);
if ("NON_PERSISTENT".equals(deliveryMode)) {
return DeliveryMode.NON_PERSISTENT;
}
else if ("PERSISTENT".equals(deliveryMode)) {
return DeliveryMode.PERSISTENT;
}
else {
return Message.DEFAULT_DELIVERY_MODE;
}
}
/**
* Returns the message type of the given URI. Defaults to {@link JmsTransportConstants#BYTES_MESSAGE_TYPE}.
*
* @see JmsTransportConstants#BYTES_MESSAGE_TYPE
* @see JmsTransportConstants#TEXT_MESSAGE_TYPE
*/
public static int getMessageType(URI uri) {
String deliveryMode = getStringParameter(MESSAGE_TYPE_PATTERN, uri);
if ("TEXT_MESSAGE".equals(deliveryMode)) {
return JmsTransportConstants.TEXT_MESSAGE_TYPE;
}
else {
return JmsTransportConstants.BYTES_MESSAGE_TYPE;
}
}
/**
* Returns the lifetime, in milliseconds, of the given URI.
*
* @see Message#DEFAULT_TIME_TO_LIVE
*/
public static long getTimeToLive(URI uri) {
return getLongParameter(TIME_TO_LIVE_PATTERN, uri, Message.DEFAULT_TIME_TO_LIVE);
}
/**
* Returns the priority of the given URI.
*
* @see Message#DEFAULT_PRIORITY
*/
public static int getPriority(URI uri) {
return getIntParameter(PRIORITY_PATTERN, uri, Message.DEFAULT_PRIORITY);
}
/**
* Returns the reply-to name of the given URI.
*
* @see Message#setJMSReplyTo(Destination)
*/
public static String getReplyToName(URI uri) {
return getStringParameter(REPLY_TO_NAME_PATTERN, uri);
}
private static String getStringParameter(Pattern pattern, URI uri) {
Matcher matcher = pattern.matcher(uri.getSchemeSpecificPart());
if (matcher.find() && matcher.groupCount() == 1) {
return matcher.group(1);
}
return null;
}
private static int getIntParameter(Pattern pattern, URI uri, int defaultValue) {
Matcher matcher = pattern.matcher(uri.getSchemeSpecificPart());
if (matcher.find() && matcher.groupCount() == 1) {
try {
return Integer.parseInt(matcher.group(1));
}
catch (NumberFormatException ex) {
// fall through to default value
}
}
return defaultValue;
}
private static long getLongParameter(Pattern pattern, URI uri, long defaultValue) {
Matcher matcher = pattern.matcher(uri.getSchemeSpecificPart());
if (matcher.find() && matcher.groupCount() == 1) {
try {
return Long.parseLong(matcher.group(1));
}
catch (NumberFormatException ex) {
// fall through to default value
}
}
return defaultValue;
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Classes supporting the org.springframework.ws.transport.jms package.
</body>
</html>

View File

@@ -0,0 +1,278 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.mail;
import java.util.Properties;
import javax.mail.Folder;
import javax.mail.FolderClosedException;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.URLName;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import org.springframework.scheduling.SchedulingAwareRunnable;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.transport.WebServiceMessageReceiver;
import org.springframework.ws.transport.mail.monitor.MonitoringStrategy;
import org.springframework.ws.transport.mail.monitor.PollingMonitoringStrategy;
import org.springframework.ws.transport.mail.monitor.Pop3PollingMonitoringStrategy;
import org.springframework.ws.transport.mail.support.MailTransportUtils;
import org.springframework.ws.transport.support.AbstractAsyncStandaloneMessageReceiver;
/**
* Server-side component for receiving email messages using JavaMail. Requires a {@link #setTransportUri(String)
* transport} URI, {@link #setStoreUri(String) store} URI, and {@link #setMonitoringStrategy(MonitoringStrategy)
* monitoringStrategy} to be set, in addition to the {@link #setMessageFactory(WebServiceMessageFactory) messageFactory}
* and {@link #setMessageReceiver(WebServiceMessageReceiver) messageReceiver} required by the base class.
* <p/>
* The {@link MonitoringStrategy} is used to detect new incoming email request. If the <code>monitoringStrategy</code>
* is not explicitly set, this receiver will use the {@link Pop3PollingMonitoringStrategy} for POP3 servers, and the
* {@link PollingMonitoringStrategy} for IMAP servers.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public class MailMessageReceiver extends AbstractAsyncStandaloneMessageReceiver {
private Session session = Session.getInstance(new Properties(), null);
private URLName storeUri;
private URLName transportUri;
private Folder folder;
private Store store;
private InternetAddress from;
private MonitoringStrategy monitoringStrategy;
/** Sets the from address to use when sending response messages. */
public void setFrom(String from) throws AddressException {
this.from = new InternetAddress(from);
}
/**
* Set JavaMail properties for the {@link Session}.
* <p/>
* A new {@link Session} will be created with those properties. Use either this method or {@link #setSession}, but
* not both.
* <p/>
* Non-default properties in this instance will override given JavaMail properties.
*/
public void setJavaMailProperties(Properties javaMailProperties) {
session = Session.getInstance(javaMailProperties, null);
}
/**
* Set the JavaMail <code>Session</code>, possibly pulled from JNDI.
* <p/>
* Default is a new <code>Session</code> without defaults, that is completely configured via this instance's
* properties.
* <p/>
* If using a pre-configured <code>Session</code>, non-default properties in this instance will override the
* settings in the <code>Session</code>.
*
* @see #setJavaMailProperties
*/
public void setSession(Session session) {
Assert.notNull(session, "Session must not be null");
this.session = session;
}
/**
* Sets the JavaMail Store URI to be used for retrieving request messages. Typically takes the form of
* <code>[imap|pop3]://user:password@host:port/INBOX</code>. Setting this property is required.
* <p/>
* For example, <code>imap://john:secret@imap.example.com/INBOX</code>
*
* @see Session#getStore(URLName)
*/
public void setStoreUri(String storeUri) {
this.storeUri = new URLName(storeUri);
}
/**
* Sets the JavaMail Transport URI to be used for sending response messages. Typically takes the form of
* <code>smtp://user:password@host:port</code>. Setting this property is required.
* <p/>
* For example, <code>smtp://john:secret@smtp.example.com</code>
*
* @see Session#getTransport(URLName)
*/
public void setTransportUri(String transportUri) {
this.transportUri = new URLName(transportUri);
}
/**
* Sets the monitoring strategy to use for retrieving new requests. Default is the {@link
* PollingMonitoringStrategy}.
*/
public void setMonitoringStrategy(MonitoringStrategy monitoringStrategy) {
this.monitoringStrategy = monitoringStrategy;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(storeUri, "Property 'storeUri' is required");
Assert.notNull(transportUri, "Property 'transportUri' is required");
if (monitoringStrategy == null) {
String protocol = storeUri.getProtocol();
if ("pop3".equals(protocol)) {
monitoringStrategy = new Pop3PollingMonitoringStrategy();
}
else if ("imap".equals(protocol)) {
monitoringStrategy = new PollingMonitoringStrategy();
}
else {
throw new IllegalArgumentException("Cannot determine monitoring strategy for \"" + protocol + "\". " +
"Set the 'monitoringStrategy' explicitly.");
}
}
super.afterPropertiesSet();
}
@Override
protected void onActivate() throws MessagingException {
openSession();
openFolder();
}
@Override
protected void onStart() {
if (logger.isInfoEnabled()) {
logger.info("Starting mail receiver [" + MailTransportUtils.toPasswordProtectedString(storeUri) + "]");
}
execute(new MonitoringRunnable());
}
@Override
protected void onStop() {
if (logger.isInfoEnabled()) {
logger.info("Stopping mail receiver [" + MailTransportUtils.toPasswordProtectedString(storeUri) + "]");
}
closeFolder();
}
@Override
protected void onShutdown() {
if (logger.isInfoEnabled()) {
logger.info("Shutting down mail receiver [" + MailTransportUtils.toPasswordProtectedString(storeUri) + "]");
}
closeFolder();
closeSession();
}
private void openSession() throws MessagingException {
store = session.getStore(storeUri);
if (logger.isDebugEnabled()) {
logger.debug("Connecting to store [" + MailTransportUtils.toPasswordProtectedString(storeUri) + "]");
}
store.connect();
}
private void openFolder() throws MessagingException {
if (folder != null && folder.isOpen()) {
return;
}
folder = store.getFolder(storeUri);
if (folder == null || !folder.exists()) {
throw new IllegalStateException("No default folder to receive from");
}
if (logger.isDebugEnabled()) {
logger.debug("Opening folder [" + MailTransportUtils.toPasswordProtectedString(storeUri) + "]");
}
folder.open(monitoringStrategy.getFolderOpenMode());
}
private void closeFolder() {
MailTransportUtils.closeFolder(folder, true);
}
private void closeSession() {
MailTransportUtils.closeService(store);
}
private class MonitoringRunnable implements SchedulingAwareRunnable {
public void run() {
try {
openFolder();
while (isRunning()) {
try {
Message[] messages = monitoringStrategy.monitor(folder);
for (Message message : messages) {
MessageHandler handler = new MessageHandler(message);
execute(handler);
}
}
catch (FolderClosedException ex) {
logger.debug("Folder closed, reopening");
if (isRunning()) {
openFolder();
}
}
catch (MessagingException ex) {
logger.warn(ex);
}
}
}
catch (InterruptedException ex) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
catch (MessagingException ex) {
logger.error(ex);
}
}
public boolean isLongLived() {
return true;
}
}
private class MessageHandler implements SchedulingAwareRunnable {
private final Message message;
public MessageHandler(Message message) {
this.message = message;
}
public void run() {
MailReceiverConnection connection = new MailReceiverConnection(message, session);
connection.setTransportUri(transportUri);
connection.setFrom(from);
try {
handleConnection(connection);
}
catch (Exception ex) {
logger.error("Could not handle incoming mail connection", ex);
}
}
public boolean isLongLived() {
return false;
}
}
}

View File

@@ -0,0 +1,168 @@
/*
* 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.mail;
import java.io.IOException;
import java.net.URI;
import java.util.Properties;
import javax.mail.Session;
import javax.mail.URLName;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.ws.transport.mail.monitor.PollingMonitoringStrategy;
import org.springframework.ws.transport.mail.support.MailTransportUtils;
/**
* {@link WebServiceMessageSender} implementation that uses Mail {@link MimeMessage}s. Requires a {@link
* #setTransportUri(String) transport} and {@link #setStoreUri(String) store} URI to be set.
* <p/>
* Calling {@link WebServiceConnection#receive(WebServiceMessageFactory)} on connections created by this message sender
* will result in a blocking call, for the amount of milliseconds specified by the {@link #setReceiveSleepTime(long)
* receiveSleepTime} property. This will give the server time to formulate a response message. By default, this propery
* is set to 1 minute. For a proper request-response conversation to work, this property value must not be smaller the
* {@link PollingMonitoringStrategy#setPollingInterval(long) pollingInterval} property of the server-side message
* receiver polling strategy.
* <p/>
* This message sender supports URI's of the following format: <blockquote> <tt><b>mailto:</b></tt><i>to</i>[<tt><b>?</b></tt><i>param-name</i><tt><b>=</b></tt><i>param-value</i>][<tt><b>&amp;</b></tt><i>param-name</i><tt><b>=</b></tt><i>param-value</i>]*
* </blockquote> where the characters <tt><b>:</b></tt>, <tt><b>?</b></tt>, and <tt><b>&amp;</b></tt> stand for
* themselves. The <i>to</i> represents a RFC 822 mailbox. Valid <i>param-name</i> include:
* <p/>
* <blockquote><table> <tr><th><i>param-name</i></th><th><i>Description</i></th></tr>
* <tr><td><tt>subject</tt></td><td>The subject of the request message.</td></tr> </table></blockquote>
* <p/>
* Some examples of email URIs are:
* <p/>
* <blockquote><tt>mailto:john@example.com</tt><br> <tt>mailto:john@example.com@?subject=SOAP%20Test</tt><br></blockquote>
*
* @author Arjen Poutsma
* @see <a href="http://www.ietf.org/rfc/rfc2368.txt">The mailto URL scheme</a>
* @since 1.5.0
*/
public class MailMessageSender implements WebServiceMessageSender, InitializingBean {
/**
* Default timeout for receive operations. Set to 1000 * 60 milliseconds (i.e. 1 minute).
*/
public static final long DEFAULT_RECEIVE_TIMEOUT = 1000 * 60;
private long receiveSleepTime = DEFAULT_RECEIVE_TIMEOUT;
private Session session = Session.getInstance(new Properties(), null);
private URLName storeUri;
private URLName transportUri;
private InternetAddress from;
/**
* Sets the from address to use when sending request messages.
*/
public void setFrom(String from) throws AddressException {
this.from = new InternetAddress(from);
}
/**
* Set JavaMail properties for the {@link Session}.
* <p/>
* A new {@link Session} will be created with those properties. Use either this method or {@link #setSession}, but
* not both.
* <p/>
* Non-default properties in this instance will override given JavaMail properties.
*/
public void setJavaMailProperties(Properties javaMailProperties) {
session = Session.getInstance(javaMailProperties, null);
}
/**
* Set the sleep time to use for receive calls, <strong>in milliseconds</strong>. The default is 1000 * 60 ms, that
* is 1 minute.
*/
public void setReceiveSleepTime(long receiveSleepTime) {
this.receiveSleepTime = receiveSleepTime;
}
/**
* Set the JavaMail <code>Session</code>, possibly pulled from JNDI.
* <p/>
* Default is a new <code>Session</code> without defaults, that is completely configured via this instance's
* properties.
* <p/>
* If using a pre-configured <code>Session</code>, non-default properties in this instance will override the
* settings in the <code>Session</code>.
*
* @see #setJavaMailProperties
*/
public void setSession(Session session) {
Assert.notNull(session, "Session must not be null");
this.session = session;
}
/**
* Sets the JavaMail Store URI to be used for retrieving response messages. Typically takes the form of
* <code>[imap|pop3]://user:password@host:port/INBOX</code>. Setting this property is required.
* <p/>
* For example, <code>imap://john:secret@imap.example.com/INBOX</code>
*
* @see Session#getStore(URLName)
*/
public void setStoreUri(String storeUri) {
this.storeUri = new URLName(storeUri);
}
/**
* Sets the JavaMail Transport URI to be used for sending response messages. Typically takes the form of
* <code>smtp://user:password@host:port</code>. Setting this property is required.
* <p/>
* For example, <code>smtp://john:secret@smtp.example.com</code>
*
* @see Session#getTransport(URLName)
*/
public void setTransportUri(String transportUri) {
this.transportUri = new URLName(transportUri);
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(transportUri, "'transportUri' is required");
Assert.notNull(storeUri, "'storeUri' is required");
}
public WebServiceConnection createConnection(URI uri) throws IOException {
InternetAddress to = MailTransportUtils.getTo(uri);
MailSenderConnection connection =
new MailSenderConnection(session, transportUri, storeUri, to, receiveSleepTime);
if (from != null) {
connection.setFrom(from);
}
String subject = MailTransportUtils.getSubject(uri);
if (subject != null) {
connection.setSubject(subject);
}
return connection;
}
public boolean supports(URI uri) {
return uri.getScheme().equals(MailTransportConstants.MAIL_URI_SCHEME);
}
}

View File

@@ -0,0 +1,254 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.mail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Address;
import javax.mail.Header;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.transport.AbstractReceiverConnection;
import org.springframework.ws.transport.TransportConstants;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.mail.support.MailTransportUtils;
/**
* Implementation of {@link WebServiceConnection} that is used for server-side Mail access. Exposes a {@link Message}
* request and response message.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public class MailReceiverConnection extends AbstractReceiverConnection {
private final Message requestMessage;
private final Session session;
private Message responseMessage;
private ByteArrayOutputStream responseBuffer;
private String responseContentType;
private URLName transportUri;
private InternetAddress from;
/** Constructs a new Mail connection with the given parameters. */
protected MailReceiverConnection(Message 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 Message getRequestMessage() {
return requestMessage;
}
/** Returns the response message, if any, for this connection. */
public Message getResponseMessage() {
return responseMessage;
}
/*
* Package-friendly setters
*/
void setTransportUri(URLName transportUri) {
this.transportUri = transportUri;
}
void setFrom(InternetAddress from) {
this.from = from;
}
/*
* URI
*/
public URI getUri() throws URISyntaxException {
try {
Address[] recipients = requestMessage.getRecipients(Message.RecipientType.TO);
if (!ObjectUtils.isEmpty(recipients) && recipients[0] instanceof InternetAddress) {
return MailTransportUtils.toUri((InternetAddress) recipients[0], requestMessage.getSubject());
}
else {
throw new URISyntaxException("", "Could not determine To header");
}
}
catch (MessagingException ex) {
throw new URISyntaxException("", ex.getMessage());
}
}
/*
* Errors
*/
public String getErrorMessage() throws IOException {
return null;
}
public boolean hasError() throws IOException {
return false;
}
/*
* Receiving
*/
@Override
protected Iterator<String> getRequestHeaderNames() throws IOException {
try {
List<String> headers = new ArrayList<String>();
Enumeration<?> enumeration = requestMessage.getAllHeaders();
while (enumeration.hasMoreElements()) {
Header header = (Header) enumeration.nextElement();
headers.add(header.getName());
}
return headers.iterator();
}
catch (MessagingException ex) {
throw new IOException(ex.getMessage());
}
}
@Override
protected Iterator<String> getRequestHeaders(String name) throws IOException {
try {
String[] headers = requestMessage.getHeader(name);
return Arrays.asList(headers).iterator();
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
@Override
protected InputStream getRequestInputStream() throws IOException {
try {
return requestMessage.getInputStream();
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
@Override
protected void addResponseHeader(String name, String value) throws IOException {
try {
responseMessage.addHeader(name, value);
if (TransportConstants.HEADER_CONTENT_TYPE.equals(name)) {
responseContentType = value;
}
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
@Override
protected OutputStream getResponseOutputStream() throws IOException {
return responseBuffer;
}
/*
* Sending
*/
@Override
protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
try {
responseMessage = requestMessage.reply(false);
responseMessage.setFrom(from);
responseBuffer = new ByteArrayOutputStream();
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
@Override
protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
Transport transport = null;
try {
responseMessage.setDataHandler(
new DataHandler(new ByteArrayDataSource(responseContentType, responseBuffer.toByteArray())));
transport = session.getTransport(transportUri);
transport.connect();
responseMessage.saveChanges();
transport.sendMessage(responseMessage, responseMessage.getAllRecipients());
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
finally {
MailTransportUtils.closeService(transport);
}
}
private class ByteArrayDataSource implements DataSource {
private byte[] data;
private String contentType;
public ByteArrayDataSource(String contentType, byte[] data) {
this.data = data;
this.contentType = contentType;
}
public String getContentType() {
return contentType;
}
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(data);
}
public String getName() {
return "ByteArrayDataSource";
}
public OutputStream getOutputStream() throws IOException {
throw new UnsupportedOperationException();
}
}
}

View File

@@ -0,0 +1,337 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.mail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Header;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.search.HeaderTerm;
import javax.mail.search.SearchTerm;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.transport.AbstractSenderConnection;
import org.springframework.ws.transport.TransportConstants;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.mail.support.MailTransportUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Implementation of {@link WebServiceConnection} that is used for client-side Mail access. Exposes a {@link Message}
* request and response message.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public class MailSenderConnection extends AbstractSenderConnection {
private static final Log logger = LogFactory.getLog(MailSenderConnection.class);
private final Session session;
private MimeMessage requestMessage;
private Message responseMessage;
private String requestContentType;
private boolean deleteAfterReceive = false;
private final URLName storeUri;
private final URLName transportUri;
private ByteArrayOutputStream requestBuffer;
private InternetAddress from;
private final InternetAddress to;
private String subject;
private final long receiveTimeout;
private Store store;
private Folder folder;
/** Constructs a new Mail connection with the given parameters. */
protected MailSenderConnection(Session session,
URLName transportUri,
URLName storeUri,
InternetAddress to,
long receiveTimeout) {
Assert.notNull(session, "'session' must not be null");
Assert.notNull(transportUri, "'transportUri' must not be null");
Assert.notNull(storeUri, "'storeUri' must not be null");
Assert.notNull(to, "'to' must not be null");
this.session = session;
this.transportUri = transportUri;
this.storeUri = storeUri;
this.to = to;
this.receiveTimeout = receiveTimeout;
}
/** Returns the request message for this connection. */
public Message getRequestMessage() {
return requestMessage;
}
/** Returns the response message, if any, for this connection. */
public Message getResponseMessage() {
return responseMessage;
}
/*
* Package-friendly setters
*/
void setFrom(InternetAddress from) {
this.from = from;
}
void setSubject(String subject) {
this.subject = subject;
}
/*
* URI
*/
public URI getUri() throws URISyntaxException {
return MailTransportUtils.toUri(to, subject);
}
/*
* Sending
*/
@Override
protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
try {
requestMessage = new MimeMessage(session);
requestMessage.setRecipient(Message.RecipientType.TO, to);
requestMessage.setSentDate(new Date());
if (from != null) {
requestMessage.setFrom(from);
}
if (subject != null) {
requestMessage.setSubject(subject);
}
requestBuffer = new ByteArrayOutputStream();
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
@Override
protected void addRequestHeader(String name, String value) throws IOException {
try {
requestMessage.addHeader(name, value);
if (TransportConstants.HEADER_CONTENT_TYPE.equals(name)) {
requestContentType = value;
}
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
@Override
protected OutputStream getRequestOutputStream() throws IOException {
return requestBuffer;
}
@Override
protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
Transport transport = null;
try {
requestMessage.setDataHandler(
new DataHandler(new ByteArrayDataSource(requestContentType, requestBuffer.toByteArray())));
transport = session.getTransport(transportUri);
transport.connect();
requestMessage.saveChanges();
transport.sendMessage(requestMessage, requestMessage.getAllRecipients());
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
finally {
MailTransportUtils.closeService(transport);
}
}
/*
* Receiving
*/
@Override
protected void onReceiveBeforeRead() throws IOException {
try {
String requestMessageId = requestMessage.getMessageID();
Assert.hasLength(requestMessageId, "No Message-ID found on request message [" + requestMessage + "]");
try {
Thread.sleep(receiveTimeout);
}
catch (InterruptedException e) {
// Re-interrupt current thread, to allow other threads to react.
Thread.currentThread().interrupt();
}
openFolder();
SearchTerm searchTerm = new HeaderTerm(MailTransportConstants.HEADER_IN_REPLY_TO, requestMessageId);
Message[] responses = folder.search(searchTerm);
if (responses.length > 0) {
if (responses.length > 1) {
logger.warn("Received more than one response for request with ID [" + requestMessageId + "]");
}
responseMessage = responses[0];
}
if (deleteAfterReceive) {
responseMessage.setFlag(Flags.Flag.DELETED, true);
}
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
private void openFolder() throws MessagingException {
store = session.getStore(storeUri);
store.connect();
folder = store.getFolder(storeUri);
if (folder == null || !folder.exists()) {
throw new IllegalStateException("No default folder to receive from");
}
if (deleteAfterReceive) {
folder.open(Folder.READ_WRITE);
}
else {
folder.open(Folder.READ_ONLY);
}
}
@Override
protected boolean hasResponse() throws IOException {
return responseMessage != null;
}
@Override
protected Iterator<String> getResponseHeaderNames() throws IOException {
try {
List<String> headers = new ArrayList<String>();
Enumeration<?> enumeration = responseMessage.getAllHeaders();
while (enumeration.hasMoreElements()) {
Header header = (Header) enumeration.nextElement();
headers.add(header.getName());
}
return headers.iterator();
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
@Override
protected Iterator<String> getResponseHeaders(String name) throws IOException {
try {
String[] headers = responseMessage.getHeader(name);
return Arrays.asList(headers).iterator();
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
@Override
protected InputStream getResponseInputStream() throws IOException {
try {
return responseMessage.getDataHandler().getInputStream();
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
public boolean hasError() throws IOException {
return false;
}
public String getErrorMessage() throws IOException {
return null;
}
@Override
public void onClose() throws IOException {
MailTransportUtils.closeFolder(folder, deleteAfterReceive);
MailTransportUtils.closeService(store);
}
private class ByteArrayDataSource implements DataSource {
private byte[] data;
private String contentType;
public ByteArrayDataSource(String contentType, byte[] data) {
this.data = data;
this.contentType = contentType;
}
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(data);
}
public OutputStream getOutputStream() throws IOException {
throw new UnsupportedOperationException();
}
public String getContentType() {
return contentType;
}
public String getName() {
return "ByteArrayDataSource";
}
}
}

View File

@@ -0,0 +1,38 @@
/*
* 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.mail;
import org.springframework.ws.transport.TransportConstants;
/**
* Declares Mail-specific transport constants.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public interface MailTransportConstants extends TransportConstants {
/**
* The "mail" URI scheme.
*/
String MAIL_URI_SCHEME = "mailto";
/**
* The "In-Reply-To" header.
*/
String HEADER_IN_REPLY_TO = "In-Reply-To";
}

View File

@@ -0,0 +1,48 @@
/*
* 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.mail;
import javax.mail.MessagingException;
import org.springframework.ws.transport.TransportException;
/**
* Exception that is thrown when an error occurs in the Mail transport.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public class MailTransportException extends TransportException {
private final MessagingException messagingException;
public MailTransportException(String msg, MessagingException ex) {
super(msg + ": " + ex.getMessage());
initCause(ex);
messagingException = ex;
}
public MailTransportException(MessagingException ex) {
super(ex.getMessage());
initCause(ex);
messagingException = ex;
}
public MessagingException getMessagingException() {
return messagingException;
}
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.mail.monitor;
import javax.mail.FetchProfile;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.search.AndTerm;
import javax.mail.search.FlagTerm;
import javax.mail.search.SearchTerm;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Abstract base class for the {@link MonitoringStrategy} interface. Exposes a {@link #setDeleteMessages(boolean)
* deleteMessages} property, and includes a basic workflow for message monitoring.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public abstract class AbstractMonitoringStrategy implements MonitoringStrategy {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
private boolean deleteMessages = true;
/**
* Sets whether messages should be marked as {@link javax.mail.Flags.Flag#DELETED DELETED} after they have been
* read. Default is <code>true</code>.
*/
public void setDeleteMessages(boolean deleteMessages) {
this.deleteMessages = deleteMessages;
}
public int getFolderOpenMode() {
return deleteMessages ? Folder.READ_WRITE : Folder.READ_ONLY;
}
/**
* Monitors the given folder, and returns any new messages when they arrive. This implementation calls {@link
* #waitForNewMessages(Folder)}, then searches for new messages using {@link #searchForNewMessages(Folder)}, fetches
* the messages using {@link #fetchMessages(Folder, Message[])}, and finally {@link #setDeleteMessages(boolean)
* deletes} the messages, if {@link #setDeleteMessages(boolean) deleteMessages} is <code>true</code>.
*
* @param folder the folder to monitor
* @return the new messages
* @throws MessagingException in case of JavaMail errors
* @throws InterruptedException when a thread is interrupted
*/
public final Message[] monitor(Folder folder) throws MessagingException, InterruptedException {
waitForNewMessages(folder);
Message[] messages = searchForNewMessages(folder);
if (logger.isDebugEnabled()) {
logger.debug("Found " + messages.length + " new messages");
}
if (messages.length > 0) {
fetchMessages(folder, messages);
}
if (deleteMessages) {
deleteMessages(folder, messages);
}
return messages;
}
/**
* Template method that blocks until new messages arrive in the given folder. Typical implementations use {@link
* Thread#sleep(long)} or the IMAP IDLE command.
*
* @param folder the folder to monitor
* @throws MessagingException in case of JavaMail errors
* @throws InterruptedException when a thread is interrupted
*/
protected abstract void waitForNewMessages(Folder folder) throws MessagingException, InterruptedException;
/**
* Retrieves new messages from the given folder. This implementation creates a {@link SearchTerm} that searches for
* all messages in the folder that are {@link javax.mail.Flags.Flag#RECENT RECENT}, not {@link
* javax.mail.Flags.Flag#ANSWERED ANSWERED}, and not {@link javax.mail.Flags.Flag#DELETED DELETED}. The search term
* is used to {@link Folder#search(SearchTerm) search} for new messages.
*
* @param folder the folder to retrieve new messages from
* @return the new messages
* @throws MessagingException in case of JavaMail errors
*/
protected Message[] searchForNewMessages(Folder folder) throws MessagingException {
if (!folder.isOpen()) {
return new Message[0];
}
Flags supportedFlags = folder.getPermanentFlags();
SearchTerm searchTerm = null;
if (supportedFlags != null) {
if (supportedFlags.contains(Flags.Flag.RECENT)) {
searchTerm = new FlagTerm(new Flags(Flags.Flag.RECENT), true);
}
if (supportedFlags.contains(Flags.Flag.ANSWERED)) {
FlagTerm answeredTerm = new FlagTerm(new Flags(Flags.Flag.ANSWERED), false);
if (searchTerm == null) {
searchTerm = answeredTerm;
}
else {
searchTerm = new AndTerm(searchTerm, answeredTerm);
}
}
if (supportedFlags.contains(Flags.Flag.DELETED)) {
FlagTerm deletedTerm = new FlagTerm(new Flags(Flags.Flag.DELETED), false);
if (searchTerm == null) {
searchTerm = deletedTerm;
}
else {
searchTerm = new AndTerm(searchTerm, deletedTerm);
}
}
}
return searchTerm != null ? folder.search(searchTerm) : folder.getMessages();
}
/**
* Fetches the specified messages from the specified folder. Default implementation {@link Folder#fetch(Message[],
* FetchProfile) fetches} every {@link javax.mail.FetchProfile.Item}.
*
* @param folder the folder to fetch messages from
* @param messages the messages to fetch
* @throws MessagingException in case of JavMail errors
*/
protected void fetchMessages(Folder folder, Message[] messages) throws MessagingException {
FetchProfile contentsProfile = new FetchProfile();
contentsProfile.add(FetchProfile.Item.ENVELOPE);
contentsProfile.add(FetchProfile.Item.CONTENT_INFO);
contentsProfile.add(FetchProfile.Item.FLAGS);
folder.fetch(messages, contentsProfile);
}
/**
* Deletes the given messages from the given folder. Only invoked when {@link #setDeleteMessages(boolean)} is
* <code>true</code>.
*
* @param folder the folder to delete messages from
* @param messages the messages to delete
* @throws MessagingException in case of JavaMail errors
*/
protected void deleteMessages(Folder folder, Message[] messages) throws MessagingException {
for (Message message : messages) {
message.setFlag(Flags.Flag.DELETED, true);
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.mail.monitor;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.event.MessageCountAdapter;
import javax.mail.event.MessageCountEvent;
import javax.mail.event.MessageCountListener;
import org.springframework.util.Assert;
import com.sun.mail.imap.IMAPFolder;
/**
* Implementation of the {@link MonitoringStrategy} interface that uses the IMAP IDLE command for asynchronous message
* detection.
* <p/>
* <b>Note</b> that this implementation is only suitable for use with IMAP servers which support the IDLE command.
* Additionally, this strategy requires JavaMail version 1.4.1.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public class ImapIdleMonitoringStrategy extends AbstractMonitoringStrategy {
private MessageCountListener messageCountListener;
@Override
protected void waitForNewMessages(Folder folder) throws MessagingException, InterruptedException {
Assert.isInstanceOf(IMAPFolder.class, folder);
IMAPFolder imapFolder = (IMAPFolder) folder;
// retrieve unseen messages before we enter the blocking idle call
if (searchForNewMessages(folder).length > 0) {
return;
}
if (messageCountListener == null) {
createMessageCountListener();
}
folder.addMessageCountListener(messageCountListener);
try {
imapFolder.idle();
}
finally {
folder.removeMessageCountListener(messageCountListener);
}
}
private void createMessageCountListener() {
messageCountListener = new MessageCountAdapter() {
@Override
public void messagesAdded(MessageCountEvent e) {
Message[] messages = e.getMessages();
for (Message message : messages) {
try {
// this will return the flow to the idle call, above
message.getLineCount();
}
catch (MessagingException ex) {
// ignore
}
}
}
};
}
}

View File

@@ -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.mail.monitor;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
/**
* Defines the contract for objects that monitor a given folder for new messages. Allows for multiple implementation
* strategies, including polling, or event-driven techniques such as IMAP's <code>IDLE</code> command.
*
* @author Arjen Poutsma
*/
public interface MonitoringStrategy {
/**
* Monitors the given folder, and returns any new messages when they arrive.
*
* @param folder the folder in which to look for new messages
* @return the new messages
* @throws MessagingException in case of JavaMail errors
* @throws InterruptedException if a thread is interrupted
*/
Message[] monitor(Folder folder) throws MessagingException, InterruptedException;
/**
* Returns the folder open mode to be used by this strategy. Can be either {@link Folder#READ_ONLY} or {@link
* Folder#READ_WRITE}.
*/
int getFolderOpenMode();
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.mail.monitor;
import javax.mail.Folder;
import javax.mail.MessagingException;
/**
* Implementation of the {@link MonitoringStrategy} interface that uses a simple polling mechanism. Defines a {@link
* #setPollingInterval(long) polling interval} property which defines the interval in between message polls.
* <p/>
* <b>Note</b> that this implementation is not suitable for use with POP3 servers. Use the {@link
* Pop3PollingMonitoringStrategy} instead.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public class PollingMonitoringStrategy extends AbstractMonitoringStrategy {
/** Defines the default polling frequency. Set to 1000 * 60 milliseconds (i.e. 1 minute). */
public static final long DEFAULT_POLLING_FREQUENCY = 1000 * 60;
private long pollingInterval = DEFAULT_POLLING_FREQUENCY;
/**
* Sets the interval used in between message polls, <strong>in milliseconds</strong>. The default is 1000 * 60 ms,
* that is 1 minute.
*/
public void setPollingInterval(long pollingInterval) {
this.pollingInterval = pollingInterval;
}
@Override
protected void waitForNewMessages(Folder folder) throws MessagingException, InterruptedException {
Thread.sleep(pollingInterval);
afterSleep(folder);
}
/**
* Invoked after the {@link Thread#sleep(long)} method has been invoked. This implementation calls {@link
* Folder#getMessageCount()}, to force new messages to be seen.
*
* @param folder the folder to check for new messages
* @throws MessagingException in case of JavaMail errors
*/
protected void afterSleep(Folder folder) throws MessagingException {
folder.getMessageCount();
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.mail.monitor;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.springframework.ws.transport.mail.support.MailTransportUtils;
/**
* Implementation of the {@link MonitoringStrategy} interface that uses a simple polling mechanism suitable for POP3
* servers. Since POP3 does not have a native mechanism to determine which messages are "new", this implementation
* simply retrieves all messages in the {@link Folder}, and delete them afterwards. All messages in the POP3 mailbox are
* therefore, by definition, new.
* <p/>
* Setting the {@link #setDeleteMessages(boolean) deleteMessages} property is therefore ignored: messages are always
* deleted.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public class Pop3PollingMonitoringStrategy extends PollingMonitoringStrategy {
public Pop3PollingMonitoringStrategy() {
super.setDeleteMessages(true);
}
@Override
public void setDeleteMessages(boolean deleteMessages) {
}
/**
* Re-opens the folder, if it closed.
*/
@Override
protected void afterSleep(Folder folder) throws MessagingException {
if (!folder.isOpen()) {
folder.open(Folder.READ_WRITE);
}
}
/**
* Simply returns {@link Folder#getMessages()}.
*/
@Override
protected Message[] searchForNewMessages(Folder folder) throws MessagingException {
return folder.getMessages();
}
/**
* Deletes the given messages from the given folder, and closes it to expunge deleted messages.
*
* @param folder the folder to delete messages from
* @param messages the messages to delete
* @throws MessagingException in case of JavaMail errors
*/
@Override
protected void deleteMessages(Folder folder, Message[] messages) throws MessagingException {
super.deleteMessages(folder, messages);
// expunge deleted mails, and make sure we've retrieved them before closing the folder
for (Message message : messages) {
new MimeMessage((MimeMessage) message);
}
MailTransportUtils.closeFolder(folder, true);
}
}

View File

@@ -0,0 +1,6 @@
<html>
<body>
Provides the MonitoringStrategy interface and implementations. Used for monitoring a JavaMail Folder for new email
messages.
</body>
</html>

View File

@@ -0,0 +1,5 @@
<html>
<body>
Package providing support for handling messages via email.
</body>
</html>

View File

@@ -0,0 +1,188 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.mail.support;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.mail.Folder;
import javax.mail.MessagingException;
import javax.mail.Service;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.URLName;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import org.springframework.util.StringUtils;
import org.springframework.ws.transport.mail.MailTransportConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Collection of utility methods to work with Mail transports.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public abstract class MailTransportUtils {
private static final Pattern TO_PATTERN = Pattern.compile("^([^\\?]+)");
private static final Pattern SUBJECT_PATTERN = Pattern.compile("subject=([^\\&]+)");
private static final Log logger = LogFactory.getLog(MailTransportUtils.class);
private MailTransportUtils() {
}
public static InternetAddress getTo(URI uri) {
Matcher matcher = TO_PATTERN.matcher(uri.getSchemeSpecificPart());
if (matcher.find()) {
for (int i = 1; i <= matcher.groupCount(); i++) {
String group = matcher.group(i);
if (group != null) {
try {
return new InternetAddress(group);
}
catch (AddressException e) {
// try next group
}
}
}
}
return null;
}
public static String getSubject(URI uri) {
Matcher matcher = SUBJECT_PATTERN.matcher(uri.getSchemeSpecificPart());
if (matcher.find()) {
return matcher.group(1);
}
return null;
}
/**
* Close the given JavaMail Service and ignore any thrown exception. This is useful for typical <code>finally</code>
* blocks in manual JavaMail code.
*
* @param service the JavaMail Service to close (may be <code>null</code>)
* @see Transport
* @see Store
*/
public static void closeService(Service service) {
if (service != null) {
try {
service.close();
}
catch (MessagingException ex) {
logger.debug("Could not close JavaMail Service", ex);
}
}
}
/**
* Close the given JavaMail Folder and ignore any thrown exception. This is useful for typical <code>finally</code>
* blocks in manual JavaMail code.
*
* @param folder the JavaMail Folder to close (may be <code>null</code>)
*/
public static void closeFolder(Folder folder) {
closeFolder(folder, false);
}
/**
* Close the given JavaMail Folder and ignore any thrown exception. This is useful for typical <code>finally</code>
* blocks in manual JavaMail code.
*
* @param folder the JavaMail Folder to close (may be <code>null</code>)
* @param expunge whether all deleted messages should be expunged from the folder
*/
public static void closeFolder(Folder folder, boolean expunge) {
if (folder != null && folder.isOpen()) {
try {
folder.close(expunge);
}
catch (MessagingException ex) {
logger.debug("Could not close JavaMail Folder", ex);
}
}
}
/** Returns a string representation of the given {@link URLName}, where the password has been protected. */
public static String toPasswordProtectedString(URLName name) {
String protocol = name.getProtocol();
String username = name.getUsername();
String password = name.getPassword();
String host = name.getHost();
int port = name.getPort();
String file = name.getFile();
String ref = name.getRef();
StringBuilder tempURL = new StringBuilder();
if (protocol != null) {
tempURL.append(protocol).append(':');
}
if (StringUtils.hasLength(username) || StringUtils.hasLength(host)) {
tempURL.append("//");
if (StringUtils.hasLength(username)) {
tempURL.append(username);
if (StringUtils.hasLength(password)) {
tempURL.append(":*****");
}
tempURL.append("@");
}
if (StringUtils.hasLength(host)) {
tempURL.append(host);
}
if (port != -1) {
tempURL.append(':').append(Integer.toString(port));
}
if (StringUtils.hasLength(file)) {
tempURL.append('/');
}
}
if (StringUtils.hasLength(file)) {
tempURL.append(file);
}
if (StringUtils.hasLength(ref)) {
tempURL.append('#').append(ref);
}
return tempURL.toString();
}
/**
* Converts the given internet address into a <code>mailto</code> URI.
*
* @param to the To: address
* @param subject the subject, may be <code>null</code>
* @return a mailto URI
*/
public static URI toUri(InternetAddress to, String subject) throws URISyntaxException {
if (StringUtils.hasLength(subject)) {
return new URI(MailTransportConstants.MAIL_URI_SCHEME, to.getAddress() + "?subject=" + subject, null);
}
else {
return new URI(MailTransportConstants.MAIL_URI_SCHEME, to.getAddress(), null);
}
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Classes supporting the org.springframework.ws.transport.mail package.
</body>
</html>

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.support;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.util.ClassUtils;
/**
* Abstract base class for asynchronous standalone, server-side transport objects. Contains a Spring {@link
* TaskExecutor}, and various lifecycle callbacks.
*
* @author Arjen Poutsma
*/
public abstract class AbstractAsyncStandaloneMessageReceiver extends AbstractStandaloneMessageReceiver
implements BeanNameAware {
/** Default thread name prefix. */
public final String DEFAULT_THREAD_NAME_PREFIX = ClassUtils.getShortName(getClass()) + "-";
private TaskExecutor taskExecutor;
private String beanName;
/**
* Set the Spring {@link TaskExecutor} to use for running the listener threads. Default is {@link
* SimpleAsyncTaskExecutor}, starting up a number of new threads.
* <p/>
* Specify an alternative task executor for integration with an existing thread pool, such as the {@link
* org.springframework.scheduling.commonj.WorkManagerTaskExecutor} to integrate with WebSphere or WebLogic.
*/
public void setTaskExecutor(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
@Override
public void afterPropertiesSet() throws Exception {
if (taskExecutor == null) {
taskExecutor = createDefaultTaskExecutor();
}
super.afterPropertiesSet();
}
/**
* Create a default TaskExecutor. Called if no explicit TaskExecutor has been specified.
* <p/>
* The default implementation builds a {@link org.springframework.core.task.SimpleAsyncTaskExecutor} with the
* specified bean name (or the class name, if no bean name specified) as thread name prefix.
*
* @see org.springframework.core.task.SimpleAsyncTaskExecutor#SimpleAsyncTaskExecutor(String)
*/
protected TaskExecutor createDefaultTaskExecutor() {
String threadNamePrefix = beanName != null ? beanName + "-" : DEFAULT_THREAD_NAME_PREFIX;
return new SimpleAsyncTaskExecutor(threadNamePrefix);
}
/**
* Executes the given {@link Runnable} via this receiver's {@link TaskExecutor}.
*
* @see #setTaskExecutor(TaskExecutor)
*/
protected void execute(Runnable runnable) {
taskExecutor.execute(runnable);
}
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.support;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.Lifecycle;
/**
* Abstract base class for standalone, server-side transport objects. Provides a basic, thread-safe implementation of
* the {@link Lifecycle} interface, and various template methods to be implemented by concrete sub classes.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public abstract class AbstractStandaloneMessageReceiver extends SimpleWebServiceMessageReceiverObjectSupport
implements Lifecycle, DisposableBean {
private volatile boolean active = false;
private boolean autoStartup = true;
private boolean running = false;
private final Object lifecycleMonitor = new Object();
/** Return whether this server is currently active, that is, whether it has been set up but not shut down yet. */
public final boolean isActive() {
synchronized (lifecycleMonitor) {
return active;
}
}
/** Return whether this server is currently running, that is, whether it has been started and not stopped yet. */
public final boolean isRunning() {
synchronized (lifecycleMonitor) {
return running;
}
}
/**
* Set whether to automatically start the receiver after initialization.
* <p/>
* Default is <code>true</code>; set this to <code>false</code> to allow for manual startup.
*/
public void setAutoStartup(boolean autoStartup) {
this.autoStartup = autoStartup;
}
/** Calls {@link #activate()} when the BeanFactory initializes the receiver instance. */
@Override
public void afterPropertiesSet() throws Exception {
activate();
}
/** Calls {@link #shutdown()} when the BeanFactory destroys the receiver instance. */
public void destroy() {
shutdown();
}
/**
* Initialize this server. Starts the server if {@link #setAutoStartup(boolean) autoStartup} hasn't been turned
* off.
*/
public final void activate() throws Exception {
synchronized (lifecycleMonitor) {
active = true;
}
onActivate();
if (autoStartup) {
start();
}
}
/** Start this server. */
public final void start() {
synchronized (lifecycleMonitor) {
running = true;
}
onStart();
}
/** Stop this server. */
public final void stop() {
synchronized (lifecycleMonitor) {
running = false;
}
onStop();
}
/** Shut down this server. */
public final void shutdown() {
synchronized (lifecycleMonitor) {
running = false;
active = false;
}
onShutdown();
}
/**
* Template method invoked when {@link #activate()} is invoked.
*
* @throws Exception in case of errors
*/
protected abstract void onActivate() throws Exception;
/** Template method invoked when {@link #start()} is invoked. */
protected abstract void onStart();
/** Template method invoked when {@link #stop()} is invoked. */
protected abstract void onStop();
/** Template method invoked when {@link #shutdown()} is invoked. */
protected abstract void onShutdown();
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.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.5.0
*/
public abstract class SimpleWebServiceMessageReceiverObjectSupport extends WebServiceMessageReceiverObjectSupport
implements InitializingBean {
private WebServiceMessageReceiver messageReceiver;
/**
* Returns the <code>WebServiceMessageReceiver</code> used by this listener.
*/
public WebServiceMessageReceiver getMessageReceiver() {
return messageReceiver;
}
/**
* Sets the <code>WebServiceMessageReceiver</code> used by this listener.
*/
public void setMessageReceiver(WebServiceMessageReceiver messageReceiver) {
this.messageReceiver = messageReceiver;
}
@Override
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());
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.xmpp;
import java.io.ByteArrayInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.util.Assert;
import org.jivesoftware.smack.packet.Message;
/**
* Input stream that wraps a {@link Message}.
*
* @author Gildas Cuisinier
* @author Arjen Poutsma
* @since 2.0
*/
class MessageInputStream extends FilterInputStream {
MessageInputStream(Message message, String encoding) throws IOException {
super(createInputStream(message, encoding));
}
private static InputStream createInputStream(Message message, String encoding) throws IOException {
Assert.notNull(message, "'message' must not be null");
Assert.notNull(encoding, "'encoding' must not be null");
String text = message.getBody();
byte[] contents = text != null ? text.getBytes(encoding) : new byte[0];
return new ByteArrayInputStream(contents);
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.xmpp;
import java.io.ByteArrayOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import org.springframework.util.Assert;
import org.jivesoftware.smack.packet.Message;
/**
* Output stream that wraps a {@link Message}.
*
* @author Gildas Cuisinier
* @author Arjen Poutsma
* @since 2.0
*/
class MessageOutputStream extends FilterOutputStream {
private final Message message;
private final String encoding;
MessageOutputStream(Message message, String encoding) {
super(new ByteArrayOutputStream());
Assert.notNull(message, "'message' must not be null");
Assert.notNull(encoding, "'encoding' must not be null");
this.message = message;
this.encoding = encoding;
}
@Override
public void flush() throws IOException {
super.flush();
ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
String text = new String(bos.toByteArray(), encoding);
message.setBody(text);
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.xmpp;
import org.springframework.ws.transport.support.AbstractStandaloneMessageReceiver;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
/**
* Server-side component for receiving XMPP (Jabber) messages. Requires a {@linkplain #setConnection(XMPPConnection)
* connection} to be set, in addition to the {@link #setMessageFactory(org.springframework.ws.WebServiceMessageFactory)
* messageFactory} and {@link #setMessageReceiver(org.springframework.ws.transport.WebServiceMessageReceiver)
* messageReceiver} required by the base class.
*
* @author Gildas Cuisinier
* @author Arjen Poutsma
* @see org.springframework.ws.transport.xmpp.support.XmppConnectionFactoryBean
* @since 2.0
*/
public class XmppMessageReceiver extends AbstractStandaloneMessageReceiver {
/** Default encoding used to read from and write to {@link org.jivesoftware.smack.packet.Message} messages. */
public static final String DEFAULT_MESSAGE_ENCODING = "UTF-8";
private XMPPConnection connection;
private WebServicePacketListener packetListener;
private String messageEncoding = DEFAULT_MESSAGE_ENCODING;
public XmppMessageReceiver() {
}
/** Sets the {@code XMPPConnection} to use. Setting this property is required. */
public void setConnection(XMPPConnection connection) {
this.connection = connection;
}
@Override
protected void onActivate() throws XMPPException {
if (!connection.isConnected()) {
connection.connect();
}
}
@Override
protected void onStart() {
if (logger.isInfoEnabled()) {
logger.info("Starting XMPP receiver [" + connection.getUser() + "]");
}
packetListener = new WebServicePacketListener();
PacketFilter packetFilter = new PacketTypeFilter(Message.class);
connection.addPacketListener(packetListener, packetFilter);
}
@Override
protected void onStop() {
if (logger.isInfoEnabled()) {
logger.info("Stopping XMPP receiver [" + connection.getUser() + "]");
}
connection.removePacketListener(packetListener);
packetListener = null;
}
@Override
protected void onShutdown() {
if (logger.isInfoEnabled()) {
logger.info("Shutting down XMPP receiver [" + connection.getUser() + "]");
}
if (connection.isConnected()) {
connection.disconnect();
}
}
private class WebServicePacketListener implements PacketListener {
public void processPacket(Packet packet) {
logger.info("Received " + packet);
if (packet instanceof Message) {
Message message = (Message) packet;
try {
XmppReceiverConnection wsConnection = new XmppReceiverConnection(connection, message);
wsConnection.setMessageEncoding(messageEncoding);
handleConnection(wsConnection);
}
catch (Exception ex) {
logger.error(ex);
}
}
}
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.xmpp;
import java.io.IOException;
import java.net.URI;
import java.util.UUID;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.ws.transport.xmpp.support.XmppTransportUtils;
import org.jivesoftware.smack.XMPPConnection;
/**
* {@link WebServiceMessageSender} implementation that uses XMPP {@link org.jivesoftware.smack.packet.Message}s.
* Requires a {@link #setConnection(org.jivesoftware.smack.XMPPConnection) connection}to be set.
* <p/>
* This message sender supports URI's of the following format: <blockquote> <tt><b>xmpp:</b></tt><i>to</i> </blockquote>
* The <i>to</i> represents a Jabber ID.
*
* @author Gildas Cuisinier
* @author Arjen Poutsma
* @since 2.0
*/
public class XmppMessageSender implements WebServiceMessageSender, InitializingBean {
/** Default timeout for receive operations: -1 indicates a blocking receive without timeout. */
public static final long DEFAULT_RECEIVE_TIMEOUT = -1;
/** Default encoding used to read from and write to {@link org.jivesoftware.smack.packet.Message} messages. */
public static final String DEFAULT_MESSAGE_ENCODING = "UTF-8";
private long receiveTimeout = DEFAULT_RECEIVE_TIMEOUT;
private String messageEncoding = DEFAULT_MESSAGE_ENCODING;
private XMPPConnection connection;
/** Sets the {@code XMPPConnection}. Setting this property is required. */
public void setConnection(XMPPConnection connection) {
this.connection = connection;
}
/**
* Set the timeout to use for receive calls. The default is -1, which means no timeout.
*
* @see org.jivesoftware.smack.PacketCollector#nextResult(long)
*/
public void setReceiveTimeout(long receiveTimeout) {
this.receiveTimeout = receiveTimeout;
}
/**
* Sets the encoding used to read from {@link org.jivesoftware.smack.packet.Message} object. Defaults to
* <code>UTF-8</code>.
*/
public void setMessageEncoding(String messageEncoding) {
this.messageEncoding = messageEncoding;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(connection, "'connection' is required");
}
public WebServiceConnection createConnection(URI uri) throws IOException {
String to = XmppTransportUtils.getTo(uri);
String thread = createThread();
XmppSenderConnection connection = new XmppSenderConnection(this.connection, to, thread);
connection.setReceiveTimeout(receiveTimeout);
connection.setMessageEncoding(messageEncoding);
return connection;
}
public boolean supports(URI uri) {
return uri.getScheme().equals(XmppTransportConstants.XMPP_URI_SCHEME);
}
protected String createThread() {
return UUID.randomUUID().toString();
}
}

View File

@@ -0,0 +1,141 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.xmpp;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.transport.AbstractReceiverConnection;
import org.springframework.ws.transport.xmpp.support.XmppTransportUtils;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.Message;
/**
* Implementation of {@link org.springframework.ws.transport.WebServiceConnection} that is used for server-side XMPP
* access. Exposes a {@link Message} request and response message.
*
* @author Gildas Cuisinier
* @author Arjen Poutsma
* @since 2.0
*/
public class XmppReceiverConnection extends AbstractReceiverConnection {
private final XMPPConnection connection;
private final Message requestMessage;
private Message responseMessage;
private String messageEncoding;
public XmppReceiverConnection(XMPPConnection connection, Message requestMessage) {
Assert.notNull(connection, "'connection' must not be null");
Assert.notNull(requestMessage, "'requestMessage' must not be null");
this.connection = connection;
this.requestMessage = requestMessage;
}
/** Returns the request message for this connection. */
public Message getRequestMessage() {
return requestMessage;
}
/** Returns the response message, if any, for this connection. */
public Message getResponseMessage() {
return responseMessage;
}
/*
* Package-friendly setters
*/
void setMessageEncoding(String messageEncoding) {
this.messageEncoding = messageEncoding;
}
/*
* URI
*/
public URI getUri() throws URISyntaxException {
return XmppTransportUtils.toUri(requestMessage);
}
/*
* Errors
*/
public boolean hasError() {
return XmppTransportUtils.hasError(responseMessage);
}
public String getErrorMessage() {
return XmppTransportUtils.getErrorMessage(responseMessage);
}
/*
* Receiving
*/
@Override
protected Iterator<String> getRequestHeaderNames() throws IOException {
return XmppTransportUtils.getHeaderNames(requestMessage);
}
@Override
protected Iterator<String> getRequestHeaders(String name) throws IOException {
return XmppTransportUtils.getHeaders(requestMessage, name);
}
@Override
protected InputStream getRequestInputStream() throws IOException {
return new MessageInputStream(requestMessage, messageEncoding);
}
/*
* Sending
*/
@Override
protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
responseMessage = new Message(requestMessage.getFrom(), Message.Type.chat);
responseMessage.setFrom(connection.getUser());
responseMessage.setThread(requestMessage.getThread());
}
@Override
protected void addResponseHeader(String name, String value) throws IOException {
XmppTransportUtils.addHeader(responseMessage, name, value);
}
@Override
protected OutputStream getResponseOutputStream() throws IOException {
return new MessageOutputStream(responseMessage, messageEncoding);
}
@Override
protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
connection.sendPacket(responseMessage);
}
}

View File

@@ -0,0 +1,177 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.xmpp;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.transport.AbstractSenderConnection;
import org.springframework.ws.transport.xmpp.support.XmppTransportUtils;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.filter.ThreadFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
/**
* Implementation of {@link org.springframework.ws.transport.WebServiceConnection} that is used for client-side XMPP
* access. Exposes a {@link Message} request and response message.
*
* @author Gildas Cuisinier
* @author Arjen Poutsma
* @since 2.0
*/
public class XmppSenderConnection extends AbstractSenderConnection {
private final Message requestMessage;
private final XMPPConnection connection;
private Message responseMessage;
private String messageEncoding;
private long receiveTimeout;
protected XmppSenderConnection(XMPPConnection connection, String to, String thread) {
Assert.notNull(connection, "'connection' must not be null");
Assert.hasLength(to, "'to' must not be empty");
Assert.hasLength(thread, "'thread' must not be empty");
this.connection = connection;
this.requestMessage = new Message(to, Message.Type.chat);
this.requestMessage.setThread(thread);
}
/** Returns the request message for this connection. */
public Message getRequestMessage() {
return requestMessage;
}
/** Returns the response message, if any, for this connection. */
public Message getResponseMessage() {
return responseMessage;
}
/*
* Package-friendly setters
*/
void setMessageEncoding(String messageEncoding) {
this.messageEncoding = messageEncoding;
}
void setReceiveTimeout(long receiveTimeout) {
this.receiveTimeout = receiveTimeout;
}
/*
* URI
*/
public URI getUri() throws URISyntaxException {
return XmppTransportUtils.toUri(requestMessage);
}
/*
* Errors
*/
public boolean hasError() {
return XmppTransportUtils.hasError(responseMessage);
}
public String getErrorMessage() {
return XmppTransportUtils.getErrorMessage(responseMessage);
}
/*
* Sending
*/
@Override
protected void addRequestHeader(String name, String value) {
XmppTransportUtils.addHeader(requestMessage, name, value);
}
@Override
protected OutputStream getRequestOutputStream() throws IOException {
return new MessageOutputStream(requestMessage, messageEncoding);
}
@Override
protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
requestMessage.setFrom(connection.getUser());
connection.sendPacket(requestMessage);
}
/*
* Receiving
*/
@Override
protected void onReceiveBeforeRead() throws IOException {
PacketFilter packetFilter = createPacketFilter();
PacketCollector collector = connection.createPacketCollector(packetFilter);
Packet packet = receiveTimeout >= 0 ? collector.nextResult(receiveTimeout) : collector.nextResult();
if (packet instanceof Message) {
responseMessage = (Message) packet;
}
else if (packet != null) {
throw new IllegalArgumentException(
"Wrong packet type: [" + packet.getClass() + "]. Only Messages can be handled.");
}
}
private PacketFilter createPacketFilter() {
AndFilter andFilter = new AndFilter();
andFilter.addFilter(new PacketTypeFilter(Message.class));
andFilter.addFilter(new ThreadFilter(requestMessage.getThread()));
return andFilter;
}
@Override
protected boolean hasResponse() throws IOException {
return responseMessage != null;
}
@Override
protected Iterator<String> getResponseHeaderNames() {
return XmppTransportUtils.getHeaderNames(responseMessage);
}
@Override
protected Iterator<String> getResponseHeaders(String name) throws IOException {
return XmppTransportUtils.getHeaders(responseMessage, name);
}
@Override
protected InputStream getResponseInputStream() throws IOException {
return new MessageInputStream(responseMessage, messageEncoding);
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.xmpp;
import org.springframework.ws.transport.TransportConstants;
/**
* Declares XMPP-specific transport constants.
*
* @author Arjen Poutsma
* @since 2.0
*/
public interface XmppTransportConstants extends TransportConstants {
/**
* The "xmpp" URI scheme.
*/
String XMPP_URI_SCHEME = "xmpp";
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Package providing support for handling messages via xmpp.
</body>
</html>

View File

@@ -0,0 +1,136 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.xmpp.support;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
/**
* Factory to make {@link org.jivesoftware.smack.XMPPConnection} and perform connection and login on the XMPP server
*
* @author Gildas Cuisinier
* @author Arjen Poutsma
* @since 2.0
*/
public class XmppConnectionFactoryBean implements FactoryBean<XMPPConnection>, InitializingBean, DisposableBean {
private static final int DEFAULT_PORT = 5222;
private XMPPConnection connection;
private String host;
private int port = DEFAULT_PORT;
private String serviceName;
private String username;
private String password;
private String resource;
/** Sets the server host to connect to. */
public void setHost(String host) {
this.host = host;
}
/**
* Sets the the server port to connect to.
* <p/>
* Defaults to {@code 5222}.
*/
public void setPort(int port) {
Assert.isTrue(port > 0, "'port' must be larger than 0");
this.port = port;
}
/** Sets the service name to connect to. */
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setResource(String resource) {
this.resource = resource;
}
public void afterPropertiesSet() throws XMPPException {
ConnectionConfiguration configuration = createConnectionConfiguration(host, port, serviceName);
Assert.notNull(configuration, "'configuration' must not be null");
Assert.hasText(username, "'username' must not be empty");
Assert.hasText(password, "'password' must not be empty");
connection = new XMPPConnection(configuration);
connection.connect();
if (StringUtils.hasText(resource)) {
connection.login(username, password, resource);
}
else {
connection.login(username, password);
}
}
public void destroy() {
connection.disconnect();
}
public XMPPConnection getObject() {
return connection;
}
public Class<XMPPConnection> getObjectType() {
return XMPPConnection.class;
}
public boolean isSingleton() {
return true;
}
/**
* Creates the {@code ConnectionConfiguration} from the given parameters.
*
* @param host the host to connect to
* @param port the port to connect to
* @param serviceName the name of the service to connect to. May be {@code null}
*/
protected ConnectionConfiguration createConnectionConfiguration(String host, int port, String serviceName) {
Assert.hasText(host, "'host' must not be empty");
if (StringUtils.hasText(serviceName)) {
return new ConnectionConfiguration(host, port, serviceName);
}
else {
return new ConnectionConfiguration(host, port);
}
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.xmpp.support;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Iterator;
import org.springframework.util.Assert;
import org.springframework.ws.transport.xmpp.XmppTransportConstants;
import org.jivesoftware.smack.packet.Message;
/**
* Collection of utility methods to work with Mail transports.
*
* @author Arjen Poutsma
* @since 2.0
*/
public abstract class XmppTransportUtils {
private XmppTransportUtils() {
}
/**
* Converts the given XMPP destination into a <code>xmpp</code> URI.
*/
public static URI toUri(Message requestMessage) throws URISyntaxException {
return new URI(XmppTransportConstants.XMPP_URI_SCHEME, requestMessage.getTo(), null);
}
public static String getTo(URI uri) {
return uri.getSchemeSpecificPart();
}
public static boolean hasError(Message message) {
return message != null && Message.Type.error.equals(message.getType());
}
public static String getErrorMessage(Message message) {
if (message == null || !Message.Type.error.equals(message.getType())) {
return null;
}
else {
return message.getBody();
}
}
public static void addHeader(Message message, String name, String value) {
message.setProperty(name, value);
}
public static Iterator<String> getHeaderNames(Message message) {
Assert.notNull(message, "'message' must not be null");
return message.getPropertyNames().iterator();
}
public static Iterator<String> getHeaders(Message message, String name) {
Assert.notNull(message, "'message' must not be null");
String value = message.getProperty(name).toString();
if (value != null) {
return Collections.singletonList(value).iterator();
}
else {
return Collections.<String>emptyList().iterator();
}
}
}

View File

@@ -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.util.Assert;
import org.springframework.ws.context.MessageContext;
import org.springframework.xml.transform.TransformerObjectSupport;
public class SimpleTestingMessageReceiver extends TransformerObjectSupport implements WebServiceMessageReceiver {
public void receive(MessageContext messageContext) throws Exception {
Assert.notNull(messageContext, "MessageContext is null");
logger.info("Received " + messageContext.getRequest());
Transformer transformer = createTransformer();
transformer.transform(messageContext.getRequest().getPayloadSource(),
messageContext.getResponse().getPayloadResult());
}
}

View File

@@ -0,0 +1,31 @@
/*
* 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.http;
import java.util.Locale;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MessageEndpoint;
import org.springframework.ws.soap.SoapMessage;
public class FaultEndpoint implements MessageEndpoint {
public void invoke(MessageContext messageContext) throws Exception {
SoapMessage response = (SoapMessage) messageContext.getResponse();
response.getSoapBody().addServerOrReceiverFault("Something went wrong", Locale.ENGLISH);
}
}

View File

@@ -0,0 +1,27 @@
/*
* 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.http;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MessageEndpoint;
/** @author Arjen Poutsma */
public class NoResponseEndpoint implements MessageEndpoint {
public void invoke(MessageContext messageContext) throws Exception {
}
}

View File

@@ -0,0 +1,28 @@
/*
* 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.http;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MessageEndpoint;
/** @author Arjen Poutsma */
public class ResponseEndpoint implements MessageEndpoint {
public void invoke(MessageContext messageContext) throws Exception {
messageContext.getResponse();
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.http;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.ws.transport.TransportConstants;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("httpserver-applicationContext.xml")
public class WebServiceHttpHandlerIntegrationTest {
private HttpClient client;
@Autowired
private int port;
private String url;
@Before
public void createHttpClient() throws Exception {
client = new HttpClient();
url = "http://localhost:" + port + "/service";
}
@Test
public void testInvalidMethod() throws IOException {
GetMethod getMethod = new GetMethod(url);
client.executeMethod(getMethod);
assertEquals("Invalid Response Code", HttpTransportConstants.STATUS_METHOD_NOT_ALLOWED,
getMethod.getStatusCode());
assertEquals("Response retrieved", 0, getMethod.getResponseContentLength());
}
@Test
public void testNoResponse() throws IOException {
PostMethod postMethod = new PostMethod(url);
postMethod.addRequestHeader(HttpTransportConstants.HEADER_CONTENT_TYPE, "text/xml");
postMethod.addRequestHeader(TransportConstants.HEADER_SOAP_ACTION,
"http://springframework.org/spring-ws/NoResponse");
Resource soapRequest = new ClassPathResource("soapRequest.xml", WebServiceHttpHandlerIntegrationTest.class);
postMethod.setRequestEntity(new InputStreamRequestEntity(soapRequest.getInputStream()));
client.executeMethod(postMethod);
assertEquals("Invalid Response Code", HttpTransportConstants.STATUS_ACCEPTED, postMethod.getStatusCode());
assertEquals("Response retrieved", 0, postMethod.getResponseContentLength());
}
@Test
public void testResponse() throws IOException {
PostMethod postMethod = new PostMethod(url);
postMethod.addRequestHeader(HttpTransportConstants.HEADER_CONTENT_TYPE, "text/xml");
postMethod.addRequestHeader(TransportConstants.HEADER_SOAP_ACTION,
"http://springframework.org/spring-ws/Response");
Resource soapRequest = new ClassPathResource("soapRequest.xml", WebServiceHttpHandlerIntegrationTest.class);
postMethod.setRequestEntity(new InputStreamRequestEntity(soapRequest.getInputStream()));
client.executeMethod(postMethod);
assertEquals("Invalid Response Code", HttpTransportConstants.STATUS_OK, postMethod.getStatusCode());
assertTrue("No Response retrieved", postMethod.getResponseContentLength() > 0);
}
@Test
public void testNoEndpoint() throws IOException {
PostMethod postMethod = new PostMethod(url);
postMethod.addRequestHeader(HttpTransportConstants.HEADER_CONTENT_TYPE, "text/xml");
postMethod.addRequestHeader(TransportConstants.HEADER_SOAP_ACTION,
"http://springframework.org/spring-ws/NoEndpoint");
Resource soapRequest = new ClassPathResource("soapRequest.xml", WebServiceHttpHandlerIntegrationTest.class);
postMethod.setRequestEntity(new InputStreamRequestEntity(soapRequest.getInputStream()));
client.executeMethod(postMethod);
assertEquals("Invalid Response Code", HttpTransportConstants.STATUS_NOT_FOUND, postMethod.getStatusCode());
assertEquals("Response retrieved", 0, postMethod.getResponseContentLength());
}
@Test
public void testFault() throws IOException {
PostMethod postMethod = new PostMethod(url);
postMethod.addRequestHeader(HttpTransportConstants.HEADER_CONTENT_TYPE, "text/xml");
postMethod
.addRequestHeader(TransportConstants.HEADER_SOAP_ACTION, "http://springframework.org/spring-ws/Fault");
Resource soapRequest = new ClassPathResource("soapRequest.xml", WebServiceHttpHandlerIntegrationTest.class);
postMethod.setRequestEntity(new InputStreamRequestEntity(soapRequest.getInputStream()));
client.executeMethod(postMethod);
assertEquals("Invalid Response Code", HttpTransportConstants.STATUS_INTERNAL_SERVER_ERROR,
postMethod.getStatusCode());
assertTrue("No Response retrieved", postMethod.getResponseContentLength() > 0);
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
import org.custommonkey.xmlunit.XMLAssert;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("jms-applicationContext.xml")
public class JmsIntegrationTest {
@Autowired
private WebServiceTemplate webServiceTemplate;
public void setWebServiceTemplate(WebServiceTemplate webServiceTemplate) {
this.webServiceTemplate = webServiceTemplate;
}
@Test
public void testTemporaryQueue() throws Exception {
String content = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
StringResult result = new StringResult();
webServiceTemplate.sendSourceAndReceiveToResult(new StringSource(content), result);
XMLAssert.assertXMLEqual("Invalid content received", content, result.toString());
}
@Test
public void testPermanentQueue() throws Exception {
String url = "jms:RequestQueue?deliveryMode=NON_PERSISTENT;replyToName=ResponseQueue";
String content = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
StringResult result = new StringResult();
webServiceTemplate.sendSourceAndReceiveToResult(url, new StringSource(content), result);
XMLAssert.assertXMLEqual("Invalid content received", content, result.toString());
}
}

View File

@@ -0,0 +1,237 @@
/*
* Copyright 2005-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
import java.io.ByteArrayOutputStream;
import java.net.URI;
import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.core.MessagePostProcessor;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.SoapVersion;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
import org.springframework.ws.transport.WebServiceConnection;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("jms-sender-applicationContext.xml")
public class JmsMessageSenderIntegrationTest {
@Autowired
private JmsMessageSender messageSender;
@Autowired
private JmsTemplate jmsTemplate;
private MessageFactory messageFactory;
private static final String SOAP_ACTION = "\"http://springframework.org/DoIt\"";
@Before
public void createMessageFactory() throws Exception {
messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
}
@Test
public void testSendAndReceiveQueueBytesMessageTemporaryQueue() throws Exception {
WebServiceConnection connection = null;
try {
URI uri = new URI("jms:SenderRequestQueue?deliveryMode=NON_PERSISTENT");
connection = messageSender.createConnection(uri);
SoapMessage soapRequest = new SaajSoapMessage(messageFactory.createMessage());
soapRequest.setSoapAction(SOAP_ACTION);
connection.send(soapRequest);
BytesMessage request = (BytesMessage) jmsTemplate.receive();
assertNotNull("No message received", request);
assertTrue("No message content received", request.readByte() != -1);
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_SOAP_ACTION, SOAP_ACTION);
response.setStringProperty(JmsTransportConstants.PROPERTY_CONTENT_TYPE,
SoapVersion.SOAP_11.getContentType());
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();
}
}
}
@Test
public void testSendAndReceiveQueueBytesMessagePermanentQueue() throws Exception {
WebServiceConnection connection = null;
try {
String responseQueueName = "SenderResponseQueue";
URI uri = new URI(
"jms:SenderRequestQueue?replyToName=" + responseQueueName + "&deliveryMode=NON_PERSISTENT");
connection = messageSender.createConnection(uri);
SoapMessage soapRequest = new SaajSoapMessage(messageFactory.createMessage());
soapRequest.setSoapAction(SOAP_ACTION);
connection.send(soapRequest);
final BytesMessage request = (BytesMessage) jmsTemplate.receive();
assertNotNull("No message received", request);
assertTrue("No message content received", request.readByte() != -1);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
messageFactory.createMessage().writeTo(bos);
final byte[] buf = bos.toByteArray();
jmsTemplate.send(responseQueueName, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
BytesMessage response = session.createBytesMessage();
response.setJMSCorrelationID(request.getJMSMessageID());
response.setStringProperty(JmsTransportConstants.PROPERTY_SOAP_ACTION, SOAP_ACTION);
response.setStringProperty(JmsTransportConstants.PROPERTY_CONTENT_TYPE,
SoapVersion.SOAP_11.getContentType());
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();
}
}
}
@Test
public void testSendAndReceiveQueueTextMessage() throws Exception {
WebServiceConnection connection = null;
try {
URI uri = new URI("jms:SenderRequestQueue?deliveryMode=NON_PERSISTENT&messageType=TEXT_MESSAGE");
connection = messageSender.createConnection(uri);
SoapMessage soapRequest = new SaajSoapMessage(messageFactory.createMessage());
soapRequest.setSoapAction(SOAP_ACTION);
connection.send(soapRequest);
TextMessage request = (TextMessage) jmsTemplate.receive();
assertNotNull("No message received", request);
assertNotNull("No message content received", request.getText());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
messageFactory.createMessage().writeTo(bos);
final String text = new String(bos.toByteArray(), "UTF-8");
jmsTemplate.send(request.getJMSReplyTo(), new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
TextMessage response = session.createTextMessage();
response.setStringProperty(JmsTransportConstants.PROPERTY_SOAP_ACTION, SOAP_ACTION);
response.setStringProperty(JmsTransportConstants.PROPERTY_CONTENT_TYPE,
SoapVersion.SOAP_11.getContentType());
response.setText(text);
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();
}
}
}
@Test
public void testSendNoResponse() throws Exception {
WebServiceConnection connection = null;
try {
URI uri = new URI("jms:SenderRequestQueue?deliveryMode=NON_PERSISTENT");
connection = messageSender.createConnection(uri);
SoapMessage soapRequest = new SaajSoapMessage(messageFactory.createMessage());
soapRequest.setSoapAction(SOAP_ACTION);
connection.send(soapRequest);
BytesMessage request = (BytesMessage) jmsTemplate.receive();
assertNotNull("No message received", request);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
messageFactory.createMessage().writeTo(bos);
SoapMessage response = (SoapMessage) connection.receive(new SaajSoapMessageFactory(messageFactory));
assertNull("Response received", response);
}
finally {
if (connection != null) {
connection.close();
}
}
}
@Test
public void testPostProcessor() throws Exception {
MessagePostProcessor processor = new MessagePostProcessor() {
public Message postProcessMessage(Message message) throws JMSException {
message.setBooleanProperty("processed", true);
return message;
}
};
JmsSenderConnection connection = null;
try {
URI uri = new URI("jms:SenderRequestQueue?deliveryMode=NON_PERSISTENT");
connection = (JmsSenderConnection) messageSender.createConnection(uri);
connection.setPostProcessor(processor);
SoapMessage soapRequest = new SaajSoapMessage(messageFactory.createMessage());
connection.send(soapRequest);
BytesMessage request = (BytesMessage) jmsTemplate.receive();
assertNotNull("No message received", request);
assertTrue("Message not processed", request.getBooleanProperty("processed"));
}
finally {
if (connection != null) {
connection.close();
}
}
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
import javax.annotation.Resource;
import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertNotNull;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("jms-receiver-applicationContext.xml")
public class WebServiceMessageListenerIntegrationTest {
private static final String CONTENT =
"<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>" + "<SOAP-ENV:Body>\n" +
"<m:GetLastTradePrice xmlns:m='http://www.springframework.org/spring-ws'>\n" +
"<symbol>DIS</symbol>\n" + "</m:GetLastTradePrice>\n" + "</SOAP-ENV:Body></SOAP-ENV:Envelope>";
@Autowired
private JmsTemplate jmsTemplate;
@Resource
private Queue responseQueue;
@Resource
private Queue requestQueue;
@Autowired
private Topic requestTopic;
@Test
public void testReceiveQueueBytesMessage() throws Exception {
final byte[] b = CONTENT.getBytes("UTF-8");
jmsTemplate.send(requestQueue, 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);
}
@Test
public void testReceiveQueueTextMessage() throws Exception {
jmsTemplate.send(requestQueue, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
TextMessage request = session.createTextMessage(CONTENT);
request.setJMSReplyTo(responseQueue);
return request;
}
});
TextMessage response = (TextMessage) jmsTemplate.receive(responseQueue);
assertNotNull("No response received", response);
}
@Test
public void testReceiveTopic() throws Exception {
final byte[] b = CONTENT.getBytes("UTF-8");
jmsTemplate.send(requestTopic, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
BytesMessage request = session.createBytesMessage();
request.writeBytes(b);
return request;
}
});
Thread.sleep(100);
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2005-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.jms.support;
import java.net.URI;
import javax.jms.DeliveryMode;
import javax.jms.Message;
import org.springframework.ws.transport.jms.JmsTransportConstants;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class JmsTransportUtilsTest {
@Test
public void getDestinationName() throws Exception {
URI uri = new URI("jms:RequestQueue?replyToName=RESP_QUEUE");
String destinationName = JmsTransportUtils.getDestinationName(uri);
assertEquals("Invalid destination", "RequestQueue", destinationName);
uri = new URI("jms:RequestQueue");
destinationName = JmsTransportUtils.getDestinationName(uri);
assertEquals("Invalid destination", "RequestQueue", destinationName);
}
@Test
public void getDeliveryMode() throws Exception {
URI uri = new URI("jms:RequestQueue?deliveryMode=NON_PERSISTENT");
int deliveryMode = JmsTransportUtils.getDeliveryMode(uri);
assertEquals("Invalid deliveryMode", DeliveryMode.NON_PERSISTENT, deliveryMode);
uri = new URI("jms:RequestQueue?deliveryMode=PERSISTENT");
deliveryMode = JmsTransportUtils.getDeliveryMode(uri);
assertEquals("Invalid deliveryMode", DeliveryMode.PERSISTENT, deliveryMode);
uri = new URI("jms:RequestQueue?replyToName=RESP_QUEUE");
deliveryMode = JmsTransportUtils.getDeliveryMode(uri);
assertEquals("Invalid deliveryMode", Message.DEFAULT_DELIVERY_MODE, deliveryMode);
}
@Test
public void getMessageType() throws Exception {
URI uri = new URI("jms:RequestQueue?messageType=BYTESMESSAGE");
int messageType = JmsTransportUtils.getMessageType(uri);
assertEquals("Invalid messageType", JmsTransportConstants.BYTES_MESSAGE_TYPE, messageType);
uri = new URI("jms:RequestQueue?messageType=TEXT_MESSAGE");
messageType = JmsTransportUtils.getMessageType(uri);
assertEquals("Invalid messageType", JmsTransportConstants.TEXT_MESSAGE_TYPE, messageType);
uri = new URI("jms:RequestQueue?replyToName=RESP_QUEUE");
messageType = JmsTransportUtils.getMessageType(uri);
assertEquals("Invalid messageType", JmsTransportConstants.BYTES_MESSAGE_TYPE, messageType);
}
@Test
public void getTimeToLive() throws Exception {
URI uri = new URI("jms:RequestQueue?timeToLive=100");
long timeToLive = JmsTransportUtils.getTimeToLive(uri);
assertEquals("Invalid timeToLive", 100, timeToLive);
uri = new URI("jms:RequestQueue?replyToName=RESP_QUEUE");
timeToLive = JmsTransportUtils.getTimeToLive(uri);
assertEquals("Invalid timeToLive", Message.DEFAULT_TIME_TO_LIVE, timeToLive);
}
@Test
public void getPriority() throws Exception {
URI uri = new URI("jms:RequestQueue?priority=5");
int priority = JmsTransportUtils.getPriority(uri);
assertEquals("Invalid priority", 5, priority);
uri = new URI("jms:RequestQueue?replyToName=RESP_QUEUE");
priority = JmsTransportUtils.getPriority(uri);
assertEquals("Invalid priority", Message.DEFAULT_PRIORITY, priority);
}
@Test
public void getReplyToName() throws Exception {
URI uri = new URI("jms:RequestQueue?replyToName=RESP_QUEUE");
String replyToName = JmsTransportUtils.getReplyToName(uri);
assertEquals("Invalid replyToName", "RESP_QUEUE", replyToName);
uri = new URI("jms:RequestQueue?priority=5");
replyToName = JmsTransportUtils.getReplyToName(uri);
Assert.assertNull("Invalid replyToName", replyToName);
}
@Test
public void jndi() throws Exception {
URI uri = new URI("jms:jms/REQUEST_QUEUE?replyToName=jms/REPLY_QUEUE");
String destination = JmsTransportUtils.getDestinationName(uri);
assertEquals("Invalid destination name", "jms/REQUEST_QUEUE", destination);
String replyTo = JmsTransportUtils.getReplyToName(uri);
assertEquals("Invalid reply to name", "jms/REPLY_QUEUE", replyTo);
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.mail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
import org.custommonkey.xmlunit.XMLAssert;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.jvnet.mock_javamail.Mailbox;
import static org.junit.Assert.assertEquals;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("mail-applicationContext.xml")
public class MailIntegrationTest {
@Autowired
private WebServiceTemplate webServiceTemplate;
@Autowired
private GenericApplicationContext applicationContext;
@After
public void clearMailbox() throws Exception {
Mailbox.clearAll();
}
@Test
public void testMailTransport() throws Exception {
String content = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
StringResult result = new StringResult();
webServiceTemplate.sendSourceAndReceiveToResult(new StringSource(content), result);
applicationContext.close();
assertEquals("Server mail message not deleted", 0, Mailbox.get("server@example.com").size());
assertEquals("No client mail message received", 1, Mailbox.get("client@example.com").size());
XMLAssert.assertXMLEqual("Invalid content received", content, result.toString());
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.mail;
import java.net.URI;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPMessage;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.transport.WebServiceConnection;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.jvnet.mock_javamail.Mailbox;
public class MailMessageSenderIntegrationTest {
private MailMessageSender messageSender;
private MessageFactory messageFactory;
private static final String SOAP_ACTION = "http://springframework.org/DoIt";
@Before
public void setUp() throws Exception {
messageSender = new MailMessageSender();
messageSender.setFrom("Spring-WS SOAP Client <client@example.com>");
messageSender.setTransportUri("smtp://smtp.example.com");
messageSender.setStoreUri("imap://imap.example.com/INBOX");
messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
messageSender.afterPropertiesSet();
}
@After
public void tearDown() throws Exception {
Mailbox.clearAll();
}
@Test
public void testSendAndReceiveQueueNoResponse() throws Exception {
WebServiceConnection connection = null;
try {
URI mailTo = new URI("mailto:server@example.com?subject=SOAP%20Test");
connection = messageSender.createConnection(mailTo);
SOAPMessage saajMessage = messageFactory.createMessage();
saajMessage.getSOAPBody().addBodyElement(new QName("http://springframework.org", "test"));
SoapMessage soapRequest = new SaajSoapMessage(saajMessage);
soapRequest.setSoapAction(SOAP_ACTION);
connection.send(soapRequest);
Assert.assertEquals("No mail message sent", 1, Mailbox.get("server@example.com").size());
}
finally {
if (connection != null) {
connection.close();
}
}
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.mail.support;
import java.net.URI;
import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import org.junit.Assert;
import org.junit.Test;
public class MailTransportUtilsTest {
@Test
public void testToPasswordProtectedString() throws Exception {
URLName name = new URLName("imap://john:secret@imap.example.com/INBOX");
String result = MailTransportUtils.toPasswordProtectedString(name);
Assert.assertEquals("Password found in string", -1, result.indexOf("secret"));
}
@Test
public void testGetTo() throws Exception {
URI uri = new URI("mailto:infobot@example.com?subject=current-issue");
InternetAddress to = MailTransportUtils.getTo(uri);
Assert.assertEquals("Invalid destination", new InternetAddress("infobot@example.com"), to);
uri = new URI("mailto:infobot@example.com");
to = MailTransportUtils.getTo(uri);
Assert.assertEquals("Invalid destination", new InternetAddress("infobot@example.com"), to);
}
@Test
public void testGetSubject() throws Exception {
URI uri = new URI("mailto:infobot@example.com?subject=current-issue");
String subject = MailTransportUtils.getSubject(uri);
Assert.assertEquals("Invalid destination", "current-issue", subject);
uri = new URI("mailto:infobot@example.com");
subject = MailTransportUtils.getSubject(uri);
Assert.assertNull("Invalid destination", subject);
}
}

View File

@@ -0,0 +1,28 @@
/*
* 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 javax.xml.transform.Source;
import org.springframework.ws.server.endpoint.PayloadEndpoint;
public class EchoPayloadEndpoint implements PayloadEndpoint {
public Source invoke(Source request) throws Exception {
return request;
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2005-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.support;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.util.Random;
import org.springframework.util.Assert;
/**
* Utility class that finds free BSD ports for use in testing scenario's.
*
* @author Ben Hale
* @author Arjen Poutsma
*/
public abstract class FreePortScanner {
private static final int MIN_SAFE_PORT = 1024;
private static final int MAX_PORT = 65535;
private static final Random random = new Random();
/**
* Returns the number of a free port in the default range.
*/
public static int getFreePort() {
return getFreePort(MIN_SAFE_PORT, MAX_PORT);
}
/**
* Returns the number of a free port in the given range.
*/
public static int getFreePort(int minPort, int maxPort) {
Assert.isTrue(minPort > 0, "'minPort' must be larger than 0");
Assert.isTrue(maxPort > minPort, "'maxPort' must be larger than minPort");
int portRange = maxPort - minPort;
int candidatePort;
int searchCounter = 0;
do {
if (++searchCounter > portRange) {
throw new IllegalStateException(
String.format("There were no ports available in the range %d to %d", minPort, maxPort));
}
candidatePort = getRandomPort(minPort, portRange);
}
while (!isPortAvailable(candidatePort));
return candidatePort;
}
private static int getRandomPort(int minPort, int portRange) {
return minPort + random.nextInt(portRange);
}
private static boolean isPortAvailable(int port) {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket();
}
catch (IOException ex) {
throw new IllegalStateException("Unable to create ServerSocket.", ex);
}
try {
InetSocketAddress sa = new InetSocketAddress(port);
serverSocket.bind(sa);
return true;
}
catch (IOException ex) {
return false;
}
finally {
try {
serverSocket.close();
}
catch (IOException ex) {
// ignore
}
}
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2005-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.xmpp.support;
import org.jivesoftware.smack.XMPPException;
import org.junit.Before;
import org.junit.Test;
/** @author Arjen Poutsma */
public class XmppConnectionFactoryBeanTest {
private XmppConnectionFactoryBean factoryBean;
@Before
public void createFactoryBean() {
factoryBean = new XmppConnectionFactoryBean();
}
@Test(expected = IllegalArgumentException.class)
public void noHost() throws XMPPException {
factoryBean.afterPropertiesSet();
}
@Test(expected = IllegalArgumentException.class)
public void noUsername() throws XMPPException {
factoryBean.setHost("jabber.org");
factoryBean.afterPropertiesSet();
}
@Test(expected = IllegalArgumentException.class)
public void wrongPort() throws XMPPException {
factoryBean.setPort(-10);
}
}

View File

@@ -0,0 +1,6 @@
log4j.rootCategory=WARN, stdout
log4j.logger.org.springframework.ws=DEBUG
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="port" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.springframework.ws.transport.support.FreePortScanner"/>
<property name="targetMethod" value="getFreePort"/>
</bean>
<bean id="httpServer" class="org.springframework.remoting.support.SimpleHttpServerFactoryBean">
<property name="port" ref="port"/>
<property name="contexts">
<map>
<entry key="/service" value-ref="webServiceHandler"/>
</map>
</property>
</bean>
<bean id="webServiceHandler" class="org.springframework.ws.transport.http.WebServiceMessageReceiverHttpHandler">
<property name="chunkedEncoding" value="true"/>
<property name="messageFactory" ref="messageFactory"/>
<property name="messageReceiver" ref="messageDispatcher"/>
</bean>
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<bean id="messageDispatcher" class="org.springframework.ws.soap.server.SoapMessageDispatcher">
<property name="endpointMappings" ref="payloadMapping"/>
</bean>
<bean id="payloadMapping" class="org.springframework.ws.soap.server.endpoint.mapping.SoapActionEndpointMapping">
<property name="mappings">
<props>
<prop key="http://springframework.org/spring-ws/NoResponse">noResponseEndpoint</prop>
<prop key="http://springframework.org/spring-ws/Response">responseEndpoint</prop>
<prop key="http://springframework.org/spring-ws/Fault">faultEndpoint</prop>
</props>
</property>
</bean>
<bean id="noResponseEndpoint"
class="org.springframework.ws.transport.http.NoResponseEndpoint"/>
<bean id="responseEndpoint"
class="org.springframework.ws.transport.http.ResponseEndpoint"/>
<bean id="faultEndpoint"
class="org.springframework.ws.transport.http.FaultEndpoint"/>
</beans>

View File

@@ -0,0 +1,7 @@
<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
<SOAP-ENV:Body>
<m:GetLastTradePrice xmlns:m='http://www.springframework.org/spring-ws'>
<symbol>DIS</symbol>
</m:GetLastTradePrice>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost?broker.persistent=false"/>
</bean>
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destinationName" value="RequestQueue"/>
<property name="messageListener">
<bean class="org.springframework.ws.transport.jms.WebServiceMessageListener">
<property name="messageFactory" ref="messageFactory"/>
<property name="messageReceiver" ref="messageDispatcher"/>
</bean>
</property>
</bean>
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="messageSender">
<bean class="org.springframework.ws.transport.jms.JmsMessageSender">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
</property>
<property name="defaultUri" value="jms:RequestQueue?deliveryMode=NON_PERSISTENT"/>
</bean>
<bean id="messageDispatcher" class="org.springframework.ws.soap.server.SoapMessageDispatcher">
<property name="endpointMappings">
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="defaultEndpoint">
<bean class="org.springframework.ws.transport.support.EchoPayloadEndpoint"/>
</property>
</bean>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost?broker.persistent=false"/>
</bean>
<bean id="requestQueue" class="org.apache.activemq.command.ActiveMQQueue">
<property name="physicalName" value="RequestQueue"/>
</bean>
<bean id="requestTopic" class="org.apache.activemq.command.ActiveMQTopic">
<property name="physicalName" value="RequestTopic"/>
</bean>
<bean id="responseQueue" class="org.apache.activemq.command.ActiveMQQueue">
<property name="physicalName" value="ResponseQueue"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="requestQueue"/>
<property name="messageListener" ref="messageListener"/>
</bean>
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="requestTopic"/>
<property name="messageListener" ref="messageListener"/>
</bean>
<bean id="messageListener" class="org.springframework.ws.transport.jms.WebServiceMessageListener">
<property name="messageFactory">
<bean class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
</property>
<property name="messageReceiver" ref="messageReceiver"/>
</bean>
<bean id="messageReceiver" class="org.springframework.ws.transport.SimpleTestingMessageReceiver"/>
</beans>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost?broker.persistent=false"/>
</bean>
<bean id="requestQueue" class="org.apache.activemq.command.ActiveMQQueue">
<property name="physicalName" value="SenderRequestQueue"/>
</bean>
<bean id="responseQueue" class="org.apache.activemq.command.ActiveMQQueue">
<property name="physicalName" value="SenderResponseQueue"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestination" ref="requestQueue"/>
</bean>
<bean id="messageSender" class="org.springframework.ws.transport.jms.JmsMessageSender">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="receiveTimeout" value="500"/>
</bean>
</beans>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="session" class="javax.mail.Session" factory-method="getInstance">
<constructor-arg>
<props/>
</constructor-arg>
</bean>
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<bean id="messagingReceiver" class="org.springframework.ws.transport.mail.MailMessageReceiver">
<property name="messageFactory" ref="messageFactory"/>
<property name="from" value="Spring-WS SOAP Server &lt;server@example.com&gt;"/>
<property name="storeUri" value="imap://server@example.com/INBOX"/>
<property name="transportUri" value="smtp://smtp.example.com"/>
<property name="messageReceiver" ref="messageDispatcher"/>
<property name="session" ref="session"/>
<property name="monitoringStrategy">
<bean class="org.springframework.ws.transport.mail.monitor.Pop3PollingMonitoringStrategy">
<property name="pollingInterval" value="500"/>
</bean>
</property>
</bean>
<bean id="messageDispatcher" class="org.springframework.ws.soap.server.SoapMessageDispatcher">
<property name="endpointMappings">
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="defaultEndpoint">
<bean class="org.springframework.ws.transport.support.EchoPayloadEndpoint"/>
</property>
</bean>
</property>
</bean>
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="messageSender">
<bean class="org.springframework.ws.transport.mail.MailMessageSender">
<property name="from" value="Spring-WS SOAP Client &lt;client@example.com&gt;"/>
<property name="transportUri" value="smtp://smtp.example.com"/>
<property name="storeUri" value="imap://client@example.com/INBOX"/>
<property name="receiveSleepTime" value="1000"/>
<property name="session" ref="session"/>
</bean>
</property>
<property name="defaultUri" value="mailto:server@example.com?subject=SOAP%20Test"/>
</bean>
</beans>