/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.axis2.transport.http.mock.server;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.apache.http.ConnectionClosedException;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpServerConnection;
import org.apache.http.HttpStatus;
import org.apache.http.entity.ContentProducer;
import org.apache.http.entity.EntityTemplate;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.DefaultHttpResponseFactory;
import org.apache.http.impl.DefaultHttpServerConnection;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpRequestHandler;
import org.apache.http.protocol.HttpRequestHandlerRegistry;
import org.apache.http.protocol.HttpService;
import org.apache.http.protocol.ResponseConnControl;
import org.apache.http.protocol.ResponseContent;
import org.apache.http.protocol.ResponseDate;
import org.apache.http.protocol.ResponseServer;
import org.apache.http.util.EntityUtils;
/**
* The purpose of this server application is facilitate to HTTP related test
* cases as a back end server based on httpcore. Original code copied from
* ElementalHttpServer class from httpcore component of Apache HTTPComponents
* project.
*
* @see http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/httpcore/src
* /examples/org/apache/http/examples/ElementalHttpServer.java
* @since 1.7.0
*
*/
public class BasicHttpServerImpl implements BasicHttpServer {
private RequestListenerThread serverThread;
private Map<String, String> headers;
private byte[] content;
private String method;
private String url;
private String responseTemplate;
boolean close;
public BasicHttpServerImpl() {
headers = new HashMap<String, String>();
content = null;
close = true;
}
/*
* (non-Javadoc)
*
* @see org.apache.axis2.transport.http.mock.server.BasicHttpServer#start()
*/
public void start() throws Exception {
serverThread = new RequestListenerThread(this);
serverThread.setDaemon(false);
serverThread.start();
}
public int getPort() {
return serverThread.getServersocket().getLocalPort();
}
/*
* (non-Javadoc)
*
* @see org.apache.axis2.transport.http.mock.server.BasicHttpServer#stop()
*/
public void stop() throws Exception {
if (close) {
serverThread.getServersocket().close();
}
}
public Map<String, String> getHeaders() {
return headers;
}
public byte[] getContent() {
return content;
}
public String getMethod() {
return method;
}
public String getUrl() {
return url;
}
public void setHeaders(Map<String, String> headers) {
}
public void setContent(byte[] content) {
this.content = content;
}
public void setMethod(String method) {
this.method = method;
}
public void setUrl(String url) {
this.url = url;
}
public int getEntityContentLength() {
return content.length;
}
public String getResponseTemplate() {
return responseTemplate;
}
public void setResponseTemplate(String responseTemplate) {
this.responseTemplate = responseTemplate;
}
public void setCloseManully(boolean close) {
this.close = close;
}
static class HttpServiceHandler implements HttpRequestHandler {
BasicHttpServer server;
public HttpServiceHandler(BasicHttpServer server) {
this.server = server;
}
/*
* (non-Javadoc)
*
* @see
* org.apache.http.protocol.HttpRequestHandler#handle(org.apache.http
* .HttpRequest, org.apache.http.HttpResponse,
* org.apache.http.protocol.HttpContext)
*/
public void handle(final HttpRequest request, final HttpResponse response,
final HttpContext context) throws HttpException, IOException {
server.setMethod(request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH));
server.setUrl(request.getRequestLine().getUri());
// process HTTP Headers
for (Header header : request.getAllHeaders()) {
server.getHeaders().put(header.getName(), header.getValue());
}
// TODO implement processing for other Entity types
if (request instanceof HttpEntityEnclosingRequest) {
HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
byte[] entityContent = EntityUtils.toByteArray(entity);
server.setContent(entityContent);
} else if (request instanceof BasicHttpRequest) {
BasicHttpRequest bhr = (BasicHttpRequest) request;
server.setContent(bhr.getRequestLine().getUri().getBytes());
}
// Handle response based on "responseTemplate"
EntityTemplate body = null;
if (server.getResponseTemplate() == null
|| server.getResponseTemplate().equals(BasicHttpServer.RESPONSE_HTTP_OK_XML)) {
response.setStatusCode(HttpStatus.SC_OK);
body = new EntityTemplate(new ContentProducer() {
public void writeTo(final OutputStream outstream) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write("<Response>ok<Response>");
writer.flush();
}
});
response.setEntity(body);
} else if (server.getResponseTemplate().equals(
BasicHttpServer.RESPONSE_HTTP_OK_LOOP_BACK)) {
response.setStatusCode(HttpStatus.SC_OK);
body = new EntityTemplate(new ContentProducer() {
public void writeTo(final OutputStream outstream) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write(new String(server.getContent()));
writer.flush();
}
});
} else if (server.getResponseTemplate().equals(BasicHttpServer.RESPONSE_HTTP_404)) {
response.setStatusCode(HttpStatus.SC_NOT_FOUND);
body = new EntityTemplate(new ContentProducer() {
public void writeTo(final OutputStream outstream) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write("<html><body><h1>");
writer.write(" not found - 404");
writer.write("</h1></body></html>");
writer.flush();
}
});
} else if (server.getResponseTemplate().equals(BasicHttpServer.RESPONSE_HTTP_200)) {
response.setStatusCode(HttpStatus.SC_OK);
body = new EntityTemplate(new ContentProducer() {
public void writeTo(final OutputStream outstream) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write("<Response> SC_ACCEPTED 202 <Response>");
writer.flush();
}
});
} else if (server.getResponseTemplate().equals(BasicHttpServer.RESPONSE_HTTP_201)) {
response.setStatusCode(HttpStatus.SC_CREATED);
body = new EntityTemplate(new ContentProducer() {
public void writeTo(final OutputStream outstream) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
//writer.write("<Response> SC_ACCEPTED 202 <Response>");
writer.flush();
}
});
} else if (server.getResponseTemplate().equals(BasicHttpServer.RESPONSE_HTTP_202)) {
response.setStatusCode(HttpStatus.SC_ACCEPTED);
body = new EntityTemplate(new ContentProducer() {
public void writeTo(final OutputStream outstream) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
//writer.write("<Response> SC_ACCEPTED 202 <Response>");
writer.flush();
}
});
} else if (server.getResponseTemplate().equals(BasicHttpServer.RESPONSE_HTTP_400)) {
response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
body = new EntityTemplate(new ContentProducer() {
public void writeTo(final OutputStream outstream) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
//writer.write("<Response> SC_ACCEPTED 202 <Response>");
writer.flush();
}
});
} else if (server.getResponseTemplate().equals(BasicHttpServer.RESPONSE_HTTP_500)) {
response.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
body = new EntityTemplate(new ContentProducer() {
public void writeTo(final OutputStream outstream) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write(" Server Error");
writer.flush();
}
});
}
// TODO - customize to send content type depend on expectations.
body.setContentType("text/html; charset=UTF-8");
response.setEntity(body);
}
}
static class RequestListenerThread extends Thread {
private final ServerSocket serversocket;
private final HttpParams params;
private final HttpService httpService;
/**
* Instantiates a new request listener thread.
*
* @param port
* the port
* @param server
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public RequestListenerThread(BasicHttpServer server) throws IOException {
this.serversocket = new ServerSocket(0);
this.params = new BasicHttpParams();
// Basic configuration.
this.params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000)
.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
.setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1");
BasicHttpProcessor httpproc = new BasicHttpProcessor();
httpproc.addInterceptor(new ResponseDate());
httpproc.addInterceptor(new ResponseServer());
httpproc.addInterceptor(new ResponseContent());
httpproc.addInterceptor(new ResponseConnControl());
// Set up request handlers
HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry();
reqistry.register("*", new HttpServiceHandler(server));
// Set up the HTTP service
this.httpService = new HttpService(httpproc, new DefaultConnectionReuseStrategy(),
new DefaultHttpResponseFactory());
this.httpService.setParams(this.params);
this.httpService.setHandlerResolver(reqistry);
}
/**
* Gets the serversocket.
*
* @return the serversocket
*/
public ServerSocket getServersocket() {
return serversocket;
}
/*
* (non-Javadoc)
*
* @see java.lang.Thread#run()
*/
public void run() {
System.out.println("Listening on port " + this.serversocket.getLocalPort());
while (!Thread.interrupted()) {
try {
// Set up HTTP connection
Socket socket = this.serversocket.accept();
DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
System.out.println("Incoming connection from " + socket.getInetAddress());
conn.bind(socket, this.params);
// Start worker thread
Thread t = new WorkerThread(this.httpService, conn);
t.setDaemon(false);
t.start();
} catch (InterruptedIOException ex) {
break;
} catch (IOException e) {
System.err.println("I/O error initialising connection thread: "
+ e.getMessage());
break;
}
}
}
}
static class WorkerThread extends Thread {
private final HttpService httpservice;
private final HttpServerConnection conn;
/**
* Instantiates a new worker thread.
*
* @param httpservice
* the httpservice
* @param conn
* the conn
*/
public WorkerThread(final HttpService httpservice, final HttpServerConnection conn) {
super();
this.httpservice = httpservice;
this.conn = conn;
}
/*
* (non-Javadoc)
*
* @see java.lang.Thread#run()
*/
public void run() {
System.out.println("New connection thread");
HttpContext context = new BasicHttpContext(null);
try {
while (!Thread.interrupted() && this.conn.isOpen()) {
this.httpservice.handleRequest(this.conn, context);
}
} catch (ConnectionClosedException ex) {
System.err.println("Client closed connection");
} catch (IOException ex) {
System.err.println("I/O error: " + ex.getMessage());
} catch (HttpException ex) {
System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage());
} finally {
try {
this.conn.shutdown();
} catch (IOException ignore) {
}
}
}
}
}