diff --git a/core/src/main/java/org/springframework/ws/transport/http/HttpServletConnection.java b/core/src/main/java/org/springframework/ws/transport/http/HttpServletConnection.java
index 1f381f65..1157adf5 100644
--- a/core/src/main/java/org/springframework/ws/transport/http/HttpServletConnection.java
+++ b/core/src/main/java/org/springframework/ws/transport/http/HttpServletConnection.java
@@ -69,6 +69,10 @@ public class HttpServletConnection extends AbstractReceiverConnection
statusCodeSet = true;
}
+ /*
+ * Errors
+ */
+
public boolean hasError() throws IOException {
return false;
}
diff --git a/core/src/main/java/org/springframework/ws/transport/http/HttpTransportConstants.java b/core/src/main/java/org/springframework/ws/transport/http/HttpTransportConstants.java
index 6a46c6a9..28376cac 100644
--- a/core/src/main/java/org/springframework/ws/transport/http/HttpTransportConstants.java
+++ b/core/src/main/java/org/springframework/ws/transport/http/HttpTransportConstants.java
@@ -44,6 +44,9 @@ public interface HttpTransportConstants extends TransportConstants {
/** The "404 Not Found" status code. */
int STATUS_NOT_FOUND = 404;
+ /** The "405 Method Not Allowed" status code. */
+ int STATUS_METHOD_NOT_ALLOWED = 405;
+
/** The "500 Server Error" status code. */
int STATUS_INTERNAL_SERVER_ERROR = 500;
diff --git a/sandbox/src/main/java/org/springframework/ws/transport/http/HttpExchangeConnection.java b/sandbox/src/main/java/org/springframework/ws/transport/http/HttpExchangeConnection.java
new file mode 100644
index 00000000..fae49d5a
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/transport/http/HttpExchangeConnection.java
@@ -0,0 +1,139 @@
+/*
+ * 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.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import com.sun.net.httpserver.HttpExchange;
+
+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;
+
+/**
+ * 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;
+
+ /** Constructs a new exchange connection with the given HttpExchange. */
+ protected HttpExchangeConnection(HttpExchange httpExchange) {
+ Assert.notNull(httpExchange, "'httpExchange' must not be null");
+ this.httpExchange = httpExchange;
+ }
+
+ /** Returns the HttpExchange for this connection. */
+ public HttpExchange getHttpExchange() {
+ return httpExchange;
+ }
+
+ public void endpointNotFound() {
+ responseStatusCode = HttpTransportConstants.STATUS_NOT_FOUND;
+ }
+
+ protected void onClose() throws IOException {
+ httpExchange.close();
+ }
+
+ /*
+ * Errors
+ */
+
+ public boolean hasError() throws IOException {
+ return false;
+ }
+
+ public String getErrorMessage() throws IOException {
+ return null;
+ }
+
+ /*
+ * Receiving request
+ */
+
+ protected Iterator getRequestHeaderNames() throws IOException {
+ return httpExchange.getRequestHeaders().keySet().iterator();
+ }
+
+ protected Iterator getRequestHeaders(String name) throws IOException {
+ List headers = httpExchange.getRequestHeaders().get(name);
+ return headers != null ? headers.iterator() : Collections.EMPTY_LIST.iterator();
+ }
+
+ protected InputStream getRequestInputStream() throws IOException {
+ return httpExchange.getRequestBody();
+ }
+
+ /*
+ * Sending response
+ */
+
+ protected void addResponseHeader(String name, String value) throws IOException {
+ httpExchange.getResponseHeaders().add(name, value);
+ }
+
+ protected OutputStream getResponseOutputStream() throws IOException {
+ if (responseBuffer == null) {
+ responseBuffer = new ByteArrayOutputStream();
+ }
+ return responseBuffer;
+ }
+
+ protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
+ byte[] buf = responseBuffer.toByteArray();
+ httpExchange.sendResponseHeaders(responseStatusCode, buf.length);
+ OutputStream responseBody = httpExchange.getResponseBody();
+ FileCopyUtils.copy(buf, responseBody);
+ }
+
+ /*
+ * 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;
+ }
+ }
+
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/transport/http/HttpServerFactoryBean.java b/sandbox/src/main/java/org/springframework/ws/transport/http/HttpServerFactoryBean.java
new file mode 100644
index 00000000..f9a349eb
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/transport/http/HttpServerFactoryBean.java
@@ -0,0 +1,201 @@
+/*
+ * 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 java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.Lifecycle;
+import org.springframework.util.Assert;
+
+/**
+ * Factory bean for the HTTP server built into Java 6.
+ *
+ * @author Arjen Poutsma
+ * @see
+ * @since 1.5.0
+ */
+public class HttpServerFactoryBean implements ApplicationContextAware, InitializingBean, Lifecycle, FactoryBean {
+
+ private static final Log logger = LogFactory.getLog(HttpServerFactoryBean.class);
+
+ public static final int DEFAULT_PORT = 8080;
+
+ private InetAddress bindAddress;
+
+ private int port = DEFAULT_PORT;
+
+ private int backlog = -1;
+
+ private boolean autoStartup = true;
+
+ private boolean running = false;
+
+ private final Object lifecycleMonitor = new Object();
+
+ private HttpServer httpServer;
+
+ private Map handlerMap = new HashMap();
+
+ private ApplicationContext applicationContext;
+
+ /**
+ * Set whether to automatically start the receiver after initialization.
+ *
true; set this to false to allow for manual startup.
+ */
+ public void setAutoStartup(boolean autoStartup) {
+ this.autoStartup = autoStartup;
+ }
+
+ /** Sets the port the server will bind to. */
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ /** Sets the server back log. */
+ public void setBacklog(int backlog) {
+ this.backlog = backlog;
+ }
+
+ public void setHandlers(Properties handlers) {
+ this.handlerMap.putAll(handlers);
+ }
+
+ public void setHandlerMap(Map handlerMap) {
+ this.handlerMap.putAll(handlerMap);
+ }
+
+ /**
+ * Sets the local internet address the server will bind to. By default, it will accept connections on any/all local
+ * addresses.
+ *
+ * @throws UnknownHostException when the given address is not known
+ * @see ServerSocket#ServerSocket(int,int,java.net.InetAddress)
+ */
+ public void setBindAddress(String bindAddress) throws UnknownHostException {
+ this.bindAddress = InetAddress.getByName(bindAddress);
+ }
+
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ this.applicationContext = applicationContext;
+ }
+
+ public void afterPropertiesSet() throws IOException {
+ if (bindAddress == null) {
+ bindAddress = InetAddress.getLocalHost();
+ }
+ InetSocketAddress bindSocketAddress = new InetSocketAddress(bindAddress, port);
+ httpServer = HttpServer.create(bindSocketAddress, backlog);
+ registerContexts(this.handlerMap);
+ if (autoStartup) {
+ start();
+ }
+ }
+
+ protected void registerContexts(Map handlerMap) {
+ if (handlerMap.isEmpty()) {
+ logger.warn("Neither 'contextMap' nor 'contexts' set on HttpServerFactoryBean");
+ }
+ else {
+ Iterator it = handlerMap.keySet().iterator();
+ while (it.hasNext()) {
+ String path = (String) it.next();
+ Object handler = handlerMap.get(path);
+ // Prepend with slash if not already present.
+ if (!path.startsWith("/")) {
+ path = "/" + path;
+ }
+ registerHandler(path, handler);
+ }
+ }
+ }
+
+ protected void registerHandler(String path, Object handler) throws BeansException, IllegalStateException {
+ Assert.notNull(path, "Path must not be null");
+ Assert.notNull(handler, "Handler object must not be null");
+
+ // Eagerly resolve handler if referencing singleton via name.
+ if (handler instanceof String) {
+ String handlerName = (String) handler;
+ if (applicationContext.isSingleton(handlerName)) {
+ handler = applicationContext.getBean(handlerName, HttpHandler.class);
+ }
+ }
+ if (handler == null || !(handler instanceof HttpHandler)) {
+ throw new IllegalStateException("Cannot resolve handler [" + handler + "] to HttpHandler instance");
+ }
+ httpServer.createContext(path, (HttpHandler) handler);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Mapped path [" + path + "] onto handler [" + handler + "]");
+ }
+ }
+
+ public void start() {
+ if (logger.isInfoEnabled()) {
+ logger.info("Starting HttpServer [" + httpServer.getAddress() + "]");
+ }
+ synchronized (lifecycleMonitor) {
+ running = true;
+ lifecycleMonitor.notifyAll();
+ }
+ httpServer.start();
+ }
+
+ public void stop() {
+ synchronized (lifecycleMonitor) {
+ running = false;
+ lifecycleMonitor.notifyAll();
+ }
+ httpServer.stop(0);
+ }
+
+ public boolean isRunning() {
+ synchronized (lifecycleMonitor) {
+ return running;
+ }
+ }
+
+ public Object getObject() throws Exception {
+ return httpServer;
+ }
+
+ public Class getObjectType() {
+ return HttpServer.class;
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/transport/http/WebServiceHttpHandler.java b/sandbox/src/main/java/org/springframework/ws/transport/http/WebServiceHttpHandler.java
new file mode 100644
index 00000000..e9179377
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/transport/http/WebServiceHttpHandler.java
@@ -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.http;
+
+import java.io.IOException;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+
+import org.springframework.ws.transport.WebServiceConnection;
+import org.springframework.ws.transport.support.SimpleWebServiceMessageReceiverObjectSupport;
+
+/**
+ * @author Arjen Poutsma
+ * @since 1.5.0
+ */
+public class WebServiceHttpHandler extends SimpleWebServiceMessageReceiverObjectSupport implements HttpHandler {
+
+ public void handle(HttpExchange httpExchange) throws IOException {
+ if ("POST".equals(httpExchange.getRequestMethod())) {
+ WebServiceConnection connection = new HttpExchangeConnection(httpExchange);
+ try {
+ handleConnection(connection);
+ }
+ catch (Exception ex) {
+ logger.error(ex);
+ }
+ }
+ else {
+ httpExchange.sendResponseHeaders(HttpTransportConstants.STATUS_METHOD_NOT_ALLOWED, -1);
+ httpExchange.close();
+ }
+ }
+}
diff --git a/sandbox/src/test/java/org/springframework/ws/transport/http/Driver.java b/sandbox/src/test/java/org/springframework/ws/transport/http/Driver.java
new file mode 100644
index 00000000..44c9ded6
--- /dev/null
+++ b/sandbox/src/test/java/org/springframework/ws/transport/http/Driver.java
@@ -0,0 +1,39 @@
+/*
+ * 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.HttpServer;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * @author Arjen Poutsma
+ * @since 1.5.0
+ */
+public class Driver {
+
+ public static void main(String[] args) throws IOException {
+ ApplicationContext context =
+ new ClassPathXmlApplicationContext("httpserver-applicationContext.xml", Driver.class);
+ HttpServer server = (HttpServer) context.getBean("httpServer");
+ System.in.read();
+ }
+
+}
diff --git a/sandbox/src/test/java/org/springframework/ws/transport/http/DummyHandler.java b/sandbox/src/test/java/org/springframework/ws/transport/http/DummyHandler.java
new file mode 100644
index 00000000..6540fb1d
--- /dev/null
+++ b/sandbox/src/test/java/org/springframework/ws/transport/http/DummyHandler.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.ws.transport.http;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+
+import org.springframework.util.FileCopyUtils;
+
+/**
+ * @author Arjen Poutsma
+ * @since 1.5.0
+ */
+public class DummyHandler implements HttpHandler {
+
+ public void handle(HttpExchange exchange) throws IOException {
+
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os));
+ writer.write("Hello world!");
+ writer.flush();
+
+ byte[] buf = os.toByteArray();
+ exchange.sendResponseHeaders(HttpTransportConstants.STATUS_OK, buf.length);
+ FileCopyUtils.copy(buf, exchange.getResponseBody());
+ exchange.close();
+ }
+}
diff --git a/sandbox/src/test/java/org/springframework/ws/transport/http/HttpServerFactoryBeanTest.java b/sandbox/src/test/java/org/springframework/ws/transport/http/HttpServerFactoryBeanTest.java
new file mode 100644
index 00000000..349a3d5c
--- /dev/null
+++ b/sandbox/src/test/java/org/springframework/ws/transport/http/HttpServerFactoryBeanTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright ${YEAR} 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 junit.framework.TestCase;
+
+public class HttpServerFactoryBeanTest extends TestCase {
+
+ private HttpServerFactoryBean bean;
+
+ protected void setUp() throws Exception {
+ bean = new HttpServerFactoryBean();
+ }
+}
\ No newline at end of file
diff --git a/sandbox/src/test/resources/org/springframework/ws/transport/http/httpserver-applicationContext.xml b/sandbox/src/test/resources/org/springframework/ws/transport/http/httpserver-applicationContext.xml
new file mode 100644
index 00000000..c9cd80b0
--- /dev/null
+++ b/sandbox/src/test/resources/org/springframework/ws/transport/http/httpserver-applicationContext.xml
@@ -0,0 +1,16 @@
+
+true; set this to false to allow for manual startup.
*/
@@ -64,16 +60,12 @@ public abstract class AbstractStandaloneMessageReceiver extends SimpleWebService
this.autoStartup = autoStartup;
}
- /**
- * Calls {@link #activate()} when the BeanFactory initializes the receiver instance.
- */
+ /** Calls {@link #activate()} when the BeanFactory initializes the receiver instance. */
public void afterPropertiesSet() throws Exception {
activate();
}
- /**
- * Calls {@link #shutdown()} when the BeanFactory destroys the receiver instance.
- */
+ /** Calls {@link #shutdown()} when the BeanFactory destroys the receiver instance. */
public void destroy() {
shutdown();
}
@@ -93,9 +85,7 @@ public abstract class AbstractStandaloneMessageReceiver extends SimpleWebService
}
}
- /**
- * Start this server.
- */
+ /** Start this server. */
public final void start() {
synchronized (lifecycleMonitor) {
running = true;
@@ -104,9 +94,7 @@ public abstract class AbstractStandaloneMessageReceiver extends SimpleWebService
onStart();
}
- /**
- * Stop this server.
- */
+ /** Stop this server. */
public final void stop() {
synchronized (lifecycleMonitor) {
running = false;
@@ -115,9 +103,7 @@ public abstract class AbstractStandaloneMessageReceiver extends SimpleWebService
onStop();
}
- /**
- * Shut down this server.
- */
+ /** Shut down this server. */
public final void shutdown() {
synchronized (lifecycleMonitor) {
running = false;
@@ -134,18 +120,12 @@ public abstract class AbstractStandaloneMessageReceiver extends SimpleWebService
*/
protected abstract void onActivate() throws Exception;
- /**
- * Template method invoked when {@link #start()} is invoked.
- */
+ /** Template method invoked when {@link #start()} is invoked. */
protected abstract void onStart();
- /**
- * Template method invoked when {@link #stop()} is invoked.
- */
+ /** Template method invoked when {@link #stop()} is invoked. */
protected abstract void onStop();
- /**
- * Template method invoked when {@link #shutdown()} is invoked.
- */
+ /** Template method invoked when {@link #shutdown()} is invoked. */
protected abstract void onShutdown();
}