This commit is contained in:
Arjen Poutsma
2007-06-15 00:37:50 +00:00
parent 999e9d98a8
commit 090d2863f5
30 changed files with 1491 additions and 223 deletions

View File

@@ -1,4 +1,5 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>spring-ws</artifactId>
@@ -21,6 +22,16 @@
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<stylesheetfile>${basedir}/../src/main/javadoc/javadoc.css</stylesheetfile>
</configuration>
</plugin>
</plugins>
</reporting>
<dependencies>
<!-- Spring-WS dependencies -->
<dependency>
@@ -56,6 +67,11 @@
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-remoting</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jmx</artifactId>
@@ -84,10 +100,10 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.jbi</groupId>
<artifactId>jbi</artifactId>
<version>1.0</version>
<scope>provided</scope>
<groupId>javax.ejb</groupId>
<artifactId>ejb</artifactId>
<version>2.1</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.xml.ws</groupId>
@@ -127,5 +143,12 @@
<version>6.0.1</version>
<scope>test</scope>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>easymock</groupId>
<artifactId>easymock</artifactId>
<version>1.2_Java1.3</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -32,11 +32,15 @@ import javax.jms.Session;
import org.apache.commons.logging.Log;
import org.springframework.jms.support.JmsUtils;
import org.springframework.util.Assert;
import org.springframework.ws.FaultAwareWebServiceMessage;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.transport.AbstractReceiverConnection;
import org.springframework.ws.transport.FaultAwareWebServiceConnection;
import org.springframework.ws.transport.jms.support.JmsTransportUtils;
/** @author Arjen Poutsma */
public class JmsReceiverConnection extends AbstractReceiverConnection implements JmsTransportConstants {
public class JmsReceiverConnection extends AbstractReceiverConnection
implements JmsTransportConstants, FaultAwareWebServiceConnection {
private final Log logger;
@@ -63,9 +67,6 @@ public class JmsReceiverConnection extends AbstractReceiverConnection implements
return false;
}
public void close() throws IOException {
}
/*
* Receiving
*/
@@ -102,15 +103,18 @@ public class JmsReceiverConnection extends AbstractReceiverConnection implements
}
/*
* Sending
*/
* Sending
*/
protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
try {
responseMessage = session.createBytesMessage();
responseMessage.setJMSCorrelationID(requestMessage.getJMSMessageID());
responseMessage.setStringProperty(PROPERTY_BINDING_VERSION, "1.0");
responseMessage.setBooleanProperty(PROPERTY_IS_FAULT, message.hasFault());
if (message instanceof FaultAwareWebServiceMessage) {
FaultAwareWebServiceMessage faultMessage = (FaultAwareWebServiceMessage) message;
responseMessage.setBooleanProperty(PROPERTY_IS_FAULT, faultMessage.hasFault());
}
}
catch (JMSException ex) {
throw new JmsTransportException("Could not create response message", ex);
@@ -152,4 +156,32 @@ public class JmsReceiverConnection extends AbstractReceiverConnection implements
}
}
public void close() throws IOException {
}
/*
* Faults
*/
public boolean hasFault() throws IOException {
try {
return requestMessage.getBooleanProperty(JmsTransportConstants.PROPERTY_IS_FAULT);
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
}
public void setFault(boolean fault) throws IOException {
if (responseMessage != null) {
try {
responseMessage.setBooleanProperty(JmsTransportConstants.PROPERTY_IS_FAULT, true);
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
}
}
}

View File

@@ -37,9 +37,11 @@ import javax.jms.TemporaryQueue;
import org.springframework.jms.connection.ConnectionFactoryUtils;
import org.springframework.jms.support.JmsUtils;
import org.springframework.util.Assert;
import org.springframework.ws.FaultAwareWebServiceMessage;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.transport.AbstractSenderConnection;
import org.springframework.ws.transport.FaultAwareWebServiceConnection;
import org.springframework.ws.transport.jms.support.JmsTransportUtils;
/** @author Arjen Poutsma */
public class JmsSenderConnection extends AbstractSenderConnection
@@ -88,6 +90,14 @@ public class JmsSenderConnection extends AbstractSenderConnection
return responseMessage;
}
public boolean hasError() throws IOException {
return false;
}
public String getErrorMessage() throws IOException {
return null;
}
/*
* Sending
*/
@@ -96,8 +106,11 @@ public class JmsSenderConnection extends AbstractSenderConnection
try {
requestMessage = session.createBytesMessage();
requestMessage.setStringProperty(PROPERTY_BINDING_VERSION, "1.0");
requestMessage.setBooleanProperty(PROPERTY_IS_FAULT, message.hasFault());
requestMessage.setStringProperty(PROPERTY_REQUEST_IRI, uri.getUri());
if (message instanceof FaultAwareWebServiceMessage) {
FaultAwareWebServiceMessage faultMessage = (FaultAwareWebServiceMessage) message;
requestMessage.setBooleanProperty(PROPERTY_IS_FAULT, faultMessage.hasFault());
}
requestMessage.setStringProperty(PROPERTY_REQUEST_IRI, uri.toString());
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
@@ -176,6 +189,10 @@ public class JmsSenderConnection extends AbstractSenderConnection
}
}
protected boolean hasResponse() throws IOException {
return responseMessage != null;
}
protected Iterator getResponseHeaderNames() throws IOException {
try {
List headerNames = new ArrayList();
@@ -216,9 +233,9 @@ public class JmsSenderConnection extends AbstractSenderConnection
ConnectionFactoryUtils.releaseConnection(connection, connectionFactory, true);
}
protected boolean hasResponse() throws IOException {
return responseMessage != null;
}
/*
* Faults
*/
public boolean hasFault() throws IOException {
if (responseMessage != null) {
@@ -234,11 +251,13 @@ public class JmsSenderConnection extends AbstractSenderConnection
}
}
public boolean hasError() throws IOException {
return false;
public void setFault(boolean fault) throws IOException {
try {
requestMessage.setBooleanProperty(JmsTransportConstants.PROPERTY_IS_FAULT, true);
}
catch (JMSException ex) {
throw new JmsTransportException(ex);
}
}
public String getErrorMessage() throws IOException {
return null;
}
}

View File

@@ -28,49 +28,17 @@ import javax.naming.Context;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.ws.transport.support.ParameterizedUri;
/**
* @author Arjen Poutsma
* @see <a href="http://mail-archives.apache.org/mod_mbox/ws-axis-dev/200701.mbox/raw/%3C80A43FC052CE3949A327527DCD5D6B27020FB65C@MAIL01.bedford.progress.com%3E/2">RI
* Scheme for Java Message Service 1.0 RC1</a>
*/
public class JmsUri implements JmsTransportConstants {
private final String uri;
private final String destination;
// keys are string parameter names; values are string parameter values
private final Map parameters = new HashMap();
public class JmsUri extends ParameterizedUri implements JmsTransportConstants {
public JmsUri(String uri) {
Assert.hasLength(uri, "'uri' must not be empty");
String scheme = URI_SCHEME + ":";
Assert.isTrue(uri.startsWith(scheme), uri + " does not start with " + scheme);
Assert.isTrue(uri.length() > scheme.length(), uri + " does not have a destination");
int paramStart = uri.indexOf('?');
if (paramStart == -1) {
destination = uri.substring(scheme.length());
}
else {
destination = uri.substring(scheme.length(), paramStart);
parseParameters(uri.substring(paramStart + 1));
}
this.uri = uri;
}
private void parseParameters(String parametersString) {
StringTokenizer params = new StringTokenizer(parametersString, "&");
while (params.hasMoreTokens()) {
String param = params.nextToken();
int paramSep = param.indexOf('=');
if (paramSep == -1) {
throw new IllegalArgumentException(param + " is not a valid parameter: it has no '='");
}
String paramName = param.substring(0, paramSep);
String paramValue = param.substring(paramSep + 1);
parameters.put(paramName, paramValue);
}
super(uri);
validateParameters();
}
@@ -85,7 +53,7 @@ public class JmsUri implements JmsTransportConstants {
}
private void validateIntegerParameter(String paramName) {
String paramValue = (String) parameters.get(paramName);
String paramValue = (String) getParameter(paramName);
if (StringUtils.hasLength(paramValue)) {
try {
Integer.parseInt(paramValue);
@@ -106,9 +74,8 @@ public class JmsUri implements JmsTransportConstants {
return getIntegerParameter(PARAM_DELIVERY_MODE, Message.DEFAULT_DELIVERY_MODE);
}
/** Returns thethe JNDI name of the destination queue or topic. */
public String getDestination() {
return destination;
return super.getDestination();
}
/**
@@ -116,7 +83,7 @@ public class JmsUri implements JmsTransportConstants {
* "<code>topic</code>", respectively.
*/
public String getDestinationType() {
return (String) parameters.get(PARAM_DESTINATION_TYPE);
return getParameter(PARAM_DESTINATION_TYPE);
}
/**
@@ -134,15 +101,10 @@ public class JmsUri implements JmsTransportConstants {
}
private int getIntegerParameter(String paramName, int defaultValue) {
String paramValue = (String) parameters.get(paramName);
String paramValue = getParameter(paramName);
return paramValue != null ? Integer.parseInt(paramValue) : defaultValue;
}
/** Returns the full JMS URI. */
public String getUri() {
return uri;
}
/** Indicates whether this URI has a connection factory name. */
public boolean hasConnectionFactoryName() {
return StringUtils.hasLength(getConnectionFactoryName());
@@ -150,7 +112,7 @@ public class JmsUri implements JmsTransportConstants {
/** Returns the JNDI name of the Java class providing the connection factory. */
public String getConnectionFactoryName() {
return (String) parameters.get(PARAM_CONNECTION_FACTORY_NAME);
return getParameter(PARAM_CONNECTION_FACTORY_NAME);
}
/** Indicates whether this URI has a "InitialContextFactory". */
@@ -164,7 +126,7 @@ public class JmsUri implements JmsTransportConstants {
* @see Context#INITIAL_CONTEXT_FACTORY
*/
public String getInitialContextFactory() {
return (String) parameters.get(PARAM_INITIAL_CONTEXT_FACTORY);
return getParameter(PARAM_INITIAL_CONTEXT_FACTORY);
}
/** Indicates whether this URI has a JNDI provider URL. */
@@ -178,7 +140,7 @@ public class JmsUri implements JmsTransportConstants {
* @see Context#PROVIDER_URL
*/
public String getJndiUrl() {
return (String) parameters.get(PARAM_JNDI_URL);
return getParameter(PARAM_JNDI_URL);
}
/** Indicates whether this URI has a reply-to name. */
@@ -192,7 +154,7 @@ public class JmsUri implements JmsTransportConstants {
* @see Message#setJMSReplyTo(Destination)
*/
public String getReplyTo() {
return (String) parameters.get(PARAM_REPLY_TO_NAME);
return getParameter(PARAM_REPLY_TO_NAME);
}
/**
@@ -203,8 +165,4 @@ public class JmsUri implements JmsTransportConstants {
return DESTINATION_TYPE_TOPIC.equals(getDestinationType());
}
/** Returns the value of a custom parameter with the given name. */
public String getCustomParameter(String paramName) {
return (String) parameters.get(paramName);
}
}

View File

@@ -14,7 +14,9 @@
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
package org.springframework.ws.transport.jms.support;
import org.springframework.ws.transport.jms.JmsTransportConstants;
/** @author Arjen Poutsma */
public class JmsTransportUtils {

View File

@@ -0,0 +1,188 @@
/*
* 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.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.event.MessageCountEvent;
import javax.mail.event.MessageCountListener;
import com.sun.mail.imap.IMAPFolder;
import org.springframework.util.Assert;
import org.springframework.ws.transport.mail.support.MailUtils;
import org.springframework.ws.transport.support.AbstractMultiThreadedMessageReceiver;
/** @author Arjen Poutsma */
public class MailMessageReceiver extends AbstractMultiThreadedMessageReceiver {
private Session session = Session.getInstance(new Properties(), null);
private URLName storeUri;
private Folder folder;
private MessageCountHandler eventHandler;
private Store store;
private boolean supportsIdle;
/**
* 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;
}
public void setStoreUri(String storeUri) {
this.storeUri = new URLName(storeUri);
}
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
Assert.notNull(storeUri, "Property 'storeUri' is required");
}
protected void onActivate() throws Exception {
openFolder();
}
protected void onStart() {
if (logger.isInfoEnabled()) {
logger.info("Starting mail receiver [" + storeUri.toString() + "]");
}
eventHandler = new MessageCountHandler();
folder.addMessageCountListener(eventHandler);
/*
try {
if (folder instanceof IMAPFolder) {
IMAPFolder f = (IMAPFolder) folder;
logger.debug(folder.isOpen());
logger.debug("Starting IDLE");
f.idle();
logger.debug("IDLE done");
supportsIdle = true;
}
}
catch (MessagingException mex) {
supportsIdle = false;
}
*/
logger.debug("Support IDLE: " + supportsIdle);
getTaskExecutor().execute(new MonitoringRunnable());
}
protected void onStop() {
if (logger.isInfoEnabled()) {
logger.info("Stopping mail receiver [" + storeUri.toString() + "]");
}
if (eventHandler != null) {
folder.removeMessageCountListener(eventHandler);
eventHandler = null;
}
}
protected void onShutdown() {
if (logger.isInfoEnabled()) {
logger.info("Shutting down mail receiver [" + storeUri.toString() + "]");
}
closeFolder();
}
protected void openFolder() throws MessagingException, MailTransportException {
store = session.getStore(storeUri);
store.connect();
folder = store.getFolder(storeUri);
if (folder == null || !folder.exists()) {
throw new MailTransportException("No default folder to receive from");
}
folder.open(Folder.READ_WRITE);
logger.info("folder contains " + folder.getMessageCount() + " messages");
}
protected void closeFolder() {
MailUtils.closeFolder(folder);
MailUtils.closeService(store);
}
private class MonitoringRunnable implements Runnable {
public void run() {
try {
while (isRunning()) {
if (supportsIdle && folder instanceof IMAPFolder) {
IMAPFolder f = (IMAPFolder) folder;
logger.debug("IDLE starts");
f.idle();
logger.debug("IDLE done");
}
else {
Thread.sleep(500); // sleep for freq milliseconds
// This is to force the IMAP server to send us
// EXISTS notifications.
folder.getMessageCount();
}
}
}
catch (InterruptedException ex) {
logger.warn(ex);
}
catch (MessagingException ex) {
logger.warn(ex);
}
}
}
private class MessageCountHandler implements MessageCountListener {
public void messagesAdded(MessageCountEvent event) {
Message[] msgs = event.getMessages();
logger.info("Got " + msgs.length + " new messages");
}
public void messagesRemoved(MessageCountEvent e) {
}
}
}

View File

@@ -0,0 +1,102 @@
/*
* 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.util.Properties;
import javax.mail.Session;
import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.AddressException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.beans.factory.InitializingBean;
/** @author Arjen Poutsma */
public class MailMessageSender implements WebServiceMessageSender, InitializingBean {
private Session session = Session.getInstance(new Properties(), null);
private URLName storeUri;
private URLName transportUri;
private InternetAddress from;
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;
}
public void setStoreUri(String storeUri) {
this.storeUri = new URLName(storeUri);
}
public void setTransportUri(String transportUri) {
this.transportUri = new URLName(transportUri);
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(from, "Property 'from' is required");
}
public WebServiceConnection createConnection(String uri) throws IOException {
MailtoUri mailtoUri = new MailtoUri(uri);
MailSenderConnection connection = new MailSenderConnection(mailtoUri, session, from);
if (transportUri != null) {
connection.setTransportUri(transportUri);
}
if (storeUri != null) {
connection.setStoreUri(storeUri);
}
return connection;
}
public boolean supports(String uri) {
return StringUtils.hasLength(uri) && uri.startsWith(MailtoUri.MAILTO_SCHEME);
}
}

View File

@@ -0,0 +1,198 @@
/*
* 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.io.InputStream;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import javax.mail.Header;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.URLName;
import javax.mail.internet.MimeMessage;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import org.springframework.util.Assert;
import org.springframework.ws.transport.AbstractReceiverConnection;
import org.springframework.ws.transport.TransportConstants;
import org.springframework.ws.transport.mail.support.MailUtils;
import org.springframework.ws.transport.jms.JmsTransportException;
import org.springframework.ws.WebServiceMessage;
/** @author Arjen Poutsma */
public class MailReceiverConnection extends AbstractReceiverConnection {
private final MimeMessage requestMessage;
private final Session session;
private MimeMessage responseMessage;
private ByteArrayOutputStream responseBuffer;
private String responseContentType;
private URLName transportUri;
public MailReceiverConnection(MimeMessage 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;
}
public String getErrorMessage() throws IOException {
return null;
}
public boolean hasError() throws IOException {
return false;
}
public void setTransportUri(URLName transportUri) {
this.transportUri = transportUri;
}
public void close() throws IOException {
}
/*
* Receiving
*/
protected Iterator getRequestHeaderNames() throws IOException {
try {
List headers = new ArrayList();
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());
}
}
protected Iterator getRequestHeaders(String name) throws IOException {
try {
String[] headers = requestMessage.getHeader(name);
return Arrays.asList(headers).iterator();
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
protected InputStream getRequestInputStream() throws IOException {
try {
return requestMessage.getDataHandler().getInputStream();
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
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);
}
}
protected OutputStream getResponseOutputStream() throws IOException {
return responseBuffer;
}
/*
* Sending
*/
protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
try {
responseMessage = (MimeMessage) requestMessage.reply(false);
responseBuffer = new ByteArrayOutputStream();
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
Transport transport = null;
try {
requestMessage.setDataHandler(
new DataHandler(new ByteArrayDataSource(responseContentType, responseBuffer.toByteArray())));
transport = session.getTransport(transportUri);
transport.connect();
requestMessage.saveChanges();
transport.sendMessage(requestMessage, requestMessage.getAllRecipients());
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
finally {
MailUtils.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,282 @@
/*
* 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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.mail.support.MailUtils;
/** @author Arjen Poutsma */
public class MailSenderConnection extends AbstractSenderConnection {
private static final Log logger = LogFactory.getLog(MailSenderConnection.class);
private final Session session;
private final MailtoUri uri;
private MimeMessage requestMessage;
private MimeMessage responseMessage;
private String requestContentType;
private boolean deleteAfterReceive = false;
private URLName storeUri;
private URLName transportUri;
private ByteArrayOutputStream requestBuffer;
private InternetAddress from;
protected MailSenderConnection(MailtoUri uri, Session session, InternetAddress from) {
Assert.notNull(uri, "'uri' must not be null");
Assert.notNull(session, "'session' must not be null");
this.uri = uri;
this.session = session;
this.from = from;
}
public MimeMessage getRequestMessage() {
return requestMessage;
}
public void setTransportUri(URLName transportUri) {
this.transportUri = transportUri;
}
public void setStoreUri(URLName storeUri) {
this.storeUri = storeUri;
}
/*
* Sending
*/
protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
try {
requestMessage = new MimeMessage(session);
requestMessage.setFrom(from);
requestMessage.setRecipient(Message.RecipientType.TO, uri.getTo());
if (uri.hasCc()) {
requestMessage.setRecipient(Message.RecipientType.CC, uri.getCc());
}
if (uri.hasSubject()) {
requestMessage.setSubject(uri.getSubject());
}
requestMessage.setSentDate(new Date());
requestBuffer = new ByteArrayOutputStream();
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
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);
}
}
protected OutputStream getRequestOutputStream() throws IOException {
return requestBuffer;
}
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 {
MailUtils.closeService(transport);
}
}
/*
* Receiving
*/
protected void onReceiveBeforeRead() throws IOException {
Store store = null;
Folder folder = null;
try {
try {
Thread.sleep(5000);
}
catch (InterruptedException e) {
logger.debug(e);
}
store = session.getStore(storeUri);
store.connect();
folder = store.getFolder(storeUri);
if (folder == null || !folder.exists()) {
throw new MailTransportException("No default folder to receive from");
}
if (deleteAfterReceive) {
folder.open(Folder.READ_WRITE);
}
else {
folder.open(Folder.READ_ONLY);
}
String requestMessageId = requestMessage.getMessageID();
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 = (MimeMessage) responses[0];
}
if (deleteAfterReceive) {
responseMessage.setFlag(Flags.Flag.DELETED, true);
}
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
finally {
MailUtils.closeFolder(folder, deleteAfterReceive);
MailUtils.closeService(store);
}
}
protected boolean hasResponse() throws IOException {
return responseMessage != null;
}
protected Iterator getResponseHeaderNames() throws IOException {
try {
List headers = new ArrayList();
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);
}
}
protected Iterator getResponseHeaders(String name) throws IOException {
try {
String[] headers = responseMessage.getHeader(name);
return Arrays.asList(headers).iterator();
}
catch (MessagingException ex) {
throw new MailTransportException(ex);
}
}
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;
}
public void close() throws IOException {
}
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,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.mail;
import org.springframework.ws.transport.TransportConstants;
/** @author Arjen Poutsma */
public interface MailTransportConstants extends TransportConstants {
/** The "In-Reply-To" header. */
String HEADER_IN_REPLY_TO = "In-Reply-To";
}

View File

@@ -24,15 +24,23 @@ import org.springframework.ws.transport.TransportException;
/** @author Arjen Poutsma */
public class MailTransportException extends TransportException {
private MessagingException messagingException;
public MailTransportException(String msg) {
super(msg);
}
public MailTransportException(String msg, JMSException ex) {
public MailTransportException(String msg, MessagingException ex) {
super(msg + ": " + ex.getMessage());
initCause(ex);
}
public MailTransportException(MessagingException ex) {
super(ex.getMessage());
initCause(ex);
}
public MessagingException getMessagingException() {
return messagingException;
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.Address;
import org.springframework.util.Assert;
import org.springframework.ws.transport.support.ParameterizedUri;
/** @author Arjen Poutsma */
public class MailtoUri extends ParameterizedUri {
static final String MAILTO_SCHEME = "mailto:";
public MailtoUri(String uri) {
super(uri);
Assert.isTrue(uri.startsWith(MAILTO_SCHEME), "Invalid uri: " + uri);
try {
InternetAddress.parse(getDestination(), false);
}
catch (AddressException ex) {
throw new IllegalArgumentException(ex);
}
}
public InternetAddress getTo() throws AddressException {
return new InternetAddress(getDestination());
}
public String getSubject() {
return getParameter("subject");
}
public boolean hasSubject() {
return hasParameter("subject");
}
public boolean hasCc() {
return hasParameter("cc");
}
public InternetAddress getCc() throws AddressException {
return new InternetAddress(getParameter("cc"));
}
}

View File

@@ -0,0 +1,22 @@
/*
* 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;
/** @author Arjen Poutsma */
public interface MonitoringStrategy {
}

View File

@@ -0,0 +1,82 @@
/*
* 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.support;
import javax.mail.Folder;
import javax.mail.MessagingException;
import javax.mail.Service;
import javax.mail.Store;
import javax.mail.Transport;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/** @author Arjen Poutsma */
public abstract class MailUtils {
private static final Log logger = LogFactory.getLog(MailUtils.class);
/**
* 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 Transport", 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) {
try {
folder.close(expunge);
}
catch (MessagingException ex) {
logger.debug("Could not close JavaMail Transport", ex);
}
}
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.support;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.util.ClassUtils;
import org.springframework.scheduling.commonj.WorkManagerTaskExecutor;
/**
* Abstract base class for standalone, server-side transport objects. Contains a Spring {@link TaskExecutor}, and
* various lifecycle callbacks.
*
* @author Arjen Poutsma
*/
public abstract class AbstractMultiThreadedMessageReceiver extends AbstractStandaloneMessagingReceiver
implements BeanNameAware {
/** Default thread name prefix. */
public final String DEFAULT_THREAD_NAME_PREFIX = ClassUtils.getShortName(getClass()) + "-";
private TaskExecutor taskExecutor;
private String beanName;
/** Returns the task executor. */
public TaskExecutor getTaskExecutor() {
return taskExecutor;
}
/**
* 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
* WorkManagerTaskExecutor} to integrate with WebSphere or WebLogic.
*/
public void setTaskExecutor(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
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);
}
}

View File

@@ -16,24 +16,12 @@
package org.springframework.ws.transport.support;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.Lifecycle;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.util.ClassUtils;
/**
* Abstract base class for standalone, server-side transport objects. Contains a Spring {@link TaskExecutor}, and
* various lifecycle callbacks.
*
* @author Arjen Poutsma
*/
public abstract class AbstractMessagingContainer extends SimpleWebServiceMessageReceiverObjectSupport
implements Lifecycle, DisposableBean, BeanNameAware {
/** Default thread name prefix. */
public final String DEFAULT_THREAD_NAME_PREFIX = ClassUtils.getShortName(getClass()) + "-";
/** @author Arjen Poutsma */
public abstract class AbstractStandaloneMessagingReceiver extends SimpleWebServiceMessageReceiverObjectSupport
implements Lifecycle, DisposableBean {
private volatile boolean active = false;
@@ -43,39 +31,6 @@ public abstract class AbstractMessagingContainer extends SimpleWebServiceMessage
private final Object lifecycleMonitor = new Object();
private TaskExecutor taskExecutor;
private String beanName;
/**
* Set whether to automatically start the listener 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;
}
/**
* 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;
}
/** Returns the task executor. */
public TaskExecutor getTaskExecutor() {
return taskExecutor;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
/** 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) {
@@ -91,23 +46,15 @@ public abstract class AbstractMessagingContainer extends SimpleWebServiceMessage
}
/**
* Create a default TaskExecutor. Called if no explicit TaskExecutor has been specified.
* Set whether to automatically start the listener after initialization.
* <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)
* Default is <code>true</code>; set this to <code>false</code> to allow for manual startup.
*/
protected TaskExecutor createDefaultTaskExecutor() {
String threadNamePrefix = beanName != null ? beanName + "-" : DEFAULT_THREAD_NAME_PREFIX;
return new SimpleAsyncTaskExecutor(threadNamePrefix);
public void setAutoStartup(boolean autoStartup) {
this.autoStartup = autoStartup;
}
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
if (taskExecutor == null) {
taskExecutor = createDefaultTaskExecutor();
}
activate();
}
@@ -167,5 +114,4 @@ public abstract class AbstractMessagingContainer extends SimpleWebServiceMessage
protected abstract void onStop();
protected abstract void onShutdown();
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.support;
import java.util.Map;
import java.util.StringTokenizer;
import org.springframework.core.CollectionFactory;
import org.springframework.util.Assert;
/** @author Arjen Poutsma */
public class ParameterizedUri {
private final String uri;
private final String scheme;
// keys are string parameter names; values are string parameter values
private final Map parameters = CollectionFactory.createLinkedCaseInsensitiveMapIfPossible(5);
private final String destination;
public ParameterizedUri(String uri) {
Assert.hasLength(uri, "'uri' must not be empty");
this.uri = uri;
int scIdx = uri.indexOf(':');
Assert.isTrue(scIdx != -1, uri + " does contain scheme");
scheme = uri.substring(0, scIdx);
Assert.isTrue(uri.length() > scheme.length(), uri + " does not have a destination");
int paramStart = uri.indexOf('?');
if (paramStart == -1) {
destination = uri.substring(scIdx + 1);
}
else {
destination = uri.substring(scIdx + 1, paramStart);
parseParameters(uri.substring(paramStart + 1));
}
}
private void parseParameters(String parametersString) {
StringTokenizer params = new StringTokenizer(parametersString, "&");
while (params.hasMoreTokens()) {
String param = params.nextToken();
int paramSep = param.indexOf('=');
if (paramSep == -1) {
throw new IllegalArgumentException(param + " is not a valid parameter: it has no '='");
}
String paramName = param.substring(0, paramSep);
String paramValue = param.substring(paramSep + 1);
parameters.put(paramName, paramValue);
}
}
/** Returns the destination of the uri. */
protected String getDestination() {
return destination;
}
public String toString() {
return uri;
}
protected String getParameter(String paramName) {
return (String) parameters.get(paramName);
}
protected boolean hasParameter(String paramName) {
return parameters.containsKey(paramName);
}
}

View File

@@ -24,10 +24,11 @@ import java.net.Socket;
import java.net.UnknownHostException;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.support.AbstractMessagingContainer;
import org.springframework.ws.transport.support.AbstractMultiThreadedMessageReceiver;
/** @author Arjen Poutsma */
public class TcpMessagingContainer extends AbstractMessagingContainer {
public class TcpMessageReceiver extends AbstractMultiThreadedMessageReceiver {
public static final int DEFAULT_PORT = 8081;
private ServerSocket serverSocket;
@@ -35,7 +36,7 @@ public class TcpMessagingContainer extends AbstractMessagingContainer {
private int backlog = -1;
private int port = -1;
private int port = DEFAULT_PORT;
/** Sets the port the server will bind to. */
public void setPort(int port) {
@@ -58,58 +59,34 @@ public class TcpMessagingContainer extends AbstractMessagingContainer {
this.bindAddress = InetAddress.getByName(bindAddress);
}
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
if (port == -1) {
throw new IllegalArgumentException("port is required");
}
openServerSocket();
}
protected void onActivate() throws IOException {
openServerSocket();
}
protected void onStart() {
if (logger.isInfoEnabled()) {
logger.info("Starting tcp server [" + serverSocket.getLocalSocketAddress() + "]");
logger.info("Starting tcp receiver [" + serverSocket.getLocalSocketAddress() + "]");
}
getTaskExecutor().execute(new SocketAcceptingRunnable());
}
protected void onStop() {
if (logger.isInfoEnabled()) {
logger.info("Stopping tcp server [" + serverSocket.getLocalSocketAddress() + "]");
logger.info("Stopping tcp receiver [" + serverSocket.getLocalSocketAddress() + "]");
}
}
protected void onShutdown() {
if (logger.isInfoEnabled()) {
logger.info("Shutting down tcp server [" + serverSocket.getLocalSocketAddress() + "]");
logger.info("Shutting down tcp receiver [" + serverSocket.getLocalSocketAddress() + "]");
}
closeServerSocket();
}
/**
* Establish a shared <code>ServerSocket</code> for this server.
* <p/>
* The default implementation delegates to <code>refreshSharedConnection</code>, which does one immediate attempt
* and throws an exception if it fails. Can be overridden to have a recovery proces in place, retrying until a
* ServerSocket can be successfully established.
*
* @see #refreshServerSocket()
* Establish a <code>ServerSocket</code> for this receiver.
*/
protected void openServerSocket() throws IOException {
refreshServerSocket();
}
/**
* Refresh the shared <code>ServerSocket</code> that this server holds.
* <p/>
* Called on startup and also after an infrastructure exception that occured during listener setup and/or
* execution.
*/
protected final void refreshServerSocket() throws IOException {
closeServerSocket();
serverSocket = new ServerSocket(port, backlog, bindAddress);
}
@@ -154,7 +131,7 @@ public class TcpMessagingContainer extends AbstractMessagingContainer {
}
public void run() {
WebServiceConnection connection = new TcpReceivingWebServiceConnection(socket);
WebServiceConnection connection = new TcpReceiverConnection(socket);
try {
handleConnection(connection);
}

View File

@@ -17,57 +17,49 @@
package org.springframework.ws.transport.tcp;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageSender;
/** @author Arjen Poutsma */
public class TcpMessageSender implements WebServiceMessageSender, InitializingBean {
public class TcpMessageSender implements WebServiceMessageSender {
private InetAddress address;
private static final String TCP_SCHEME = "tcp://";
private int port = -1;
public static final int DEFAULT_PORT = 8081;
private int timeOut = 1000;
/** Sets the port the sender will connect to. */
public void setPort(int port) {
this.port = port;
}
/** Sets the amount of milliseconds before the tcp connection will timeout. */
public void setTimeOut(int timeOut) {
this.timeOut = timeOut;
}
/**
* Sets the internet address the client will connect to.
*
* @throws java.net.UnknownHostException when the given address is not known
*/
public void setAddress(String address) throws UnknownHostException {
this.address = InetAddress.getByName(address);
public boolean supports(String uri) {
return StringUtils.hasLength(uri) && uri.startsWith(TCP_SCHEME);
}
public WebServiceConnection createConnection() throws IOException {
Socket socket = new Socket();
SocketAddress socketAddress = new InetSocketAddress(address, port);
socket.connect(socketAddress, timeOut);
return new TcpSendingWebServiceConnection(socket);
}
public void afterPropertiesSet() throws Exception {
if (port == -1) {
throw new IllegalArgumentException("port is required");
public WebServiceConnection createConnection(String uri) throws IOException {
Assert.isTrue(uri.startsWith(TCP_SCHEME), "Invalid uri: " + uri);
uri = uri.substring(TCP_SCHEME.length());
int idx = uri.indexOf(':');
String hostname;
int port;
if (idx != -1) {
hostname = uri.substring(0, idx);
port = Integer.parseInt(uri.substring(idx + 1));
} else {
hostname = uri;
port = DEFAULT_PORT;
}
Assert.notNull(address, "address is required");
Socket socket = new Socket();
SocketAddress socketAddress = new InetSocketAddress(hostname, port);
socket.connect(socketAddress, timeOut);
return new TcpSenderConnection(socket);
}
}

View File

@@ -26,18 +26,26 @@ import java.util.Collections;
import java.util.Iterator;
import org.springframework.util.Assert;
import org.springframework.ws.transport.AbstractReceivingWebServiceConnection;
import org.springframework.ws.transport.AbstractReceiverConnection;
/** @author Arjen Poutsma */
public class TcpReceivingWebServiceConnection extends AbstractReceivingWebServiceConnection {
public class TcpReceiverConnection extends AbstractReceiverConnection {
private final Socket socket;
public TcpReceivingWebServiceConnection(Socket socket) {
protected TcpReceiverConnection(Socket socket) {
Assert.notNull(socket, "socket must not be null");
this.socket = socket;
}
public boolean hasError() throws IOException {
return false;
}
public String getErrorMessage() throws IOException {
return null;
}
public void close() throws IOException {
socket.close();
}
@@ -73,7 +81,7 @@ public class TcpReceivingWebServiceConnection extends AbstractReceivingWebServic
};
}
protected void sendResponse() throws IOException {
protected void sendResponse(boolean sentFault) throws IOException {
}

View File

@@ -26,14 +26,14 @@ import java.util.Collections;
import java.util.Iterator;
import org.springframework.util.Assert;
import org.springframework.ws.transport.AbstractSendingWebServiceConnection;
import org.springframework.ws.transport.AbstractSenderConnection;
/** @author Arjen Poutsma */
public class TcpSendingWebServiceConnection extends AbstractSendingWebServiceConnection {
public class TcpSenderConnection extends AbstractSenderConnection {
private final Socket socket;
public TcpSendingWebServiceConnection(Socket socket) {
protected TcpSenderConnection(Socket socket) {
Assert.notNull(socket, "socket must not be null");
this.socket = socket;
}
@@ -42,6 +42,14 @@ public class TcpSendingWebServiceConnection extends AbstractSendingWebServiceCon
socket.close();
}
public boolean hasError() throws IOException {
return false;
}
public String getErrorMessage() throws IOException {
return null;
}
protected void addRequestHeader(String name, String value) throws IOException {
}

View File

@@ -18,14 +18,14 @@ package org.springframework.ws.transport;
import javax.xml.transform.Transformer;
import junit.framework.Assert;
import org.springframework.ws.context.MessageContext;
import org.springframework.xml.transform.TransformerObjectSupport;
import org.springframework.util.Assert;
public class SimpleTestingMessageReceiver extends TransformerObjectSupport implements WebServiceMessageReceiver {
public void receive(MessageContext messageContext) throws Exception {
Assert.assertNotNull("MessageContext is null", messageContext);
Assert.notNull(messageContext, "MessageContext is null");
logger.info("Received message");
Transformer transformer = createTransformer();
transformer.transform(messageContext.getRequest().getPayloadSource(),

View File

@@ -35,7 +35,6 @@ public class JmsUriTest extends TestCase {
assertEquals("Invalid prority", 8, uri.getPriority());
assertEquals("Invalid time to live", 10, uri.getTimeToLive());
assertEquals("Invalid reply to name", "interested", uri.getReplyTo());
assertEquals("Invalid custom property", "mystuff", uri.getCustomParameter("userprop"));
}

View File

@@ -14,9 +14,10 @@
* limitations under the License.
*/
package org.springframework.ws.transport.jms;
package org.springframework.ws.transport.jms.support;
import junit.framework.TestCase;
import org.springframework.ws.transport.jms.support.JmsTransportUtils;
public class JmsTransportUtilsTest extends TestCase {

View File

@@ -0,0 +1,32 @@
/*
* 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 org.springframework.context.support.ClassPathXmlApplicationContext;
/** @author Arjen Poutsma */
public class Driver {
public static void main(String[] args) throws IOException {
new ClassPathXmlApplicationContext("applicationContext.xml", Driver.class);
System.out.println("Started....");
System.in.read();
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.mail;
import java.util.Properties;
import javax.jms.BytesMessage;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPMessage;
import javax.mail.URLName;
import junit.framework.TestCase;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
import org.springframework.ws.transport.WebServiceConnection;
public class MailMessageSenderIntegrationTest extends TestCase {
private MailMessageSender messageSender;
private MessageFactory messageFactory;
private static final String URI = "mailto:ajwpi21@xs4all.nl?subject=SOAP Test";
private static final String SOAP_ACTION = "http://springframework.org/DoIt";
protected void setUp() throws Exception {
Properties properties = new Properties();
properties.setProperty("mail.smtp.host", "smtp.xs4all.nl");
messageSender = new MailMessageSender();
messageSender.setStoreUri("pop3://ajwpi21:sjantaL.@pop.xs4all.nl/INBOX");
messageSender.setTransportUri("smtp://ajwpi21:sjantaL.@smtp.xs4all.nl");
messageSender.setFrom("Arjen Poutsma <ajwp@xs4all.nl>");
messageSender.setJavaMailProperties(properties);
messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
}
public void testSendAndReceiveQueueNoResponse() throws Exception {
WebServiceConnection connection = null;
try {
connection = messageSender.createConnection(URI);
SOAPMessage saajMessage = messageFactory.createMessage();
SoapMessage soapRequest = new SaajSoapMessage(saajMessage);
soapRequest.setSoapAction(SOAP_ACTION);
connection.send(soapRequest);
// SoapMessage response = (SoapMessage) connection.receive(new SaajSoapMessageFactory(messageFactory));
}
finally {
if (connection != null) {
connection.close();
}
}
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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.tcp;
import java.io.IOException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/** @author Arjen Poutsma */
public class Driver {
public static void main(String[] args) throws IOException {
new ClassPathXmlApplicationContext("applicationContext.xml", Driver.class);
System.out.println("Started....");
System.in.read();
}
}

View File

@@ -31,7 +31,7 @@ import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.xml.transform.StringSource;
public class TcpServerIntegrationTest extends AbstractDependencyInjectionSpringContextTests {
public class TcpMessageReceiverIntegrationTest extends AbstractDependencyInjectionSpringContextTests {
private WebServiceMessageFactory messageFactory;
@@ -54,7 +54,7 @@ public class TcpServerIntegrationTest extends AbstractDependencyInjectionSpringC
" </SOAP-ENV:Body>\n" + "</SOAP-ENV:Envelope>";
public void testServer() throws IOException, InterruptedException {
Socket socket = new Socket("localhost", 9999);
Socket socket = new Socket("localhost", TcpMessageReceiver.DEFAULT_PORT);
Writer writer = null;
BufferedReader reader = null;
try {
@@ -74,8 +74,9 @@ public class TcpServerIntegrationTest extends AbstractDependencyInjectionSpringC
}
public void testTemplate() throws Exception {
WebServiceTemplate template = new WebServiceTemplate(messageFactory, messageSender);
template.sendAndReceive(new StringSource(REQUEST), new StreamResult(System.out));
WebServiceTemplate template = new WebServiceTemplate(messageFactory);
template.setMessageSender(messageSender);
template.sendAndReceive("tcp://localhost",new StringSource(REQUEST), new StreamResult(System.out));
}
protected String[] getConfigLocations() {

View File

@@ -0,0 +1,37 @@
<?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="messagingReceiver" class="org.springframework.ws.transport.mail.MailMessageReceiver">
<property name="storeUri" value="imap://ajwpi21:sjantaL.@imap.xs4all.nl/INBOX"/>
<property name="messageFactory" ref="messageFactory"/>
<property name="messageReceiver">
<bean class="org.springframework.ws.transport.SimpleTestingMessageReceiver"/>
</property>
</bean>
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<!-- define an MBeanExporter -->
<bean id="mbeanExporter" class="org.springframework.jmx.export.MBeanExporter">
<!-- the beans to be exported to JMX -->
<property name="beans">
<map>
<entry key="spring-ws:service=messagingContainer">
<ref local="messagingReceiver"/>
</entry>
</map>
</property>
<property name="assembler">
<bean class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
<property name="interfaceMappings">
<props>
<prop key="spring-ws:service=messagingContainer">org.springframework.context.Lifecycle</prop>
</props>
</property>
</bean>
</property>
</bean>
</beans>

View File

@@ -2,19 +2,14 @@
<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="messagingContainer" class="org.springframework.ws.transport.tcp.TcpMessagingContainer">
<property name="port" value="9999"/>
<property name="bindAddress" value="localhost"/>
<bean id="messagingReceiver" class="org.springframework.ws.transport.tcp.TcpMessageReceiver">
<property name="messageFactory" ref="messageFactory"/>
<property name="messageReceiver">
<bean class="org.springframework.ws.transport.SimpleTestingMessageReceiver"/>
</property>
</bean>
<bean id="tcpSender" class="org.springframework.ws.transport.tcp.TcpMessageSender">
<property name="port" value="9999"/>
<property name="address" value="localhost"/>
</bean>
<bean id="tcpSender" class="org.springframework.ws.transport.tcp.TcpMessageSender" />
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
@@ -24,7 +19,7 @@
<property name="beans">
<map>
<entry key="spring-ws:service=messagingContainer">
<ref local="messagingContainer"/>
<ref local="messagingReceiver"/>
</entry>
</map>
</property>